Sub-agents stream `assistant.reasoning_delta` but never emit the `assistant.reasoning` close event documented as always-sent
- Vorherrschende Sprache
- Java
- Sterne
- 10.5k
- Forks
- 1.5k
- Ø Merge
- 1 T. 11 Std.
- Gemergte PRs (30 T.)
- 128
Beschreibung
## Summary
Per the Python SDK README:
> Note: `assistant.message` and `assistant.reasoning` (final events) are **always sent regardless of streaming setting**.
And per the schema docstring on `AssistantReasoningDeltaData.reasoningId` (`session-events.schema.json` line 520-522):
> Reasoning block ID this delta belongs to, **matching the corresponding `assistant.reasoning` event**.
In practice, sub-agents stream `assistant.reasoning_delta` events (with `agentId` set on the event), but **the matching `assistant.reasoning` close is never emitted**. Instead the reasoning content lands in the sub-agent's `assistant.message.reasoningText` / `reasoningOpaque` fields. Consumers that rely on the documented per-`reasoningId` close event end up with permanently-orphaned streaming reasoning blocks for every sub-agent turn.
## Environment
- `@github/copilot` (CLI bundle): `1.0.49`
- `github-copilot-sdk` (Python): `1.0.0b4`
- Default provider (not BYOK)
- Reasoning model in use (Claude Opus / Sonnet via the default backend)
## What I'd expect (per docs)
For every sub-agent reasoning block: one or more `assistant.reasoning_delta` events with a given `reasoningId`, followed by exactly one `assistant.reasoning` event carrying that same `reasoningId` and the complete `content` — symmetric with master-agent reasoning.
## What actually happens
Code path (built bundle, `sdk/index.js` ~ L4554, inside `createAgentCallbackBridge`):
```js
case "reasoning":
u.reasoningId && u.deltaContent &&
this.emitEphemeral("assistant.reasoning_delta",
{ reasoningId: u.reasoningId, deltaContent: u.deltaContent }, r);
// ...later, when the sub-agent's response completes:
this.emit("assistant.message",
{ parentToolCallId: r, messageId: kr(), ..., reasoningOpaque, reasoningText }, r);
// No paired emit("assistant.reasoning", ...) here.
```
Compare to the main-agent path (`sdk/index.js` ~ L4541) which does:
```js
this.emit("assistant.message", { ... });
Ho && this.emitEphemeral("assistant.reasoning", { reasoningId: Ho, content: Yi ?? "" });
```
So the close emit is conditional on the main-agent code path and absent from the sub-agent bridge.
## Empirical evidence
Across six debug-mode session JSONL transcripts (~17K reasoning_delta events total) captured from a production run with multiple custom sub-agents (`planner`, `implementer`, `profiler_agent`):
- Every `assistant.reasoning_delta` carrying a sub-agent's `agentId` is **never** followed by a matching `assistant.reasoning`.
- Sub-agent `assistant.message` events for those same turns *do* carry non-empty `reasoningText` (often several KB) and `reasoningOpaque`, so the data is being retained — it just travels via the message payload instead of the documented close event.
- The two log files in the same run that contain *no* sub-agent activity (master-only) have zero orphan reasoning streams. The four files with sub-agent activity have 25 orphan streams collectively. The pattern is deterministic and 1:1 with sub-agent boundaries.
## Suggested fixes (either or both)
1. **Behavior fix:** also emit `assistant.reasoning` from the sub-agent bridge after `endCurrentStreamingMessage`, mirroring the main-agent path. This keeps the documented contract (1:1 `reasoning_delta` → `assistant.reasoning`) and matches downstream consumer expectations.
2. **Documentation fix:** if the embed-in-`assistant.message` shape is intentional for sub-agents, document it explicitly on `AssistantReasoningDeltaData` (e.g. "for sub-agent reasoning, the closing `assistant.message` event for the same `agentId` carries the complete content in `reasoningText` / `reasoningOpaque`; no separate `assistant.reasoning` event is emitted") and in the streaming-events guide referenced by #922.
Related: #922 (CLOSED — "Extended thinking/reasoning events not firing for OpenAI and Anthropic models via Copilot SDK"), #1064 (CLOSED — "BYOK Anthropic provider missing multiple session events ... reasoning ..."). Same family of bug but neither covers this specific main-vs-sub-agent asymmetry on the default provider.
Happy to provide the full JSONL fixtures if helpful.
Beitragsleitfaden
Bewertung
Dieses Issue wurde noch nicht bewertet.