From 8a991a85cc60ac22c0b5787f18d28ffc51b981ec Mon Sep 17 00:00:00 2001 From: ciregenz Date: Sun, 6 Sep 2026 12:38:54 -0700 Subject: [PATCH] [eric] canvas: the pill's compact stats flag rides extraProps past the zod gate; in the wire props the strict parse stripped it and the widget never saw it Co-Authored-By: Claude Fable 5.1 --- .../src/app/pages/AgentChat/tool-ui/ShowUiWidgetView.tsx | 4 ++-- .../src/app/pages/AgentChat/tool-ui/showUiAmbient.test.ts | 5 ++++- frontend/src/app/pages/AgentChat/tool-ui/showUiAmbient.ts | 7 +++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/pages/AgentChat/tool-ui/ShowUiWidgetView.tsx b/frontend/src/app/pages/AgentChat/tool-ui/ShowUiWidgetView.tsx index 849446d8..fada029f 100644 --- a/frontend/src/app/pages/AgentChat/tool-ui/ShowUiWidgetView.tsx +++ b/frontend/src/app/pages/AgentChat/tool-ui/ShowUiWidgetView.tsx @@ -34,8 +34,8 @@ function ShowUiWidgetView({ payload, ambient }: { payload: ShowUiPayload; ambien const fallback = [raw.src, raw.url].find((v): v is string => typeof v === 'string'); if (fallback) nav.href = fallback; } - const shaped = ambient && !perfBaselineFor('ambient') ? ambientShape(payload.name, raw) : { props: payload.props, note: null }; - let widget = ; + const shaped = ambient && !perfBaselineFor('ambient') ? ambientShape(payload.name, raw) : { props: payload.props, note: null, extraProps: {} }; + let widget = ; if (shaped.note) { widget = (
diff --git a/frontend/src/app/pages/AgentChat/tool-ui/showUiAmbient.test.ts b/frontend/src/app/pages/AgentChat/tool-ui/showUiAmbient.test.ts index 9c0ae779..2c7ab57b 100644 --- a/frontend/src/app/pages/AgentChat/tool-ui/showUiAmbient.test.ts +++ b/frontend/src/app/pages/AgentChat/tool-ui/showUiAmbient.test.ts @@ -24,11 +24,14 @@ test('a short table and other widgets pass through untouched', () => { test('a pill stats card is asked for its compact density', () => { const shaped = ambientShape('stats-display', { stats: [] }); - assert.equal(shaped.props.compact, true); + // The wire schema names no compact key and the strict parse strips unknown keys, so the flag rides extraProps (merged after the gate); in the wire props it was inert. + assert.equal(shaped.extraProps.compact, true); + assert.equal(shaped.props.compact, undefined); }); test('the widget view applies the shaping only on the ambient surface, and is memoized', () => { const src = fs.readFileSync(path.join(process.cwd(), 'src/app/pages/AgentChat/tool-ui/ShowUiWidgetView.tsx'), 'utf8'); assert.ok(src.includes("ambient && !perfBaselineFor('ambient') ? ambientShape(payload.name, raw)"), 'the chat keeps the whole table; only the pill is shaped'); + assert.ok(src.includes('extraProps={{ ...nav, ...shaped.extraProps }}'), 'the shaped extras are merged after the zod gate'); assert.ok(src.includes("export default perfBaselineFor('ambient') ? ShowUiWidgetView : React.memo(ShowUiWidgetView)")); }); diff --git a/frontend/src/app/pages/AgentChat/tool-ui/showUiAmbient.ts b/frontend/src/app/pages/AgentChat/tool-ui/showUiAmbient.ts index 0ff1bf8b..24ff335d 100644 --- a/frontend/src/app/pages/AgentChat/tool-ui/showUiAmbient.ts +++ b/frontend/src/app/pages/AgentChat/tool-ui/showUiAmbient.ts @@ -9,6 +9,8 @@ export interface AmbientShape { props: Record; /** One line under the widget when something was left out, or null. */ note: string | null; + /** Merged AFTER the zod gate: the strict parse strips every key the wire schema does not name, which is where a compact flag in the wire props silently died. */ + extraProps: Record; } export function ambientShape(name: string, props: Record): AmbientShape { @@ -17,9 +19,10 @@ export function ambientShape(name: string, props: Record): Ambi return { props: { ...props, data: props.data.slice(0, AMBIENT_TABLE_ROWS) }, note: `Showing ${AMBIENT_TABLE_ROWS} of ${total.toLocaleString()} rows. Open the chat for the whole table.`, + extraProps: {}, }; } // The vendored stats card stacks its cells vertically under 440 px; the pill is narrower than that. - if (name === 'stats-display') return { props: { ...props, compact: true }, note: null }; - return { props, note: null }; + if (name === 'stats-display') return { props, note: null, extraProps: { compact: true } }; + return { props, note: null, extraProps: {} }; }