name -> callable map goes
in, the same map comes out with every rule around every call, and the agent SDK calls the
wrapped one. Whatever framework owns the model loop, the seam is the same — the point where a
tool’s implementation is registered.
[tools.*] table — live tools the file declares (a keyed web search,
a connector operation) that run.tools() materializes already wrapped, with
run.tool_definitions(shape="openai" | "anthropic") / run.toolDefinitions() giving the model
their schemas. Below, the seam in each SDK.
OpenAI Agents SDK (Python)
@function_tool reads a function’s signature and docstring for the schema, so decorate a thin
typed function that calls the wrapped one:
Vercel AI SDK (TypeScript)
A tool is{ description, inputSchema, execute }; wrap execute:
A hand-rolled Anthropic tool loop (Python)
The rules give the model its tool schemas and answer its calls:deny surfaces as an exception (HookDenied) from the wrapped call; run.after_error is
what the error text the model should see goes through, so catch it and return the message as
the tool result.
LangChain (Python)
StructuredTool takes the implementation and a schema separately, which is what a wrapped
callable needs:
An MCP server
Wrap the handler bodies the server registers, so every client of the server — a coding agent, an SDK agent — gets the rules without knowing:Claude Agent SDK
The Claude Agent SDK runs Claude Code’s hooks. Namegateway hooks run as the hook command in
its hooks option and it behaves as in Claude Code; for an in-process
hook, call the run directly from the SDK’s hook callback — run.before_call(tool, input) on
PreToolUse, run.after_call(tool, input, result) on PostToolUse, run.end(report) on
Stop — and return the callback’s verdict from what those answer.
Your own transport
run.session(session, request_fn=...) (run.session(session, { requestFn })) puts
pre_request and post_response around a client with its own auth — an x-api-key, a
password grant, a key in the query — so a vendor SDK you did not write still goes through the
door. And run.on(event, handler, matcher=...) adds a rule from code ahead of or after the
file’s, for the one guard that has no business in a shared file.
Everything above is the same file, the same events, the same meters. Which SDK owns the loop
is the one thing the rules never need to know.