Skip to content

fix(task): report error to parent when subagent finishes with error (#52378) - #52678

Closed
JerryLiu369 wants to merge 2 commits into
anomalyco:devfrom
JerryLiu369:fix/52378-autofix
Closed

JerryLiu369 wants to merge 2 commits into
anomalyco:devfrom
JerryLiu369:fix/52378-autofix

Conversation

@JerryLiu369

@JerryLiu369 JerryLiu369 commented Oct 2, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #52378

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

When a subagent assistant message ends with finish: "error" without an explicit error object, TaskTool.runTask previously ignored the error finish status and fell through to returning empty text parts, reporting the subagent task as successfully completed (state="completed").

This fix ensures TaskTool.runTask checks for finish === "error" on the assistant message and fails the task accordingly, surfacing the failure to the parent task runner with state="error". Also adds a unit test in task.test.ts.

How did you verify your code works?

  • Tested with bun test test/tool/task.test.ts in packages/opencode. All 23 tests pass cleanly.

Screenshots / recordings

N/A

Checklist

  • I have read the CONTRIBUTING document.
  • My code follows the code style of this project.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

@r266-tech

Copy link
Copy Markdown
Contributor

The explicit finish: "error" check addresses the old task-tool path, but this PR targets dev/packages/opencode. The current contribution guide asks for v2, where subagent jobs run through packages/core instead.

On current V2 55dde881, the successfully ended stream synthesizes an assistant failure only for finish === "unknown"; "error" still does not enter that branch. The V2 reproduction already shared in #52378 exercises the real runner, job and database for both foreground and background tasks. The stubbed TaskPromptOps test here does not cover that path. The issue also has a separately reproduced length case; it needs an explicit scope decision rather than being treated as covered by the error-only check.

Would you be able to port the fix to the V2 owner and reuse packages/core/test/tool-subagent.test.ts for both delivery modes? This comment is based on the current source comparison and the linked earlier synthetic event reproduction, not a new live-provider test. AI-assisted review; no competing PR opened.

@JerryLiu369

Copy link
Copy Markdown
Author

@r266-tech Ported to the V2 owner path as requested, pushed to this branch:

  • packages/core/src/session/runner/llm.ts now synthesizes an assistant failure (InvalidProviderOutputReason) when a successfully ended stream records finish unknown or error, and suppresses Step.Ended/continuation after that failure so it surfaces as a terminal step instead of silent success.
  • packages/core/src/session/runner/publish-llm-event.ts exposes hasAssistantFailure used for the suppression.
  • Coverage: new SessionRunnerLLM case projects an error finish as a terminal assistant step failure (foreground path), plus a background delivery regression in packages/opencode/test/tool/task.test.ts asserting the parent job ends in error state with the task_id message. The original foreground task test is untouched.
  • Scope decision on length: explicitly left out, with a code comment — length is a valid truncation outcome that may carry usable partial output, so it stays outside this subagent-failure fix.

Verification on this box: packages/opencode task suite 24/24 green, packages/core session-runner suite 88/88 green, scoped tsgo typecheck clean for both packages. Repo-wide bun typecheck cannot complete in this environment (tsgo exceeds 300s and gets SIGTERM), so that one is left to CI.

@thdxr

thdxr commented Oct 10, 2026

Copy link
Copy Markdown
Member

This branch has been upgraded to V2. We're no longer taking PRs for V1. If you think this is still relevant, please port it over and open it for V2.

— from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

@thdxr thdxr closed this Oct 10, 2026
@r266-tech

Copy link
Copy Markdown
Contributor

@JerryLiu369 I verified the added core regression at 768453b4: it passes and projects the explicit error finish into an assistant error. That is useful progress on the older V2 implementation.

For the new PR requested by the maintainer, current dev has moved this decision into packages/core/src/session/runner/step.ts. It still synthesizes a failure only for unknown, using AIError / InvalidProviderOutputError. The change in the older llm.ts therefore needs porting to that current owner.

The added background test in packages/opencode/test/tool/task.test.ts uses the legacy task implementation. It does not verify the current V2 child runner, job outcome, or parent notification. Please reuse packages/core/test/tool-subagent.test.ts with the synthetic error-finish events from #52378 for both delivery modes, keeping the empty stop success control.

Leaving length outside an error-only PR is a clear scope choice; the reasoning-only truncation report in #52378 remains unresolved and should remain tracked separately. AI-assisted source review and local synthetic-test verification; no live-provider test or competing PR.

@JerryLiu369

Copy link
Copy Markdown
Author

@r266-tech Ported to the current V2 owner as requested.

  • packages/core/src/session/runner/step.ts now synthesizes InvalidProviderOutputError for a successful stream that ends with error as well as unknown, with the message matching the recorded reason. unknown keeps classification: "incomplete-stream" so it stays retryable; an explicit error gets no classification, so it stays terminal.
  • packages/core/test/tool-subagent.test.ts covers both delivery modes through the real child runner, job outcome and parent notification: foreground surfaces a tool execution failure, background ends the parent job in error and writes state="error". The empty stop case stays as the success control.
  • length is left out with a comment, per the scope decision.

New PR against dev: #54713

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

subagent: finish:"error" / MALFORMED_FUNCTION_CALL with empty content is reported to the parent as a successful completion

3 participants