anomalyco / anomalyco/opencode
opencode run --format json does not emit message.part.delta events in real time
@rekram1-node is already working on this.
Since Jul 24, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Description
Description
opencode run --format json does not emit text delta events while the model is generating a response.
The underlying OpenCode event stream produces message.part.delta events in real time, but the run command ignores them. It only emits one complete text event after the text part has finished.
This makes opencode run --format json unsuitable for integrations that need streaming output, progress reporting, or long-running task observability.
Environment
- OpenCode: 1.18.4
- Also reproduced with: 1.17.15
- Platform: macOS arm64
- Output format:
json - Provider: OpenAI-compatible third-party provider
The current dev branch appears to have the same behavior.
Reproduction
Run a prompt that takes several seconds to generate:
opencode run \
--format json \
--model provider/model \
"Write exactly 50 numbered lines about remote software collaboration. Do not use tools."
Record the time at which each stdout line is received.
Actual behavior
The output looks approximately like this:
06:44:59.965 {"type":"step_start", ...}
# No stdout events while the model is generating
06:45:09.299 {"type":"text","part":{"type":"text","text":"<complete response>","time":{"start":...,"end":...}}}
06:45:09.299 {"type":"step_finish", ...}
The complete response is emitted as a single text event immediately before step_finish.
No token-level or chunk-level text events are written to stdout during generation.
Expected behavior
When --format json is used, opencode run should expose text deltas as they are received, for example:
{"type":"text_delta","sessionID":"...","partID":"...","delta":"First chunk"}
{"type":"text_delta","sessionID":"...","partID":"...","delta":" second chunk"}
The final complete text event may still be emitted for compatibility.
Alternatively, this behavior could be enabled explicitly with a flag such as:
opencode run --format json --stream
Investigation
OpenCode's server event stream already emits message.part.delta events in real time. This can be observed by:
- Starting
opencode serve. - Subscribing to the
/eventSSE endpoint. - Sending a prompt.
The SSE stream delivers many message.part.delta events during generation, followed by the final message.part.updated event.
However, the run command only handles message.part.updated:
https://github.com/anomalyco/opencode/blob/v1.18.4/packages/opencode/src/cli/cmd/run.ts#L850-L878
In particular, text is emitted only after part.time?.end is present:
if (part.type === "text" && part.time?.end) {
if (emit("text", { part })) continue
// ...
}
The command does not appear to handle message.part.delta.
The current dev branch appears to contain the same logic:
https://github.com/anomalyco/opencode/blob/dev/packages/opencode/src/cli/cmd/run.ts#L850-L878
Impact
Applications that integrate OpenCode through opencode run --format json cannot observe generation progress.
For long-running prompts, consumers receive step_start, then no output for tens of seconds or minutes, followed by the entire response and step_finish at nearly the same time.
This prevents consumers from reliably:
- displaying streaming responses;
- reporting intermediate progress;
- distinguishing active generation from a stalled process;
- persisting incremental output;
- implementing idle or health timeouts accurately.
The server SSE API contains the required information, but CLI-based integrations cannot access it through opencode run.
Suggested fix
Handle message.part.delta inside the run event loop and emit a JSON event containing at least:
- session ID;
- message ID or part ID;
- field name;
- delta text.
For example:
if (event.type === "message.part.delta") {
const { sessionID, messageID, partID, field, delta } = event.properties
if (sessionID !== activeSessionID) continue
if (field === "text") {
emit("text_delta", {
messageID,
partID,
delta,
})
}
}
If changing the existing JSON event contract is a compatibility concern, this could be guarded by a new --stream or --include-deltas flag.
### Plugins
_No response_
### OpenCode version
latest
### Steps to reproduce
_No response_
### Screenshot and/or share link
_No response_
### Operating System
_No response_
### Terminal
_No response_
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.