Skip to content

Commit 04e776b

Browse files
docs(spec, docs): App.defaultAgent and actions-as-tools name the agent route as the one chat door (#21976)
Fixes #21968 **Merge gate:** this PR merges only once objectstack-ai/cloud#2651 has merged. That PR removes the three assistant routes. Until it lands, the corrected text would be ahead of the server. Clause-②: no ## What changed The `App.defaultAgent` docblock and one docs callout named `POST /api/v1/ai/assistant/chat`, a route the maintainer's ruling on objectstack-ai/cloud#2621 retires. Both texts now name the agent route, `POST /api/v1/ai/agents/:agentName/chat`, as the one chat door. - **`packages/spec/src/ui/app.zod.ts`, the `App.defaultAgent` docblock.** It no longer says a server route reads the key. It now describes the reader that exists, objectui at the `.objectui-sha` pin `0abd4f9f87`: the chat dock passes the active app's `defaultAgent` to the console's one surface-to-agent resolver. That resolver honours the value only when it names `ask` or `build` (legacy aliases included) and otherwise falls back to the surface default. The resolved agent is then called by name on the agent route, where the `:agentName` path segment selects the agent. The sentence on the bare `POST /api/v1/ai/chat` route stays, shortened: it reads no agent, so the key does not scope it. The ADR-0063 surface-binding paragraph and the rule that only the two platform agents resolve are unchanged. - **`content/docs/ai/actions-as-tools.mdx`.** The in-product chat-route callout lists the agent route only. It keeps its account of how the principal is taken from `req.user` and forwarded as `toolExecutionContext`. - **Changeset** `@objectstack/spec` `patch`. Measured: after `pnpm --filter @objectstack/spec build`, the new docblock text has 1 hit in each of `dist/ui/index.mjs` and `dist/ui/index.js`, and in the `dist/browser` bundles. The old route string has 0 hits in `dist`. The positive control, the unchanged ADR-0063 paragraph, has 1 hit in `dist/ui/index.mjs`. The package's `files` list also ships `src/**/*.zod.ts`. The `.d.ts` files do not carry the docblock. No schema, parse, `.describe()`, export, type or accept-set change. `check:generated` confirms that no generated reference moved. ## How the console reads the key (objectui at `0abd4f9f87`, read-only) - `ConsoleLayout.tsx` passes `activeApp?.defaultAgent` to the chat dock, both on desktop and in the mobile sheet. - `ChatDock.tsx` (`ChatDockConversation`) calls `resolveSurfaceAgent('default', { agents, appDefaultAgent: defaultAgent, aiStudioEnabled, canAuthorMetadata })`. It posts to `apiBase/agents/NAME/chat`, with the resolved name URL-encoded. - `surfaceAgent.ts` (`resolveSurfaceAgent`) runs these steps in order: 1. It keeps the value only if `isBuiltinAgentName` holds. That means `build`, `metadata_assistant`, `ask` or `data_chat`. Any other value is dropped. 2. With no kept value, the surface default applies: `build` on `studio-build`, `ask` everywhere else. 3. A `build` request falls back to `ask` when AI Studio is off. 4. An `ask` request becomes `build` for a principal who may author metadata, when the catalog serves `build`. 5. The result is matched against the live catalog, alias-aware. If nothing matches, the catalog's platform default is used. ## Census of the three retired routes, and of claims that a server route reads `defaultAgent` Searched at `c9761cd2fb` (`git grep`, outside `content/docs/releases/`): | Hit | Lane | Disposition | |---|---|---| | `packages/spec/src/ui/app.zod.ts:1658` | spec | moved with this card | | `content/docs/ai/actions-as-tools.mdx:275` | docs | moved with this card | | `packages/spec/CHANGELOG.md:29568`, `packages/client/CHANGELOG.md:3498`, `packages/runtime/CHANGELOG.md:31673` | release-owned | listed, not edited. These are historical entries. | | `packages/spec/liveness/agent.json:3` and `:70` cite cloud `routes/assistant-routes.ts#buildAssistantRoutes` | spec, ledger evidence | listed, not edited. They name the handler file, not a route path, and are anchored at `cloud cb8ee7ff`, where they stay true. `planning.maxIterations` is still live through `agent-routes.ts` and `eval-runner.ts`. This lane cannot read cloud to re-anchor them. | `skills/**`, `.claude/**`, `docs/adr/**` and `examples/**` have zero hits for the three routes. No text in `content/docs`, `skills` or `examples` says a server route reads `defaultAgent`. No test asserts the docblock text, so no needle moves. ## Tests All runs are at `7f6089bd50` (HEAD). The spec build was taken at `4e79442153`, whose source is the same; the build-input stamp matched. - `pnpm --filter @objectstack/spec build`: VERDICT command-exit 0. - `pnpm --filter @objectstack/spec check:generated`: exit 0, "All 15 generated artifacts are up to date". - `pnpm --filter @objectstack/spec run typecheck`: VERDICT command-exit 0. - `vitest run --project local` over the six `src/ui/app*.test.ts` files: 6 files, 203 tests passed. This is a declared narrowing. The diff is a comment in `app.zod.ts`, so the full spec suite is left to CI. - `node scripts/pm/dispatch-gates.mjs --ran`: 101 derived, 100 run, 1 NOT MEASURED, 0 UNRUN. - Five gates first refused with PREREQUISITE NOT MET (exit 3): `check:doc-formula-expressions`, `check:doc-security-posture`, `check:skill-examples`, `check:docs-transcript-drift` and `check:lean-entry-closure`. After a build of formula, lint, client, client-react and objectql, all five exited 0. - NOT MEASURED: `check:dual-build-cjs-loads`, reason: it needs `dist` for the whole workspace (87 packages). As a narrowed stand-in, all 19 `require` entries of `@objectstack/spec` load. CI's `Lint & Repo Gates` runs the full gate. - The six artifact-roster gates flagged under my paths also exited 0: `check-changeset-fixed`, `check:authz-resolver`, `check:error-code-casing`, `check:filter-alias-parity`, `check:meta-url-spelling` and `check:spec-changes`. - **Lint, narrowed:** `eslint --no-inline-config --format json` over the two edited source files. - Population, read from eslint's own answer: `app.zod.ts` is linted, with 0 errors and 0 warnings. The `.mdx` file is outside the population ("no matching configuration"). - Invariance: `eslint.config.mjs` never enables type-aware linting (it has no `parserOptions.project`), so this diff cannot move the result for any file it does not touch. ## Acceptance notes - objectui's `AiChatPage.tsx` also takes a `defaultAgent` prop, and resolves it with `resolveDefaultAgentName`, which is not bounded to `ask` / `build`. But the console mounts it in `apps/console/src/App.tsx` with no props, so `app.defaultAgent` never reaches it there. The docblock therefore describes only the dock path. This is noted, not filed: nothing passes the key down that path. Carrier: none. - Whether `defaultAgent` needs a server consumer is not this card's question (triage). --- _Generated by [Claude Code](https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent dcf3eb4 commit 04e776b

3 files changed

Lines changed: 27 additions & 12 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"@objectstack/spec": patch
3+
---
4+
5+
`App.defaultAgent` docblock: the agent route is the one chat door, and the console is what reads the key.
6+
7+
Clause-②: no
8+
9+
- The docblock no longer says the assistant chat endpoint (`POST /api/v1/ai/assistant/chat`) resolves this agent from `context.appName`. That route, with `GET /api/v1/ai/assistant` and `GET /api/v1/ai/assistant/skills`, was retired in the cloud AI runtime (objectstack-ai/cloud#2621, objectstack-ai/cloud#2651), and no server route reads `defaultAgent`.
10+
- It now says who does read it. The console's chat dock hands the active app's `defaultAgent` to its one surface-to-agent resolver, which honours only `ask` or `build` (legacy aliases included) and otherwise falls back to the surface default. The resolved agent is then called by name on `POST /api/v1/ai/agents/:agentName/chat`, where the path segment, not this key, selects the agent.
11+
- The ADR-0063 surface-binding paragraph and the rule that only the two platform agents resolve are unchanged, as is the note that the bare `POST /api/v1/ai/chat` resolves no agent.
12+
- The docs page `ai/actions-as-tools` lists the agent route as the only in-product chat route.
13+
- ⛔ No schema, parse, `.describe()`, export, type or accept-set change. The docblock ships in the published package, in the `dist/ui` and `dist/browser` JavaScript bundles and in the shipped `src/ui/app.zod.ts`, which is why this is a patch.

‎content/docs/ai/actions-as-tools.mdx‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,9 @@ action into AI only when its logic is safe to run on behalf of anyone the
271271
capability gate admits.
272272

273273
<Callout type="info">
274-
**ObjectOS** — the in-product chat routes
275-
(`/api/v1/ai/assistant/chat`, `/api/v1/ai/agents/:agentName/chat`) resolve the
276-
authenticated principal from `req.user` — both cookie session
277-
(`better-auth.session_token`) and Bearer token are handled — and forward it to
274+
**ObjectOS** — the in-product chat route, `/api/v1/ai/agents/:agentName/chat`,
275+
resolves the authenticated principal from `req.user` — both cookie session
276+
(`better-auth.session_token`) and Bearer token are handled — and forwards it to
278277
`aiService.chatWithTools(...)` as
279278
`toolExecutionContext: { actor, conversationId, environmentId }`. That threads the
280279
same RLS context through the runtime's built-in data tools and its

‎packages/spec/src/ui/app.zod.ts‎

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,15 +1655,18 @@ export const AppSchema = lazySchema(() => strictObject(
16551655
/**
16561656
* Default agent for this app's ambient chat surface.
16571657
*
1658-
* When set, the assistant chat endpoint (`POST /api/v1/ai/assistant/chat`)
1659-
* resolves this agent for a call carrying `context.appName`, without the
1660-
* user having to pick from a list — that route is what drives the
1661-
* resolution chain (explicit agent > `defaultAgent` of the named app >
1662-
* first active agent).
1658+
* The console's agent surfaces read this key; no server route does. The
1659+
* chat dock hands the active app's `defaultAgent` to the console's one
1660+
* surface→agent resolver (objectui `surfaceAgent.ts`, called from
1661+
* `ChatDock.tsx`), which honours it only when it names `ask` or `build`
1662+
* (legacy aliases included) and otherwise falls back to the surface
1663+
* default. The agent it resolves is then called by name on the agent route,
1664+
* `POST /api/v1/ai/agents/:agentName/chat` — the one chat door, where the
1665+
* `:agentName` path segment, not this key, selects the agent.
16631666
*
1664-
* The bare `POST /api/v1/ai/chat` route is NOT part of that chain: it
1665-
* resolves no agent and never reads `context.appName`, so this key does not
1666-
* scope it. Do not read this key as a guarantee over that endpoint.
1667+
* The bare `POST /api/v1/ai/chat` route resolves no agent at all, so this
1668+
* key does not scope it either. Do not read this key as a guarantee over
1669+
* any endpoint.
16671670
*
16681671
* ADR-0063 §1/§2 — this is a SURFACE-BINDING knob, not a custom-agent
16691672
* slot: the resolvable values are the two platform agents (`ask` for a

0 commit comments

Comments
 (0)