github / github/copilot-sdk

Sub-agents stream `assistant.reasoning_delta` but never emit the `assistant.reasoning` close event documented as always-sent

Đang mở
#1,402 1 bình luận 0 reaction 0 người được giao Xem trên GitHub
bug
Ngôn ngữ chính
Java
Star
10.5k
Fork
1.5k
Merge trung bình
1 ngày 11 giờ
Pull request đã merge (30 ngày)
128

Mô tả

## 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.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.