Skip to content

Strands Agents

Available · AgentTool per spec · approval hook · pip install "agent-adapter[strands]" (strands-agents, heavy: boto3, OTel SDK) · own environment (needs mcp<2.2; not in all)

Functions

Function (agent_adapter.integrations.strands) Returns
strands_tool(spec, *, executor=None) one AgentTool (inputSchema.json = neutral schema)
strands_tools(registry, *, executor=None) one per registry tool exported to strands
strands_approval_hook(port, registry) an async BeforeToolCallEvent callback
INTEGRATION get_integration("strands"); bind_approval(port) = the hook, resolving specs from the exported tools

Results are Strands tool results: status success with a text (strings) or json block, or status error.

Wiring

def build_agent(model: Model) -> Agent:
    tools = strands_tools(registry, executor=Executor(registry))
    agent = Agent(model=model, tools=tools, callback_handler=None)
    hook = strands_approval_hook(CallbackApproval(reviewer), registry)
    agent.hooks.add_callback(BeforeToolCallEvent, hook)  # asks before send_invoice runs
    return agent

Approval

The hook runs before every tool call. For a registry tool whose confirm rule says yes it asks the approval port once.

sequenceDiagram
  participant S as Strands Agent
  participant H as approval hook
  participant P as ApprovalPort
  participant T as AgentTool
  participant Ex as Executor
  S->>H: BeforeToolCallEvent(toolUseId, input)
  H->>P: request(tool, arguments, call_id=toolUseId)
  alt approved
    H->>S: selected_tool = one-call view holding a token
    S->>T: view.stream(tool_use, invocation_state)
    T->>Ex: run_spec(..., ctx.approval = token, if it matches)
  else denied / pending
    H->>S: cancel_tool = error text
  end
Case What happens
Approved the hook swaps in a one-call view of the tool holding a one-use token of this hook, bound to the agent's run, the toolUseId, the tool and the validated input; the executor does not ask again
Input changed after approval (a later hook), replayed view, or any value put in invocation_state no token: the executor asks its own port
Denied the call is cancelled; the model sees {"error": {"kind": "approval-denied", ...}}
Port raises ApprovalPending the call is cancelled with approval required: <id>
Edited arguments not supported: an edit is treated as a denial (logged at WARNING)
No hook registered the executor's own confirm rule and port decide (no port: denied)

Calls and errors

Item Behaviour
Call id toolUseId → ctx.call_id
Run one run id per Agent object, shared by the hook's requests and the calls
ToolArgsInvalid, ToolError, ApprovalDenied, GuardrailBlocked, RunLimitExceeded status: error with {"error": {"kind", "message"}}
Other errors raised; Strands reports Error: <message>
Outer cancellation (cancelling invoke_async) propagates with both executors and cancels the tool
A tool's own CancelledError Strands' default ConcurrentToolExecutor drops it (the result goes missing); SequentialToolExecutor propagates it