Skip to content

Continue subagent transcripts#3586

Merged
esengine merged 12 commits into
esengine:main-v2from
lifu963:agent/subagent-transcripts-mainv2
Jun 9, 2026
Merged

Continue subagent transcripts#3586
esengine merged 12 commits into
esengine:main-v2from
lifu963:agent/subagent-transcripts-mainv2

Conversation

@lifu963

@lifu963 lifu963 commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add persisted subagent transcript storage for task and skill subagents.
  • Support continuing and forking subagent transcripts with model/effort/workspace validation.
  • Adapt the review CLI to the session-based subagent runner.

Test plan

  • go test ./...

@github-actions github-actions Bot added v2 Go rewrite (1.x) — main-v2 branch, active development tui Terminal UI / CLI (internal/cli, internal/control) skills Skill system (internal/skill, internal/tool) agent Core agent loop (internal/agent, internal/control) config Configuration & setup (internal/config) labels Jun 8, 2026
@lifu963

lifu963 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

你好!@SivanCola @esengine
f44f79784daad3aff99bd545eaa26185
5155839065a7521d936ad479bd4229aa

我对 reasonix 的 subagent 做了会话复用能力的支持!subagent 可以继续延续上一次的会话记录(不再是仅支持 fresh window),可以用在主 agent 需要与 subagent 多轮对话的场景!例如:主 agent 完成开发 -> subagent review -> fix -> 再次 review -> 再次 fix -> ... -> 直到 review 通过!
本次代码变更从方案提出到实施、测试我都严格 review 过;辛苦能看一下吗?谢谢你!

@SivanCola SivanCola left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the transcript continuation work. I found one blocking issue around failed foreground runs.

In the foreground task path, RunSubAgentWithSession errors return immediately without saving the mutated session or marking the transcript failed (internal/agent/task.go). Subagent skills have the same pattern in internal/boot/boot.go. Since Agent.Run has already appended the new user prompt and any tool results before returning errors, a failed continue_from can leave the on-disk transcript/meta at the previous completed state. A later continue_from then reloads stale history and may repeat side-effecting work.

Could you persist the updated session and mark the run failed, or otherwise make the in-place continuation non-reusable after a failed mutation, for both foreground task and subagent skill paths?

Validation I ran:

  • go test ./internal/agent ./internal/skill ./internal/boot ./internal/cli passed
  • go test ./... still fails in internal/control on TestRemoveMCPServerRemovesUnconnectedLazyPlaceholder, but that reproduces on current origin/main-v2, so I treated it as existing/environment-related.

@lifu963

lifu963 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

@SivanCola
Thanks again for the review. I pushed updates addressing the requested changes.

What changed:

  • SubagentStore.SaveFailed now persists the mutated subagent session JSONL before marking the metadata as failed.
  • Foreground task continuations now call SaveFailed when RunSubAgentWithSession fails after the run has started.
  • runAs=subagent skill continuations in boot.go now use the same failure persistence path.
  • Run errors and persistence errors are preserved with errors.Join, so the original failure is still visible while persistence risk is not hidden.
  • Pre-run setup/compatibility failures, such as incompatible tool scope, are still rejected before execution and do not mark an otherwise completed ref as failed.

Validation:

  • go test ./... passes locally.
  • I also ran a live CLI end-to-end validation against DeepSeek, which exercises the same boot.Build / Controller / agent kernel used by the desktop app:
    1. Asked the main agent to call task once with subagent prompt: Reply with exactly: subagent first turn ok.
      • It returned a subagent ref and the expected answer.
    2. Asked the main agent to call task again with continue_from=<same ref> and prompt: Continue the same subagent transcript. Reply with exactly: subagent second turn ok.
      • The same ref was reused, and the persisted subagent JSONL contained both user turns.
    3. Asked the main agent to continue the same ref with max_steps=1 and prompt: Before any final answer, call read_file on missing-file-for-failure-test.txt.
      • The subagent performed the read_file tool call, then failed/paused after the max-step limit.
      • The subagent metadata was marked failed, and the failed continuation prompt/tool result were persisted in the JSONL transcript.
    4. Tried continue_from=<same ref> again.
      • It was rejected with failed and cannot be continued, confirming the ref is no longer reusable after a failed mutation.

I also merged latest origin/main-v2 into this PR branch and resolved the boot conflict. The PR should no longer be blocked by merge conflicts.

