Skip to content

agent_manager has no way to surface or resolve human-in-the-loop approvals #29

Description

@AmitAvital1

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:

  1. 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).
  2. Add a decision endpoint, e.g.
    POST /conversations/{id}/approvals/{approval_id}/decision, calling into
    the engine's resume(...).
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions