Skip to content

refactor(codemode): before/after hooks for tool and extension calls - #49242

Merged
rekram1-node merged 1 commit into
v2from
call-hook
Sep 16, 2026
Merged

rekram1-node merged 1 commit into
v2from
call-hook

Conversation

@rekram1-node

@rekram1-node rekram1-node commented Sep 15, 2026 •

Copy link
Copy Markdown
Collaborator

Hooks around every call the program makes into the host — tools and extension globals — named after the two things a host registers. They replace onToolCallStart/onToolCallEnd, which only fit tools, needed an index to pair up, and could not deny.

CodeMode.make({
  tools,
  extensions,
  hooks: {
    "tool.before":      (call) => Effect.void,          // { name, input }        fail to deny
    "tool.after":       (call, result) => Effect.void,  // result: how it ended
    "extension.before": (call) => Effect.void,          // { extension, name, args }
    "extension.after":  (call, result) => Effect.void,
  },
})

type CallResult =
  | { status: "success"; value: unknown }
  | { status: "failure"; error: unknown }
  | { status: "interrupted" }

Same shape as the plugin API's execute.before/execute.after. after observes and cannot change the result. The same call object reaches before and after, so a host pairs them by identity with no index. Functions inside an extension result (res.json()) are part of a value's API and do not fire hooks. result.toolCalls and maxToolCalls are unchanged and still count tools only; a denied tool call was still admitted, so it appears in both.

 tool-runtime.ts
-  ToolCallStarted / ToolCallEnded / ToolCallHooks, observeEnd (index, outcome, durationMs, message)
+  ToolInvocation / ExtensionInvocation / CallResult / Hooks
+  hooked(call, before, after, run)   one helper: before, run, after with the outcome; used by tools and extensions
 extensions.ts  wrap(value, label, describe?)
+  a global's call runs inside the extension hooks; the host sees its own thrown/rejected error, then it crosses out

Core

The only consumer migrates here. progressHooks(record) appends a running row in before and settles it in after, keyed by a WeakMap from the call object to its row.

Once #49235 (fetch) lands on top, fetch requests show under execute in the TUI with no further plumbing.

Checks

  • packages/codemode bun test 5123 pass / 0 fail. Hook tests cover tools and extensions, denial from either before, a tool defect and an interrupted extension call as seen by after, every previous interruption case, and error location on a bad extension result (parity with other built-in errors).
  • packages/core test/tool-execute.test.ts + test/codemode 27 pass; existing toolCalls metadata assertion unchanged.
  • bun run check 35/35.

@rekram1-node
rekram1-node force-pushed the call-hook branch 4 times, most recently from a6e848b to b3972af Compare September 16, 2026 03:05
@rekram1-node rekram1-node changed the title refactor(codemode): observe every host call through one onCall hook refactor(codemode): wrap every host call in one middleware Sep 16, 2026
@rekram1-node rekram1-node changed the title refactor(codemode): wrap every host call in one middleware refactor(codemode): observe every host call through one onCall hook Sep 16, 2026
@rekram1-node
rekram1-node force-pushed the call-hook branch 2 times, most recently from a489d1f to 4eba358 Compare September 16, 2026 03:12
@rekram1-node rekram1-node changed the title refactor(codemode): observe every host call through one onCall hook refactor(codemode): before/after hooks for tool and extension calls Sep 16, 2026
@rekram1-node
rekram1-node merged commit c57733a into v2 Sep 16, 2026
10 checks passed
@rekram1-node
rekram1-node deleted the call-hook branch September 16, 2026 04:05
jinhuang712 pushed a commit to jinhuang712/opencode that referenced this pull request Sep 26, 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