Key takeaways
- The model's tool request is only a suggestion and the actual execution must be controlled by the runtime.
- tool runtime is divided into registry, schema validation, permission gate, executor, and result formatter.
- Read-only tools can be parallelized, but write tools must preserve order.
- Errors and rejections should also be made model-visible results so as not to break the loop.
In this article, we will look at tool runtime.
In an AI agent, a tool is not a simple list of functions. If the model requests “I want to call this tool with these arguments,” the runtime must verify that the request is actually possible. You need to verify that the tool name is correct, that the input schema is valid, that it can be run with the current permissions, and that it is safe to run in parallel.
If you look at Claude Code-type agents from a runtime perspective, tool execution is an independent layer separated from the model loop.
1. Tool request is a suggestion, not an execution command.
A model can “request” a tool call. However, it is up to the application to decide whether to run it or not.
Models can make the following mistakes:
- Create a tool name that does not exist.
- Omitting required arguments.
- Requests a dangerous shell command.
- The file writing order is misjudged.
- I am trying to send sensitive information to an external service.
So a tool request is not an execution command, but rather a suggestion for the runtime to review.
2. Capability registry design
A registry defines “what can run.”
| field | explanation |
|---|---|
| public name | Tool name exposed to model |
| description | Explanation for reference when selecting a model |
| input schema | Argument validation rules |
| risk level | Risk levels such as read, write, shell, network, secret, etc. |
| availability | Availability in current mode/workspace/policy |
| executor | actual execution function |
| result formatter | Convert results to model-visible message |
As more tools become available, the registry and executor need to be separated. The registry is a list of possible functions, and the executor is responsible for how to process this request.
3. Schema validation and error messages
Input validation is required before running the tool. Schema validation is not a simple type check but is part of model feedback.
If an incorrect input is received, the runtime should not break the loop with an exception, but should create an error result that the model can understand.
# How to read: The items below are summarized examples to quickly check the action flow.Request: file_read(path=null)→ schema validation failedto tool result: path must be a stringto model can be retried with different arguments
4. Permission gate and execution order
You should not run it immediately after the schema has passed. Authority judgment is required.
Permission judgment must look at the risk level of the tool itself, input values, current permission mode, workspace trust, user rules, and organizational policy.
| risk | default processing |
|---|---|
| read-only local metadata | Auto-acceptable |
| file read | Allowable within workspace range |
| file write | Approval or stated policy required |
| shell command | Approval required after risk classification |
| network send | Requires confirmation of destination and data range |
| secret access | default deny |
5. Parallel and serial execution
Running all tools in parallel is fast. But it's not safe. Read-only tools can be parallelized, but the order of writing files or executing shells is important.
| tool personality | execution strategy |
|---|---|
| read-only, no side effect | Can run in parallel |
| write, state mutation | Serial execution recommended |
| shell command | Conservatively run serially |
| external API mutation | Serial or transaction required |
| unknown risk | Serial execution defaults |
The criterion for parallelization is not speed, but side effects.
6. Result formatter and reinjection
The tool results have different screen output and model-visible messages. A short summary is good for the screen, but the model needs structured observations to make further inferences.
The tool results must contain at least the following information:
- Original tool request id
- Success/Failure
- Model-readable summary of results
- If there is an error, the cause
- Content with sensitive information removed
- Audit summary to leave on the ledger
7. tool runtime viewed through concept code
The code below is newly written code for explanation purposes.
# How to read: Conceptual code that describes runtime boundaries, not a clone of the actual implementation.class CapabilitySpec: # Initializes runtime dependencies and state storage that the object will reference in later steps. def __init__(self, name, schema, risk, can_run, execute, format_result): self.name = name self.schema = schema self.risk = risk self.can_run = can_run self.execute = execute self.format_result = format_result # Processes a single tool request through validation, permission evaluation, execution, and result formatting steps.async def execute_tool_request(request, runtime): spec = runtime.capabilities.find(request.name) if spec is None: return ToolResult.error(request.id, "This tool cannot be used.") parsed = spec.schema.validate(request.arguments) if not parsed.ok: return ToolResult.error(request.id, parsed.message) if not spec.can_run(runtime.context): return ToolResult.error(request.id, "The tool is disabled in the current run mode.") decision = await runtime.permissions.evaluate(spec, parsed.value) await runtime.ledger.write("permission_decision", decision.summary()) if not decision.allowed: return ToolResult.denied(request.id, decision.reason) try: raw_output = await spec.execute(parsed.value, runtime.execution_context) return spec.format_result(request.id, raw_output) except Exception as error: return ToolResult.error(request.id, summarize_error(error)) # Read-only tools run in parallel, and tools with side effects run in sequence.async def execute_tool_batch(requests, runtime): readonly, ordered = split_by_side_effect(requests, runtime.capabilities) for result in await run_parallel(readonly, lambda req: execute_tool_request(req, runtime)): yield result for req in ordered: yield await execute_tool_request(req, runtime)
Here, error, rejection, and success all becomeToolResult. The key is not to break the loop, but to create observations that can be used for the next model inference.
8. Practical checklist
# How to read: The items below are summarized examples to quickly check the action flow.tool runtime Checklist [ ] View tool requests as suggestions to be reviewed, not as execution commands.[ ] The capability registry and executor are separated.[ ] Tool name lookup failure also produces a result message.[ ] Schema validation failure returns to model-visible error.[ ] Permission check occurs immediately before actual execution.[ ] read-only can be parallelized, and write preserves order.[ ] Tool results are divided into screen summary, model message, and ledger summary.[ ] unknown risk tools are conservatively treated as requiring serialization or approval.
Case of failure: Matching only the tool name and omitting the execution policy
The most common failure is passing the tool definition to the model and deciding, "Now this is a function calling." It works fine in the initial demo. The model selectsread_file, enters the path, and runtime reads the file and returns the result. But problems soon arise in real products. The reader and writer tools run simultaneously in the same queue, permission checks are only performed on UI buttons but not on the executor, and failed tool calls are not left in the transcript.
In this structure, the runtime fluctuates the moment the model creates an invalid argument. For example, if a tool likedelete_cachetakes an optionalscopeargument and schema validation is lax, an empty scope could be interpreted as deleting the entire cache. Alternatively, tools marked as read-only may update the refresh token internally, creating a side effect. Even if the model is not malicious, if the tool's risk rating is not expressed at runtime, it becomes an operational incident.
Implementation example: Specifying pre-execution checkpoints
tool runtime must have at least the following order. The key is to not turn model requests straight into function calls.
ToolRequest-> name lookup-> schema validation-> capability policy-> permission check-> concurrency planner-> executor-> normalized ToolResult
type Risk = "read" | "write" | "external" | "destructive"; type ToolCapability = { name: string; risk: Risk; schemaVersion: string; requiresApproval: boolean;}; function canExecute(capability: ToolCapability, mode: "auto" | "review") { if (capability.risk === "destructive") return false; if (capability.requiresApproval && mode === "auto") return false; return true;}
Even this small amount of separation allows the runtime to determine whether the tool can be parallelized, whether user approval is required, and how to explain failure to the model. The important thing is thatcanExecutemust be a policy shared by both the UI and the executor. Even if you block it on the screen, if the executor doesn't check again, there will be a bypass route.
| boundary | responsibility | Problems that arise when missing |
|---|---|---|
| registry | Check tool name and capabilities | hallucinated tool ends with runtime exception |
| schema | Input format and default value validation | Dangerous defaults run silently |
| permission | Check user/workspace permissions | An execution path outside the UI appears. |
| result formatter | Normalize success and failure to the same type | Model fails to recover from failure cause |
Operational example: Securely exposing a file writer
Let's say we expose thewrite_filetool in our coding agent. Although this tool appears to simply be a function that takes a path and content, it requires at least four checkpoints at runtime. First, check if the path is in the workspace. Second, distinguish whether the target file is created or modified. Third, check if writing is possible in the current authorization mode. Fourth, after execution, the diff and result summary are left in the transcript.
| checkpoint | Confirmation details | Failure handling |
|---|---|---|
| schema | path and content types, whether empty or not | model-visible validation error |
| scope | Block paths outside the workspace | permission denied result |
| intent | Distinguish between creation, modification, and overwriting | Approve or deny user |
| audit | Changed files, size, summary history | Warning when ledger write fails |
Without this flow, it would be difficult for users to determine the cause when a model accidentally creates an absolute path, overwrites an entire existing file, or runs the same operation twice. In particular, if you only treat “tool execution failure” as an exception, the model will not see the cause of the failure. Failures should also be normalized toToolResultto provide observation values necessary for the next decision, such as "could not write due to permissions," "schema is incorrect," and "target file is outside the workspace."
The point of comparison is clear. An agent that only has a list of function calls becomes more dangerous as more tools are attached to it. On the other hand, an agent with a capability registry and permission gate can consistently manage the risk level and execution conditions of each tool even as the number of tools increases.
finish
tool runtime is the agent's point of contact with the outside world. Rather than immediately executing the model request, the runtime must verify, approve, and record product-level reliability.
The next article covers the last lines of defense: permissions, transcript, and cost. These three are not additional features but core layers that determine agent productivity.

댓글
GitHub 계정으로 로그인하면 댓글을 남길 수 있습니다. 댓글은 GitHub Discussions를 통해 운영됩니다.