feat(plugin): tool.execute.before can shortcircuit with a canned output#35613
Closed
jackieju wants to merge 2 commits into
Closed
feat(plugin): tool.execute.before can shortcircuit with a canned output#35613jackieju wants to merge 2 commits into
jackieju wants to merge 2 commits into
Conversation
Adds an optional 'shortcircuit' field to the output object passed to the
'tool.execute.before' plugin hook. When a plugin sets it to a
{ title, output, metadata } object, opencode skips the real tool
execution and returns that value as the tool_result, firing the normal
'tool.execute.after' hook with the shortcircuit'd output.
Motivation: historical session replay. When replaying an old conversation
to harvest training data for a local model, we want the LLM to see the
exact same tool_result it saw originally without actually re-running the
underlying Read/Grep/Edit/Bash/etc. This keeps the LLM's reasoning path
identical to the historical run while guaranteeing zero side effects on
the current machine — no files touched, no shells invoked, no network.
Implementation is scoped to the primary tool execute path in
'packages/opencode/src/session/tools.ts'. The MCP resource listing paths
in the same file are untouched because they never write to disk and are
outside the replay use case.
The hook contract stays fully backwards-compatible: existing plugins that
don't set 'shortcircuit' see identical behaviour.
…-mode paths Applies the shortcircuit mechanism introduced in the previous commit to every remaining tool.execute.before trigger in the codebase: - session/tools.ts MCP resource list / listTemplates / read paths - session/tools.ts generic MCP-served tool execution path - tool/code-mode.ts MCP catalog tool execution path Every tool call — built-in or MCP-provided — can now be intercepted by a plugin returning shortcircuit output, guaranteeing zero side effects on the machine during historical replay. Task-tool spawning (session/prompt.ts) is intentionally NOT shortcircuited: tasks spawn sub-agent sessions whose own tool calls go through the already-instrumented execute paths, so sub-agent reasoning is preserved while every leaf tool call remains interceptable.
Contributor
|
This PR doesn't fully meet our contributing guidelines and PR template. What needs to be fixed:
Please edit this PR description to address the above within 2 hours, or it will be automatically closed. If you believe this was flagged incorrectly, please let a maintainer know. |
Contributor
|
The following comment was made by an LLM, it may be inaccurate: Potential Duplicate Found:
You should check PR #32679 to determine if it's already merged, closed, or needs to be coordinated with the current PR. |
jackieju
added a commit
to jackieju/AIAgentLocalMemory
that referenced
this pull request
Jul 6, 2026
opencode run does not accept --print — passing it causes yargs to print help and exit before the LLM is invoked. Removed the flag from every invocation in replay-history.sh; opencode run without --print prints the response directly to stdout which is what we want. Also updates the README replay section: - documents the two safety modes (shortcircuit / read-only agent) - includes build instructions for the fork - links the upstream PR anomalyco/opencode#35613 - flags the known end-to-end integration gap (session.idle event does not always fire under headless opencode run, so pairs.jsonl may not grow during a replay until a follow-up wires an alternate trigger; the safety mechanism itself is fully verified)
Contributor
|
This pull request has been automatically closed because it was not updated to meet our contributing guidelines within the 2-hour window. Feel free to open a new pull request that follows our guidelines. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds an optional
shortcircuitfield to the output object passed to thetool.execute.beforeplugin hook. When a plugin sets it to a{ title, output, metadata }object, opencode skips the real tool execution and returns that value as the tool_result, firing the normaltool.execute.afterhook with the shortcircuited output.Why
Enables use cases where a plugin already knows the correct tool result and wants to serve it without executing the actual tool. Original motivation: historical session replay for local-model training. When replaying an old conversation to harvest training data, we want the LLM to see the exact same tool_result it saw the first time — no re-reading files, no re-running shells, no re-fetching URLs — while its reasoning path stays identical. Shortcircuit is the minimum runtime hook that makes this possible without either forking the tool registry or writing an MCP proxy layer.
Other plausible uses:
How
Every
tool.execute.beforetrigger in the codebase now inspects the mutated output object. Ifshortcircuitis set, opencode:shortcircuitas the tool result.tool.execute.afterwith that result (plugins that log/react to tool completion still work).execute.Instrumented sites:
packages/opencode/src/session/tools.ts— primary built-in tool execute pathpackages/opencode/src/session/tools.ts— MCP resource list / listTemplates / read pathspackages/opencode/src/session/tools.ts— generic MCP-served tool execute pathpackages/opencode/src/tool/code-mode.ts— MCP catalog tool execute pathpackages/opencode/src/session/prompt.ts(task tool dispatching to a sub-agent) is intentionally not shortcircuited: it spawns a sub-agent session whose own tool calls go through the already-instrumented paths, so shortcircuit still applies at leaf tools while sub-agent reasoning is preserved.Compatibility
Fully backwards-compatible. The new field is optional; existing plugins that don't set
shortcircuitsee identical behavior to before.Testing
bun typecheckfrompackages/opencodeandpackages/plugin— passes.bun run build --single --skip-embed-web-ui; smoke test (opencode --version) passes.Downstream
Consuming plugin implementation (for context): jackieju/AIAgentLocalMemory uses this hook to replay historical opencode sessions into a training dataset for a local LLM, with zero side effects on the user's filesystem.