withCompaction's checkpoint store is now a signed token the browser holds per thread and sends back as forwardedProps.contextCheckpoint. The server keeps no conversation. withCompaction reuses the checkpoint only while the history still starts with the summarized messages; later summaries fold forward from it. Measured locally on a 60-pair history: NanoGPT turn 2 took 18.5 s instead of about 70 s; OpenRouter turns 2-3 took 3.2 s with no summary call.
37 KiB
Unified landing and story product
src/routes/, src/router.tsx, src/start.ts and src/server.ts form one TanStack Start app. / renders src/apps/landing/; /start, /chat, /history and /about render src/apps/product/. Shared UI lives in src/components/ui/, shared pure helpers in src/lib/, and the database/runtime/admin in src/autokit/. Route-owned styles keep the landing, story app and admin surfaces separate.
The landing loader reads the existing Autokit content tables. Both surfaces use the Autokit 27 session, the Operator CLI and HTTP handlers, and the landing’s S3 database, with local and production timelines. The pathless _public route renders one native <Outlet /> inside a persistent app stage. Its index child shows the start screen in the desktop hero; /start, /chat, /history and /about center it below the shared header. public-layout.tsx keeps the animated background and header mounted. The phone chrome and marketing sections disappear on app routes. App menus remain portalled into the app frame. defaultViewTransition and the shared storytellurx-app snapshot name animate the frame; layout mode follows presented route matches so the old hero position is captured before it moves. Mobile hides the preview with CSS.
The persona contracts and historical parity evidence below describe the story product. Unqualified product paths are relative to src/apps/product/; tests remain in src/tests/.
V1 parity: native AI and independently authored personas
Baseline: 40124c2. Reference: ../storytellurx and live V1. Local implementation and commits; no push or deployment. The latest instruction introduces one consistent folder per persona. Shared infrastructure keeps flat type-first folders.
Persona folder and export contract
src/apps/product/personas/{id}/
definition.ts # definition: public data, no React/server imports
persona.ts # personaUI: typed component/style registry
components.tsx # Metrics + optional persona-owned slot overrides
styles.stylex.ts # personaStyles + persona metric styles
theme.stylex.ts # theme and getTheme(state)
archive.md # supplied instructions; server imports only
instructions.server.ts # personaInstructions: own archive + trusted instructions
The same rail applies to Samantha69, Nelly, Xixi, Hisoka, Cybelle, Galatée, Polaire, gateway and pause. No additional persona subfolders. Shared code stays at the roots of components/, hooks/, contexts/, standard-schemas/, registries/, functions/, server/, storage/, styles/, content/, tests/ and fixtures/. Routes and Autokit retain framework conventions.
No empty scaffolds, generic utils.ts, wildcard barrels or catch-all providers. Every new file needs named exports and a real consumer before implementation.
contexts/persona-presentation-context.tsx exports PersonaPresentationContext and usePersonaPresentation for the native layout and part views. Its read-only story state is computed once from native messages. It also carries the native persistence failure flag and one ephemeral imageMessageId activated by native onFinish, so automatic image requests distinguish fresh completions from restored history; it has no message copy or replacement chat lifecycle. This avoids replaying the same story patches separately for every rendered bubble.
Core consumes typed persona slots
Before, central maps and components selected persona behavior:
-stylex.props(chatStyles.transcript, transcriptStyles[state.personaId])
-<PersonaMetrics state={state} />
-<NarrativeComposer personaId={state.personaId} ... />
+const persona = personaUIRegistry[state.personaId];
+stylex.props(chatStyles.transcript, persona.styles.transcript)
+<persona.components.Metrics state={state} />
+<persona.components.Composer
+ state={state}
+ styles={persona.styles}
+ Suggestion={persona.components.Suggestion}
+ {...nativeComposerProps}
+/>
Each persona.ts exports the same contract:
export const personaUI = {
definition,
getTheme,
styles: personaStyles,
statusVariant: "classical",
titleMotion: { from: "'wght' 300", to: "'wght' 400" },
components: { ...defaultPersonaComponents, Metrics },
} satisfies PersonaUI;
registries/persona-ui-contract.ts declares typed slots for Metrics, Bubble, Explanation, Composer, Suggestion, Image, Status, Background, StateChanges and SubmitIndicator. Shared defaults receive presentation props and do not import the registry. A persona can override a slot in its own components.tsx without changing native chat mechanics.
export type PersonaUIRegistry = {
[Id in PersonaId]: PersonaUI & { definition: PersonaDefinition & { id: Id } };
};
export const personaUIRegistry = {
samantha69,
nelly,
xixi,
hisoka,
cybelle,
galatee,
polaire,
storytellurx_gateway,
storytellurx_pause,
} satisfies PersonaUIRegistry;
The public catalog imports definition.ts without importing UI. Only persona server modules import archives; the server registry consumes their validated instructions.server.ts exports. A persona cannot import another persona's implementation. Shared defaults prevent duplicated markup and mechanics; persona folders own identity-specific decisions.
Picker image fitting and localized composer placeholders also belong to each persona. The core supplies placeholder={persona.definition.placeholder[locale]} and composes persona.styles.pickerImage. It contains no named-persona styling condition and no placeholder_{id} locale lookup. Both languages retain the supplied strings exactly. Architecture checks reject literal named persona IDs in shared presentation modules.
Native ownership replaces custom publication concepts
-new ApprovedTurnAdapter(() => resolveNarrativeTurn(...))
-PublishedTurnSchema
-selectCommittedTurns(messages)
-selectVisibleTurn(committed, visibleMessageIds)
+chat({ adapter: provider, ...createChatRequest(messages, context), stream: true })
+useChat({ connection, outputSchema: ModelTurnSchema, persistence, threadId })
+message.parts
+message.metadata?.requestPreview
+useMessageScrollerVisibility().visibleMessageIds
Native middleware validates the completed structured response, then forwards the original event with approved data. It forwards schema JSON deltas after the native structured-output.start event, and filters unrelated commentary and provider-private reasoning. It does not construct stream events or run a nested chat. Native generation result middleware also replaces the custom image adapter.
TanStack owns messages, parts, run status, tools, interrupts, stream parsing, cancellation and transcript persistence. createChatUI owns part dispatch. Unpatched shadcn MessageScroller owns bottom following, manual reading and visibility with autoScroll enabled and row anchors disabled (REUI ai-chat-9). Motion owns animation timing; Matter owns picker physics; Base UI owns horizontal suggestion scrolling, disclosure state, button behavior and dialog focus. See the reference composition and current acceptance matrix.
Application rules remain: ModelTurnSchema describes story data; applyStatePatch defines explicit bounded field/array semantics; readState derives persisted story state from valid completed native assistant parts. Its explicit presentation mode also reads the active native partial, accepting independently validated state fields while incomplete enums remain at their preceding values. No published/committed lifecycle, second message store, custom visibility observer or wrapper hook that merely renames native values.
Streaming outputSchema provides types but does not establish runtime validation. Retain completed-object validation in native middleware. Do not add Robot/XState/Jotai/Effect without a requirement native lifecycle cannot express.
Shared export contracts
| File | Exports | Consumers |
|---|---|---|
| standard-schemas/persona.schema.ts | PersonaIdSchema, PersonaDefinitionSchema, inferred types | definitions, registries, routes |
| standard-schemas/persona-instructions.schema.ts | PersonaInstructionsSchema, PersonaInstructions | persona server modules, server registry |
| standard-schemas/narrative-state.schema.ts | NarrativeStateSchema, StatePatchSchema, inferred types | state rules, provider options, UI |
| standard-schemas/narrative-turn.schema.ts | ModelTurnSchema, SystemTurnSchema, PersonaTurnSchema, SuggestionSchema, inferred types | native chat, headless parts |
| standard-schemas/chat-request.schema.ts | ChatContextSchema, ModelIdSchema, LocaleSchema, inferred types | routes, request options |
| standard-schemas/request-preview.schema.ts | RequestPreviewSchema, RequestPreview | native metadata, inspector |
| standard-schemas/image-request.schema.ts | ImageRequestSchema, inferred type | image endpoint |
| standard-schemas/conversation-history.schema.ts | HistoryEntrySchema, HistoryExportSchema, inferred types | metadata index, export |
| registries/persona-ui-contract.ts | PersonaUI, PersonaStyles, typed slot props | persona modules, shared defaults |
| registries/persona-ui-registry.ts | personaUIRegistry | shell, native chat |
| registries/persona-catalog.ts | personaCatalog, selectablePersonas, getPublicPersona, personaImageSrc | picker, initialization, server registration |
| registries/persona-registry.server.ts | getPersonaDefinition, validatePersonaRegistry | provider instructions |
| registries/model-catalog.ts | modelCatalog, getPublicModel, normalizeModelId | routes, model/status pickers |
| registries/model-registry.server.ts | getModelDefinition | server request options |
| functions/apply-narrative-state-patch.ts | initialNarrativeState, applyStatePatch | initialization, state derivation, validation |
| functions/select-narrative-state.ts | readState | views, history metadata |
| functions/create-initial-messages.ts | createInitialMessages | native chat initialization |
| functions/markdown-typography.ts | markdownTypography | native NarrativeText renderer |
| server/create-chat-request.server.ts | createChatRequest | native chat endpoint |
| server/create-response-middleware.server.ts | createResponseMiddleware | createChatRequest + neutral native fixtures |
| server/create-model-adapter.server.ts | createModelAdapter, createImageAdapter | native endpoints |
| server/image-middleware.server.ts | imageMiddleware | native image endpoint |
| components/narrative-chat.tsx | NarrativeChat, useNarrativeChatContext (native accessor) | route, image composition |
| components/persona-ui-defaults.tsx | defaultPersonaComponents | persona registration |
| components/narrative-text.tsx | NarrativeText | native text parts, fragments, explanations, suggestions |
| components/persona-submit-indicator.tsx | TextSubmitIndicator, PaperPlaneSubmitIndicator | persona SubmitIndicator slots |
| components/narrative-composer.tsx | NarrativeComposer | default composer slot |
| components/turn-receipt.tsx | TurnReceipt | native structured turn renderer; Base UI owns disclosure |
| components/public-shell.tsx | PublicShell | routes, native layout |
| components/public-header.tsx | PublicHeader | shell |
| components/public-about.tsx | PublicAbout | about route |
| components/persona-picker.tsx | PersonaPicker | start route |
| components/model-picker.tsx | ModelPicker | start route |
| components/conversation-status.tsx | ConversationStatus | native layout |
| components/persona-metric-primitives.tsx | MetricNumber, MetricBreathingLabel, MetricLens, MetricSemantics, resonanceFrames | persona components |
| components/persona-suggestion.tsx | PersonaSuggestion | persona Suggestion slots |
| components/narrative-state-changes.tsx | NarrativeStateChanges | default StateChanges slot |
| components/request-inspector.tsx | RequestInspector | native message metadata |
| components/generated-image.tsx | GeneratedImage | native message composition |
| components/conversation-background.tsx | ConversationBackground | visible-message presentation |
| components/conversation-history.tsx | ConversationHistory | history route |
| components/history-preference.tsx | HistoryPreference | history UI |
| hooks/use-persona-physics.ts | usePersonaPhysics | picker |
| hooks/use-history-preference.ts | useHistoryPreference | preference UI |
| contexts/locale-context.tsx | LocaleProvider, useLocale | public presentation |
| contexts/persona-presentation-context.tsx | PersonaPresentationContext, usePersonaPresentation | native layout and part views |
| storage/conversation-storage.ts | historyStorage, createConversationPersistence, deleteHistory, deleteAllHistory, exportHistory | native chat, history UI |
| storage/history-index-storage.ts | listHistory, updateHistoryIndex, removeHistoryIndex, subscribeHistoryIndex |
metadata UI, native persistence delegation |
| storage/preference-storage.ts | readPreferences, writePreferences, subscribePreferences | opt-in preference |
| styles/design-tokens.stylex.ts | personaVars, spacing, motionTokens | shared styles, persona themes |
| styles/*.stylex.ts | named shared style maps | owning shared components |
| content/*-messages.ts | locale dictionary | locale context, initial messages |
| content/initial-prompts.json | supplied V1 starter data | initial messages |
| content/about-description.html | unchanged published rich-text fragment | PublicAbout |
| fixtures/native-conversation-stream.ts | neutralTurn, nativeConversationStream, nativeIncrementalConversationResponse, nativeImageStream, neutralImageDataUrl | offline fixture verification, browser tests |
| playwright.config.ts | default Playwright config | public browser test runner |
Import boundaries
standard-schemas → Zod + schemas
functions → schemas + data-only definitions/content + native types + pure formatting packages
persona UI → own definition/components/styles/theme + shared primitives
public catalog → persona definition.ts only
server registry → persona instructions.server.ts exports
components → public registries + schemas/functions/hooks/styles + packages
routes → validated search + component/server delegation
No public import graph may reach .server.ts, archives or Autokit server infrastructure. Pure state/schema modules cannot import React runtime, storage or routes. Shared application modules cannot import route files. Production cannot import tests/fixtures. Architecture tests enforce boundaries; the mapped PersonaUIRegistry type enforces complete registration and matching identity keys at compile time. Obsolete archive/theme/metric/starter lookup keys are removed: persona modules import their owned values directly.
Parity and remaining proof
Reference flow: seven-persona picker → supported Google/Hermès model selection → scrolling chat. Preserve model-driven pause, 1–5 fragments, persona suggestions (3–6), gateway suggestions (0–2), original copy, metrics, image presentation and public inspector. Suggestions fill the draft; Enter sends, Shift+Enter inserts a newline, IME composition must not submit. Native image results become media parts in their owning assistant message.
Approved differences: opt-in device history (off initially), supported current model names, progressive native structured output with final validation before committing state (the user’s later streaming request supersedes the initial complete-turn-only reveal). No new Stop flow. Public CSS uses StyleX with explicit styleResolution: "application-order" so authored shorthands are emitted and slot composition follows application order; The story surface does not use Tailwind; the separate landing stylesheet compiles only its own sources, including its sound-aware Button. Autokit precompiled admin CSS remains isolated.
Reference shell: 384px max-width; 32px header; 12px/16px header type.
Owning sources: public-shell.stylex.ts + persona-owned theme/style slots.
Proof required: public keyboard tests + computed styles + screenshots.
test("persona registration preserves the public conversation", async ({ page }) => {
await page.goto("/chat?persona-id=samantha69&model-id=gemini");
await expect(page.getByTestId("public-shell")).toHaveCSS("max-width", "384px");
await expect(page.getByRole("textbox", { name: "Votre message" })).toBeVisible();
await expect(page).toHaveScreenshot("samantha-introduction.png");
});
Before claiming parity: save reference/current screenshot, accessibility and computed-style evidence for all seven personas at 390×844, 768×1024 and 1440×900. Cover deterministic/settled/dragged picker, low/medium/high metrics, fragments, suggestions, inspector focus restoration, image success/failure/history restoration, pause, locale, storage failure, reduced motion, keyboard and zoom. Never update baselines to conceal differences. Neutral fixtures exercise mechanics without new narrative content.
The /about route preserves the supplied localized flow copy and the published sites.description_html fragment recovered with curl on 2026-09-08. The original 6,915 bytes stay in content/about-description.html; its SHA-256 is verified. About uses V1’s plain monospace shell/header. Scoped public-about.css applies descendant typography to preserved rich-text markup, an intentional exception to atomic StyleX authoring for that static fragment.
Historical pre-composition verification covered combined/fallback provider paths, validation failure, cancellation, withheld draft/reasoning and inspector metadata, with a passing production build and 195 public browser cases. Those counts do not certify the later progressive-rendering and native-composition changes. Screenshot baseline comparison remains separate from behavioral verification; full pixel parity is not claimed.
Accepted data constraint adjustment: the 88 original starters in src/apps/product/content/initial-prompts.json contain French labels/prompts up to 69/351 characters and English labels/prompts up to 60/305. The shared SuggestionSchema therefore permits bounded labels of 70 and drafts of 400 characters, preserving the supplied text without truncation or a separate initialization schema. Contract tests validate every original starter in both locales.
Provider retry ownership
Text generation uses TanStack AI 0.70.0, ai-client 0.40.0, ai-react 0.31.0, ai-openai 0.30.1 and ai-compaction 0.3.0 (patches/@tanstack__ai@0.70.0.patch aligns one adapter declaration with exactOptionalPropertyTypes). Both gateways use the OpenAI-compatible Chat Completions adapter with SDK maxRetries: 0. A transient provider failure before any output (connection, HTTP 408/409/429/5xx) is retried inside the same request by the response middleware's onModelError hook, at most twice. The browser response-recovery flow then owns one budget: an initial request plus at most two automatic attempts, waiting 1/2 seconds, each carrying X-Generation-Attempt. Recoverable failures include connection errors, interrupted output, HTTP 408/409/429/5xx, idle or attempt timeouts, and a completed turn without fragments. Other formatting mistakes are coerced on the server (fitTurn) and never reach recovery. Authentication, credits, configuration, refusals, cancellation, and unknown errors stop the cycle.
Recovery uses isolated native ChatClient runs against the same pre-turn history; every candidate regenerates the original turn, and nothing of the failed reply is sent back. Readable partial text stays mounted until a candidate passes server schema and state validation. Metrics, suggestions, and image generation use validated completed turns only. Stop, panic, context changes and unmount cancel both backoff and candidate requests; stale candidates cannot commit. Exhausted cycles require manual retry, and restored incomplete browser history never starts requests automatically.
There is no server conversation store or durable-stream log. Request disconnection still aborts the provider. Browser history remains local. Validation logs contain issue codes and paths, never values or raw output; upstream gateway retention is independent. Resuming after a dropped connection generates a new candidate rather than replaying stored server events.
Long histories are compacted by withCompaction + summarizeOldest (context-budget.server.ts). Its checkpoint store is carried by the browser, not the server: after a summary the server emits a context.checkpoint event holding the summary and the summarized prefix's hash, HMAC-signed with APP_KEY and bound to the thread. The text connection keeps the latest token per thread in memory, out of the chat, and sends it back as forwardedProps.contextCheckpoint. withCompaction reuses it only while the history still starts with the summarized messages, and later summaries fold new messages into it instead of re-summarizing the whole history (measured 20 Oct: a long NanoGPT turn without the summary call took 18.5 s instead of about 70 s). A reload, an edited history or an unverifiable token simply summarizes again.
Image generation separately uses the OpenAI SDK's native maxRetries: 4 through the TanStack image adapter. Offline tests exercise both gateways, exact text/image request ceilings, server-side retries, cancellation, and failure classification. Browser tests verify preserved text, inline progress, completion-only state updates, manual recovery, and single image activation.
Continuation audit: image envelope and browser evidence
The image hook supplies body: { messageId }. TanStack merges that body with the generation input and creates the data/forwardedProps envelope itself. Nesting forwardedProps in the hook body made the endpoint reject automatic image requests. Native HTTP regressions now verify the exact flat wire shape and reject the former nested shape before provider execution.
The public suite includes 126 persona/metric/locale cases and 69 behavior cases across three viewports. It covers all seven personas in French/English at 0/0.5/1 metrics, one/five fragments, three/six suggestions, draft filling, inspector focus, picker/model navigation, failure/retry, imagery, pause, history and IME composition. The explicit STORYTELLURX_CAPTURE_CURRENT=1 mode retains every behavioral assertion and attaches current screenshots without baseline comparison. Default execution still requires V1 baselines; capture success does not claim visual parity. Helium and curl are authorized options, not mandatory gates for other work.
The historical 2026-09-08 pre-composition production-browser run passed 195/195 cases, including all 126 metric/state interactions. After the final status inset and Nelly octave corrections, all 171 affected cases passed again. That checkpoint checked restored history with bottom positioning. The current REUI ai-chat-9 composition uses native bottom positioning without another model request; fresh whole-app verification is pending the external local-s3 dependency restoration. The paired capture runner saved 126 reference/current pairs with accessibility trees and computed styles. The completed final capture refresh reuses unchanged V1 references. All 126 shell/input/form/submit rectangles match within 0.01px. Input font sizes/line heights and all 378 semantic meters were also verified against the paired evidence. No baseline has been updated to hide a difference.
Typography and browser corrections
The user requested @bureaudouble/typographe on 2026-09-08. Its existing alpha.9 dependency is now direct, along with the already resolved HTML parser. Typography is an approved change to punctuation and line breaking; persona fonts, layout, schemas, drafts, saved transcripts and inspector data retain their separate responsibilities.
// components/narrative-text.tsx — consumed by native parts and suggestions
const { locale } = useLocale();
return <TextPart {...props} extensions={typography[locale]} />;
functions/markdown-typography.ts exports the single TanStack Markdown extension (@tanstack/ai-react 0.29 renders with TanStack Markdown, which escapes raw HTML and removes executable URLs itself). It returns only text to the existing Markdown tree's text nodes: Typographe’s generated markup is not admitted. Code, links, URLs and literal HTML/entity-bearing text stay exact. Alpha.9 exposes an HTML-string API. Generated indexed spans share quote context across inline emphasis within each block; only their text returns to the original nodes. The library handles widows inside the final multiword text node; it does not bind a final single word across separate inline nodes. Application code does not recreate that missing rule. Tests exercise French/English quotes and punctuation, widows, emphasis, code, URLs, escaped HTML, sanitization and unchanged transcript values. No punctuation rules are copied into application code.
Browser evidence found and corrected: SSR controls accepting input before hydration (useHydrated now gates composer and preference); picker grid blending; header colors, corners and button reset; model detail color; About layout and published content; classical presentation for every persona except gateway; persona-owned explanation labels and send indicators; Samantha metric typography. Automatic images now activate from native onFinish, because native runId becomes null at completion. Initial messages, setMessages and persistence restoration do not fire that callback.
Native completion and storage failures now have browser proof, including displayed French/English typography across bold text. Production validation middleware is shared unchanged with the neutral fixtures so invalid-output cases exercise the actual publication boundary.
The current chat uses the supplied shadcn composition: default MessageScroller.Provider, native scrollAnchor on user messages, a bounded transcript viewport and a sibling composer in normal footer flow. The header remains visible during scrolling. The application has no composer resize observer, compensating inset variable or header-direction scroll handler. Persona fonts, tokens, metrics and decoration remain independently owned. See Chat composition for the source comparison and exact TSX changes.
The native scroller uses REUI ai-chat-9’s autoScroll provider and scrollAnchor={false} on every message. It follows arriving content at the live edge and releases following on manual wheel, touch or keyboard navigation. The package owns the jump control and all scroll calculations. No custom collapse handler, user-turn spacer, or shadcn package patch is used.
Suggestion rows use Base UI ScrollArea.Root, Viewport, Content, horizontal Scrollbar and Thumb; the real viewport is also the existing Motion card effect’s scroll container. Content grows naturally, with no empty suggestion placeholders. Public state/details use a closed-by-default TurnReceipt; expanded content has natural height and no inner constrained scroller. The textarea stays focusable and read-only while the native run is busy. Send and retry use Base UI buttons with existing native callbacks.
Variable-font medium weight is declared with the correct axes in the owning personas. Reduced-motion presentation keeps static suggestion emphasis and a representative Nelly waveform. Hisoka, Nelly, Xixi and Polaire use V1’s rendered sRGB primary values to preserve their palette across different CSS compiler gamut conversions. Typography wrapping, keyboard focus, complete-turn validation, opt-in history and reduced-motion behavior are explicit usability changes.
Historical pre-composition verification: 298 unit/integration tests passed; type-aware check has zero errors and three existing warnings; production build passes. The complete 195-case browser run passes, followed by 171 passing affected-case checks after the final spacing corrections. The final paired visual refresh contains 126 reference/current pairs with accessibility and computed-style artifacts in /private/tmp/stx-parity/matrix-complete. These local captures are not approved screenshot baselines; typography wrapping and reduced-motion differences remain explicit. No deployment or push is authorized.
Source size
The historical pre-composition application contained 7,538 physical TypeScript/TSX/CSS lines in 139 source files, including the preserved Autokit setup. The same count at checkpoint 053afbc is 14,361 lines in 82 files: a 47.5% reduction. Counts include blanks/comments and exclude tests, fixtures and the generated route tree. The former single-chat README’s 94.2% reduction described a different, much smaller scope and has been removed. Persona-owned UI and validation are retained instead of pursuing an arbitrary line-reduction target.
Native progressive rendering
The user’s streaming request replaces the initial complete-turn-only presentation. StructuredOutputPart.partial is the sole partial-data source: TanStack owns JSON parsing, assembly, SSE transport and lifecycle. Components render available fragments, rewrite text and disabled suggestion labels as they arrive. Public explanations and state changes stream inside the closed-by-default receipt and become visible on explicit expansion; receipt counters reflect available fields. The active partial’s valid state fields update the shell, persona registry, metrics and state-change view. No second draft store or parser exists.
Only the active latest assistant part is previewed. Completion still passes ModelTurnSchema and state validation; failure or cancellation removes provisional presentation and restores completed state. Images, actionable suggestions and the public inspector wait for a validated final result. Persisted transcript parts retain TanStack’s native streaming/error statuses; only completed parts enter subsequent model context and history state. Malformed partial text values never reach Markdown or React as objects.
Server validation diagnostics report Zod issue paths/codes/constraints without logging response prose or request credentials. Native RUN_ERROR.code selects localized quota, availability and format errors in the composer. The Gemini adapter patch preserves provider codes through TanStack’s toRunErrorPayload; no custom provider-error parser is added.