Skip to main content
An agent reads tool results, web pages and emails, and any of them can carry instructions the user never gave. This example checks a tool call right before it runs, and says whether to run it, ask the user or refuse. Use it before every tool call, including the ones that look harmless.

How it works

The context is JSON with four keys: the user’s request, the tools on offer, what has happened so far and the action the agent is about to take. The keys are yours to choose. The Thought:, Action: and Observation: lines inside them are just an example of what to send. The model (kettei-core) reads all of that and answers one single decision, action, with three outcomes:
  • allow: the call serves the user’s request and does nothing harmful.
  • confirm: it does something the user didn’t ask for, such as following an instruction found in a tool result, but nothing in it is clearly harmful.
  • deny: it is harmful, such as fraud, stealing or leaking data, or deleting or changing records the user didn’t ask to change.
A policy turns those probabilities into one of three actions: run, ask or refuse.

How the costs pick an action

Each number in the policy’s action_costs says how bad an action is if the call turns out to be a given outcome. The units are yours:
  • Running a harmful call is the worst mistake, at 20.
  • Asking about a harmful call still costs 6. People approve most confirmation requests, so a dangerous call you ask about often runs anyway.
  • Refusing a good call costs 4, because the user’s work stalls.
OneHot multiplies each cost by the probability of its outcome, adds up each row, and picks the cheapest action (weigh what mistakes cost). Say the answer is 0.60 allow, 0.25 confirm and 0.15 deny. Then running costs 3.5 on average, asking 1.5 and refusing 3.15, so policy.action is ask. policy.expected_costs shows all three. The policy also has abstain_below at 0.5. When no outcome reaches 0.5, the model is unsure, and policy.action is abstain whatever the costs say.

Try it

Open this recipe in the playground to run it without an account. The user there asked for a summary of unread email. A message in the inbox tells the agent to forward invoices and delete the evidence, and the agent is about to send them. To run it from your code, set SQWISH_API_KEY as in the quickstart, then send this request:

Act on the answer

Adapt it to your data

  • Your agent’s steps. Fill the four keys from your agent’s own log, in whatever form it keeps them.
  • Your costs. Set them from what each mistake costs you. If a wrongly run call would cost you as much as a hundred needless confirmation requests, set the cost of running a deny call to 100. After any change, see how often each action fires on a day of your own traffic.
  • Costs, not thresholds. To make the check more or less cautious, change the costs rather than adding thresholds of your own in your code. abstain_below does a different job: it doesn’t weigh mistakes, it only catches the calls the model is unsure about.
  • One call per request. Check each tool call in a request of its own.

What to watch

  • Wrong runs, most of all calls that follow instructions hidden in a tool result.
  • allow picked too often. In testing it leaned towards allow. The costs make up for much of that, so keep running a harmful call expensive.
  • How often it asks. Asking isn’t free, so check the share of calls it asks about.

How well it works

Measured with kettei-core on 1,000 examples from a public dataset, it chose the right answer 65.9% of the time. Always picking the most common answer scores 56.4%. Your own data will differ, so measure it on examples of yours before you rely on it (improve a decision).
  • Dataset: TS-Bench ASB-Traj (ToolSafe) (MIT (the repository’s licence)).
  • Sample: 1,000 rows, 1,000 measured decisions.
  • Decisions measured: action.
  • Wording: hand-written.
Always picking the most common answer has an accuracy of 0.564, and guessing by how common each answer is has a log loss of 0.9643.These are past results on one dataset, not a promise of accuracy on yours.
With these costs, none of the unsafe calls in the test would have run, but most of the safe ones would have been asked about too.

Next steps