AI chat architecture
newsence chat runs in the standalone workers/think-worker Cloudflare Worker.
ThinkChatAgentV2 owns the live conversation, Think recovery state, native
Workspace scratch files, tool loop, and Podcast Workflow integration. The
app Worker owns authentication and product transactions; Core owns canonical
resource retrieval and Cloudflare AI Search.
Request flow
Section titled “Request flow”flowchart LR
UI["Web chat UI\nuseAgentChat"]
Think["ThinkChatAgentV2\nDO SQLite + Think"]
Workspace["Native Workspace\nsession-local files in DO SQLite"]
Execute["execute\nWorker isolate + Code Mode"]
Browser["Browser Run\nChromium / CDP"]
Domain["App DOMAIN binding\nauth + product authority"]
Autumn["Autumn\nsubscriptions + credits"]
Core["Core binding\nresources + AI Search"]
Gateway["AI Gateway\nrouting + telemetry"]
Model["AI providers"]
Workflow["Podcast Workflow"]
UI <--> Think
Think <--> Workspace
Think --> Execute
Execute <--> Workspace
Execute <--> Browser
Think <--> Domain
Think --> Autumn
Domain --> Autumn
Domain <--> Core
Think --> Gateway
Gateway <--> Model
Think <--> Workflow
web-tanstack/src/components/chat/ChatPanel.tsxopens the authenticated Think agent route and submits ordinary AI SDK UI messages. Optional typed context refs are persisted in the user message metadata.- The app proxy admits the session and forwards to
ThinkChatAgentV2. Postgres stores the session catalog, reconnect allocation, and deletion fence; Think Session/DO SQLite stores the transcript and resumable runtime state. beforeTurn()reads AI feature flags and credit admission directly from Autumn, then resolves the model, product workspace, and user-message context. Read-only product retrieval and the plan-allowed native actions are exposed directly to Think.- The
knowledgetool calls one app-owned Domain RPC. Search uses Core AI Search, read uses live document/resource authorization, and workspace listing returns flattened document/resource refs from direct workspace memberships. Each read is continuation-based and capped at 16 KiB. - Native Workspace stores session-local files in DO SQLite.
readsupports text, images, and PDFs; other scratch operations use virtualbashorexecutewithstate.*. Duplicate top-level file tools are excluded. Bash is rooted at/with networking disabled.executeruns JavaScript in a Worker isolate; scratch is never product truth. - When the user has the web-search entitlement,
executealso exposescdp.*through the Browser Run binding. The product prompt restricts browser use to public, read-only access. Explicit product actions publish documents and media. - Think persists native tool/action parts. Podcast Workflow events upsert terminal podcast data into the transcript without replacing the native tool call/result pair.
- The turn starts only after Think’s direct Autumn credit check. Text models use Autumn’s official AI SDK middleware to report provider token usage after each completed generation. Image, speech, and raw-binding calls check for a positive balance before dispatch and report measured tokens directly afterward. Gateway records remain operational telemetry only.
Tool surface
Section titled “Tool surface”| Tool | Responsibility |
|---|---|
knowledge |
Public-corpus search, authorized source read, current-workspace source listing |
ask_user |
Pause for one to three material user decisions and resume from typed client output |
read |
Read session-local text and provide images/PDFs to multimodal models |
bash |
Virtual Bash over Workspace files, rooted at /, with networking disabled |
execute |
Worker-isolated JavaScript with state.* filesystem operations and entitlement-gated cdp.* browser operations |
create-document |
Generate Markdown and persist an app-owned document |
edit-document |
Edit an authorized document with app-side snapshot semantics |
generate-image |
Generate, meter, and persist an image resource |
create-podcast |
Start the durable workspace audio workflow |
Image generation is entitlement-gated, and document and podcast creation are exposed only for workspace-scoped chats. Think and the model decide among currently active tools from their descriptions and schemas; the system prompt does not encode a fixed routing sequence.
The old /corpus virtual filesystem no longer exists. Product resources,
documents, and workspaces are typed database objects, not paths. Message
metadata already contains attachment refs and the runtime already carries the
current workspace scope, so no context-discovery round trip is required.
Native Workspace does not mirror or mount Postgres product data. Every product read rechecks current authority. Code Mode’s direct outbound networking is disabled; public web access goes through its entitlement-gated browser connector.
The application does not configure a Container or Sandbox binding. bash is
virtual Bash, and execute uses a Worker isolate rather than a Linux container.
The browser connector uses Chromium/CDP; Kitesurf is not enabled by the current
session options. There are no separately registered exec or browser_* tools.
Code Mode returns nested connector operations in execute.output.calls after
each execution pass. These are native execution-log entries, not separate chat
tool calls. The current ChatPanel displays generic tool markers without
expanding those entries or streaming individual connector operations.
Exactly-once boundaries
Section titled “Exactly-once boundaries”Think Actions provide the local action ledger and native persisted result parts. App Domain methods revalidate product ownership; Postgres mutations use transactions and constraints, while the app owns R2 write and cleanup lifecycle. Long-running Podcast work remains a Workflow with a stable podcast/workflow identity. Manual Autumn token events carry stable idempotency keys. The official text middleware is deliberately best-effort after provider completion; it logs a tracking failure but does not discard the generated result or persist a separate application billing outbox.
Web rendering
Section titled “Web rendering”| File | Responsibility |
|---|---|
components/chat/ChatPanel.tsx |
Session allocation, Think connection, send/retry, state/cache synchronization, and page/embedded shell |
components/chat/ChatConversation.tsx |
Message tree, empty state, retry and streaming affordances |
components/chat/ChatMessageContent.tsx |
Ordered text, reasoning, native tool/action progress and results, and Podcast data parts |
components/chat/PromptComposer.tsx |
Input, model, typed context, audio shortcut, submit/stop |
AI usage ownership
Section titled “AI usage ownership”web-tanstack/autumn.config.tsdefines subscriptions, recurring monetary grants, reset cadence, product flags, and numeric plan capacities. Autumn is the subscription and entitlement authority; Stripe remains the payment processor behind it.workers/think-worker/src/ai/autumn-billing.tsreads the authoritative Autumn customer, checks AI credits and product flags, and tracks provider usage. Web server modules read the same customer’s plan capacities when enforcing transactional product limits; PostgreSQL owns actual resource counts, not a parallel billing ledger.workers/think-worker/src/ai/model.tswraps text models with Autumn’s official AI SDK middleware. Autumn resolves provider/model token pricing and records usage after a completed generate or stream.- Image, podcast-script, TTS, and the raw Workers AI title path use a positive
balance check followed by
trackTokens. Tracking failures are observable but intentionally do not replace a provider result with an error. workers/think-worker/src/ai/model.tscreates trusted Gateway correlation metadata.product-ailogs omit prompt/response payloads and remain operational telemetry only.
See Prompt construction and AI usage for the prompt, admission, and observability contracts.