Skip to content

Feature request: add ToolCallHookAction::Replace { args } variant for arg-mutating hooks #1744

@liamcrumm

Description

@liamcrumm

Summary

ToolCallHookAction (in crates/rig-core/src/agent/prompt_request/hooks.rs) currently has three variants:

  • Continue
  • Skip { reason: String }
  • Terminate { reason: String }

There is no Replace { args: serde_json::Value } variant, which means a PromptHook implementation cannot intercept and rewrite a tool call's arguments mid-flight. Hooks can only let the call proceed unchanged, skip it, or terminate the loop.

This is a real limitation for any middleware that needs to mutate (not just gate) tool arguments before execution — for example, guardrail / policy / DLP libraries that want to redact PII, normalize parameters, or substitute scoped credentials before the tool runs.

Use case

We're building Agent Shield (an open guardrails specification + reference implementation) and have a rig adapter at agent_shield_rig. Our Stage 3 (tool_execution_validation) policies can produce mutated arguments — e.g. phone_number: "555-867-5309"phone_number: "[REDACTED]". The hook needs to hand those mutated args back to rig so the tool sees the safe version.

Because there's no Replace { args } variant, our PromptHook impl (ShieldHook) currently fails closed (returns Skip { reason }) on any Stage-3 mutation, and customers needing full Stage-3 coverage have to fall back to a tool-wrapping pattern (GuardedRigTool) that wraps each tool before constructing the agent. That works, but it loses the elegance of the hook-based composition story.

Proposed change

Add a fourth variant to ToolCallHookAction:

pub enum ToolCallHookAction {
    Continue,
    Skip { reason: String },
    Terminate { reason: String },
    Replace { args: serde_json::Value },   // ← new
}

When the agent loop processes a Replace { args } action, it would substitute the provided args for the original tool-call arguments and continue with the call.

Why this matters beyond AgentShield

This pattern (mutating-not-just-gating middleware) is common in agent ecosystems:

  • Semantic Kernel's IAutoFunctionInvocationFilter (.NET) lets filters rewrite arguments via context.Arguments.
  • Vercel AI SDK's onStepFinish callback lets steps rewrite tool inputs.
  • LangChain's tool callbacks can rewrite tool args before execution.

rig having only Continue/Skip/Terminate puts it slightly behind those ecosystems on the middleware-composition story. Adding Replace { args } would close the gap.

Backward compatibility

Adding an enum variant is a breaking change for anyone exhaustively matching on ToolCallHookAction, so this likely belongs in a minor version bump. The existing variants stay; existing hooks continue to compile and behave identically.

Happy to contribute

If the rig maintainers are open to this, we'd be happy to send a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions