import { useState } from 'preact/hooks'; import { askAgent } from '../api.js'; import { renderWithNums } from '../numText.jsx'; // FINAL_SPEC.md §7.1 — inline SVG path, currentColor, no icon font. const SPARK_PATH = 'M8,0 L10,6 L16,8 L10,10 L8,16 L6,10 L0,8 L6,6 Z'; export function SparkIcon({ size = 16 }) { return ( ); } // The live LangGraph router emits route "REFUSE"; the offline keyword // fallback router emits "refusal" — match either (see ChatPanel.jsx). const isRefusalRoute = (route) => /^refus(e|al)$/i.test(route || ''); /** The response-surface strip (FINAL_SPEC §7.4): THINKING / GROUNDED answer * + citation chip / OUT OF SCOPE refusal — shared by the panel/tile explain * affordance and the selection-explain popover. */ export function ExplainStrip({ state, floating = false }) { return (
THINKING
)} {state.status === 'network-error' && (OUT OF SCOPE — request failed ( {state.message})
)} {state.status === 'done' && isRefusalRoute(state.route) && ( <>OUT OF SCOPE
{renderWithNums(state.answer)}
> )} {state.status === 'done' && !isRefusalRoute(state.route) && ( <>GROUNDED
{renderWithNums(state.answer)}
{state.route &&⚙ {state.route}}
>
)}