Assistant: drop a2ui surfaces, fall back to markdown tables

CK 1.60+ validates generated a2ui ops against a component catalog before
painting, and our agent's ops fail validation — surfaces hang at
"Building interface" forever (MAF also drops RunAgentInput.context, so
the catalog/guidelines never even reach the model). Disable a2ui end to
end until the pipeline matures:

- server.ts: a2ui { enabled: false }; RENDER_TOOLS no longer includes
  render_a2ui
- App.tsx: remove the a2ui provider prop
- agent.py: prompt now asks for clean markdown tables for lists and
  structured data; render_spending_summary card guidance unchanged

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Carlos Escalante
2026-07-04 16:09:56 -06:00
parent bbae121fec
commit 4687fa9669
3 changed files with 16 additions and 15 deletions

View File

@@ -34,7 +34,9 @@ How to answer:
(e.g. net worth + recent transactions). (e.g. net worth + recent transactions).
- Format currency with the appropriate symbol: ₡ for CRC (no decimals), $ for - Format currency with the appropriate symbol: ₡ for CRC (no decimals), $ for
USD (two decimals), € for EUR (two decimals). USD (two decimals), € for EUR (two decimals).
- When showing lists, prefer markdown tables over prose. - When showing lists or structured data (transactions, breakdowns, funds),
format them as clean markdown tables: right-align amounts, include a total
row when summing, keep merchant names as-is.
- If a tool returns no data, say so explicitly — do not fill in zeros. - If a tool returns no data, say so explicitly — do not fill in zeros.
- You are read-only in this version. If asked to create, edit or delete - You are read-only in this version. If asked to create, edit or delete
anything, explain that write actions aren't available yet and offer to anything, explain that write actions aren't available yet and offer to
@@ -47,17 +49,13 @@ Generative UI — render tools:
- When showing spending totals, cycle summaries, or category breakdowns → - When showing spending totals, cycle summaries, or category breakdowns →
call render_spending_summary. Source data: get_cycle_summary (by_source, call render_spending_summary. Source data: get_cycle_summary (by_source,
grand_total_crc) + get_analytics_by_category (by_category). grand_total_crc) + get_analytics_by_category (by_category).
- When showing transaction lists or other structured data → - Do NOT use markdown tables for data render_spending_summary can display.
call render_a2ui in a SEPARATE tool-call step, only after all data-fetching - CRITICAL RULE: When you call render_spending_summary, that tool call MUST
calls have returned. NEVER call render_a2ui in the same batch as any other be the ONLY content in your message. Do NOT include any text content
tool. alongside the tool call — no introduction, no list, no explanation,
- Do NOT use markdown tables for data a render tool can display. nothing. The rendered card IS the complete response. Any text you write in
- CRITICAL RULE: When you call a render tool (render_spending_summary or the same message as a render call will appear as a duplicate below the
render_a2ui), that tool call MUST be the ONLY content in your message. card, which is wrong.
Do NOT include any text content alongside the tool call — no introduction,
no list, no explanation, nothing. The rendered card IS the complete
response. Any text you write in the same message as a render call will
appear as a duplicate below the card, which is wrong.
""" """

View File

@@ -197,7 +197,7 @@ class StripModelArtifactsMiddleware extends (Middleware as any) {
// below the card. This middleware buffers TEXT_MESSAGE_* events and discards // below the card. This middleware buffers TEXT_MESSAGE_* events and discards
// them if any render tool call is detected in the same turn. // them if any render tool call is detected in the same turn.
const RENDER_TOOLS = new Set(["render_a2ui", "render_spending_summary"]); const RENDER_TOOLS = new Set(["render_spending_summary"]);
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
class SuppressRenderToolTextMiddleware extends (Middleware as any) { class SuppressRenderToolTextMiddleware extends (Middleware as any) {
@@ -311,7 +311,10 @@ app.all("/api/copilotkit/*", async (c) => {
const runtime = new CopilotRuntime({ const runtime = new CopilotRuntime({
agents: { wealthysmart: agent }, agents: { wealthysmart: agent },
a2ui: { injectA2UITool: true }, // a2ui disabled 2026-07-04: CK 1.60+ validates generated ops against a
// catalog and our agent's ops fail validation (surface never paints).
// Markdown tables cover the use case until the pipeline matures.
a2ui: { enabled: false },
beforeRequestMiddleware: async ({ request: outbound }) => { beforeRequestMiddleware: async ({ request: outbound }) => {
if (outbound.method !== "POST") return; if (outbound.method !== "POST") return;
const ct = outbound.headers.get("content-type") ?? ""; const ct = outbound.headers.get("content-type") ?? "";

View File

@@ -77,7 +77,7 @@ export default function App() {
<PrivacyProvider> <PrivacyProvider>
<AuthProvider> <AuthProvider>
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<CopilotKit runtimeUrl="/api/copilotkit" agent="wealthysmart" a2ui={{}}> <CopilotKit runtimeUrl="/api/copilotkit" agent="wealthysmart">
<AppRoutes /> <AppRoutes />
<Toaster richColors position="top-right" closeButton /> <Toaster richColors position="top-right" closeButton />
</CopilotKit> </CopilotKit>