Sub-agents stream `assistant.reasoning_delta` but never emit the `assistant.reasoning` close event documented as always-sent
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 45/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 静か
- 技術スタック
- javascript, python
調査の方向性
sdk/index.js の createAgentCallbackBridge (~L4554) 付近から始め、~L4541 付近の main-agent パスと比較してください。session-events.schema.json の 520-522 行目と README の契約を確認し、sub-agents が対応する assistant.reasoning イベントを発行すべきか、assistant.message の形式を文書化すべきかを判断してください。選択した動作が一貫して実装され、記載された reasoningId イベントシーケンスに対して検証されれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Summary
Per the Python SDK README:
Note:
assistant.messageandassistant.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.reasoningevent.
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.49github-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):
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:
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_deltacarrying a sub-agent'sagentIdis never followed by a matchingassistant.reasoning. - Sub-agent
assistant.messageevents for those same turns do carry non-emptyreasoningText(often several KB) andreasoningOpaque, 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)
- Behavior fix: also emit
assistant.reasoningfrom the sub-agent bridge afterendCurrentStreamingMessage, mirroring the main-agent path. This keeps the documented contract (1:1reasoning_delta→assistant.reasoning) and matches downstream consumer expectations. - Documentation fix: if the embed-in-
assistant.messageshape is intentional for sub-agents, document it explicitly onAssistantReasoningDeltaData(e.g. "for sub-agent reasoning, the closingassistant.messageevent for the sameagentIdcarries the complete content inreasoningText/reasoningOpaque; no separateassistant.reasoningevent 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.
- 主要言語
- Java
- スター
- 10.5k
- フォーク
- 1.5k
- 平均マージ
- 1日 9時間
- マージ済み PR(30日)
- 131
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
github/copilot-sdk のほかの issue
-
agentic-workflows
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
github/copilot-sdk#2709 · コメント 1 件 ·
-
難易度 1/5 1時間未満 初心者へのやさしさ 78/100
github/copilot-sdk#2673 ·
-
bug testing
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
github/copilot-sdk#2628 ·
-
agentic-workflows
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
github/copilot-sdk#2627 · コメント 1 件 ·
-
agentic-workflows
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
github/copilot-sdk#2493 ·
github/copilot-sdk の issue をすべて見る
似ている issue
-
awaiting triage bug Causes friction Hop Gui P1 P2 Transforms
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
apache/flink-agents#1152 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
jenkinsci/blueocean-plugin#5417 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
objectionary/eo-graphs#75 ·