anthropics / anthropics/claude-agent-sdk-typescript

query() iterator ends without `result` event after subagent + end_turn

Offen
#339 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
bug
Vorherrschende Sprache
Shell
Sterne
1.8k
Forks
226
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beschreibung

## Summary

The `query()` async iterator drains cleanly **without ever yielding a terminal `SDKResultMessage`** for the main-agent turn when (a) that turn invoked the `Agent` tool / subagent, AND (b) the entry path supplies a push-based `AsyncIterable` with no further user messages buffered. The final `assistant` message is yielded with `stop_reason: "end_turn"`, then the iterator simply ends. No `result`, no error.

This is distinct from #333 — that one **hangs** after the last `tool_result`; ours **ends** after a clean `end_turn`. Same neighborhood (missing terminal event), different surface.

## Environment

- `@anthropic-ai/claude-agent-sdk` **0.2.76** (we have not yet retested on 0.3.157 — see "Will retest on latest?" below)
- Subscription auth, model `claude-sonnet-4-6`
- Container per run; one `query()` per process
- `MessageStream` is a custom push-based `AsyncIterable` that stays open between IPC-arrived user messages, specifically to keep `isSingleUserTurn=false` and allow subagents to run

## Trace evidence

A scheduled-task tick produced this session JSONL (parent-level messages only — subagent abstracted as a single tool_use/tool_result pair):

| # | type | detail |
|---|---|---|
| 4 | assistant | thinking only, stop_reason=null (partial) |
| 5 | assistant | `tool_use: Agent` (subagent invocation), stop_reason=tool_use |
| 6 | user | tool_result (subagent return) |
| 7 | assistant | thinking only, stop_reason=null (partial) |
| 8 | assistant | **~5,320 output tokens of final text, stop_reason=end_turn** |

No `type: "result"` entry follows line 8. The iterator in our consumer ends cleanly (no error thrown, no hang) with `resultCount === 0`.

The final assistant turn's content is well-formed and complete — the model finished its work. The SDK just never emitted the corresponding `SDKResultMessage`, so a consumer that relies on `result` as the signal to flush output gets nothing.

## Trigger conditions

Reproduces consistently when **all three** hold:
1. The main agent invokes the built-in `Agent` tool / subagent at least once in the turn
2. After the subagent returns, the main agent produces additional assistant content (text or further tools)
3. The driving `AsyncIterable` has no follow-up user message buffered when the main agent reaches `end_turn`

In our deployment this hit the scheduled-task entry path 100% of the time (8+ instances over a multi-hour window). When we rewrote the prompt to forbid the `Agent` tool and run the same logic inline (single turn, no subagent), the bug stopped reproducing. That is our current production mitigation alongside a defensive fallback emit in our consumer.

## Expected vs actual

- **Expected:** after `stop_reason=end_turn`, the SDK yields an `SDKResultMessage` (subtype `success` or `error_*`) and then closes the iterator.
- **Actual:** the iterator yields the `end_turn` assistant message, then closes the iterator. No result message.

## Possibly related

- #333 — similar "missing terminal event" symptom on the tool_result→assistant transition, but iterator hangs rather than ending
- #289 (resume drops tool_use/tool_result on large JSONL) — different surface but adjacent area

## Will retest on latest?

Happy to retest on 0.3.157 if helpful — wanted to file with our actual evidence (0.2.76) first since the version delta is significant and didn't want to lose the repro context. The changelog between 0.2.76 and 0.3.157 doesn't mention a fix matching this symptom, but I may have missed it.

I can also share the full session JSONL and a minimal repro harness if useful.

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.