Problem
docs/HUMAN_IN_THE_LOOP.md describes the approval gate added to the engine:
every tool call requires explicit approval unless the agent sets auto: true.
The bare engine HTTP API (agentctl serve, src/agent_engine/api/app.py)
fully supports this — /invoke and /stream return pending_approval in
their response, and GET /runs/{run_id} +
POST /runs/{run_id}/approvals/{approval_id}/decision (with /approve and
/reject shortcuts) let a caller resolve it.
agent_manager — the conversation-history + widget layer used by the
embeddable chat widget — has none of this:
SendMessageResponse (src/agent_manager/api/schemas.py) has no
pending_approval field at all.
POST /conversations/{id}/messages
(src/agent_manager/api/routes.py::send_message) just returns
result.answer, result.visited, result.used_tools — when the engine
pauses for approval, answer is simply empty. No error, no indication
anything is pending.
- There is no endpoint anywhere in
agent_manager to submit an approval
decision.
Impact
Any agent served through agent-manager (i.e. through the embeddable
widget) that doesn't set auto: true silently breaks on its first tool
call: the widget shows an empty response with no explanation, and there is
no way to ever unblock it via the API. auto: true works around it by
skipping the approval gate entirely, but that's a workaround, not a fix —
it means "use the widget" and "use tool approval" are currently mutually
exclusive.
Suggested fix
Mirror what agent_engine/api/app.py already does, adapted to
agent_manager's conversation-oriented shape:
- Add
pending_approval to SendMessageResponse (and confirm/extend the
streaming path — RunStreamEvent already has a pending_approval event
type; check how much of this is already reachable via
/conversations/{id}/messages/stream).
- Add a decision endpoint, e.g.
POST /conversations/{id}/approvals/{approval_id}/decision, calling into
the engine's resume(...).
- Update
widget.js to render an approve/deny prompt when a response
carries a pending approval, instead of showing an empty message.
Found while building a demo integration where the agent needed both tool
approval and the embeddable widget.
Problem
docs/HUMAN_IN_THE_LOOP.mddescribes the approval gate added to the engine:every tool call requires explicit approval unless the agent sets
auto: true.The bare engine HTTP API (
agentctl serve,src/agent_engine/api/app.py)fully supports this —
/invokeand/streamreturnpending_approvalintheir response, and
GET /runs/{run_id}+POST /runs/{run_id}/approvals/{approval_id}/decision(with/approveand/rejectshortcuts) let a caller resolve it.agent_manager— the conversation-history + widget layer used by theembeddable chat widget — has none of this:
SendMessageResponse(src/agent_manager/api/schemas.py) has nopending_approvalfield at all.POST /conversations/{id}/messages(
src/agent_manager/api/routes.py::send_message) just returnsresult.answer,result.visited,result.used_tools— when the enginepauses for approval,
answeris simply empty. No error, no indicationanything is pending.
agent_managerto submit an approvaldecision.
Impact
Any agent served through
agent-manager(i.e. through the embeddablewidget) that doesn't set
auto: truesilently breaks on its first toolcall: the widget shows an empty response with no explanation, and there is
no way to ever unblock it via the API.
auto: trueworks around it byskipping the approval gate entirely, but that's a workaround, not a fix —
it means "use the widget" and "use tool approval" are currently mutually
exclusive.
Suggested fix
Mirror what
agent_engine/api/app.pyalready does, adapted toagent_manager's conversation-oriented shape:pending_approvaltoSendMessageResponse(and confirm/extend thestreaming path —
RunStreamEventalready has apending_approvaleventtype; check how much of this is already reachable via
/conversations/{id}/messages/stream).POST /conversations/{id}/approvals/{approval_id}/decision, calling intothe engine's
resume(...).widget.jsto render an approve/deny prompt when a responsecarries a pending approval, instead of showing an empty message.
Found while building a demo integration where the agent needed both tool
approval and the embeddable widget.