DocsOverview

Human in the Loop

TUTORIAL

Insert human approval steps into your agent workflows for sensitive operations.

The Safety Problem#

You don't want an agent to delete a production database or send an email to the CEO without checking first. AKIOS allows tools to pause execution and wait for permission.

State Running

Agent processes inputs and selects tools normally.

State Paused

Execution halts before sensitive tool call.

State Resumed

Continues with human approval or feedback.

1

FLAG_TOOL_AS_REQUIRES_APPROVAL

tools/email.ts
const sendEmail = new Tool({
  name: 'send_email',
  description: 'Sends an email to a user.',
  schema: z.object({ 
    to: z.string(), 
    subject: z.string(), 
    body: z.string() 
  }),
  // CRITICAL: This flag pauses the agent
  requiresApproval: true, 
  
  handler: async ({ to, subject, body }) => {
    await mailer.send({ to, subject, body })
    return "Email sent successfully."
  }
})
2

HANDLE_THE_INTERRUPTION

When the agent tries to call this tool, `run()` will return early with a status of `paused`.

server.ts
const result = await agent.run("Send an email to boss@corp.com saying 'I quit'")

if (result.status === 'paused' && result.pendingToolCall) {
  const { tool, input } = result.pendingToolCall
  
  // 1. Show UI to user
  console.log(`Agent wants to ${tool} with inputs:`, input)
  console.log("Approve? (y/n)")
  
  // 2. Wait for user input (mocked here)
  const userApproved = true 
  
  // 3. Resume execution
  if (userApproved) {
    const finalResult = await agent.resume(result.id, { approved: true })
    console.log(finalResult.output)
  } else {
    const finalResult = await agent.resume(result.id, { 
      approved: false, 
      feedback: "Don't do that. Be polite." 
    })
    console.log(finalResult.output) // Agent will likely apologize and retry
  }
}

Persistent State

For this to work in a web app, you need a persistent `MemoryStore` so the agent can be rehydrated when the user approves (which might be hours later).