Skip to content

feat(plugin): tool.execute.before can shortcircuit with a canned output#35613

Closed
jackieju wants to merge 2 commits into
anomalyco:devfrom
jackieju:replay-shortcircuit
Closed

feat(plugin): tool.execute.before can shortcircuit with a canned output#35613
jackieju wants to merge 2 commits into
anomalyco:devfrom
jackieju:replay-shortcircuit

Conversation

@jackieju

@jackieju jackieju commented Jul 6, 2026

Copy link
Copy Markdown

What

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 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:

  • Caching an expensive tool result across replays or CI runs.
  • Deterministic tests / recordings.
  • Sandboxing tool calls to a canned safe response during audit.

How

Every tool.execute.before trigger in the codebase now inspects the mutated output object. If shortcircuit is set, opencode:

  1. Uses shortcircuit as the tool result.
  2. Fires tool.execute.after with that result (plugins that log/react to tool completion still work).
  3. Returns without ever invoking the tool's real execute.

Instrumented sites:

  • packages/opencode/src/session/tools.ts — primary built-in tool execute path
  • packages/opencode/src/session/tools.ts — MCP resource list / listTemplates / read paths
  • packages/opencode/src/session/tools.ts — generic MCP-served tool execute path
  • packages/opencode/src/tool/code-mode.ts — MCP catalog tool execute path

packages/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 shortcircuit see identical behavior to before.

Testing

  • bun typecheck from packages/opencode and packages/plugin — passes.
  • Built a fork binary via 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.

jackieju added 2 commits July 7, 2026 04:58
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.
@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

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.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
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)
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
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.

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Jul 6, 2026
@github-actions github-actions Bot closed this Jul 6, 2026
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.

1 participant