Backend Connection
Purpose
This directory owns the chat package's connection to the backend: the same platform Command Center talks to. It holds the transport and endpoint helpers for agent sessions, runtime access and readiness, the chat request, and model providers. UI state stays outside this directory.
Every Agent uses the same session-bound runtime contract. There is no Agent-type-specific runtime bootstrap and no coding-agent service discovery layer.
See ADR 096 for the package and the routes it calls, ADR 098 for the unified Agent decision, and AgentSession Resolution for the end-to-end sequence.
The Connection
connection.ts is the one input every client takes. The package reads no environment variable and
no configuration file; whoever mounts the chat builds a connection and passes it in:
const connection = createChatBackendConnection({
apiBaseUrl: "https://api.example.com",
rewriteRequestUrl: (url, target) => url.toString(),
sendPlatformRequest: (request) => sendAsThePerson(request),
});
apiBaseUrlis the platform API base URL, absolute.rewriteRequestUrlis optional. It receives the full URL the package is about to request and where the request is going ("platform"or"agent-runtime"), and returns the address the browser should request instead.sendPlatformRequestis optional and is how an application owns authentication. Every platform request goes to it as a standardRequestwithout any credential (platform-request.tsremoves theAuthorizationa client set), and itsResponseis used as it comes: the application adds the person's credential, renews it after a401, and sends the request again. Without it, clients send thetokentheir caller passes. Requests to the Agent's runtime never go through it.
The rewrite exists because the platform API and the Agent's runtime answer browser requests only
from the origins on their allow-lists. An application served from another origin reaches them
through an address on its own origin that forwards the call, and the rewrite is where it says
which one. Command Center uses it for its development proxy, and the standalone application for
its own (/__platform__). The package never detects a
development build and never knows about a proxy.
Every request goes through the rewrite. connection.test.ts holds each client to that, and to
the sender when there is one, because one client
that skipped the rewrite would break an application that depends on it. The only request that does
not is the direct test turn to a custom provider's own endpoint, which must never pass through a
proxy.
Entry Points
agent-session-runtime-access.tscallsPOST /api/v1/agent-sessions/{session_uid}/resolve-runtime-access/and normalizes the backendruntime_interactionandruntime_presenceenvelopes.assistant-endpoint.tsresolves a concrete session's runtime endpoint and bearer token, then owns consistent authorization refresh-and-retry behavior for runtime requests.fetchVerifiedAgentSessionRuntimeAccessis the access every caller uses: the platform decision plus the check that the Agent answers (ADR 093).agent-runtime-serving.tsis that check: oneGET {rpc_url}/api/chatwith the runtime token, the fifteen-second memo of an Agent that answered, the wake clock of one that does not, and the client-builtwakingandcheckingdecisions.runtime-interaction.tsnormalizes the backend admission decision and identifies transient states without deriving policy from diagnostics.requestThroughRuntimeWakeholds a request that met a transient decision until the shared poller reports the Agent ready, then sends it.agent-sessions-api.tsowns AgentSession list/detail/archive/delete, managed session creation, and handle-based get-or-create transport.agent-session-readiness.tsdefines the shared detail, insights, and history readiness model.agent-session-request.tsbuilds session-bound assistant request payloads (ADR 060).local-agent-api.tsowns the routes of an Agent on the developer's machine (ADR 099), under the local source's same-origin path:/readyand/health(local mode only), the chat check, the session list and history (ms-tau-sdk#47; a 404 means live-only), the Agent's identity, the provider catalog (the platform's shape, parsed bymodel-catalog-api.ts), the session's model, and cancel. It never calls a platform route and never sends a credential.session-history-api.ts,session-insights-api.ts, andsession-cancel-api.tsown their respective AgentSession operations.session-history.ts,session-insights.ts, andmessage-provenance.tsnormalize what they return.model-catalog-api.tsreads the platform's canonical/api/v1/model-providers/catalog, andrun-config-selection.tsresolves a provider, model, and thinking choice against it.model-provider-auth-api.tsandcustom-model-provider-api.tsown provider authentication and Organization-scoped provider administration.custom-model-provider-model-json.tsreads and writes a custom model as JSON.custom-model-direct-chat.tssends one stateless test turn straight from the browser to an Organization custom provider's OpenAI-compatible endpoint (/chat/completionsor/responses) and parses the streamed reply. It is the only module here that does not talk to the platform or an Agent runtime: no Agent, AgentSession, runtime access, or platform JWT is involved.command-center-agent-icons-api.tsreads the agent icon projection and an icon's bytes (ADR 090).tool-activity.ts,error-source.ts,http-error.ts, anduser-scope.tsare the shared helpers: tool activity labels, where an error came from, HTTP error text, and the user scope of a request. See provider errors.
Runtime Contract
Callers must provide a concrete AgentSession ID. Runtime resolution calls:
POST /api/v1/agent-sessions/{session_uid}/resolve-runtime-access/
mode: "token" must include a usable rpc_url and token. mode: "unavailable" may omit both and
must preserve the backend detail and interaction decision. The frontend must use the returned URL
and token as one access bundle.
runtime_interaction.can_submit is the admission decision. Notice copy, severity, operation,
and retry timing are backend-owned. runtime_presence is diagnostic only.
One exception, ADR 093: the platform answers ready for every deployed Agent, idle or not, so a
ready is confirmed by asking the Agent itself. Until it answers, the access result carries a
client-built waking decision (can_submit: false) and every consumer waits as for a
platform-reported wake. Only a ready can be downgraded; a blocked or transient platform decision
is never upgraded or re-checked. A message request is sent only after a check succeeded and is
never re-sent after a network failure.
Runtime code must not read user preferences, discover services, or choose an Agent implicitly. Whoever mounts the chat chooses the Agent and the session; after that every session uses this exact runtime flow.
Environment and Identity
AgentSession collection reads require organization_environment_uid. User-scoped chat catalogs
also include created_by_user_uid, and returned records are rejected if their serialized
Environment differs from the active Environment.
Handle-session requests send the Agent UID, handle, name, and optional run configuration. User identity comes from authenticated backend context and must not be supplied by the frontend.
Maintenance Notes
- Keep this directory free of assistant-ui hooks and presentation state.
- Every new client takes
connectionand builds its address withresolvePlatformApiUrlorresolveRequestUrl. Add it toconnection.test.ts. - Never read
import.meta.env, a configuration file, or a host module here. The boundary check fails the build on it. - Never add a configured endpoint fallback for a session-bound production runtime request. The
Agent's runtime is reached only through the
rpc_urlthe platform returns. - Do not branch runtime resolution by Agent name or type.
- Do not reintroduce coding-agent service list/detail/deploy endpoints or deployment defaults.
- Keep transient polling driven by backend
retry_after_ms, paused while the document is hidden, and stopped on ready or terminal state. - Keep provider/model catalog loading independent of runtime access.
custom-model-direct-chat.tsmirrors the request an Agent sends a custom provider (stream: true,stream_options.include_usage,store: false,max_completion_tokensormax_output_tokens,reasoning_effortwithoffomitted, API key as bearer unless an explicitAuthorizationheader is configured) minus tools, so a passing test predicts agent execution. Update it when that request shape changes. It must never send the platform JWT or cookies (credentials: "omit"), log or persist caller-supplied secrets, or be routed through a proxy or the connection's rewrite: the endpoint has to be HTTPS (browsers block plain HTTP from an HTTPS page, loopback excepted) and must allow CORS from the application's origin. A browser cannot tell a CORS rejection from an unreachable host, so both surface as onenetworkerror stage.- Treat a
404history read for a fresh session as an empty transcript, not a failed session. - Keep archived and active session queries explicitly scoped and UID-first.