Skip to content

Two places document bare POST /api/v1/ai/chat as agent-resolved — it resolves no agent at all #10510

Description

@baozhoutao

Found while verifying cloud#1487 (bare /ai/chat offered the full ToolRegistry). Two shipped declarations claim the bare chat endpoint resolves an agent. It does not — the route has no agent identity, which is precisely why AIService fell back to the whole tool registry for it.

Site 1 — packages/client/src/index.ts:4243 (client.ai.agents JSDoc):

/ai/chat talks to the environment's default agent; these talk to one you name.

The cloud route (packages/service-ai/src/routes/ai-routes.ts, POST /api/v1/ai/chat) loads no agent, consults no AgentRuntime, and binds no skills. client.ai.chat() reaches a raw, agent-less chat plane; client.ai.agents.chat() is the only SDK method that reaches an agent.

Site 2 — packages/spec/src/ui/app.zod.ts:1502-1504 (App.defaultAgent JSDoc):

When set, the ambient chat endpoint (POST /api/v1/ai/chat with context.appName) auto-resolves to this agent without the user having to pick from a list.

The bare route never reads context.appName. The app.defaultAgent resolution chain lives in AgentRuntime.resolveDefaultAgent (cloud packages/service-ai/src/agent-runtime.ts:519-540) and is driven by the assistant routes (assistant-routes.ts:171-179, "explicit > defaultAgent(app) > first active") — i.e. POST /api/v1/ai/assistant/chat, not POST /api/v1/ai/chat.

Why this is worth fixing rather than shrugging at. Both sites read as a security-relevant guarantee: if the bare endpoint were agent-resolved, its tool offer would be scoped by that agent's skills (ADR-0063 §1/§5, the property cloud#1480/PR #1485 restored). It is not, and the gap between the two claims and the implementation is what made the bare route the third door onto that leak. A reader auditing "which endpoints are surface-scoped?" from these declarations gets the wrong answer at both sites.

Two possible resolutions — this needs a decision, not just an edit:

  • Correct the docs. Site 1 names the agent routes as the agent-bearing surface; site 2 names the ambient/assistant endpoint as the one that reads context.appName. Cheapest, and truthful today.
  • Make the implementation match. Route the bare endpoint through the same default-agent chain the assistant route uses. That is a behaviour change for every bare-chat caller and belongs in the cloud repo; it would also supersede the capability gate cloud#1487 just landed.

Cross-refs: cloud#1487 (the fix that closed the tool leak on this route), cloud#1480 / cloud PR #1485 (the agent-scope fix these declarations describe), cloud#1015 (the sibling inert-permissions finding).

Filed unassigned by the cloud#1487 dev seat; recorded rather than fixed because it is out of that card's scope and lands in this repo.

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions