Skip to content

feat(core): add opencode job_list, job_output, job_wait, and job_stop tools - #60497

Open
kitlangton wants to merge 1 commit into
t902-tool-seamfrom
t902-job-tools
Open

kitlangton wants to merge 1 commit into
t902-tool-seamfrom
t902-job-tools

Conversation

@kitlangton

Copy link
Copy Markdown
Contributor

Agents can now list, read live output from, wait on, and stop background jobs through tools.opencode.job_* without polling with sleep.
The four tools live in the opencode Code Mode catalog (codemode: true, pinned: true) so they stay out of the direct top-level tool list unless Code Mode is disabled. Stacked on #60495.

🔍 Origin: reported in #36423, #36424, and #56940

💡 Why: Once a build, server, Code Mode script, or subagent moved to the background, an agent had no way to inspect its live progress, wait boundedly when blocked on its output, or stop a stuck process (#36423, #36424, #56940) — and in a 120-run small-model eval across Haiku 5.5, DeepSeek V4.1 Flash, MiniMax M3, and Gemini 3.5 Flash Lite, putting job_* directly into top-level tool definitions caused smaller models to call job_output / job_wait with made-up IDs, whereas keeping them in tools.opencode.* produced 0 misfires (15/15 pass).

🆕 Now you can: Call tools.opencode.job_list, job_output, job_wait, and job_stop inside Code Mode (or as opencode_job_* when Code Mode is disabled), scoped strictly to jobs owned by the calling session.

+ tools.opencode.job_list({ status?: "running" | "all" }) // excludes the calling execute script itself
+ tools.opencode.job_output({ id })                       // live partial output or final settled output
+ tools.opencode.job_wait({ id, yield_after? })           // bounded wait (defaults to 10s)
+ tools.opencode.job_stop({ id })                         // cancels job (+ descendant jobs when stopping a subagent)

📊 Proof

Case Before After
Agent stops a hung background shell, Code Mode script, or subagent (#36423, #36424) ❌ No stop tool ✅ job_stop cancels the job and any descendant subagent jobs
Agent checks live logs or waits boundedly on a background job (#56940) ❌ Resorts to sleep && cat ✅ job_output / job_wait read live snapshots directly
Cross-session or self-call isolation — ✅ Rejects other sessions' jobs and excludes the caller's own execute call

New integration tests in packages/core/test/tool-job.test.ts fail without the change; 2 suites (17 assertions) pass.

👀 Read: packages/core/src/tool/plugin/job.ts in requireOwned and stopDescendantSessions — requireOwned rejects both foreign-session jobs and the active execute call's own callID so a script never lists or cancels itself. The rest is routine.

Checks run
  • bun run script/test.ts test/tool-job.test.ts (packages/core): 2 pass, 0 fail
  • bun run typecheck && bun run typecheck:tsc (packages/core): 0 errors

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant