ai, ai-persistence: a nested subagent that waits runs again from the start under withPersistence
Maintainer thường phản hồi trong vòng 1 ngày
@tombeckenham đang làm issue này rồi.
Từ ngày 22/10/2026.
Đánh giá
Issue này chưa được đánh giá.
Mô tả
TanStack AI version
@tanstack/ai and @tanstack/ai-persistence on main, after #1806.
Framework/Library version
Node 24.8.0. Server only.
Describe the bug and the steps to reproduce it
Under withPersistence, a nested subagent that waits on an interrupt runs again from the start after the resume.
Since #1806, a waiting child resumes from loadChild(...).pending, the stored messages, not from the client card. The store keeps a nested child in its own thread (subagent:<id>). So the pending of the outer child has its tool call, but no card for the nested child that waits. Core then finds no suspended child inside the outer child (readSubagentTurn in agents/turn.ts), and runs the nested child again.
Steps:
- A lead agent calls a
researcheragent tool. The researcher calls awriteragent tool. The writer callswrite_file, which needs approval. - Run the turn. It stops on the writer's approval.
- Resolve the approval.
- The writer runs again from its prompt.
write_filedoes not run. A real model asks for the approval again.
packages/ai-harness/tests/subagent-waits.test.ts "waits for an agent that an agent tool calls, and both go on" on feat/harness-core fails on this.
A quick fix copies the nested cards from the client onto the stored message. That trusts the client's messages for the nested child, which #1806 closed one level up: a forged card can change the args of the nested tool call before the approval runs it. Do not ship that.
Fix design: the card is a pointer, the store gives the contents
LoadChildtakes an optional parent (packages/ai/src/activities/chat/middleware/load-child.ts):(subagentRunId, options?: { parentSubagentRunId?: string }). The result also getsinterruptIds?andparentToolCallId?, read from the stored info, so the card is not the source.withPersistencepasses the parent on (packages/ai-persistence/src/middleware.ts,provideLoadChild): with a parent, the caller is{ threadId: ctx.threadId, subagentRunId: parentSubagentRunId }. The existing check inloadChild(marker.parentThreadId !== ownerThread(caller)) proves that the nested child belongs to that parent. Core asks for a nested child only after it loaded the parent, so the chain is checked from the top.loadChildreturnsinterruptIdsandparentToolCallId(packages/ai-persistence/src/subagent-runs.ts), fromstoredSubagentInfo.- Core rebuilds nested cards from the store (
packages/ai/src/activities/chat/agents/spawn.ts,runChild): for each card subagent part whoseparentToolCallIdis a tool call in the storedpending, callload(id, { parentSubagentRunId }). Nopendingmeans throw "not waiting", as the top level does. Build the part from the store: messages frompending,interruptIds,parentToolCallId,status: 'suspended'. Take only the id from the card. Repeat for deeper nesting.
The LoadChild change is additive. A loader that ignores the parent fails closed for nested children.
Tests:
- The nested resume:
write_fileruns once after the approval, and the writer model is called twice. - A nested card with changed
write_fileargs does not change what runs (like the #1806 forged-card test, one level down). - A nested card that names a child of another parent throws "not waiting".
Docs: the pending line in docs/chat/subagents.md. Add a changeset.
Your Minimal, Reproducible Example - (Sandbox Highly Recommended)
packages/ai-harness/tests/subagent-waits.test.ts on feat/harness-core, test "waits for an agent that an agent tool calls, and both go on". The same three-level setup works with plain chat() and withPersistence on main.
Do you intend to try to help solve this bug with your own PR?
Yes, I am already working on a fix
Terms & Code of Conduct
- I agree to follow this project's Code of Conduct
- I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.
- Ngôn ngữ chính
- TypeScript
- Star
- 3.2k
- Fork
- 372
- Merge trung bình
- 1 ngày 16 giờ
- Pull request đã merge (30 ngày)
- 244
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của TanStack/ai
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 35/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Durable resume through withPersistence never fills ctx.inputResponse for mcp_input interruptsCó thể đã có người làm @tombeckenham đã nhận 3 ngày trước. Đang mởwaiting-on: maintainer
TanStack/ai#1885 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
ai-ollama: streamed chat() reports finishReason "stop" when done_reason is "length"Có thể đã có người làm @AlemTuzlak đã nhận 4 ngày trước. Đang mởwaiting-on: maintainer
TanStack/ai#1852 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Discriminate status-dependent record and option types (RunRecord, SessionIndexEntry, InputState, durable-only options)Có thể đã có người làm @jherr đã nhận 10 ngày trước. Đang mởenhancement waiting-on: maintainer
TanStack/ai#1799 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
move to modelschemasCó thể đã có người làm @jherr đã nhận 11 ngày trước. Đang mởhas-pr waiting-on: maintainer
TanStack/ai#1788 · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
Merit-Systems/x402scan#1312 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Native Web
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 80/100
digitalfabrik/integreat-app#4517 ·
Maintainer thường phản hồi trong vòng 2 ngày
-
TLS guide repeats certs/ in the certificate directoryCó thể đã có người làm @maheshrijal đã nhận hôm nay. Đang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 92/100
prometheus/docs#3156 ·
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 83/100
medusajs/dtc-starter#90 ·
Maintainer thường phản hồi trong vòng 1 ngày