Agent SDKInput & OutputHandle Approvals

Handle Approvals

When Amara wants to run a tool that changes the world — writing a file, executing a shell command, calling an external API — you often want a human to sign off first. The Syntic Agent SDK lets you intercept each tool call before it executes and decide, in code, whether to allow it, block it, or modify its input.

Approvals turn an autonomous agent into a supervised one. They are the primary mechanism for keeping a person in the loop on high-stakes actions while letting routine, read-only work proceed uninterrupted.

Registering an approval callback

Provide a canUseTool callback in the options. The SDK invokes it with the tool name and its proposed input, and awaits your decision. Return an allow decision to proceed, or a deny decision with a reason that is fed back to the model.

import { query } from "@syntic/agent-sdk";
 
const result = query({
  prompt: "Clean up the temp directory.",
  options: {
    canUseTool: async (toolName, input) => {
      if (toolName === "Bash" && /rm\s+-rf/.test(input.command)) {
        return { behavior: "deny", message: "Refusing recursive delete." };
      }
      return { behavior: "allow", updatedInput: input };
    },
  },
});
async def can_use_tool(tool_name, tool_input):
    if tool_name == "Bash" and "rm -rf" in tool_input.get("command", ""):
        return {"behavior": "deny", "message": "Refusing recursive delete."}
    return {"behavior": "allow", "updated_input": tool_input}
 
query(prompt="Clean up the temp directory.",
      options={"can_use_tool": can_use_tool})

Prompting a real person

The callback is just async code, so you can suspend the agent while you ask a human. Push the pending tool call to a UI, a Slack message, or an approvals queue, then resolve the promise once someone responds. The agent stays paused — holding its place in the loop — until your callback returns.

You can also rewrite the tool input before allowing it, which is useful for narrowing scope, injecting safe defaults, or redacting sensitive arguments. When you deny a call, the message you return becomes context for Amara, so a clear explanation helps the model choose a better next step rather than retrying blindly. For coarser, rule-based gating that does not need a live decision, see Permissions.