Files
classic-models-agent-assistant/CLAUDE.md
T
Stéphane Tailland ebf864f7ba feat: the orchestrating agent
Entry point for the estate: understands a request, consults the specialists
that can settle it, composes one answer. LangGraph 1.2.11, a2a-sdk 1.1.2, both
current as of August 2026.

It holds no data, and the realm is what enforces that rather than the prompt.
classic-models-agent-assistant is granted two optional scopes — one per
specialist, plus the inference endpoint — and every domain audience it could
request comes back Invalid scopes. An injection that succeeds here finds no
path to a domain because there is none. "No scopes at all" was too absolute:
the agent has to reason, and inference is not a domain.

The two-hop token chain was the heaviest unproven thing in the design and it
holds: sub stays the end user through all four hops, so their own roles apply
at the far end and the MCP server filters tool discovery for the right human.
azp names the last agent, not the first — Keycloak accepts actor_token and
emits no act claim, so an orchestrator's identity survives only in the traces.

Verified end to end: a routed question answered from the specialist's data; a
question outside every remit refused rather than answered from memory; and a
write proposed through the orchestrator, held by the specialist in
input-required, relayed here unchanged, approved by the user through the same
conversation, and written. The orchestrator never owns that decision.

The graph is plan → delegate → plan, tools described by what a specialist
decides rather than what it holds, delegations in one step run concurrently and
capped at eight counted in calls. Rebuilt per turn, because its tools carry the
user's token.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 12:26:20 +02:00

2.9 KiB

Assistant — orchestrating agent

Framework: LangGraph · Mode: conversational · Client id: classic-models-agent-assistant

The single entry point for users. Understands the request, delegates to specialists over A2A, composes the answer.

Scopes

None. This agent has no MCP server and no domain scope, by design. It is the component that sees raw user text, therefore the prompt-injection target, and it must be structurally incapable of exfiltrating data. If you find yourself wanting to give it a domain scope, the work belongs in a specialist instead.

What it calls

Every other agent, over A2A: Ventes, Catalogue, Support, Approvisionnement, Recouvrement. It calls them in parallel when the request allows.

Example: "can we ship order 10248?" → Ventes (order contents) and Approvisionnement (stock) concurrently, then compose.

Why LangGraph here

The orchestrator is where the routing logic is worth making explicit. A graph states which specialist is consulted when, and where the composition happens — useful when a request fans out and the answers must be reconciled.

Watch out

LangGraph's MultiServerMCPClient fixes its headers at construction and rebuilding it loses in-memory checkpoints (langchain-mcp-adapters #172, #194, #235). This agent has no MCP servers, so it is not affected — but do not copy an MCP pattern from here into a specialist.

"No scopes at all" was too absolute. The agent has to reason, so it holds llm-proxy-audience as well as one audience per specialist. Inference is not a domain. What the rule means, and what the realm enforces, is that no domain audience is reachable from here.

Answer.needs_the_user is the other thing not to lose: a specialist that parks a decision must have its message relayed unchanged. Paraphrasing a proposed write hides what is about to happen, and approving it here would move the decision to the component with the weakest standing to make it.

Before writing code

Read classic-models-agent-platform/CLAUDE.md first. It holds the identity model, the MCP and LLM endpoints, the token-exchange recipe and the known blockers. This file only covers what is specific to this agent.

Non-negotiables

  • Inference goes through the estate's LLM endpoint, https://llm-dev.sttlab.local/llm/v1/chat/completions. Calling a model provider directly bypasses the rate limits and prompt guards.
  • One client per conversation turn, built with freshly exchanged tokens. Here that is the A2A client and the graph itself: both carry the user's token.
  • Never name the middleware. The agent talks to URLs that honour a contract. Write "the MCP server", "the LLM endpoint", "the gateway" — never a product name, in code, comments, commits or docs.
  • A2A calls return answers, not data. Expose narrow decision-shaped skills, never a generic query.
  • Deliverables in English.