Stand-in
Purpose
A scripted stand-in for the backend the chat package calls: every platform API route and every
Agent runtime route of ADR 096, section 3. It keeps sessions, transcripts, and model providers in
memory and answers in the shapes the package's clients in ../../src/backend/ parse. The standalone
application's tests run against it (ADR 096, section 9), and ?stand-in runs the application on it
in development, with no platform and no token.
Entry Points
createStandIn(options)(index.ts) returns a stand-in:fetch, to put in place of the global one, and what a test reads and scripts:requests,findRequests(method, path), andunhandledRequests(requests without a route; a complete stand-in keeps it empty);sessions, with their transcripts, andturns, the chat turns with the body the chat sent, the frames streamed back, and how each ended;failNextTurn(errorText?): the next turn streams an error frame instead of a reply;holdReplies()andreleaseReplies(): replies wait after their reasoning, so a run can be stopped.
installStandIn(options)replaceswindow.fetchfor the page (../main.tsxcalls it for?stand-in), prefills the connect form when nothing is stored underchat-standalone.settings, and puts the stand-in onwindow.chatStandIn, so its script can be driven from the browser console. It streams with a small delay per frame so a reply can be watched.standInIdentity(identity.ts): the platform URL, person, Environment, Agent, runtime URL, and runtime token it uses by default.
Modules: http.ts (reading requests, answers, abort), identity.ts (identities and the shared
context), sessions.ts, model-providers.ts, and agent-runtime.ts (the route families).
Behaviour
- Platform requests are matched by path on any origin, with the application's
/__platform__prefix removed, so they are answered absolute (tests) or through the development proxy prefix. Runtime requests are those under the runtime URL runtime access returns; none reaches the network. WithinstallStandIn()anything else still goes to the network (a custom provider's own endpoint, which the direct test conversation calls, is not answered). - Platform routes take any bearer token; runtime routes take only the runtime token.
- The stand-in's Agent answers under any Agent uid, and it serves the person and the Environment the chat names on its scoped reads, so a form filled with real values connects too.
- A new session gets the model
stand-in-cloud/swift-1, thinkingmedium. A turn is answered with the model of the session the request carries (ADR 060): reasoning, astand_in_searchtool call with its input and output, adata-sourcespart, and text that echoes the message and names the model. A model whose provider is not signed in (stand-in-labsat first) answers with an error frame that says so. - The history route returns the transcript so far, stamped with the session's Agent, and
404for a session nobody has written to yet. - A provider sign-in completes on the second read of its attempt. Custom providers and their models are validated and join the catalog.
Maintenance Notes
- When a client in
../../src/backend/changes what it sends or parses, change the route here in the same change.../StandaloneApp.client.test.tsxdrives the package's own clients against every route, so a shape that drifts fails there. - A new route the package calls gets a handler here; until it has one, it shows up in
unhandledRequests. - Keep it deterministic: uids count up per kind, and replies depend only on the message and the session's model.
- Name the platform, not its implementation, in messages and comments.