Prompt construction and credits
The chat Worker owns model orchestration and local cost calculations. Product plan state, credit balances, and the append-only ledger remain app-domain data accessed through the DOMAIN service binding.
Prompt construction
Section titled “Prompt construction”buildMessages() in workers/chat-worker/src/chat/ai/prompts.ts composes the canonical system prompt and the enriched content injected into the latest user message.
The system prompt contains:
- role and response rules;
- Markdown and citation format contracts;
- multi-step tool and error-recovery rules;
- an optional workspace catalog or workspace-capability block;
- the output-language directive.
Tool-specific invocation policy belongs in each AI SDK tool’s description and input schema. Do not duplicate the registry in a second system-prompt section.
Attached context
Section titled “Attached context”buildAttachedContextBlock() adds metadata keys, not full resource bodies:
# Attached Context
| Key | Type | Name ||-----|------|------|| resource:abc-123 | resource | Article title || document:def-456 | document | Research report |The model calls read-context with all relevant keys in one batch. Resource bodies come from Core corpus RPC; document bodies come from the app Worker’s DOMAIN.readDocuments RPC. This keeps the initial prompt bounded and avoids loading attachments the model does not need.
When a chat is bound to a Workspace, the engine may also add the app-domain workspace summary. In scope-free chats, it can add the user’s Workspace catalog and the authoritative capability to create another Workspace.
Citation contract
Section titled “Citation contract”If an answer uses tool results, each factual claim must cite a numbered Markdown link such as [1](https://example.com), and the response must end with a matching numbered ## Sources list. The prompt forbids bare numeric markers and fabricated URLs.
The UI renders these as ordinary Markdown links. Citations are display content; they are not resource_links rows.
Token and credit estimates
Section titled “Token and credit estimates”workers/chat-worker/src/chat/billing/cost.ts defines the pure estimation functions.
- English text uses an estimate of roughly 4 characters per token.
- CJK-heavy text interpolates toward roughly 1.8 characters per token.
- Chat preflight assumes a chat-sized output and applies 1.3× headroom.
- Content creation uses a larger fixed output estimate.
- One credit represents USD 0.001 of model cost.
These values protect prepaid balance before execution. Text settlement uses actual provider usage when available; image and audio settlement use the catalog’s per-generation or per-episode price.
Billing ownership
Section titled “Billing ownership”web-tanstack/src/lib/billing/plans.tsowns plans, feature gates, monthly grants, allowed models, and product limits.web-tanstack/src/server/domain/billing.tsowns subscription snapshots, credit accounts, the append-only ledger, idempotent settlement, and atomic deduction.workers/chat-worker/src/chat/ai/model-catalog.tsowns model identity and local pricing metadata.workers/chat-worker/src/chat/billing/owns cost estimates, preflight checks, and settlement calls throughDOMAIN.
The chat Worker must not query subscription or credit tables directly.
Billing facade
Section titled “Billing facade”workers/chat-worker/src/chat/billing/server.ts exposes:
| Method | Responsibility |
|---|---|
assertChatQuota(...) |
Preflight a chat turn against an already-loaded snapshot |
checkText(...) |
Fresh balance check before an in-stream document generation |
checkImage(...) |
Fresh feature and balance check before image generation |
checkAudio(...) |
Fresh balance check before podcast synthesis |
trackText(...) |
Settle actual text usage through DOMAIN |
trackImage(...) |
Settle one image generation through DOMAIN |
trackAudio(...) |
Settle one audio episode through DOMAIN |
Settlement requests include stable idempotency keys derived from turn, resource, document, or podcast identifiers. Durable Workflow callers receive settlement failures and own their retry policy; user-facing non-durable paths use the billing facade’s bounded retry behavior.
Failure behavior
Section titled “Failure behavior”- Insufficient balance throws
QuotaExceededErrorand maps to the frontend’s upgrade flow. - A plan-disabled feature throws
FeatureNotAvailableError. - A snapshot or capability RPC failure must surface as an error; it must not be converted into a forged free-plan limit.
- Tools throw on operational failure so AI SDK marks the tool result as an error.
See AI chat architecture for the full request and tool flow.