@lifu963 lifu963 requested a review from SivanCola June 9, 2026 08:47
@github-actions github-actions Bot added the desktop Wails desktop app (desktop/**) label Jun 9, 2026
@lifu963

lifu963 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

@SivanCola @esengine

改说中文好了,哈哈。

更新一下本轮补充内容:

这次在 subagent 会话复用能力之外,补齐了对应的 lifecycle 管理,避免主会话删除后遗留 subagent transcript。

具体做了两部分:

1)为 subagent transcript 写入可靠的父会话归属

  • 新建的 task / subagent skill transcript 现在会写入 ParentSession
  • continue_from 只允许继续当前父会话 owned 的 subagent,避免两个父会话共同修改同一个 subagent transcript
  • fork_from 主要用于主会话 fork/branch 场景:新会话从旧会话 fork 出来时,历史里可能还引用旧的 subagent ref。如果新会话想复用这段 subagent 历史,就用 fork_from 复制出一个新 ref,并让它归属于新会话。这样后续删除、恢复、永久删除,都能按各自父会话清晰管理。

2)主会话 trash / restore / purge / delete 时级联处理 subagent artifacts

  • Desktop 中把父 session 放入回收站时,会把它拥有的 sa_*.jsonlsa_*.meta.json 一起移入同一个 trash item。
  • Desktop restore 时,会把这些 subagent artifacts 一起恢复回 sessions/subagents/
  • Desktop permanent delete / purge 时,会一起永久删除。
  • ACP session/delete 和 HTTP /delete-session 也会删除该父 session 拥有的 subagent artifacts。

测试方面,我做了三层验证:

  • 单元/集成测试:

    • go test ./internal/agent ./internal/boot ./internal/control ./internal/acp ./internal/serve
    • cd desktop && go test .
  • 真实 DeepSeek API E2E:

    • fresh task 能创建持久化 subagent,并写入正确 ParentSession
    • 同一父会话下 continue_from 可以继续追加 transcript。
    • 不同父会话下 continue_from 会被拒绝,并提示使用 fork_from
    • fork_from 可以复制旧 subagent transcript,生成归属于当前父会话的新 ref。
    • HTTP /delete-session 删除父会话时,只删除该父会话 owned 的 subagent,不会误删 fork 后属于其他父会话的 subagent。
  • 真实 macOS Desktop GUI 验收:

    • 编译并启动 Wails app。
    • 在真实 app 中调用 task 生成 subagent。
    • 将父 session 移入回收站后,确认父 .jsonl / .meta / checkpoint 和 owned subagent .jsonl / .meta.json 一起进入 .trash/<parent>.jsonl/
    • 从回收站恢复后,确认父 session 和 subagent artifacts 一起回到 active session 目录。
    • 永久删除后,确认父 session trash item 和 owned subagent artifacts 都被彻底删除。

另外,我也检查了当前分支与最新 origin/main-v2 的合并情况:没有阻塞性 merge conflict。本轮更新已经推送到 PR 分支。

lifu963 and others added 12 commits June 9, 2026 09:12
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Ensure persisted subagent transcripts record the active parent session and prevent in-place continuation from a different parent, keeping fork_from as the explicit copy path.

Co-authored-by: Cursor <cursoragent@cursor.com>
Move owned subagent artifacts with desktop trash/restore and delete them from hard-delete paths so parent session cleanup no longer leaves reusable child transcripts behind.

Co-authored-by: Cursor <cursoragent@cursor.com>
Persisted sub-agent transcripts made a parent session mandatory, so
`reasonix run` (headless, which never mints a session path) failed every
task/subagent-skill call with "subagent transcript parent session is
required". Fall back to a non-persisted run when no parent session is
active — restoring pre-transcript behaviour — and reserve continue_from/
fork_from for sessions that actually have a persisted owner.

Adds a headless-run regression guard plus task-level ephemeral coverage.
@esengine esengine force-pushed the agent/subagent-transcripts-mainv2 branch from 825fa6d to cf4a3d2 Compare June 9, 2026 16:16
@esengine

esengine commented Jun 9, 2026

Copy link
Copy Markdown
Owner

/e2e

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

🤖 e2e bot failed — see the run log.

@esengine

esengine commented Jun 9, 2026

Copy link
Copy Markdown
Owner

/e2e

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

🤖 Reasonix e2e benchmark

Accuracy: 4/5 (80%) · Cache hit: 78% · Tokens: 254,258 (prompt 251,307 / completion 2,951) · Compactions: 3 · Cost: ¥ 0.0647

Task Result Steps Prompt Completion Cache hit Compact Cost
compaction ❌ fail 8 128,553 1,108 58% 3 ¥ 0.0571
fix-add-bug ✅ pass 4 37,637 325 99% 0 ¥ 0.0019
fizzbuzz ✅ pass 3 28,308 522 99% 0 ¥ 0.0019
palindrome ✅ pass 3 28,226 498 99% 0 ¥ 0.0018
subagent-delegation ✅ pass 3 28,583 498 99% 0 ¥ 0.0020

Real provider run. Cache-hit % is cached prompt tokens / total prompt tokens.

agent: PR head (cf4a3d2) · triggered by @esengine

@lifu963

lifu963 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Reasonix e2e benchmark

Accuracy: 4/5 (80%) · Cache hit: 78% · Tokens: 254,258 (prompt 251,307 / completion 2,951) · Compactions: 3 · Cost: ¥ 0.0647

Task Result Steps Prompt Completion Cache hit Compact Cost
compaction ❌ fail 8 128,553 1,108 58% 3 ¥ 0.0571
fix-add-bug ✅ pass 4 37,637 325 99% 0 ¥ 0.0019
fizzbuzz ✅ pass 3 28,308 522 99% 0 ¥ 0.0019
palindrome ✅ pass 3 28,226 498 99% 0 ¥ 0.0018
subagent-delegation ✅ pass 3 28,583 498 99% 0 ¥ 0.0020
Real provider run. Cache-hit % is cached prompt tokens / total prompt tokens.

agent: PR head (cf4a3d2) · triggered by @esengine

我看了这次 compaction e2e 失败的 run log。
这次失败看起来不是本 PR 的改动导致的。

日志里 compaction 任务没有调用 task / subagent;它正确走完了章节线索,也得到了正确答案内容:Aldermoor-Verrin;但最后尝试写入 story/answer.txt(其实应该写入 answer.txt),所以这是输出路径放错导致的 fail。

本 PR 没有改 internal/agent/compact.go、e2e harness、compaction 任务定义或 write_file;真正和本 PR 相关的 subagent-delegation e2e 是通过的。

因此,我倾向于认为这条 compaction fail 不是本 PR 引入的问题,而是任务提示在输出路径上不够明确,导致模型把正确答案写到了错误目录。

@esengine esengine merged commit 5939500 into esengine:main-v2 Jun 9, 2026
13 checks passed
SuMuxi66 pushed a commit to SuMuxi66/DeepSeek-Reasonix that referenced this pull request Jun 10, 2026
* feat(agent): add subagent transcript store

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(agent): continue task subagent transcripts

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(skill): continue subagent skill transcripts

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor(agent): require subagent transcript store

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(boot): record effective subagent identity

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(agent): release source lock after fork copy

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli): run review with explicit subagent session

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(agent): persist failed subagent transcripts

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(agent): mark failed foreground continuations

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(agent): bind subagents to parent sessions

Ensure persisted subagent transcripts record the active parent session and prevent in-place continuation from a different parent, keeping fork_from as the explicit copy path.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(session): cascade subagent lifecycle cleanup

Move owned subagent artifacts with desktop trash/restore and delete them from hard-delete paths so parent session cleanup no longer leaves reusable child transcripts behind.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(agent): run sub-agents ephemerally without a parent session

Persisted sub-agent transcripts made a parent session mandatory, so
`reasonix run` (headless, which never mints a session path) failed every
task/subagent-skill call with "subagent transcript parent session is
required". Fall back to a non-persisted run when no parent session is
active — restoring pre-transcript behaviour — and reserve continue_from/
fork_from for sessions that actually have a persisted owner.

Adds a headless-run regression guard plus task-level ephemeral coverage.

---------

Co-authored-by: lifu963 <lifu963@lifu963deMacBook-Air-2.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: esengine <359807859@qq.com>
@lifu963 lifu963 deleted the agent/subagent-transcripts-mainv2 branch June 13, 2026 07:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Core agent loop (internal/agent, internal/control) config Configuration & setup (internal/config) desktop Wails desktop app (desktop/**) skills Skill system (internal/skill, internal/tool) tui Terminal UI / CLI (internal/cli, internal/control) v2 Go rewrite (1.x) — main-v2 branch, active development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants