diff --git a/docs/extensions.md b/docs/extensions.md index 9fd9e3b32..ec3c5ae16 100644 --- a/docs/extensions.md +++ b/docs/extensions.md @@ -252,7 +252,7 @@ Cancelable pre-events: ### Tool lifecycle -- `tool_call` (pre-exec, may block) +- `tool_call` (pre-exec, may block, or revise the tool's execution `input`) - `tool_result` (post-exec, may patch content/details/isError) - `tool_execution_start` / `tool_execution_update` / `tool_execution_end` (observability) - `tool_approval_requested` / `tool_approval_resolved` (observability; emitted by `wrapper.ts` only when a tool requires approval and an approval handler is registered) diff --git a/docs/hooks.md b/docs/hooks.md index 934b1e973..1d7d779c4 100644 --- a/docs/hooks.md +++ b/docs/hooks.md @@ -110,7 +110,7 @@ Hook events are strongly typed in `types.ts`. ### Tool events (pre/post model) -- `tool_call` (pre-execution) → can return `{ block?: boolean; reason?: string }` +- `tool_call` (pre-execution) → can return `{ block?: boolean; reason?: string; input?: Record }`. A non-blocking handler that returns `input` replaces the arguments the tool executes with (the raw execution input, not the normalized `event.input` view); ignored when `block` is true, and not applied to `computer` tool calls. - `tool_result` (post-execution) → can return `{ content?; details?; isError? }` This is the hook subsystem’s core pre/post interception model. @@ -197,7 +197,7 @@ Inside `HookRunner`, order is deterministic by registration sequence: Conflict behavior by event type: -- `tool_call`: last returned result wins unless a handler blocks; first block short-circuits +- `tool_call`: last returned result wins unless a handler blocks; first block short-circuits. A returned `input` (execution-argument override) follows the same last-wins rule; handlers do not observe each other's revisions - `tool_result`: last returned override wins (no short-circuit) - `context`: chained; each handler receives prior handler’s message output - `before_agent_start`: first returned message is kept; later messages ignored diff --git a/docs/skills/authoring-hooks.md b/docs/skills/authoring-hooks.md index 7054bb3aa..f735ff713 100644 --- a/docs/skills/authoring-hooks.md +++ b/docs/skills/authoring-hooks.md @@ -39,7 +39,7 @@ export default function myExtension(pi: ExtensionAPI): void { | Event | Fires | Can return | |---|---|---| -| `tool_call` | Before every tool execution | `{ block?: boolean; reason?: string }` | +| `tool_call` | Before every tool execution | `{ block?: boolean; reason?: string; input?: Record }` | | `tool_result` | After every tool execution | `{ content?; details?; isError?: boolean }` | ### Session lifecycle diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index c4777f2be..f9f9771a5 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -3,6 +3,7 @@ ## [Unreleased] ### Added +- A `tool_call` handler (extension or hook) can now return `input` to revise the arguments a tool executes with, not just `block` it. The returned object is the raw execution input passed to the tool (ignored when `block` is set, and not applied to `computer` tool calls), enabling wrappers that normalize or rewrite a built-in's arguments without reimplementing the tool. - `omp usage` now surfaces auto-disabled credentials as red `✗` tombstone rows (identity, how long ago, the shortened upstream cause — e.g. `Refresh token expired` — and a re-login hint), including a provider section when no active credential remains. User-driven tombstones (`replaced by newer credential`, `deleted by user`) and API-key rows stay hidden. Requires a broker with `GET /v1/credentials/disabled`; older brokers degrade to no tombstone rows. - `omp usage` warns about Anthropic's ~30-day OAuth grant lifetime: accounts whose interactive login (`authorizedAt`) is within a week of the deadline get a yellow `⚠ re-login within