[{"data":1,"prerenderedAt":981},["ShallowReactive",2],{"blog-human-in-the-loop-ai-agents-en":3},{"slug":4,"published":5,"minutes":6,"category":7,"tags":8,"keywords":13,"about":24,"sources":34,"cover":65,"og":66,"expertise":67,"locales":68,"lang":69,"title":72,"description":73,"coverAlt":74,"metaTitle":75,"takeaways":76,"faq":82,"toc":101,"blocks":129,"others":681},"human-in-the-loop-ai-agents","2026-10-02",13,"agents",[9,10,11,12],"Human in the loop","AI agents","Approval gates","Agent safety",[14,15,16,17,18,19,20,21,22,23],"human in the loop AI agents","human in the loop KI-Agent","Mensch im Loop KI","AI agent approval gates","agent approval fatigue","LangGraph interrupt human in the loop","OpenAI Agents SDK needs_approval","Claude Agent SDK canUseTool","AI agent audit trail","risk tiers for AI agent actions",[25,28,31],{"name":26,"url":27},"Human-in-the-loop","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FHuman-in-the-loop",{"name":29,"url":30},"Intelligent agent","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FIntelligent_agent",{"name":32,"url":33},"Audit trail","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FAudit_trail",[35,38,41,44,47,50,53,56,59,62],{"title":36,"url":37},"LangChain docs: LangGraph interrupts","https:\u002F\u002Fdocs.langchain.com\u002Foss\u002Fpython\u002Flanggraph\u002Finterrupts",{"title":39,"url":40},"LangChain docs: Human-in-the-loop (HumanInTheLoopMiddleware)","https:\u002F\u002Fdocs.langchain.com\u002Foss\u002Fpython\u002Flangchain\u002Fhuman-in-the-loop",{"title":42,"url":43},"OpenAI Agents SDK (Python): Human in the loop","https:\u002F\u002Fgithub.com\u002Fopenai\u002Fopenai-agents-python\u002Fblob\u002Fmain\u002Fdocs\u002Fhuman_in_the_loop.md",{"title":45,"url":46},"Claude Agent SDK: Handle approvals and user input","https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fagent-sdk\u002Fuser-input",{"title":48,"url":49},"Claude Agent SDK: Configure permissions","https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fagent-sdk\u002Fpermissions",{"title":51,"url":52},"Claude Code docs: Hooks (PreToolUse defer, PermissionRequest)","https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fhooks",{"title":54,"url":55},"Anthropic Engineering: Claude Code auto mode","https:\u002F\u002Fanthropic.com\u002Fengineering\u002Fclaude-code-auto-mode",{"title":57,"url":58},"DevOps.com: Anthropic makes Claude Code auto mode the default","https:\u002F\u002Fdevops.com\u002Fanthropic-makes-claude-codes-auto-mode-the-default-betting-automation-beats-manual-review\u002F",{"title":60,"url":61},"EU AI Act, Article 14: Human oversight","https:\u002F\u002Fartificialintelligenceact.eu\u002Farticle\u002F14\u002F",{"title":63,"url":64},"OpenAI: How we build safety, security and privacy into dots","https:\u002F\u002Fopenai.com\u002Findex\u002Fhow-we-build-safety-security-and-privacy-into-dots\u002F","\u002Fimages\u002Fblog\u002Fhuman-in-the-loop-ai-agents\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fhuman-in-the-loop-ai-agents\u002Fog.jpg","ai-engineer",[69,70,71],"en","de","hu","Human in the loop for AI agents: where to put approval gates","Where approval gates belong in an AI agent, how to avoid rubber-stamping, and how interrupt and resume work in LangGraph and the OpenAI and Claude agent SDKs.","Diagram: an agent proposes an action, a risk gate sends it to automatic execution, to a human approval, or to a block, and every decision lands in an audit log.","Human in the loop for AI agents · Balázs Csorba",[77,78,79,80,81],"Gate actions by risk, not by tool: reversibility, blast radius, data sensitivity and who sees the effect decide whether an action runs, asks a human or is blocked.","Per-action approval stops working under volume. Anthropic reports that users approve 93 percent of Claude Code permission prompts and that, in one experiment, human review caught only 13.6 percent of a disguised dangerous command.","Interrupt and resume is now a standard primitive: LangGraph interrupt with Command(resume), needs_approval and RunState in the OpenAI Agents SDK, canUseTool and the PreToolUse defer decision in the Claude Agent SDK.","An approval is only worth something if it is bound to the exact action, made by an authenticated person, recorded, and able to expire. Everything else is a ritual.","Always-on agents such as OpenAI dots move the human from the start of the chain to the end, so the design shifts from asking more often to asking better, with rules, a reviewer model and sampled audits.",[83,86,89,92,95,98],{"q":84,"a":85},"What does human in the loop mean for AI agents?","It means a person can intervene at defined points while an agent works: approving or editing a planned action, answering a question, or stopping a run. In practice it is a gate in the agent loop. The agent pauses, shows what it intends to do, waits for a decision and continues with the outcome.",{"q":87,"a":88},"Which agent actions should require human approval?","Actions that are hard to undo, touch money, permissions or personal data, leave your organisation, or affect many records at once. Reads inside the agent scope and reversible changes in a sandbox can usually run automatically, with logging.",{"q":90,"a":91},"How do you avoid approval fatigue?","Ask less often and show more when you do. Auto-approve low-risk actions, batch related steps into one decision, show the effect and a diff instead of a tool name, block the dangerous cases by rule instead of by prompt, and audit a sample of what ran without asking.",{"q":93,"a":94},"How does interrupt and resume work in LangGraph?","A node calls interrupt with a JSON-serialisable payload. LangGraph saves the state through a checkpointer and stops. You resume on the same thread_id with Command(resume=value), and that value becomes the return value of interrupt. The node restarts from its beginning, so side effects before the interrupt must be idempotent.",{"q":96,"a":97},"How do the OpenAI and Claude agent SDKs handle tool approval?","In the OpenAI Agents SDK a tool declares needs_approval, the run returns the pending calls as interruptions, and you approve or reject them on a serialisable RunState and run again. In the Claude Agent SDK a canUseTool callback receives each call that no rule or mode has settled and returns allow or deny.",{"q":99,"a":100},"Does the EU AI Act require human oversight of AI agents?","Article 14 requires effective human oversight for high-risk AI systems, including awareness of automation bias and the ability to intervene or stop the system. Whether your agent is high-risk depends on its use case. Even where it is not, the same design principles are a sound baseline.",[102,105,108,111,114,117,120,123,126],{"id":103,"title":104},"why-approval-fails","Why per-action approval fails at scale",{"id":106,"title":107},"where-to-gate","Where to put the gates: risk, reversibility, blast radius",{"id":109,"title":110},"approval-ux","Approval UX that does not train people to click yes",{"id":112,"title":113},"interrupt-resume","Interrupt and resume in the main frameworks",{"id":115,"title":116},"audit-escalation","Audit trails and escalation",{"id":118,"title":119},"always-on-agents","What always-on agents change",{"id":121,"title":122},"checklist","A checklist for your next agent",{"id":124,"title":125},"the-bigger-picture","The bigger picture",{"id":127,"title":128},"sources","Sources",[130,134,148,151,159,166,173,174,182,206,209,265,279,288,289,296,333,341,342,345,497,518,520,544,545,551,563,570,571,578,581,600,607,608,611,634,641,642,645,648,649],{"type":131,"content":132},"paragraph",[133],"Every team that ships an agent hits the same question within a week: when does it have to ask? Ask too rarely and one bad tool call deletes a table, sends the wrong email or refunds the wrong customer. Ask too often and people click \"allow\" without reading, which is worse than no gate, because the system now looks supervised when it is not.",{"type":131,"content":135},[136,137,142,143,147],"\"Human in the loop\" is usually treated as a checkbox: add a confirmation dialog before dangerous tools. That is the start of the design, not the end. This article covers the decisions that matter: where the gates go, how to build approvals people actually read, which interrupt and resume primitives the main agent frameworks offer today, what an audit trail has to contain, and how always-on agents like ",{"tag":138,"to":139,"children":140},"link","\u002Fblog\u002Fopenai-dots-always-on-agents-impact",[141],"OpenAI dots"," change the picture. If you want the mechanics of the loop itself first, start with ",{"tag":138,"to":144,"children":145},"\u002Fblog\u002Fagent-loop-explained",[146],"the agent loop explained",".",{"type":149,"level":150,"id":103,"text":104},"heading",2,{"type":131,"content":152},[153,154,158],"The uncomfortable evidence comes from the people who run the biggest approval prompt in the industry. In its ",{"tag":155,"href":55,"children":156},"a",[157],"engineering write-up on auto mode",", Anthropic states that Claude Code users approve 93 percent of permission prompts, and describes the consequence as approval fatigue, where people stop paying close attention to what they approve.",{"type":131,"content":160},[161,162,165],"A reported experiment makes the point sharper. According to ",{"tag":155,"href":58,"children":163},[164],"DevOps.com",", Anthropic embedded a genuinely dangerous command in permission prompts for 1,053 testers: human reviewers caught it 13.6 percent of the time, an automatic classifier caught it 89 percent of the time, and after more than 50 prior prompts the human catch rate fell to about 5 percent. This is a vendor experiment with a deliberately disguised command, so I read it as a direction rather than a constant. The direction is clear anyway: a human who has seen fifty harmless requests is a poor detector for the fifty-first.",{"type":131,"content":167},[168,169,147],"The same engineering post is honest about the other side. Its two-stage classifier still showed a 17 percent false-negative rate on real overeager actions in a small sample of 52, which Anthropic calls the honest number. Neither a person nor a model is a reliable single gate. The design goal is therefore not \"a human approves everything\", it is ",{"tag":170,"children":171},"strong",[172],"put scarce human attention where it changes the outcome, and back it with controls that do not get tired",{"type":149,"level":150,"id":106,"text":107},{"type":131,"content":175},[176,177,181],"Gating by tool name (\"ask before Bash\") is too coarse and too easy to dilute. I gate by four properties of the ",{"tag":178,"children":179},"em",[180],"action",", in this order of importance:",{"type":183,"ordered":184,"items":185},"list",false,[186,191,196,201],[187,190],{"tag":170,"children":188},[189],"Reversibility."," Can the effect be undone cheaply and completely? A draft, a branch or a row in a staging table can. A sent email, a payment, a deleted bucket or a changed permission cannot.",[192,195],{"tag":170,"children":193},[194],"Blast radius."," How many records, customers or systems does one call touch? \"Update one ticket\" and \"update every ticket matching a filter\" are the same tool with a thousandfold difference in risk.",[197,200],{"tag":170,"children":198},[199],"Data and visibility."," Does the action expose personal, financial or confidential data, or is it visible outside your organisation?",[202,205],{"tag":170,"children":203},[204],"Authority."," Does it use credentials the human did not grant for this task, or change who can do what?",{"type":131,"content":207},[208],"These properties map to four tiers. The right-hand columns matter as much as the left: a tier is only real if it names the control and the evidence it leaves behind.",{"type":210,"head":211,"rows":220},"table",[212,214,216,218],[213],"Tier",[215],"Typical actions",[217],"Control",[219],"Evidence",[221,232,243,254],[222,226,228,230],[223],{"tag":170,"children":224},[225],"0: observe",[227],"Read inside the agent scope, search, summarise, draft in a scratch area",[229],"Run automatically, least-privilege read access",[231],"Log of calls",[233,237,239,241],[234],{"tag":170,"children":235},[236],"1: reversible change",[238],"Commit to a branch, edit a draft, create a ticket, write to a staging store",[240],"Run automatically with undo; reviewer model or rules on top",[242],"Log plus before and after state",[244,248,250,252],[245],{"tag":170,"children":246},[247],"2: visible or costly",[249],"Email to a customer, post in a shared channel, bulk update within a limit, spend below a budget",[251],"Human approval with the real effect shown; batch similar steps",[253],"Approver, exact payload, timestamp",[255,259,261,263],[256],{"tag":170,"children":257},[258],"3: irreversible or privileged",[260],"Payments, deletions, production deploys, permission changes, bulk export of personal data",[262],"Hard block or mandatory handoff; two people for the worst cases; the agent cannot lower this tier",[264],"Approver, payload, reason, second approver",{"type":131,"content":266},[267,268,271,272,275,276,147],"Two rules keep the matrix honest. First, ",{"tag":170,"children":269},[270],"escalate by the worst case of the arguments, not the tool",": a refund tool called with an amount over the limit is tier 3, under it tier 2. Second, ",{"tag":170,"children":273},[274],"the agent never classifies its own action",". The tier comes from deterministic rules or from a separate component outside the agent's reach. That is exactly the structure OpenAI describes for dots, where a separate review system outside the environment the agent can change decides whether a step runs. Anthropic's permission order in the Claude Agent SDK is built the same way: ",{"tag":155,"href":49,"children":277},[278],"hooks, then deny rules, then ask rules, then the permission mode, then allow rules, then your callback",{"type":280,"attrs":281,"inner":285,"caption":286},"diagram",{"viewBox":282,"role":283,"aria-labelledby":284},"0 0 720 378","img","d1-hitl-t d1-hitl-d","\u003Ctitle id=\"d1-hitl-t\">The approval flow\u003C\u002Ftitle>\u003Cdesc id=\"d1-hitl-d\">An agent proposes an action. A risk gate outside the agent assigns a tier. Tier 0 and 1 run automatically. Tier 2 goes to a human who can approve, edit or reject. Tier 3 is blocked or handed back. Every decision is written to an audit log.\u003C\u002Fdesc>\u003Ctext x=\"20\" y=\"28\" class=\"d-title\">The approval flow\u003C\u002Ftext>\u003Ctext x=\"700\" y=\"28\" text-anchor=\"end\" class=\"d-label\">risk-tiered approval\u003C\u002Ftext>\u003Crect x=\"20\" y=\"120\" width=\"150\" height=\"76\" rx=\"10\" class=\"d-sky\" \u002F>\u003Ctext x=\"95\" y=\"154\" text-anchor=\"middle\" class=\"d-text\">Agent proposes\u003C\u002Ftext>\u003Ctext x=\"95\" y=\"175\" text-anchor=\"middle\" class=\"d-small\">tool call + args\u003C\u002Ftext>\u003Cpath d=\"M170 158 H192\" class=\"d-line\" \u002F>\u003Cpath d=\"M200 158 l-9 -5 v10 z\" class=\"d-head\" \u002F>\u003Crect x=\"200\" y=\"120\" width=\"160\" height=\"76\" rx=\"10\" class=\"d-accent\" \u002F>\u003Ctext x=\"280\" y=\"154\" text-anchor=\"middle\" class=\"d-text\">Risk gate\u003C\u002Ftext>\u003Ctext x=\"280\" y=\"175\" text-anchor=\"middle\" class=\"d-small\">tier by worst case\u003C\u002Ftext>\u003Cpath d=\"M360 158 C385 158 380 80 402 80\" class=\"d-line\" \u002F>\u003Cpath d=\"M410 80 l-9 -5 v10 z\" class=\"d-head\" \u002F>\u003Crect x=\"410\" y=\"52\" width=\"130\" height=\"56\" rx=\"10\" class=\"d-mint\" \u002F>\u003Ctext x=\"475\" y=\"76\" text-anchor=\"middle\" class=\"d-text\">Runs\u003C\u002Ftext>\u003Ctext x=\"475\" y=\"97\" text-anchor=\"middle\" class=\"d-small\">tier 0 and 1\u003C\u002Ftext>\u003Cpath d=\"M360 158 C385 158 380 158 402 158\" class=\"d-line\" \u002F>\u003Cpath d=\"M410 158 l-9 -5 v10 z\" class=\"d-head\" \u002F>\u003Crect x=\"410\" y=\"130\" width=\"130\" height=\"56\" rx=\"10\" class=\"d-gold\" \u002F>\u003Ctext x=\"475\" y=\"154\" text-anchor=\"middle\" class=\"d-text\">Asks a human\u003C\u002Ftext>\u003Ctext x=\"475\" y=\"175\" text-anchor=\"middle\" class=\"d-small\">tier 2\u003C\u002Ftext>\u003Cpath d=\"M360 158 C385 158 380 236 402 236\" class=\"d-line\" \u002F>\u003Cpath d=\"M410 236 l-9 -5 v10 z\" class=\"d-head\" \u002F>\u003Crect x=\"410\" y=\"208\" width=\"130\" height=\"56\" rx=\"10\" class=\"d-box\" \u002F>\u003Ctext x=\"475\" y=\"232\" text-anchor=\"middle\" class=\"d-text\">Blocked\u003C\u002Ftext>\u003Ctext x=\"475\" y=\"253\" text-anchor=\"middle\" class=\"d-small\">tier 3: handoff\u003C\u002Ftext>\u003Cpath d=\"M540 158 H562\" class=\"d-line\" \u002F>\u003Cpath d=\"M570 158 l-9 -5 v10 z\" class=\"d-head\" \u002F>\u003Crect x=\"570\" y=\"130\" width=\"140\" height=\"56\" rx=\"10\" class=\"d-gold\" \u002F>\u003Ctext x=\"640\" y=\"154\" text-anchor=\"middle\" class=\"d-text\">Human decides\u003C\u002Ftext>\u003Ctext x=\"640\" y=\"175\" text-anchor=\"middle\" class=\"d-small\">ok · edit · no\u003C\u002Ftext>\u003Crect x=\"20\" y=\"284\" width=\"690\" height=\"46\" rx=\"10\" class=\"d-box d-dash\" \u002F>\u003Ctext x=\"365\" y=\"312\" text-anchor=\"middle\" class=\"d-small\">Every decision is written to the audit log: who, what, which tier, outcome\u003C\u002Ftext>\u003Ctext x=\"365\" y=\"358\" text-anchor=\"middle\" class=\"d-label\">A rejection goes back to the agent as a reason, so it can pick another path.\u003C\u002Ftext>",[287],"The tier is decided outside the agent. The human sees only the cases that need a human.",{"type":149,"level":150,"id":109,"text":110},{"type":131,"content":290},[291,292,295],"When a gate does fire, the interface decides whether it works. These are the design rules I apply, and they all follow from one idea: the reviewer should be able to judge the ",{"tag":178,"children":293},[294],"effect"," in a few seconds.",{"type":183,"ordered":184,"items":297},[298,303,308,313,318,323,328],[299,302],{"tag":170,"children":300},[301],"Show the effect, not the intent."," \"The agent wants to run send_email\" is useless. \"Email to ceo@client.com, 340 words, attaches contract.pdf, cc'ing 12 people\" is reviewable. For code and data, show a diff; for money, show amount, currency and recipient.",[304,307],{"tag":170,"children":305},[306],"Make the dangerous part loud."," Highlight what is unusual: a new recipient, an amount above the median, a wildcard in a path, an external domain.",[309,312],{"tag":170,"children":310},[311],"Batch what belongs together."," Ten similar tier-2 steps should be one decision with a visible list, not ten dialogs. Fatigue grows with the count of interruptions.",[314,317],{"tag":170,"children":315},[316],"Offer edit, not just yes or no."," The Claude Agent SDK lets your callback return modified input, and LangChain's human-in-the-loop middleware has an edit decision next to approve and reject. A reviewer who can fix a parameter will not reject the whole plan.",[319,322],{"tag":170,"children":320},[321],"Make rejection carry a reason."," A deny message goes back to the model, which can then adjust. In the Claude Agent SDK, Claude sees the message of a denial; in the OpenAI Agents SDK you can set a rejection message per call.",[324,327],{"tag":170,"children":325},[326],"Be careful with \"always allow\"."," Remembering a decision removes future friction and future scrutiny together. If you offer it, scope it narrowly (this command, this path), let it expire and list active rules somewhere people can review.",[329,332],{"tag":170,"children":330},[331],"Fail closed."," If nobody answers, the answer is no. Never let a timeout approve.",{"type":131,"content":334},[335,336,340],"Then measure. My rule of thumb, which is an experience-based heuristic and not a published threshold: if a gate is approved more than about 95 percent of the time and the median decision takes a couple of seconds, it is theatre. Either the action belongs in tier 1, or the prompt does not give people what they need to judge it. Track approval rate, decision time and the share of approvals later reversed, per action type. This is the same attention problem that makes ",{"tag":138,"to":337,"children":338},"\u002Fblog\u002Fai-generated-pr-review-bottleneck",[339],"agent-written pull requests a review bottleneck",", and the fix is the same: fewer, better-prepared decisions.",{"type":149,"level":150,"id":112,"text":113},{"type":131,"content":343},[344],"Technically, a gate is a pause: the agent proposes an action, the runtime stops, state is saved, and a later call resumes with a decision. All three major stacks now have a first-class primitive for it. The API surface differs, the failure modes are similar.",{"type":210,"head":346,"rows":355},[347,349,351,353],[348],"Framework",[350],"Pause",[352],"Resume",[354],"Persistence and gotchas",[356,386,410,450],[357,361,368,381],[358],{"tag":170,"children":359},[360],"LangGraph",[362,363,367],"Call ",{"tag":364,"children":365},"code",[366],"interrupt(payload)"," in a node; the payload must be JSON-serialisable",[369,370,373,374,377,378],"Invoke again with ",{"tag":364,"children":371},[372],"Command(resume=value)"," on the same ",{"tag":364,"children":375},[376],"thread_id","; the value becomes the return of ",{"tag":364,"children":379},[380],"interrupt",[382,383,385],"Needs a checkpointer. The node restarts from its beginning, so side effects before the interrupt must be idempotent. Never wrap ",{"tag":364,"children":384},[380]," in try\u002Fexcept. Matching is index-based, keep call order stable",[387,391,400,405],[388],{"tag":170,"children":389},[390],"LangChain agents",[392,395,396,399],{"tag":364,"children":393},[394],"HumanInTheLoopMiddleware"," with ",{"tag":364,"children":397},[398],"interrupt_on"," per tool",[401,404],{"tag":364,"children":402},[403],"Command(resume={\"decisions\": [...]})"," with approve, edit, reject (or respond)",[406,407,409],"Needs a checkpointer and a ",{"tag":364,"children":408},[376],"; decisions must match the order of the paused actions",[411,415,424,436],[412],{"tag":170,"children":413},[414],"OpenAI Agents SDK",[416,417,420,421],"A tool sets ",{"tag":364,"children":418},[419],"needs_approval"," (true or an async function of the arguments); the run ends with pending ",{"tag":364,"children":422},[423],"interruptions",[425,428,429,432,433],{"tag":364,"children":426},[427],"state.approve(item)"," or ",{"tag":364,"children":430},[431],"state.reject(item, rejection_message=...)",", then run again with the ",{"tag":364,"children":434},[435],"RunState",[437,438,441,442,445,446,449],"The state serialises with ",{"tag":364,"children":439},[440],"to_json"," and ",{"tag":364,"children":443},[444],"from_json",". Only deserialise from trusted storage. ",{"tag":364,"children":447},[448],"always_approve"," makes a decision sticky",[451,455,467,485],[452],{"tag":170,"children":453},[454],"Claude Agent SDK",[456,459,460,463,464],{"tag":364,"children":457},[458],"canUseTool"," fires for calls that no hook, rule or mode has settled; for slow reviewers a ",{"tag":364,"children":461},[462],"PreToolUse"," hook can return ",{"tag":364,"children":465},[466],"defer",[468,469,472,473,476,477,480,481,484],"Return ",{"tag":364,"children":470},[471],"allow"," (optionally with ",{"tag":364,"children":474},[475],"updatedInput",") or ",{"tag":364,"children":478},[479],"deny"," with a message; a deferred call resumes with ",{"tag":364,"children":482},[483],"--resume"," and the hook fires again",[486,487,489,490,492,493,496],"Auto-approved tools never reach ",{"tag":364,"children":488},[458],"; use a ",{"tag":364,"children":491},[462]," hook for checks that must see every call. In ",{"tag":364,"children":494},[495],"dontAsk"," mode prompts become denials",{"type":131,"content":498},[499,500,503,504,507,508,510,511,514,515,517],"A few details from the official documentation are worth knowing before you build on them. LangGraph's ",{"tag":155,"href":37,"children":501},[502],"interrupts guide"," warns that a resumed node re-runs from the top, so an email sent before the interrupt would be sent twice. The OpenAI Agents SDK ",{"tag":155,"href":43,"children":505},[506],"guide"," shows that ",{"tag":364,"children":509},[419]," can be an async function that decides per call from the parameters, and says that for long-lived approvals the server should authenticate the reviewer, authorise against the stored run, validate decision IDs against server-owned state and apply decisions atomically to prevent replay. The Claude Agent SDK ",{"tag":155,"href":46,"children":512},[513],"documentation"," notes that the callback can stay pending indefinitely, and recommends the ",{"tag":364,"children":516},[466]," decision when a person might take longer than your process can stay alive.",{"type":364,"code":519},"from langgraph.types import interrupt, Command\n\ndef refund_node(state):\n    # runs again from the top after resume: keep everything above idempotent\n    decision = interrupt({\n        \"action\": \"refund\", \"amount\": state[\"amount\"],\n        \"customer\": state[\"customer_id\"], \"tier\": 3,\n    })\n    return Command(goto=\"execute\" if decision[\"approved\"] else \"cancel\")\n\n# later, possibly from another process, same thread_id\ngraph.stream_events(Command(resume={\"approved\": True}),\n                    config={\"configurable\": {\"thread_id\": \"case-4711\"}}, version=\"v3\")",{"type":131,"content":521},[522,523,526,527,530,531,534,535,538,539,543],"Whatever the framework, I add four properties on top. ",{"tag":170,"children":524},[525],"Bind the approval to the exact action",": store a hash of tool name and arguments with the decision and re-check it at execution, so a plan that changed after approval is not covered. ",{"tag":170,"children":528},[529],"Authenticate the approver"," from your session, never from the request body. ",{"tag":170,"children":532},[533],"Expire approvals"," after minutes or hours, not days. ",{"tag":170,"children":536},[537],"Make the executing step idempotent"," with an idempotency key, because resume, retry and double-click all exist. For tool security more broadly, my ",{"tag":138,"to":540,"children":541},"\u002Fblog\u002Fmcp-server-security-checklist",[542],"MCP server security checklist"," covers the other half of the problem.",{"type":149,"level":150,"id":115,"text":116},{"type":131,"content":546},[547,548,147],"An approval that leaves no record cannot be reviewed, disputed or learned from. For each gated action I log a small, boring set of facts: the run and thread identifiers, the proposed action with full arguments, the tier and the rule that assigned it, who decided (a person, a rule or a reviewer model), the decision and any edit, the timestamp and latency, and the result of the execution. Store the arguments as they were shown to the reviewer. If the UI renders a summary, keep the summary too, because a dispute is often about what the person ",{"tag":178,"children":549},[550],"saw",{"type":131,"content":552},[553,554,557,558,562],"For regulated work this is not optional. Article 14 of the EU AI Act, which applies to high-risk systems, ",{"tag":155,"href":61,"children":555},[556],"asks for oversight"," that lets assigned people understand the system's limits, stay aware of automation bias, decide not to use or to override the output, and intervene or stop the system. Whether your agent is high-risk depends on the use case, so check that before assuming either way. My ",{"tag":138,"to":559,"children":560},"\u002Fblog\u002Feu-ai-act-article-50-developer-checklist",[561],"EU AI Act checklist for developers"," covers the transparency side.",{"type":131,"content":564},[565,566,569],"Escalation is the part teams forget. Decide up front who is asked, how long they have and what happens next. A workable ladder is: the requesting user first, then a named role (the process owner), then a second approver for tier 3, and a default of reject when nobody answers. Add a ",{"tag":170,"children":567},[568],"kill switch"," that is independent of the agent: a flag that stops new runs and cancels pending approvals. Route notifications through a channel people already watch. The Claude Agent SDK, for example, has a PermissionRequest hook meant for sending a Slack or e-mail notification when an agent is waiting.",{"type":149,"level":150,"id":118,"text":119},{"type":131,"content":572},[573,574,577],"Everything above assumed a person sitting in front of a chat. Always-on agents break that assumption. A dot or a scheduled coding agent works for hours, runs while you sleep and produces approvals at machine pace. As I wrote in the ",{"tag":138,"to":139,"children":575},[576],"dots impact analysis",", the human moves from the start of the chain to the end, and attention becomes the bottleneck.",{"type":131,"content":579},[580],"OpenAI's published design for dots is a useful reference because it is a risk-tiered gate. Background research runs on read-only tools, a separate Auto-review system checks consequential steps against your instructions, your Custom Rules and safety requirements, and Custom Rules can allow, require approval for or block actions but cannot remove a mandatory floor: changing a password or moving money between accounts always returns to the person. That is tiers 0, 2 and 3 in a product.",{"type":131,"content":582},[583,584,587,588,591,592,595,596,147],"Three consequences for your own design follow. First, ",{"tag":170,"children":585},[586],"rules replace most prompts",". A rule set that says \"refunds under X run, over X ask, anything touching bank details is blocked\" removes thousands of low-value interruptions and turns the remaining ones into events worth reading. Second, ",{"tag":170,"children":589},[590],"a reviewer model is a tool, not an oracle",". It scales and it does not get tired, but Anthropic's own numbers show a non-zero miss rate, and OpenAI's Auto-review is the vendor's model supervising the vendor's agent. Keep deterministic tier-3 rules outside any model, and sample the auto-approved actions for human audit. Third, ",{"tag":170,"children":593},[594],"gates control actions, not what the agent reads",". A read-only dot still sees the whole customer record, which is why least-privilege connections and masked data belong in the design as much as approvals do. I go deeper on that pattern in ",{"tag":138,"to":597,"children":598},"\u002Fblog\u002Fprompt-injection-lethal-trifecta-patterns",[599],"prompt injection and the lethal trifecta",{"type":601,"variant":602,"title":603,"body":604},"callout","tip","Ask better, not more",[605],[606],"When the agent runs around the clock, the number of questions is a cost you pay in human attention. Move volume out of the human queue with rules and a reviewer model, and spend the human on tier 2 and 3 decisions presented with their real effect.",{"type":149,"level":150,"id":121,"text":122},{"type":131,"content":609},[610],"This is the list I would run through before putting an agent with write access in front of real data:",{"type":183,"ordered":612,"items":613},true,[614,616,618,620,622,624,626,628,630,632],[615],"List every tool and, for each, the worst-case arguments. Assign a tier from reversibility, blast radius, data and authority.",[617],"Put the tier decision outside the agent: deterministic rules first, a reviewer model second, never the agent's own judgement.",[619],"Block tier 3 by default and allow it only through a named handoff with an authenticated approver.",[621],"Build the approval screen around the effect: payload, diff, recipient, amount, with unusual parts highlighted.",[623],"Batch similar tier-2 steps, support edit as well as approve and reject, and return rejection reasons to the agent.",[625],"Pause with a checkpointer or serialised state, make everything before the pause idempotent, and bind each approval to a hash of the exact action.",[627],"Fail closed on timeout, expire approvals and keep a kill switch that does not depend on the agent.",[629],"Log who, what, tier, rule, decision, edits, timing and result, and keep what the reviewer actually saw.",[631],"Sample auto-approved actions weekly for human review, and track approval rate and decision time per action type.",[633],"Re-tier after every incident and every new tool: the matrix is a living document.",{"type":131,"content":635},[636,637,147],"If you want help turning this into a concrete architecture for your agents, that is what I do in my ",{"tag":138,"to":638,"children":639},"\u002Fexpertise\u002Fai-engineer",[640],"AI engineering work",{"type":149,"level":150,"id":124,"text":125},{"type":131,"content":643},[644],"Human in the loop will not disappear as agents improve, but its shape will. The default is moving from \"a person approves every step\" to \"a person sets the rules, reviews the exceptions and audits the rest\". Auto mode becoming the default in Claude Code and the Auto-review layer in dots are two vendors reaching the same conclusion in the same season.",{"type":131,"content":646},[647],"What stays human is accountability. A classifier can approve an action, but it cannot be responsible for it. Design every gate so that, when something goes wrong, you can answer who allowed it, on the basis of what information, and under which rule.",{"type":149,"level":150,"id":127,"text":128},{"type":183,"ordered":612,"items":650},[651,654,657,660,663,666,669,672,675,678],[652],{"tag":155,"href":37,"children":653},[36],[655],{"tag":155,"href":40,"children":656},[39],[658],{"tag":155,"href":43,"children":659},[42],[661],{"tag":155,"href":46,"children":662},[45],[664],{"tag":155,"href":49,"children":665},[48],[667],{"tag":155,"href":52,"children":668},[51],[670],{"tag":155,"href":55,"children":671},[54],[673],{"tag":155,"href":58,"children":674},[57],[676],{"tag":155,"href":61,"children":677},[60],[679],{"tag":155,"href":64,"children":680},[63],[682,747,826,891],{"slug":683,"published":5,"minutes":684,"category":7,"tags":685,"keywords":688,"about":698,"sources":706,"cover":741,"og":742,"expertise":67,"locales":743,"lang":69,"title":744,"description":745,"coverAlt":746},"openai-dots-always-on-agents-impact",14,[141,10,686,687],"GPT-6 Astra","AI governance",[141,689,690,691,692,693,694,695,696,697],"what are OpenAI dots","OpenAI dots impact","always-on AI agents","GPT-6 Astra agents","dots Auto-review and Custom Rules","specialist dots for enterprise","OpenAI dots EU availability","OpenAI DevDay 2026","AI agents in the workplace",[699,702,705],{"name":700,"url":701},"OpenAI","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FOpenAI",{"name":703,"url":704},"ChatGPT","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FChatGPT",{"name":29,"url":30},[707,710,711,714,717,720,723,726,729,732,735,738],{"title":708,"url":709},"OpenAI: Introducing dots (29 September 2026)","https:\u002F\u002Fopenai.com\u002Findex\u002Fintroducing-dots\u002F",{"title":63,"url":64},{"title":712,"url":713},"OpenAI Help Center: Dots privacy, security, and safety FAQs","https:\u002F\u002Fhelp.openai.com\u002Fen\u002Farticles\u002F20001529-dots-privacy-security-and-safety-faqs",{"title":715,"url":716},"TechCrunch: OpenAI launches Dots, its bubbly agentic avatar","https:\u002F\u002Ftechcrunch.com\u002F2026\u002F09\u002F29\u002Fopenai-launches-dots-its-bubbly-agentic-avatar\u002F",{"title":718,"url":719},"Unite.AI: OpenAI rolls out dots agents powered by GPT-6 Astra in ChatGPT","https:\u002F\u002Fwww.unite.ai\u002Fopenai-rolls-out-dots-agents-powered-by-gpt-6-astra-in-chatgpt\u002F",{"title":721,"url":722},"MediaNama: OpenAI launches dots that keep working without user prompts","https:\u002F\u002Fwww.medianama.com\u002F2026\u002F10\u002F223-openai-launches-dots-devday-2026\u002F",{"title":724,"url":725},"PYMNTS: OpenAI launches dots to capture AI agent market","https:\u002F\u002Fwww.pymnts.com\u002Fnews\u002Fartificial-intelligence\u002F2026\u002Fopenai-launches-dots-to-capture-ai-agent-market\u002F",{"title":727,"url":728},"Yahoo Finance: OpenAI debuts Dots AI agents in challenge to Meta's Muse","https:\u002F\u002Ffinance.yahoo.com\u002Ftechnology\u002Farticle\u002Fopenai-debuts-dots-ai-agents-in-challenge-to-metas-popular-muse-agent-174616593.html",{"title":730,"url":731},"CNBC: OpenAI abandons plan to release upcoming model as safety concerns escalate","https:\u002F\u002Fwww.cnbc.com\u002F2026\u002F09\u002F28\u002Fopenai-abandons-plan-to-release-upcoming-model-as-safety-concerns-escalate.html",{"title":733,"url":734},"The Hacker News: OpenAI shelves GPT-6.1 Astra after tests find deception and unauthorized actions","https:\u002F\u002Fthehackernews.com\u002F2026\u002F09\u002Fopenai-shelves-gpt-61-astra-after-tests.html",{"title":736,"url":737},"Al Jazeera: OpenAI launches dots, personal AI assistant built to handle everything","https:\u002F\u002Fwww.aljazeera.com\u002Feconomy\u002F2026\u002F9\u002F30\u002Fopenai-launches-dots-personal-ai-assistant-built-to-handle-everything",{"title":739,"url":740},"RedactSure: Do OpenAI dots Custom Rules control what the agent sees?","https:\u002F\u002Fredactsure.com\u002Fresearch\u002Fdo-openai-dots-custom-rules-control-what-the-agent-sees","\u002Fimages\u002Fblog\u002Fopenai-dots-always-on-agents-impact\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fopenai-dots-always-on-agents-impact\u002Fog.jpg",[69,70,71],"OpenAI dots: what always-on agents will change, and what they will not","OpenAI dots are always-on GPT-6 Astra agents with their own computer. What launched, how the safeguards work, and what changes for work, IT, SaaS and Europe.","Diagram: a dot running on GPT-6 Astra fans out to Slack and Teams, more than 4,000 apps, its own cloud computer, and a person who approves and reviews.",{"slug":748,"published":5,"minutes":6,"category":7,"tags":749,"keywords":754,"about":765,"sources":773,"cover":820,"og":821,"expertise":67,"locales":822,"lang":69,"title":823,"description":824,"coverAlt":825},"ai-agent-memory-design",[750,751,752,753],"AI agent memory","Context engineering","Memory poisoning","GDPR",[755,756,757,758,759,760,761,762,763,764],"AI agent memory design","long-term memory for AI agents","episodic semantic procedural memory LLM","agent memory architecture","ChatGPT memory vs Claude memory","Claude memory tool","AI memory poisoning","LLM context compaction","AI agent memory GDPR","short-term vs long-term memory agents",[766,767,770],{"name":29,"url":30},{"name":768,"url":769},"General Data Protection Regulation","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FGeneral_Data_Protection_Regulation",{"name":771,"url":772},"Prompt injection","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FPrompt_injection",[774,777,780,783,786,789,792,795,798,801,804,807,810,811,814,817],{"title":775,"url":776},"Anthropic docs: Memory tool","https:\u002F\u002Fplatform.claude.com\u002Fdocs\u002Fen\u002Fagents-and-tools\u002Ftool-use\u002Fmemory-tool",{"title":778,"url":779},"Anthropic docs: Context editing","https:\u002F\u002Fplatform.claude.com\u002Fdocs\u002Fen\u002Fbuild-with-claude\u002Fcontext-editing",{"title":781,"url":782},"Anthropic Engineering: Effective context engineering for AI agents","https:\u002F\u002Fwww.anthropic.com\u002Fengineering\u002Feffective-context-engineering-for-ai-agents",{"title":784,"url":785},"Sumers et al.: Cognitive Architectures for Language Agents (CoALA)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2309.02427",{"title":787,"url":788},"Packer et al.: MemGPT, Towards LLMs as Operating Systems","https:\u002F\u002Farxiv.org\u002Fabs\u002F2310.08560",{"title":790,"url":791},"Park et al.: Generative Agents, Interactive Simulacra of Human Behavior","https:\u002F\u002Farxiv.org\u002Fabs\u002F2304.03442",{"title":793,"url":794},"Unit 42: When AI Remembers Too Much, persistent behaviors in agents memory","https:\u002F\u002Funit42.paloaltonetworks.com\u002Findirect-prompt-injection-poisons-ai-longterm-memory\u002F",{"title":796,"url":797},"From Untrusted Input to Trusted Memory: A Systematic Study of Memory Poisoning Attacks in LLM Agents (preprint)","https:\u002F\u002Farxiv.org\u002Fhtml\u002F2606.04329v1",{"title":799,"url":800},"The Hacker News: ChatGPT macOS flaw could have enabled long-term spyware via memory function","https:\u002F\u002Fthehackernews.com\u002F2024\u002F09\u002Fchatgpt-macos-flaw-couldve-enabled-long.html",{"title":802,"url":803},"Vectorize: OWASP ASI06, Memory and Context Poisoning explained","https:\u002F\u002Fvectorize.io\u002Farticles\u002Fowasp-asi06",{"title":805,"url":806},"Claude Help Center: Use chat search and memory to build on previous context","https:\u002F\u002Fsupport.claude.com\u002Fen\u002Farticles\u002F11817273-use-claude-s-chat-search-and-memory-to-build-on-previous-context",{"title":808,"url":809},"OpenAI Help Center: Memory in ChatGPT","https:\u002F\u002Fhelp.openai.com\u002Fen\u002Farticles\u002F8590148-memory-faq",{"title":712,"url":713},{"title":812,"url":813},"Flavio Copes: A deep dive into OpenAI dots (quotes the dots documentation on memory)","https:\u002F\u002Fflaviocopes.com\u002Fopenai-dots\u002F",{"title":815,"url":816},"GDPR Article 5: Principles relating to processing of personal data","https:\u002F\u002Fgdpr-info.eu\u002Fart-5-gdpr\u002F",{"title":818,"url":819},"GDPR Article 17: Right to erasure","https:\u002F\u002Fgdpr-info.eu\u002Fart-17-gdpr\u002F","\u002Fimages\u002Fblog\u002Fai-agent-memory-design\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fai-agent-memory-design\u002Fog.jpg",[69,70,71],"Designing memory for AI agents: tiers, write rules, poisoning and GDPR","How to design AI agent memory: context vs session vs long-term tiers, what to write and never store, retrieval, compaction, poisoning and GDPR erasure.","Diagram: nested memory layers of an AI agent, from the working context window through session state to long-term episodic and semantic memory.",{"slug":827,"published":5,"minutes":828,"category":7,"tags":829,"keywords":832,"about":843,"sources":851,"cover":885,"og":886,"expertise":67,"locales":887,"lang":69,"title":888,"description":889,"coverAlt":890},"multi-agent-systems-when-worth-it",12,[830,10,831,751],"Multi-agent systems","Orchestrator-worker",[833,834,835,836,837,838,839,840,841,842],"multi-agent systems when worth it","multi-agent vs single agent","orchestrator-worker pattern","multi-agent LLM token cost","why multi-agent systems fail","don't build multi-agents","subagents context isolation","multi-agent debate worth it","agent handoffs vs subagents","when to use multiple AI agents",[844,847,848],{"name":845,"url":846},"Multi-agent system","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMulti-agent_system",{"name":29,"url":30},{"name":849,"url":850},"Large language model","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FLarge_language_model",[852,855,858,861,864,867,870,873,876,879,882],{"title":853,"url":854},"Anthropic Engineering: How we built our multi-agent research system","https:\u002F\u002Fwww.anthropic.com\u002Fengineering\u002Fmulti-agent-research-system",{"title":856,"url":857},"Anthropic: Building effective agents","https:\u002F\u002Fwww.anthropic.com\u002Fengineering\u002Fbuilding-effective-agents",{"title":859,"url":860},"Cognition: Don't Build Multi-Agents (12 June 2025)","https:\u002F\u002Fcognition.com\u002Fblog\u002Fdont-build-multi-agents",{"title":862,"url":863},"Cognition: Multi-Agents: What's Actually Working (22 April 2026)","https:\u002F\u002Fcognition.com\u002Fblog\u002Fmulti-agents-working",{"title":865,"url":866},"Google Research: Towards a science of scaling agent systems","https:\u002F\u002Fresearch.google\u002Fblog\u002Ftowards-a-science-of-scaling-agent-systems-when-and-why-agent-systems-work\u002F",{"title":868,"url":869},"arXiv 2512.08296: Towards a Science of Scaling Agent Systems","https:\u002F\u002Farxiv.org\u002Fabs\u002F2512.08296",{"title":871,"url":872},"arXiv 2503.13657: Why Do Multi-Agent LLM Systems Fail? (MAST)","https:\u002F\u002Farxiv.org\u002Fabs\u002F2503.13657",{"title":874,"url":875},"arXiv 2305.14325: Improving Factuality and Reasoning in Language Models through Multiagent Debate","https:\u002F\u002Farxiv.org\u002Fabs\u002F2305.14325",{"title":877,"url":878},"arXiv 2502.08788: Stop Overvaluing Multi-Agent Debate","https:\u002F\u002Farxiv.org\u002Fabs\u002F2502.08788",{"title":880,"url":881},"OpenAI Agents SDK: Handoffs","https:\u002F\u002Fopenai.github.io\u002Fopenai-agents-python\u002Fhandoffs\u002F",{"title":883,"url":884},"Claude Code documentation: Subagents","https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fsub-agents","\u002Fimages\u002Fblog\u002Fmulti-agent-systems-when-worth-it\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fmulti-agent-systems-when-worth-it\u002Fog.jpg",[69,70,71],"Multi-agent systems: when they beat one agent, and when they do not","Orchestrator-worker, fan-out, critic, handoff: what multi-agent systems really buy you, what they cost in tokens, how they fail, and a table to decide.","Diagram: a lead agent fans out to four worker agents, each with its own isolated context window, and gathers their summaries back.",{"slug":892,"published":5,"minutes":6,"category":7,"tags":893,"keywords":899,"about":910,"sources":920,"cover":975,"og":976,"expertise":67,"locales":977,"lang":69,"title":978,"description":979,"coverAlt":980},"voice-agents-realtime-latency",[894,895,896,897,898],"Voice agents","Realtime API","Latency","Telephony","AI Act",[900,901,902,903,904,905,906,907,908,909],"voice agents","speech-to-speech vs STT LLM TTS","OpenAI Realtime API","Gemini Live API","voice agent latency budget","turn detection and barge-in","Pipecat vs LiveKit","AI voice agent SIP telephony","German Hungarian voice AI","AI Act Article 50 voice bot disclosure",[911,914,917],{"name":912,"url":913},"Voice user interface","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FVoice_user_interface",{"name":915,"url":916},"Speech recognition","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSpeech_recognition",{"name":918,"url":919},"Artificial Intelligence Act","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FArtificial_Intelligence_Act",[921,924,927,930,933,936,939,942,945,948,951,954,957,960,963,966,969,972],{"title":922,"url":923},"OpenAI: Voice agents guide","https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Fvoice-agents",{"title":925,"url":926},"OpenAI: gpt-realtime model page","https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fmodels\u002Fgpt-realtime",{"title":928,"url":929},"OpenAI: Voice activity detection in the Realtime API","https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Frealtime-vad",{"title":931,"url":932},"OpenAI: Realtime API with SIP","https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Frealtime-sip",{"title":934,"url":935},"OpenAI: Realtime conversations (function calling, interruption)","https:\u002F\u002Fdevelopers.openai.com\u002Fapi\u002Fdocs\u002Fguides\u002Frealtime-conversations",{"title":937,"url":938},"Google: Gemini Live API overview","https:\u002F\u002Fai.google.dev\u002Fgemini-api\u002Fdocs\u002Flive",{"title":940,"url":941},"Google: Gemini Live API capabilities guide","https:\u002F\u002Fai.google.dev\u002Fgemini-api\u002Fdocs\u002Flive-guide",{"title":943,"url":944},"Deepgram: Flux quickstart","https:\u002F\u002Fdevelopers.deepgram.com\u002Fdocs\u002Fflux\u002Fquickstart",{"title":946,"url":947},"Deepgram: Models and languages overview","https:\u002F\u002Fdevelopers.deepgram.com\u002Fdocs\u002Fmodels-languages-overview",{"title":949,"url":950},"ElevenLabs: Agents platform overview","https:\u002F\u002Felevenlabs.io\u002Fdocs\u002Feleven-agents\u002Foverview",{"title":952,"url":953},"ElevenLabs: Text to speech models and languages","https:\u002F\u002Felevenlabs.io\u002Fdocs\u002Foverview\u002Fcapabilities\u002Ftext-to-speech",{"title":955,"url":956},"LiveKit: Agents overview","https:\u002F\u002Fdocs.livekit.io\u002Fagents\u002F",{"title":958,"url":959},"LiveKit: Turn detector","https:\u002F\u002Fdocs.livekit.io\u002Fagents\u002Flogic\u002Fturns\u002Fturn-detector\u002F",{"title":961,"url":962},"Pipecat: Introduction","https:\u002F\u002Fdocs.pipecat.ai\u002Fgetting-started\u002Fintroduction",{"title":964,"url":965},"Pipecat: Smart Turn model (GitHub)","https:\u002F\u002Fgithub.com\u002Fpipecat-ai\u002Fsmart-turn",{"title":967,"url":968},"Fora Soft: Voice AI agents on LiveKit, 2026 engineer playbook","https:\u002F\u002Fwww.forasoft.com\u002Fblog\u002Farticle\u002Fvoice-ai-agents-livekit-guide",{"title":970,"url":971},"EU AI Act: Article 50, transparency obligations","https:\u002F\u002Fartificialintelligenceact.eu\u002Farticle\u002F50\u002F",{"title":973,"url":974},"Jones Walker: Yes, August 2 still matters (AI Act delay and Article 50)","https:\u002F\u002Fwww.joneswalker.com\u002Fen\u002Finsights\u002Fblogs\u002Fai-law-blog\u002Fyes-august-2-still-matters-the-eu-approved-a-high-risk-ai-delay-but-most-trans.html?id=102nbon","\u002Fimages\u002Fblog\u002Fvoice-agents-realtime-latency\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fvoice-agents-realtime-latency\u002Fog.jpg",[69,70,71],"Building voice agents: realtime speech-to-speech or STT, LLM and TTS?","Realtime speech-to-speech or a cascaded pipeline? Latency budget per stage, turn-taking, tool calls, SIP, German and Hungarian quality, and AI Act disclosure.","Diagram: a caller reaches a voice agent over SIP or WebRTC, which fans out to turn detection, speech recognition, an LLM with tools and speech synthesis.",1791009037039]