ai: rich-output blocks via lazy-fetched typed-fence protocol

Assistant replies can now emit typed fenced blocks that render as
@crema/*-ui components inline at their position in the reply.

- message-body.tsx: segmented rendering — alternating prose chunks and
  block dispatch (was: all blocks appended at end). Renderers for kpi,
  table, chart-bar/-line/-donut/-spark, code, diff, flowchart, orgchart,
  steps, checklist, welcome, hint, plus the legacy card kinds.
- block-schemas.ts: single source of truth — BLOCK_INDEX (one-line
  purpose per kind, always in prompt) + SCHEMAS (full JSON shape +
  example, fetched on demand).
- admin-tools.ts: new get_block_schema(kind) tool the model calls once
  per kind per thread to fetch the exact schema. Keeps the always-on
  prompt small (~110 tokens vs ~400 inline).
- assistant.tsx: replaces the inline schema dump with the generated
  thin index.
- ai.tsx: empty-state preview button injects a synthetic assistant
  message exercising every block, for renderer/theme smoke-testing.
- console.css + ai.tsx: shrink ATLAS headline so it doesn't slip under
  the composer with the added preview button.
- tsconfig.json + app.css: wire lib-data-ui, lib-code-ui, lib-diagram-ui,
  lib-onboarding-ui as siblings.

Adding a new block kind = add the lib paths, add a renderer case, add
a schema entry. No prompt edits required.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
jules
2026-05-02 22:47:36 +10:00
parent cdb96499be
commit 9cbe921db7
8 changed files with 966 additions and 143 deletions

View File

@@ -31,6 +31,15 @@ const PROBE_TIMEOUT_MS = 3000
// "Available actions" in the system prompt only lists what's on screen NOW;
// this catalog tells the model what exists elsewhere so it can plan
// multi-step flows (navigate → wait_for → fill → click) in a single block.
// Rich-output protocol: typed fenced blocks the chat renderer turns into UI
// from @crema/*-ui. The system prompt only carries a thin INDEX (kind →
// one-line purpose) — full schemas live in app/lib/block-schemas.ts and are
// fetched on demand via the get_block_schema tool. Adding a new block kind
// = edit block-schemas.ts + the renderer; no prompt edit required.
import { blockIndexForPrompt } from "~/lib/block-schemas"
const RICH_OUTPUT_PREFACE = blockIndexForPrompt()
const UI_CONTROL_PREFACE = `You are the operator's assistant inside Arcadia Admin — the platform-admin web app for the Arcadia multi-tenant SaaS backend (Phoenix, /api/v1). The signed-in user is a platform administrator. Help them inspect and manage tenants, users, billing, audit logs, feature flags, and other platform surfaces.
You can both answer factual questions about the current state (use the "Admin context" block below) and drive the UI. A virtual cursor is shown to the user — every step should target an element so the cursor visibly moves.
@@ -104,6 +113,7 @@ function buildAdminPreface(activeAgent: Agent | undefined, uiControl: boolean):
const ctx = formatAdminContextForPrompt()
const parts = [
"You are the operator's assistant inside Arcadia Admin. Be precise and direct. You have native function tools attached to this conversation — call them whenever the user asks about live platform state (counts, statuses, listings, lookups). Never invent tenant slugs, user counts, or statuses; if you need data, call a tool.",
RICH_OUTPUT_PREFACE,
ARCADIA_KNOWLEDGE,
persona,
ctx,