Generated flows
Every node below is read out of the source the flow runs through — the route table in packages/web/src/server/index.ts and the EnsoObservation union in packages/core/src/observation.ts. Nothing here is drawn by hand, so a route or a kind that moves changes this page or fails the docs gate.
Control plane
Section titled “Control plane”The 8 control routes: what the browser can ask the runtime to do. Observation routes are the next diagram’s first stage rather than a second copy of it.
flowchart LR Browser["Browser"] Browser -->|POST /api/projects| R_POST_api_projects["respondToProjectRegistration → ProjectRegistry.register"] Browser -->|DELETE /api/projects/:projectId| R_DELETE_api_projects_projectId["respondToProjectRemoval → ProjectRegistry.remove"] Browser -->|POST /api/threads/:threadId/abort| R_POST_api_threads_threadId_abort["respondToAbort → abortThread"] R_POST_api_threads_threadId_abort --> H_respondToAbort_abortThread["abortThread()"] H_respondToAbort_abortThread --> Runtime Browser -->|POST /api/threads/:threadId/command| R_POST_api_threads_threadId_command["respondToHostCommand → runHostCommand"] Browser -->|POST /api/threads/:threadId/configure| R_POST_api_threads_threadId_configure["respondToConfigure → configureThread"] Browser -->|POST /api/threads/:threadId/dialog| R_POST_api_threads_threadId_dialog["respondToDialog → answerThreadDialog"] R_POST_api_threads_threadId_dialog --> H_respondToDialog_answerThreadDialog["answerThreadDialog()"] H_respondToDialog_answerThreadDialog --> Runtime Browser -->|POST /api/threads/:threadId/mode| R_POST_api_threads_threadId_mode["respondToModeChange → changeThreadMode"] R_POST_api_threads_threadId_mode --> H_respondToModeChange_changeThreadMode["changeThreadMode()"] H_respondToModeChange_changeThreadMode --> Runtime Browser -->|POST /api/threads/:threadId/prompt| R_POST_api_threads_threadId_prompt["respondToPrompt → promptThread"] R_POST_api_threads_threadId_prompt --> H_respondToPrompt_promptThread["promptThread()"] H_respondToPrompt_promptThread --> Runtime Runtime["ThreadRuntime"] --> Observations["EnsoObservation stream"]
| Node | Contract | Input | Source |
|---|---|---|---|
respondToProjectRegistration → ProjectRegistry.register |
POST /api/projects |
body: EnsoProjectRegistration — an absolute path strictly under a root enso.config.json declares (projects.roots), optional title |
packages/web/src/server/index.ts:1046 |
respondToProjectRemoval → ProjectRegistry.remove |
DELETE /api/projects/:projectId |
path: projectId (sixteen hex digits) |
packages/web/src/server/index.ts:79 |
respondToAbort → abortThread |
POST /api/threads/:threadId/abort |
path: threadId; no body |
packages/web/src/server/index.ts:71packages/web/src/server/follow.ts:668 |
respondToHostCommand → runHostCommand |
POST /api/threads/:threadId/command |
path: threadId; body: EnsoHostCommandRun — model with provider/id, thinking with a level, login with provider/authType, logout with a provider, compact with nothing; a view row (context) is the page’s to open, never run |
packages/web/src/server/index.ts:75 |
respondToConfigure → configureThread |
POST /api/threads/:threadId/configure |
path: threadId; body: EnsoSessionConfiguration — optional model (provider/id), thinking (a level that model supports) and mode; applied in that order under one lease, a value equal to the current one left alone |
packages/web/src/server/index.ts:77 |
respondToDialog → answerThreadDialog |
POST /api/threads/:threadId/dialog |
path: threadId; body: DialogAnswer |
packages/web/src/server/index.ts:70packages/web/src/server/follow.ts:363 |
respondToModeChange → changeThreadMode |
POST /api/threads/:threadId/mode |
path: threadId; body: EnsoPermissionModeChange |
packages/web/src/server/index.ts:73packages/web/src/server/follow.ts:399 |
respondToPrompt → promptThread |
POST /api/threads/:threadId/prompt |
path: threadId; body: EnsoPromptBody |
packages/web/src/server/index.ts:69packages/web/src/server/follow.ts:265 |
Observation pipeline
Section titled “Observation pipeline”One pi event becomes one observation and crosses six stages to reach the browser store. The union declares 24 kinds; the mapper produces 22 of them, and the rest are produced by the prompt route (see Observations for the per-kind producer, carrier and consumer).
flowchart LR Pi["pi runtime event"] Pi --> Mapper["mapPiEvent (22 kinds)"] Mapper --> Schema["EnsoObservation"] Schema --> Frame["observation frame"] Frame --> Connection["follow connection"] Connection --> Adapter["to-agui chunk"] Adapter --> Router["custom event router"] Router --> Store["browser store"]
| Stage | Contract | Source |
|---|---|---|
mapPiEvent (22 kinds) |
Observations | packages/web/src/host/map-events.ts:285 |
EnsoObservation |
Core exports | packages/core/src/observation.ts:567 |
observation frame |
Observations | packages/web/src/server/follow.ts:179 |
follow connection |
Routes | packages/web/src/follow-connection.ts:449 |
to-agui chunk |
Observations | packages/web/src/to-agui.ts:76 |
custom event router |
Observations | packages/web/src/custom-event-router.ts:195 |
Kinds, in the union’s order of declaration: text-delta, thinking-delta, tool-call, tool-result, custom-entry, permission-mode, permission-mode-rejected, model, message-start, message-end, session-usage, turn-start, turn-end, provider-refused, provider-retry, provider-retry-ended, queue, prompt-rejected, extension-error, extension-ui-request, dialog-settled, run-ended, settled, unmapped.