@tangle-network/agent-app 0.47.10 → 0.47.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/assistant/index.js +4 -4
- package/dist/chat-react/index.js +2 -2
- package/dist/chat-routes/index.js +17 -0
- package/dist/chat-routes/index.js.map +1 -1
- package/dist/{chunk-E5HZ4JPA.js → chunk-4I76LTZS.js} +7 -2
- package/dist/chunk-4I76LTZS.js.map +1 -0
- package/dist/{chunk-J35PLM4G.js → chunk-F32T3DRJ.js} +2 -2
- package/dist/{chunk-PX3FB6QZ.js → chunk-FMEL7VJR.js} +3 -3
- package/dist/{chunk-IR5OBDO2.js → chunk-TTYJIMTR.js} +2 -2
- package/dist/{mention-editor-4KS5HCV6.js → mention-editor-4PYZJM5A.js} +2 -2
- package/dist/studio-react/index.js +2 -2
- package/dist/web-react/index.js +4 -4
- package/package.json +3 -3
- package/dist/chunk-E5HZ4JPA.js.map +0 -1
- /package/dist/{chunk-J35PLM4G.js.map → chunk-F32T3DRJ.js.map} +0 -0
- /package/dist/{chunk-PX3FB6QZ.js.map → chunk-FMEL7VJR.js.map} +0 -0
- /package/dist/{chunk-IR5OBDO2.js.map → chunk-TTYJIMTR.js.map} +0 -0
- /package/dist/{mention-editor-4KS5HCV6.js.map → mention-editor-4PYZJM5A.js.map} +0 -0
|
@@ -295,7 +295,12 @@ function ModelPicker({ value, onChange, models, loading, renderProviderBadge, re
|
|
|
295
295
|
const panelId = useId();
|
|
296
296
|
const sortedModels = useMemo(() => sortModelsByFreshness(models), [models]);
|
|
297
297
|
useEffect(() => {
|
|
298
|
-
if (open)
|
|
298
|
+
if (!open) return;
|
|
299
|
+
const focus = () => inputRef.current?.focus();
|
|
300
|
+
focus();
|
|
301
|
+
if (typeof requestAnimationFrame !== "function") return;
|
|
302
|
+
const frame = requestAnimationFrame(focus);
|
|
303
|
+
return () => cancelAnimationFrame(frame);
|
|
299
304
|
}, [open]);
|
|
300
305
|
const selected = sortedModels.find((m) => m.id === value);
|
|
301
306
|
const filtered = useMemo(() => {
|
|
@@ -547,4 +552,4 @@ export {
|
|
|
547
552
|
EffortMeter,
|
|
548
553
|
EffortPicker
|
|
549
554
|
};
|
|
550
|
-
//# sourceMappingURL=chunk-
|
|
555
|
+
//# sourceMappingURL=chunk-4I76LTZS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/web-react/provider-logo.tsx","../src/web-react/controls.tsx"],"sourcesContent":["/**\n * Provider brand marks — real logo path data (simple-icons / SVG Logos, both\n * CC0) inlined so the picker shows actual provider identity instead of\n * colored-initial monograms. Providers without a usable mark fall back to a\n * tinted monogram chip. Aliases (z-ai/zai, moonshot/moonshotai, deepseek_ai)\n * normalize to one entry.\n */\n\nimport type { ReactNode } from 'react'\n\ninterface LogoDef {\n viewBox: string\n fill: string\n paths: string[]\n}\n\nconst LOGOS: Record<string, LogoDef> = {\n anthropic: { viewBox: '0 0 24 24', fill: '#D97757', paths: [\"M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z\"] },\n google: { viewBox: '0 0 24 24', fill: '#8E75B2', paths: [\"M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81\"] },\n deepseek: { viewBox: '0 0 24 24', fill: '#4D6BFE', paths: [\"M23.748 4.651c-.254-.124-.364.113-.512.233-.051.04-.094.09-.137.137-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.155-.708-.311-.955-.65-.172-.24-.219-.509-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.094.172.187.129.323-.082.28-.18.553-.266.833-.055.179-.137.218-.328.14a5.5 5.5 0 0 1-1.737-1.179c-.857-.828-1.631-1.743-2.597-2.46a12 12 0 0 0-.689-.47c-.985-.957.13-1.743.387-1.836.27-.098.094-.433-.778-.428-.872.003-1.67.295-2.687.685a3 3 0 0 1-.465.136 9.6 9.6 0 0 0-2.883-.101c-1.885.21-3.39 1.1-4.497 2.622C.082 8.776-.231 10.854.152 13.02c.403 2.284 1.568 4.175 3.36 5.653 1.857 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.132-.284 4.994-1.86.47.234.962.328 1.78.398.629.058 1.235-.031 1.705-.129.735-.155.684-.836.418-.961-2.155-1.004-1.682-.595-2.112-.926 1.095-1.295 2.768-3.598 3.284-6.733.05-.346.115-.834.108-1.114-.004-.171.035-.238.23-.257a4.2 4.2 0 0 0 1.545-.475c1.397-.763 1.96-2.016 2.093-3.517.02-.23-.004-.467-.247-.588M11.58 18.168c-2.088-1.642-3.101-2.183-3.52-2.16-.39.024-.32.472-.234.763.09.288.207.487.371.74.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.168-1.361-.801-2.5-1.86-3.301-3.306-.775-1.393-1.225-2.888-1.299-4.482-.02-.385.094-.522.477-.592a4.7 4.7 0 0 1 1.53-.038c2.131.311 3.946 1.264 5.467 2.774.868.86 1.525 1.887 2.202 2.89.72 1.066 1.494 2.082 2.48 2.915.348.291.626.513.892.677-.802.09-2.14.109-3.055-.615zm1.001-6.44a.306.306 0 0 1 .415-.287.3.3 0 0 1 .113.074.3.3 0 0 1 .086.214c0 .17-.136.307-.308.307a.303.303 0 0 1-.306-.307m3.11 1.596c-.2.081-.4.151-.591.16a1.25 1.25 0 0 1-.798-.254c-.274-.23-.47-.358-.551-.758a1.7 1.7 0 0 1 .015-.588c.07-.327-.007-.537-.238-.727-.188-.156-.426-.199-.689-.199a.6.6 0 0 1-.254-.078.253.253 0 0 1-.114-.358 1 1 0 0 1 .192-.21c.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.392.451.462.576.685.915.176.264.336.536.446.848.066.194-.02.353-.25.45\"] },\n mistral: { viewBox: '0 0 24 24', fill: '#FA520F', paths: [\"M17.143 3.429v3.428h-3.429v3.429h-3.428V6.857H6.857V3.43H3.43v13.714H0v3.428h10.286v-3.428H6.857v-3.429h3.429v3.429h3.429v-3.429h3.428v3.429h-3.428v3.428H24v-3.428h-3.43V3.429z\"] },\n xai: { viewBox: '0 0 24 24', fill: '#000000', paths: [\"M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z\"] },\n nvidia: { viewBox: '0 0 24 24', fill: '#76B900', paths: [\"M8.948 8.798v-1.43a6.7 6.7 0 0 1 .424-.018c3.922-.124 6.493 3.374 6.493 3.374s-2.774 3.851-5.75 3.851c-.398 0-.787-.062-1.158-.185v-4.346c1.528.185 1.837.857 2.747 2.385l2.04-1.714s-1.492-1.952-4-1.952a6.016 6.016 0 0 0-.796.035m0-4.735v2.138l.424-.027c5.45-.185 9.01 4.47 9.01 4.47s-4.08 4.964-8.33 4.964c-.37 0-.733-.035-1.095-.097v1.325c.3.035.61.062.91.062 3.957 0 6.82-2.023 9.593-4.408.459.371 2.34 1.263 2.73 1.652-2.633 2.208-8.772 3.984-12.253 3.984-.335 0-.653-.018-.971-.053v1.864H24V4.063zm0 10.326v1.131c-3.657-.654-4.673-4.46-4.673-4.46s1.758-1.944 4.673-2.262v1.237H8.94c-1.528-.186-2.73 1.245-2.73 1.245s.68 2.412 2.739 3.11M2.456 10.9s2.164-3.197 6.5-3.533V6.201C4.153 6.59 0 10.653 0 10.653s2.35 6.802 8.948 7.42v-1.237c-4.84-.6-6.492-5.936-6.492-5.936z\"] },\n meta: { viewBox: '0 0 24 24', fill: '#0467DF', paths: [\"M6.915 4.03c-1.968 0-3.683 1.28-4.871 3.113C.704 9.208 0 11.883 0 14.449c0 .706.07 1.369.21 1.973a6.624 6.624 0 0 0 .265.86 5.297 5.297 0 0 0 .371.761c.696 1.159 1.818 1.927 3.593 1.927 1.497 0 2.633-.671 3.965-2.444.76-1.012 1.144-1.626 2.663-4.32l.756-1.339.186-.325c.061.1.121.196.183.3l2.152 3.595c.724 1.21 1.665 2.556 2.47 3.314 1.046.987 1.992 1.22 3.06 1.22 1.075 0 1.876-.355 2.455-.843a3.743 3.743 0 0 0 .81-.973c.542-.939.861-2.127.861-3.745 0-2.72-.681-5.357-2.084-7.45-1.282-1.912-2.957-2.93-4.716-2.93-1.047 0-2.088.467-3.053 1.308-.652.57-1.257 1.29-1.82 2.05-.69-.875-1.335-1.547-1.958-2.056-1.182-.966-2.315-1.303-3.454-1.303zm10.16 2.053c1.147 0 2.188.758 2.992 1.999 1.132 1.748 1.647 4.195 1.647 6.4 0 1.548-.368 2.9-1.839 2.9-.58 0-1.027-.23-1.664-1.004-.496-.601-1.343-1.878-2.832-4.358l-.617-1.028a44.908 44.908 0 0 0-1.255-1.98c.07-.109.141-.224.211-.327 1.12-1.667 2.118-2.602 3.358-2.602zm-10.201.553c1.265 0 2.058.791 2.675 1.446.307.327.737.871 1.234 1.579l-1.02 1.566c-.757 1.163-1.882 3.017-2.837 4.338-1.191 1.649-1.81 1.817-2.486 1.817-.524 0-1.038-.237-1.383-.794-.263-.426-.464-1.13-.464-2.046 0-2.221.63-4.535 1.66-6.088.454-.687.964-1.226 1.533-1.533a2.264 2.264 0 0 1 1.088-.285z\"] },\n moonshotai: { viewBox: '0 0 24 24', fill: '#16191E', paths: [\"m1.053 16.91 9.538 2.55a21 20.981 0 0 0 .06 2.031l5.956 1.592a12 11.99 0 0 1-15.554-6.172m-1.02-5.79 11.352 3.035a21 20.981 0 0 0-.469 2.01l10.817 2.89a12 11.99 0 0 1-1.845 2.004L.658 15.918a12 11.99 0 0 1-.625-4.796m1.593-5.146L13.573 9.17a21 20.981 0 0 0-1.01 1.874l11.297 3.02a21 20.981 0 0 1-.67 2.362l-11.55-3.087L.125 10.26a12 11.99 0 0 1 1.499-4.285ZM6.067 1.58l11.285 3.016a21 20.981 0 0 0-1.688 1.719l7.824 2.091a21 20.981 0 0 1 .513 2.664L2.107 5.218a12 11.99 0 0 1 3.96-3.638M21.68 4.866 7.222 1.003A12 11.99 0 0 1 21.68 4.866\"] },\n openai: { viewBox: '0 0 256 260', fill: '#10A37F', paths: [\"M239.184 106.203a64.72 64.72 0 0 0-5.576-53.103C219.452 28.459 191 15.784 163.213 21.74A65.586 65.586 0 0 0 52.096 45.22a64.72 64.72 0 0 0-43.23 31.36c-14.31 24.602-11.061 55.634 8.033 76.74a64.67 64.67 0 0 0 5.525 53.102c14.174 24.65 42.644 37.324 70.446 31.36a64.72 64.72 0 0 0 48.754 21.744c28.481.025 53.714-18.361 62.414-45.481a64.77 64.77 0 0 0 43.229-31.36c14.137-24.558 10.875-55.423-8.083-76.483m-97.56 136.338a48.4 48.4 0 0 1-31.105-11.255l1.535-.87l51.67-29.825a8.6 8.6 0 0 0 4.247-7.367v-72.85l21.845 12.636c.218.111.37.32.409.563v60.367c-.056 26.818-21.783 48.545-48.601 48.601M37.158 197.93a48.35 48.35 0 0 1-5.781-32.589l1.534.921l51.722 29.826a8.34 8.34 0 0 0 8.441 0l63.181-36.425v25.221a.87.87 0 0 1-.358.665l-52.335 30.184c-23.257 13.398-52.97 5.431-66.404-17.803M23.549 85.38a48.5 48.5 0 0 1 25.58-21.333v61.39a8.29 8.29 0 0 0 4.195 7.316l62.874 36.272l-21.845 12.636a.82.82 0 0 1-.767 0L41.353 151.53c-23.211-13.454-31.171-43.144-17.804-66.405zm179.466 41.695l-63.08-36.63L161.73 77.86a.82.82 0 0 1 .768 0l52.233 30.184a48.6 48.6 0 0 1-7.316 87.635v-61.391a8.54 8.54 0 0 0-4.4-7.213m21.742-32.69l-1.535-.922l-51.619-30.081a8.39 8.39 0 0 0-8.492 0L99.98 99.808V74.587a.72.72 0 0 1 .307-.665l52.233-30.133a48.652 48.652 0 0 1 72.236 50.391zM88.061 139.097l-21.845-12.585a.87.87 0 0 1-.41-.614V65.685a48.652 48.652 0 0 1 79.757-37.346l-1.535.87l-51.67 29.825a8.6 8.6 0 0 0-4.246 7.367zm11.868-25.58L128.067 97.3l28.188 16.218v32.434l-28.086 16.218l-28.188-16.218z\"] },\n}\n\nconst ALIASES: Record<string, string> = {\n moonshot: 'moonshotai',\n deepseek_ai: 'deepseek',\n 'x-ai': 'xai',\n 'meta-llama': 'meta',\n}\n\nconst MONOGRAM: Record<string, { bg: string; fg: string }> = {\n cohere: { bg: '#fae8ff', fg: '#c026d3' },\n groq: { bg: '#fce7f3', fg: '#db2777' },\n cerebras: { bg: '#ccfbf1', fg: '#0d9488' },\n zai: { bg: '#ede9fe', fg: '#7c3aed' },\n 'z-ai': { bg: '#ede9fe', fg: '#7c3aed' },\n tuner: { bg: '#dbeafe', fg: '#2563eb' },\n}\n\nexport interface ProviderLogoProps {\n provider?: string\n size?: number\n}\n\n/** Real brand mark when we have one; tinted monogram otherwise. */\nexport function ProviderLogo({ provider, size = 16 }: ProviderLogoProps): ReactNode {\n const key = ALIASES[provider ?? ''] ?? provider ?? ''\n const logo = LOGOS[key]\n if (logo) {\n return (\n <svg width={size} height={size} viewBox={logo.viewBox} role=\"img\" aria-label={key}>\n {logo.paths.map((d, i) => (\n <path key={i} d={d} fill={logo.fill} />\n ))}\n </svg>\n )\n }\n // Unknown providers fall back to a neutral monogram drawn from theme tokens\n // (secondary tile, muted glyph) — the previous hardcoded grays (#f3f4f6 /\n // #6b7280) were tuned for light mode and read as a washed-out hole on dark.\n // `style` rather than the `fill` attribute so the var() references resolve.\n const mono = MONOGRAM[key]\n return (\n <svg width={size} height={size} viewBox=\"0 0 16 16\" role=\"img\" aria-label={key || 'model'}>\n <rect width=\"16\" height=\"16\" rx=\"4\" style={{ fill: mono ? mono.bg : 'hsl(var(--secondary))' }} />\n <text x=\"8\" y=\"11.6\" textAnchor=\"middle\" style={{ fill: mono ? mono.fg : 'hsl(var(--muted-foreground))' }} fontSize=\"9\" fontWeight=\"700\" fontFamily=\"system-ui, sans-serif\">\n {(key || '?').charAt(0).toUpperCase()}\n </text>\n </svg>\n )\n}\n","/**\n * Shared chat-shell control primitives — the LEAF that both the web-react barrel\n * (`./index`) and the composer children (`./agent-session-controls`,\n * `./seat-paywall`) import directly, so neither child has to reach back through\n * the barrel (which would re-create an import cycle). The barrel re-exports the\n * public names (`usePopover`, `usePending`, `ModelPicker`, `EffortPicker`, …)\n * unchanged, so the published export surface is identical.\n *\n * Styling contract matches the rest of `web-react`: Tailwind classes against the\n * shared design tokens; the glyphs are inline SVGs, no icon-library dependency.\n */\n\nimport {\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type ReactNode,\n type RefObject,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { ProviderLogo } from './provider-logo'\nimport {\n MAX_RECOMMENDED_MODELS,\n sortModelsByFreshness,\n type CatalogModel,\n} from '../runtime/model-catalog'\n\n// ── shared glyphs (no icon-library dependency) ────────────────────────────\n\nexport function ChevronDown({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n )\n}\n\nfunction SearchGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </svg>\n )\n}\n\nfunction SparkleGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M12 3v3m0 12v3M3 12h3m12 0h3M5.6 5.6l2.1 2.1m8.6 8.6 2.1 2.1m0-12.8-2.1 2.1M7.7 16.3l-2.1 2.1\" />\n </svg>\n )\n}\n\n/** lucide `brain` (v1.27) inlined — `/web-react` ships no icon-library\n * dependency, so the thinking glyph follows the same pattern as the rest of\n * this set. */\nexport function BrainGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M12 18V5\" />\n <path d=\"M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4\" />\n <path d=\"M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5\" />\n <path d=\"M17.997 5.125a4 4 0 0 1 2.526 5.77\" />\n <path d=\"M18 18a4 4 0 0 0 2-7.464\" />\n <path d=\"M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517\" />\n <path d=\"M6 18a4 4 0 0 1-2-7.464\" />\n <path d=\"M6.003 5.125a4 4 0 0 0-2.526 5.77\" />\n </svg>\n )\n}\n\n/** lucide `check` — the selected-row mark in the picker menus. */\nexport function CheckGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n )\n}\n\n/**\n * Keyboard + pointer model for a trigger-and-popover pair, dependency-free.\n * Outside-mousedown and Escape both close; Escape also returns focus to the\n * trigger so keyboard users aren't dropped at the top of the document. The\n * returned `triggerProps` carry the ARIA contract (`aria-haspopup`/\n * `aria-expanded`); spread them onto the trigger button.\n *\n * `panelRef` belongs to the popover panel and MUST be wired when the panel is\n * rendered through {@link PopoverSurface}: a portaled panel is not inside\n * `containerRef`, so a container-only outside test reads every click on the\n * menu's own rows as an outside click and closes before the row's handler runs.\n */\nexport function usePopover(open: boolean, setOpen: (open: boolean) => void) {\n const containerRef = useRef<HTMLDivElement>(null)\n const triggerRef = useRef<HTMLButtonElement>(null)\n const panelRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (!open) return\n function onMouseDown(e: MouseEvent) {\n const target = e.target as Node\n if (containerRef.current?.contains(target)) return\n const panel = panelRef.current\n if (panel?.contains(target)) return\n // A popover opened FROM this one portals as a SIBLING at body level, so\n // `contains` cannot see it and a click on its rows would read as outside.\n // Surfaces stamp their ancestor chain, so descendancy survives the portal.\n const ownPath = panel?.getAttribute(POPOVER_SURFACE_ATTR)\n const hitPath =\n target instanceof Element\n ? target.closest(`[${POPOVER_SURFACE_ATTR}]`)?.getAttribute(POPOVER_SURFACE_ATTR)\n : null\n if (ownPath && hitPath && (hitPath === ownPath || hitPath.startsWith(`${ownPath}${POPOVER_PATH_SEPARATOR}`))) return\n setOpen(false)\n }\n function onKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') {\n setOpen(false)\n triggerRef.current?.focus()\n }\n }\n document.addEventListener('mousedown', onMouseDown)\n document.addEventListener('keydown', onKeyDown)\n return () => {\n document.removeEventListener('mousedown', onMouseDown)\n document.removeEventListener('keydown', onKeyDown)\n }\n }, [open, setOpen])\n\n return {\n containerRef,\n triggerRef,\n panelRef,\n triggerProps: {\n ref: triggerRef,\n 'aria-haspopup': true as const,\n 'aria-expanded': open,\n },\n }\n}\n\n// ── PopoverSurface ────────────────────────────────────────────────────────\n\n/** Distance between the trigger and the panel it opens. */\nconst POPOVER_GAP = 8\n/** Minimum distance the panel keeps from every viewport edge. */\nconst POPOVER_VIEWPORT_MARGIN = 16\n/** Floor for the computed max-height, so a cramped side still shows rows\n * rather than collapsing to a sliver the user cannot read. */\nconst POPOVER_MIN_HEIGHT = 120\n\n/**\n * Marks the portaled panel in the DOM. Products and audits (see\n * `playground/scripts/popover-hit-test.mjs`) select on this rather than on a\n * Tailwind class, which is presentation and free to change.\n *\n * Its VALUE is the surface's ancestor path (`outer/inner`), which is what\n * restores \"is this click inside my popover\" after the portal flattens two\n * nested panels into two siblings of `<body>`.\n */\nexport const POPOVER_SURFACE_ATTR = 'data-agent-app-popover'\nconst POPOVER_PATH_SEPARATOR = '/'\n\n/**\n * `PopoverSurface` is now mounted (closed) inside every server-rendered\n * composer, so its hooks run on the server once per composer per request.\n * React 18 logs \"useLayoutEffect does nothing on the server\" for that; React 19\n * does not (measured silent on react-dom 19.2.8). The peer floor is `react >=18`,\n * so bind the synchronous hook only where there is a DOM and the effect hook\n * elsewhere — placement never runs on the server either way.\n */\nconst useBrowserLayoutEffect = typeof document !== 'undefined' ? useLayoutEffect : useEffect\n\nexport interface PopoverSurfaceProps {\n open: boolean\n /** The trigger the panel anchors to — `usePopover`'s `triggerRef`. */\n triggerRef: RefObject<HTMLElement | null>\n /** `usePopover`'s `panelRef`; also what the outside-click test consults. */\n panelRef: RefObject<HTMLDivElement | null>\n /** Presentation classes. Placement and elevation are owned here — a caller\n * must not pass `absolute`/`fixed`/`top-*`/`bottom-*`/`z-*`. */\n className?: string\n role?: string\n id?: string\n /** Make the panel at least as wide as its trigger. A portaled panel has no\n * `w-full` to inherit — the trigger is no longer its offset parent — so a\n * menu that used to stretch to a full-width trigger declares it here. */\n matchTriggerWidth?: boolean\n children: ReactNode\n}\n\n/**\n * The floating panel every canonical picker opens.\n *\n * It renders through a PORTAL to `document.body` and anchors itself to the\n * trigger in viewport coordinates, because an in-place `absolute` panel's\n * visibility is decided by markup this package does not own. Measured in\n * production: the shipped chat composer docks these controls inside a\n * horizontally scrolling rail (`overflow-x-auto`), and a scroll container\n * clips every positioned descendant whose containing block sits inside it —\n * so a correct 420x457 menu with correct coordinates painted zero pixels and\n * could not be clicked. An ancestor `transform`/`filter`/`contain` would trap\n * it the same way through the stacking context instead of the clip. Leaving\n * the DOM subtree is the only placement a host cannot re-break.\n *\n * Placement prefers ABOVE the trigger (these controls dock at the bottom of a\n * composer), flips below when there is more room there, clamps horizontally\n * into the viewport, and caps its own height to the space on the chosen side.\n * The panel is `visibility: hidden` for the measure pass so it never paints at\n * the pre-placement origin.\n */\nexport function PopoverSurface({\n open,\n triggerRef,\n panelRef,\n className,\n role,\n id,\n matchTriggerWidth,\n children,\n}: PopoverSurfaceProps) {\n const surfaceId = useId()\n const [style, setStyle] = useState<CSSProperties>(() => ({\n position: 'fixed',\n top: 0,\n left: 0,\n visibility: 'hidden',\n }))\n\n const place = useCallback(() => {\n const trigger = triggerRef.current\n const panel = panelRef.current\n if (!trigger || !panel) return\n const anchor = trigger.getBoundingClientRect()\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n\n // `scrollHeight` is the panel's CONTENT height, so it does not feed back\n // on the `maxHeight` this function just applied — reading `offsetHeight`\n // here would measure the previous pass's clamp and ratchet the panel\n // smaller on every scroll event.\n const contentHeight = panel.scrollHeight\n const panelWidth = panel.offsetWidth\n\n const roomAbove = anchor.top - POPOVER_GAP - POPOVER_VIEWPORT_MARGIN\n const roomBelow = viewportHeight - anchor.bottom - POPOVER_GAP - POPOVER_VIEWPORT_MARGIN\n const above = contentHeight <= roomAbove || roomAbove >= roomBelow\n const maxHeight = Math.max(POPOVER_MIN_HEIGHT, above ? roomAbove : roomBelow)\n const height = Math.min(contentHeight, maxHeight)\n\n const top = above ? Math.max(POPOVER_VIEWPORT_MARGIN, anchor.top - POPOVER_GAP - height) : anchor.bottom + POPOVER_GAP\n const rightBound = Math.max(POPOVER_VIEWPORT_MARGIN, viewportWidth - panelWidth - POPOVER_VIEWPORT_MARGIN)\n const left = Math.min(Math.max(POPOVER_VIEWPORT_MARGIN, anchor.left), rightBound)\n\n setStyle({\n position: 'fixed',\n top,\n left,\n maxHeight,\n visibility: 'visible',\n ...(matchTriggerWidth ? { minWidth: anchor.width } : {}),\n })\n }, [matchTriggerWidth, panelRef, triggerRef])\n\n // Layout effect: placement is resolved before the browser paints, so the\n // panel is never seen at the origin it mounts at.\n useBrowserLayoutEffect(() => {\n if (!open) {\n setStyle({ position: 'fixed', top: 0, left: 0, visibility: 'hidden' })\n return\n }\n place()\n }, [open, place])\n\n useEffect(() => {\n if (!open) return\n const onViewportChange = () => place()\n // `capture` so the rail's OWN scroll re-anchors the panel — a scroll inside\n // an ancestor does not bubble to window.\n window.addEventListener('scroll', onViewportChange, true)\n window.addEventListener('resize', onViewportChange)\n return () => {\n window.removeEventListener('scroll', onViewportChange, true)\n window.removeEventListener('resize', onViewportChange)\n }\n }, [open, place])\n\n if (!open || typeof document === 'undefined') return null\n\n const ownerPath = triggerRef.current?.closest?.(`[${POPOVER_SURFACE_ATTR}]`)?.getAttribute(POPOVER_SURFACE_ATTR)\n const path = ownerPath ? `${ownerPath}${POPOVER_PATH_SEPARATOR}${surfaceId}` : surfaceId\n\n return createPortal(\n <div\n ref={panelRef}\n id={id}\n role={role}\n style={style}\n {...{ [POPOVER_SURFACE_ATTR]: path }}\n className={`z-[1000] ${className ?? ''}`}\n >\n {children}\n </div>,\n document.body,\n )\n}\n\n/**\n * Focus treatment for a row inside a popover panel.\n *\n * The ring itself now comes from the `:focus-visible` floor in tokens.css, so\n * this no longer restates a width or a colour. What it still has to say is\n * WHERE the ring is drawn: a popover option is a full-width row inside a panel\n * that clips its own corners (`overflow-hidden rounded-xl`), and an outward\n * ring on the first or last row is clipped away by that panel. Pulling the\n * offset negative draws the same ring just inside the row instead.\n */\nexport const POPOVER_OPTION_FOCUS = 'focus-visible:[outline-offset:-2px]'\n\n/**\n * The one overlay elevation for floating surfaces — picker menus, popovers,\n * drawers, modals. Reads the theme's `--shadow-overlay` token, so every overlay\n * lifts with the same shadow and re-themes from one source. The floating\n * composer uses the quieter `shadow-raised` rung instead.\n *\n * Written as an arbitrary value rather than the preset's `shadow-overlay`\n * utility, because that utility only exists where the preset is part of the\n * Tailwind build. A host that gets its tokens through a precompiled bundle —\n * `@tangle-network/sandbox-ui` ships brand's tokens inlined, with no `@theme`\n * block surviving the compile — receives `--shadow-overlay` as a plain custom\n * property, from which no `shadow-overlay` utility can be generated, and these\n * surfaces render flat. The arbitrary form emits from the class alone and works\n * either way.\n */\nexport const OVERLAY_SHADOW = 'shadow-[var(--shadow-overlay)]'\n\n/**\n * Root geometry for a picker — the box that holds the trigger — in one place\n * because every picker in this family has to agree on it.\n *\n * Shrink-wrapping (`inline-flex`) is the default: these controls dock on a\n * composer row where an expanding pill shoves its neighbours around. A STACKED\n * panel wants the opposite — the compact `AgentSessionControls` gear popover\n * lays its controls out in a column, and a shrink-wrapped root there makes a\n * trigger's own `w-full` a no-op, since it fills a box the trigger itself\n * sized. That is what left Agent backend short of the panel edge and Thinking\n * narrower still.\n *\n * The panel is portaled ({@link PopoverSurface}), so widening the root widens\n * the TRIGGER only. A menu that should follow it declares `matchTriggerWidth`.\n */\nexport function pickerRootClass(fullWidth: boolean): string {\n return `relative ${fullWidth ? 'flex w-full' : 'inline-flex'}`\n}\n\n/**\n * How a picker's TRIGGER is drawn. The menu it opens is the same either way.\n *\n * - `chip` (default): the 36px bordered pill — `rounded-full border\n * border-border bg-card font-medium`. A consumer that names no variant\n * renders exactly what it rendered before this prop existed.\n * - `quiet`: a 28px borderless text button — muted label, small glyph, a\n * surface fill on hover and while the menu is open, nothing else. For a\n * composer whose card already draws the border: three pills docked under\n * the input there read as three more cards, not as the input's controls.\n */\nexport type PickerVariant = 'chip' | 'quiet'\n\n/** The quiet trigger at rest: geometry, type, and keyboard focus. */\nconst QUIET_PICKER_TRIGGER_BASE =\n 'inline-flex h-7 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-md bg-transparent px-2 text-sm font-normal text-muted-foreground transition focus:outline-none focus-visible:ring-2 focus-visible:ring-ring'\n\n/** The fills a quiet trigger shows on hover and while its menu is open — the\n * only two states it draws. Reads `data-state`, which every picker trigger\n * in this family stamps. */\nconst QUIET_PICKER_TRIGGER_INTERACTIVE =\n 'hover:bg-accent hover:text-foreground data-[state=open]:bg-accent data-[state=open]:text-foreground'\n\n/**\n * Trigger classes for a `quiet` picker. Height, padding, radius, and type are\n * fixed here so the triggers on one composer row agree; a caller adds only\n * width (`w-full`) and alignment (`justify-between`).\n *\n * The focus ring is drawn on the element rather than left to the tokens.css\n * `:focus-visible` floor: a quiet trigger sits beside the composer's own action\n * buttons (attach, dictate, send), which draw `focus-visible:ring-2\n * focus-visible:ring-ring`, and a row whose controls answer keyboard focus two\n * different ways reads as two families.\n *\n * `interactive: false` is for a PINNED control (see `HarnessPicker`'s\n * `lockReason`): it keeps the resting treatment and draws no hover or open\n * fill, because a fill promises a menu the control will not open.\n */\nexport function quietPickerTriggerClass({ interactive = true }: { interactive?: boolean } = {}): string {\n return interactive\n ? `${QUIET_PICKER_TRIGGER_BASE} ${QUIET_PICKER_TRIGGER_INTERACTIVE}`\n : `${QUIET_PICKER_TRIGGER_BASE} cursor-default`\n}\n\n/**\n * Guard an async action against double-submit. `run` ignores re-entrant calls\n * while a promise is in flight and flips `pending` so the caller can disable\n * the control — the fix for double-charge / double-approve on a slow network.\n * Settles (success or throw) before clearing, and no-ops state updates after\n * unmount.\n */\nexport function usePending(): { pending: boolean; run: (action: () => void | Promise<void>) => void } {\n const [pending, setPending] = useState(false)\n const inFlight = useRef(false)\n const mounted = useRef(true)\n useEffect(() => {\n mounted.current = true\n return () => {\n mounted.current = false\n }\n }, [])\n const run = (action: () => void | Promise<void>) => {\n if (inFlight.current) return\n let result: void | Promise<void>\n try {\n result = action()\n } catch {\n return\n }\n if (!(result instanceof Promise)) return\n inFlight.current = true\n setPending(true)\n void result.finally(() => {\n inFlight.current = false\n if (mounted.current) setPending(false)\n })\n }\n return { pending, run }\n}\n\n// ── ModelPicker ───────────────────────────────────────────────────────────\n\nexport interface ModelPickerProps {\n value: string\n onChange: (id: string) => void\n /** Catalogue models — from `GET`ing the app's catalogue route (see\n * `runtime/model-catalog`), plus any product-specific entries appended. */\n models: CatalogModel[]\n loading?: boolean\n /** Render a provider logo/badge; default is a generic sparkle. */\n renderProviderBadge?: (provider: string) => ReactNode\n /** Section label for `featured` models. */\n recommendedLabel?: string\n /** Pin a labeled section to the TOP of the list (above Recommended) for the\n * models a product wants surfaced first — e.g. a tuner app's own fine-tuned\n * models (`{ label: 'Your Fine-Tuned Models', match: (m) => m.provider === 'tuner' }`).\n * Matching models are shown only in this section, not duplicated below. */\n priorityGroup?: {\n label: string\n match: (model: CatalogModel) => boolean\n }\n /** Trigger treatment — see {@link PickerVariant}. Default `chip`. */\n variant?: PickerVariant\n}\n\nfunction formatPrice(p?: string): string | undefined {\n if (!p) return undefined\n const n = Number(p)\n if (isNaN(n) || n === 0) return undefined\n const perM = n * 1_000_000\n return perM >= 1 ? `$${perM.toFixed(0)}/M` : `$${perM.toFixed(2)}/M`\n}\n\nfunction formatContext(len?: number): string | undefined {\n if (!len) return undefined\n if (len >= 1_000_000) return `${(len / 1_000_000).toFixed(1)}M ctx`\n if (len >= 1_000) return `${Math.round(len / 1_000)}K ctx`\n return `${len} ctx`\n}\n\nfunction SectionHeader({ children }: { children: ReactNode }) {\n return (\n <div className=\"px-3 pb-1 pt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {children}\n </div>\n )\n}\n\nfunction ModelRow({\n model,\n selected,\n onSelect,\n renderProviderBadge,\n}: {\n model: CatalogModel\n selected: boolean\n onSelect: () => void\n renderProviderBadge?: (provider: string) => ReactNode\n}) {\n const price = formatPrice(model.pricing?.prompt)\n const ctx = formatContext(model.contextLength)\n return (\n <button\n type=\"button\"\n onClick={onSelect}\n className={`flex w-full items-center gap-2.5 rounded-md px-3 py-2.5 text-left text-sm transition ${POPOVER_OPTION_FOCUS} ${\n selected ? 'bg-primary/10 font-medium' : 'hover:bg-accent'\n }`}\n >\n {renderProviderBadge ? renderProviderBadge(model.provider) : <ProviderLogo provider={model.provider} size={16} />}\n <span className=\"truncate\">{model.name}</span>\n {!model.supportsTools && (\n <span className=\"shrink-0 rounded bg-secondary px-1.5 py-0.5 text-xs font-medium text-muted-foreground\">\n no tools\n </span>\n )}\n <span className=\"ml-auto flex shrink-0 items-center gap-2 text-xs text-muted-foreground\">\n {ctx && <span>{ctx}</span>}\n {price && <span>{price}</span>}\n </span>\n </button>\n )\n}\n\n/**\n * Searchable model picker pill + popover. A featured model is recommended\n * only when it is also that provider's newest entry. Older featured models\n * stay visible in their provider group instead of jumping above new releases.\n *\n * This is the CANONICAL ecosystem model picker (see \"UI chrome ownership\n * (picker canon)\" in AGENTS.md). sandbox-ui's `dashboard/ModelPicker` is\n * legacy — deprecated, frozen, removed at sandbox-ui's next major; new code\n * belongs here.\n */\nexport function ModelPicker({ value, onChange, models, loading, renderProviderBadge, recommendedLabel = 'Recommended', priorityGroup, variant = 'chip' }: ModelPickerProps) {\n const [open, setOpen] = useState(false)\n const [query, setQuery] = useState('')\n const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen)\n const inputRef = useRef<HTMLInputElement>(null)\n const panelId = useId()\n const sortedModels = useMemo(() => sortModelsByFreshness(models), [models])\n\n useEffect(() => {\n if (!open) return\n\n // PopoverSurface is portaled and its placement effect can commit a second\n // render after the panel mounts. Focus once after that commit so the\n // browser keeps the search field active instead of restoring focus to the\n // trigger button. Guard the browser-only scheduler for SSR and test hosts.\n const focus = () => inputRef.current?.focus()\n focus()\n if (typeof requestAnimationFrame !== 'function') return\n const frame = requestAnimationFrame(focus)\n return () => cancelAnimationFrame(frame)\n }, [open])\n\n const selected = sortedModels.find((m) => m.id === value)\n\n const filtered = useMemo(() => {\n const q = query.trim().toLowerCase()\n if (!q) return null\n return sortedModels.filter(\n (m) =>\n m.id.toLowerCase().includes(q) ||\n m.name.toLowerCase().includes(q) ||\n (m.description?.toLowerCase() ?? '').includes(q) ||\n m.provider.toLowerCase().includes(q),\n )\n }, [sortedModels, query])\n\n const sections = useMemo(() => {\n const isPriority = priorityGroup ? (m: CatalogModel) => priorityGroup.match(m) : () => false\n const priority = priorityGroup ? sortedModels.filter(isPriority) : []\n const seenProviders = new Set<string>()\n const newestIds = new Set<string>()\n for (const model of sortedModels) {\n const provider = model.provider.toLowerCase()\n if (seenProviders.has(provider)) continue\n seenProviders.add(provider)\n newestIds.add(model.id)\n }\n const recommended = sortedModels\n .filter((model) => {\n if (!model.featured || isPriority(model)) return false\n return newestIds.has(model.id)\n })\n .slice(0, MAX_RECOMMENDED_MODELS)\n const recommendedIds = new Set(recommended.map((model) => model.id))\n const byProvider: Array<{ provider: string; items: CatalogModel[] }> = []\n for (const m of sortedModels) {\n if (recommendedIds.has(m.id) || isPriority(m)) continue\n const last = byProvider[byProvider.length - 1]\n if (last && last.provider === m.provider) last.items.push(m)\n else byProvider.push({ provider: m.provider, items: [m] })\n }\n return { priority, recommended, byProvider }\n }, [sortedModels, priorityGroup])\n\n const select = (id: string) => {\n onChange(id)\n setOpen(false)\n setQuery('')\n }\n\n return (\n <div ref={containerRef} className=\"relative inline-flex\">\n <button\n type=\"button\"\n {...triggerProps}\n aria-controls={open ? panelId : undefined}\n onClick={() => setOpen(!open)}\n data-state={open ? 'open' : 'closed'}\n className={\n variant === 'quiet'\n ? quietPickerTriggerClass()\n : 'inline-flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent'\n }\n >\n {selected ? (renderProviderBadge ? renderProviderBadge(selected.provider) : <ProviderLogo provider={selected.provider} size={16} />) : <SparkleGlyph className=\"h-3.5 w-3.5 text-muted-foreground\" />}\n <span className=\"max-w-[160px] truncate\">{selected?.name ?? value}</span>\n <ChevronDown className=\"h-3.5 w-3.5 text-muted-foreground\" />\n </button>\n\n <PopoverSurface\n open={open}\n id={panelId}\n triggerRef={triggerRef}\n panelRef={panelRef}\n className={`flex w-[420px] max-w-[calc(100vw-2rem)] flex-col overflow-hidden rounded-xl border border-card-edge bg-popover ${OVERLAY_SHADOW}`}\n >\n <div className=\"shrink-0 border-b border-border px-3 py-2\">\n <div className=\"flex items-center gap-2 rounded-lg border border-strong bg-background px-3 py-2\">\n <SearchGlyph className=\"h-3.5 w-3.5 text-muted-foreground\" />\n <input\n ref={inputRef}\n type=\"text\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search models...\"\n className=\"flex-1 bg-transparent text-sm placeholder:text-muted-foreground\"\n />\n </div>\n </div>\n {/* `min-h-0` is what lets the list absorb the surface's computed\n max-height on a short viewport instead of overflowing the panel. */}\n <div className=\"max-h-[400px] min-h-0 overflow-y-auto p-1 pb-2\">\n {loading && <div className=\"px-3 py-4 text-center text-sm text-muted-foreground\">Loading models...</div>}\n {!loading && filtered && (\n <>\n {filtered.length === 0 && (\n <div className=\"px-3 py-4 text-center text-sm text-muted-foreground\">No models match your search</div>\n )}\n {filtered.map((m) => (\n <ModelRow key={m.id} model={m} selected={m.id === value} onSelect={() => select(m.id)} renderProviderBadge={renderProviderBadge} />\n ))}\n </>\n )}\n {!loading && !filtered && models.length === 0 && (\n <div className=\"px-3 py-4 text-center text-sm text-muted-foreground\">No models available</div>\n )}\n {!loading && !filtered && models.length > 0 && (\n <>\n {priorityGroup && sections.priority.length > 0 && (\n <>\n <SectionHeader>{priorityGroup.label}</SectionHeader>\n {sections.priority.map((m) => (\n <ModelRow key={m.id} model={m} selected={m.id === value} onSelect={() => select(m.id)} renderProviderBadge={renderProviderBadge} />\n ))}\n </>\n )}\n {sections.recommended.length > 0 && (\n <>\n <SectionHeader>{recommendedLabel}</SectionHeader>\n {sections.recommended.map((m) => (\n <ModelRow key={m.id} model={m} selected={m.id === value} onSelect={() => select(m.id)} renderProviderBadge={renderProviderBadge} />\n ))}\n </>\n )}\n {sections.byProvider.map((g) => (\n <div key={g.provider}>\n <SectionHeader>{g.provider}</SectionHeader>\n {g.items.map((m) => (\n <ModelRow key={m.id} model={m} selected={m.id === value} onSelect={() => select(m.id)} renderProviderBadge={renderProviderBadge} />\n ))}\n </div>\n ))}\n </>\n )}\n </div>\n </PopoverSurface>\n </div>\n )\n}\n\n// ── EffortPicker ──────────────────────────────────────────────────────────\n\n/** One reasoning-budget level: the engine `id` is unchanged (the value the\n * product sends to the loop); only the user-facing `label` is renamed to the\n * plainer \"how hard should it think\" vocabulary from docs/product-surfaces.md.\n * `low`→Quick, `medium`→Standard, `high`→Extended. The mapping is overridable\n * via `EffortPickerProps.levels`, so a product can relabel without losing the\n * ids the runtime expects. */\nexport interface EffortLevel {\n id: string\n label: string\n}\n\n/**\n * The engine ids this package NAMES, and the word each one reads as.\n *\n * Deliberately WIDER than {@link DEFAULT_EFFORT_LEVELS}: the default list is\n * what a picker OFFERS when a product declares nothing, while this is the\n * vocabulary — the labels a named id keeps wherever it appears. The two are\n * different questions, and folding them together is what made a real engine\n * rung read as its own id: `xhigh` and `ultracode` are rungs claude-code\n * applies above `high`, so a product declaring them got \"Xhigh\" while every\n * neighbouring rung had a plain English word. Naming them here is what stops\n * each product inventing its own — the drift `effortLevelsFromIds` exists to\n * prevent. They stay OUT of the offered default because most backends do not\n * apply them, and offering a rung the backend ignores is the defect\n * `effortLevels` was added to close.\n */\nconst KNOWN_EFFORT_LABELS = {\n off: 'Off',\n low: 'Quick',\n medium: 'Standard',\n high: 'Extended',\n xhigh: 'Extra',\n ultracode: 'Ultra',\n} as const\n\nexport const DEFAULT_EFFORT_LEVELS: readonly EffortLevel[] = [\n { id: 'off', label: KNOWN_EFFORT_LABELS.off },\n { id: 'low', label: KNOWN_EFFORT_LABELS.low },\n { id: 'medium', label: KNOWN_EFFORT_LABELS.medium },\n { id: 'high', label: KNOWN_EFFORT_LABELS.high },\n]\n\n/**\n * The user-facing label for an engine level id: the canonical vocabulary when\n * the id is one this package names, otherwise the id itself made readable\n * (`auto` -> \"Auto\", `ultra-code` -> \"Ultra code\"). Never invents a depth word,\n * so an id nobody declared a label for still reads as ITSELF and never as some\n * other level.\n */\nexport function effortLevelLabel(id: string): string {\n const known = (KNOWN_EFFORT_LABELS as Record<string, string | undefined>)[id]\n if (known) return known\n const words = id.replace(/[-_]+/g, ' ').trim()\n return words ? words.charAt(0).toUpperCase() + words.slice(1) : id\n}\n\n/**\n * Build a levels list from the engine ids a backend applies — the shape the\n * removed `ComposerAgentControls` took as `reasoning.available`, so a product\n * migrating that list has one call to make instead of a hand-written label map\n * per product (which is how \"Quick\" and \"Low\" drift apart across surfaces).\n */\nexport function effortLevelsFromIds(ids: readonly string[]): readonly EffortLevel[] {\n return ids.map((id) => ({ id, label: effortLevelLabel(id) }))\n}\n\n/**\n * The list {@link EffortPicker} RENDERS for `value` — the declared levels, plus\n * `value` itself when the declaration omits it.\n *\n * A picker cannot honestly resolve a selected value it was not given, and the\n * failure it used to take instead — fall back to the middle entry — renders the\n * session's real depth as a DIFFERENT level's name. That is exactly the defect\n * `levels` was added to prevent: the legacy adapter's `available` list excluded\n * the `auto` sentinel because the old picker injected it, so a product mapping\n * that list straight across ships a session running on `auto` labelled\n * \"Extended\". Admitting the value is not offering a new choice — it is\n * reporting the state the session is already in, and it disappears from the\n * list as soon as the user picks a declared level.\n *\n * A blank value is not admitted (there is no honest label for it); the picker\n * renders no selection instead.\n */\nexport function reconcileEffortLevels(\n value: string,\n levels: readonly EffortLevel[] = DEFAULT_EFFORT_LEVELS,\n): readonly EffortLevel[] {\n if (!value || levels.some((l) => l.id === value)) return levels\n return [{ id: value, label: effortLevelLabel(value) }, ...levels]\n}\n\n// ── effort strength meter ─────────────────────────────────────────────────\n\n/** Segments the meter draws — fixed geometry so the ladder stays tabular\n * across levels (and across the trigger and its menu rows). */\nexport const EFFORT_METER_SEGMENTS = 4\n\n/** Filled-segment opacity ladder: translucent on the left, heavy on the\n * right — the ramp carries strength even at a glance, the count carries it\n * exactly. Unfilled segments sit at a fixed ghost opacity. */\nconst EFFORT_METER_FILL_OPACITY = [0.25, 0.5, 0.75, 1] as const\nconst EFFORT_METER_GHOST_OPACITY = 0.15\n\n/** Level ids that mean \"no reasoning\" — the meter renders all-ghost. */\nconst OFF_LEVEL_IDS: ReadonlySet<string> = new Set(['off', 'none'])\n\n/**\n * Ids that name a POLICY rather than a depth: `auto` means \"let the harness and\n * model decide\", so it has no position on a strength ladder.\n *\n * Without this it lands wherever the declaration puts it and draws a filled\n * meter — measured on a product that offers `auto` first: every harness read\n * `Auto` at a FULL four bars, including `cli-base`, which has no agent to think\n * at all. A meter is a claim about how hard the run will think, and a sentinel\n * cannot make that claim.\n */\nconst UNPLACEABLE_LEVEL_IDS: ReadonlySet<string> = new Set(['auto'])\n\n/**\n * Filled-segment count for a level: 0 for off/none (or an id the levels list\n * does not carry); otherwise the level's position among the non-off choices\n * scaled onto the meter, so the ladder reads low < medium < high and the top\n * level fills the whole scale. The canonical four levels land 0 / 1 / 2 / 4.\n */\nexport function effortMeterFill(\n levelId: string,\n levels: readonly EffortLevel[] = DEFAULT_EFFORT_LEVELS,\n): number {\n if (OFF_LEVEL_IDS.has(levelId) || UNPLACEABLE_LEVEL_IDS.has(levelId)) return 0\n const active = levels.filter((l) => !OFF_LEVEL_IDS.has(l.id) && !UNPLACEABLE_LEVEL_IDS.has(l.id))\n const index = active.findIndex((l) => l.id === levelId)\n if (index < 0 || active.length === 0) return 0\n return Math.max(1, Math.floor(((index + 1) * EFFORT_METER_SEGMENTS) / active.length))\n}\n\n/**\n * The thinking-strength meter: four 12px bars, filled count = level, filled\n * opacity ramping 25→100% left to right (unfilled at a faint ghost). Purely\n * decorative — the level name is always rendered as text beside it, so the\n * meter is `aria-hidden` and adds no second accessible name.\n */\nexport function EffortMeter({ fill, className }: { fill: number; className?: string }) {\n return (\n <span aria-hidden className={`inline-flex items-center gap-[2px] ${className ?? ''}`}>\n {Array.from({ length: EFFORT_METER_SEGMENTS }, (_, i) => (\n <span\n key={i}\n className=\"h-3 w-[3px] rounded-full bg-current\"\n style={{ opacity: i < fill ? EFFORT_METER_FILL_OPACITY[i] : EFFORT_METER_GHOST_OPACITY }}\n />\n ))}\n </span>\n )\n}\n\nexport interface EffortPickerProps {\n value: string\n onChange: (id: string) => void\n /** Selectable levels (engine id + user-facing label). Defaults to the plain\n * \"Thinking\" vocabulary; override to relabel without changing the ids the\n * runtime receives.\n *\n * A list that omits the current `value` is not a rendering error the picker\n * papers over: `value` is reconciled INTO the rendered list under its own\n * name (see {@link reconcileEffortLevels}), because a control must report\n * the depth the session is running at and never some other list entry. */\n levels?: readonly EffortLevel[]\n /** Prefix shown before the active level on the pill — the \"what is this\"\n * context the bare value lacked. Default \"Thinking\". Pass '' to hide it. */\n label?: string\n /** Fill the container instead of shrink-wrapping — opt-in, default `false`;\n * see {@link pickerRootClass} for when and why. */\n fullWidth?: boolean\n /** Trigger treatment — see {@link PickerVariant}. Default `chip`. */\n variant?: PickerVariant\n}\n\n/** Thinking-budget selector pill, styled to match {@link ModelPicker}. Show\n * it only when the selected model `supportsReasoning`. \"Thinking\" is the\n * plain-English name for what was internally called \"effort\".\n *\n * The CANONICAL ecosystem effort picker — sandbox-ui's reasoning menu (inside\n * its `chat/AgentSessionControls`) is legacy and frozen. */\nexport function EffortPicker({ value, onChange, levels = DEFAULT_EFFORT_LEVELS, label = 'Thinking', fullWidth = false, variant = 'chip' }: EffortPickerProps) {\n const [open, setOpen] = useState(false)\n const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen)\n const panelId = useId()\n const rendered = reconcileEffortLevels(value, levels)\n // The strength ladder is computed over the DECLARED levels only, so admitting\n // the selected value cannot shift where the declared ones sit on the meter.\n // A level the declaration does not carry has no position on that ladder, so\n // it renders with NO meter — an all-ghost meter is what `off` looks like, and\n // \"we cannot place this\" is not \"no thinking\".\n const isDeclared = (id: string) => levels.some((l) => l.id === id) && !UNPLACEABLE_LEVEL_IDS.has(id)\n const selected = rendered.find((l) => l.id === value)\n\n return (\n <div ref={containerRef} className={pickerRootClass(fullWidth)}>\n <button\n type=\"button\"\n {...triggerProps}\n aria-controls={open ? panelId : undefined}\n onClick={() => setOpen(!open)}\n title={label ? `${label} — how hard the agent reasons before answering` : 'Reasoning effort'}\n data-state={open ? 'open' : 'closed'}\n className={`${\n variant === 'quiet'\n ? quietPickerTriggerClass()\n : 'inline-flex min-h-[36px] shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent'\n } ${fullWidth ? 'w-full' : ''}`}\n >\n <BrainGlyph className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n {/* Full width gives the label the slack, so the meter and chevron park\n on the trailing edge and the glyph stays against the text. */}\n <span className={fullWidth ? 'flex-1 truncate text-left' : undefined}>\n {label ? <span className=\"text-muted-foreground\">{label}: </span> : null}\n {selected ? selected.label : '—'}\n </span>\n {/* Quiet inherits the trigger's tone, so the meter is muted at rest\n and lifts with the label on hover. */}\n {selected && isDeclared(selected.id) && (\n <EffortMeter\n fill={effortMeterFill(selected.id, levels)}\n className={variant === 'quiet' ? 'shrink-0' : 'shrink-0 text-foreground'}\n />\n )}\n <ChevronDown className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n </button>\n <PopoverSurface\n open={open}\n id={panelId}\n role=\"menu\"\n triggerRef={triggerRef}\n panelRef={panelRef}\n // A portaled panel has no `w-full` to inherit, so a full-width trigger\n // hands its measured width to the panel instead.\n matchTriggerWidth={fullWidth}\n className={`w-44 overflow-y-auto rounded-xl border border-card-edge bg-popover p-1 ${OVERLAY_SHADOW}`}\n >\n {rendered.map((l) => (\n <button\n key={l.id}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={l.id === value}\n onClick={() => {\n onChange(l.id)\n setOpen(false)\n }}\n className={`flex min-h-[40px] w-full items-center gap-2 rounded-md px-3 py-2 text-left text-sm transition ${POPOVER_OPTION_FOCUS} ${\n l.id === value ? 'bg-primary/10 font-medium' : 'hover:bg-accent'\n }`}\n >\n <BrainGlyph className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"truncate\">{l.label}</span>\n {isDeclared(l.id) && (\n <EffortMeter fill={effortMeterFill(l.id, levels)} className=\"ml-auto text-foreground\" />\n )}\n {l.id === value && (\n <CheckGlyph className={`${isDeclared(l.id) ? '' : 'ml-auto '}h-3.5 w-3.5 shrink-0 text-primary`} />\n )}\n </button>\n ))}\n </PopoverSurface>\n </div>\n )\n}\n"],"mappings":"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","names":["jsx","jsxs"]}
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
OVERLAY_SHADOW,
|
|
3
3
|
PopoverSurface,
|
|
4
4
|
usePopover
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-4I76LTZS.js";
|
|
6
6
|
import {
|
|
7
7
|
UNTITLED_SESSION_LABEL,
|
|
8
8
|
mergeSessionPages,
|
|
@@ -812,4 +812,4 @@ export {
|
|
|
812
812
|
formatSessionTimestamp,
|
|
813
813
|
SessionHistoryPanel
|
|
814
814
|
};
|
|
815
|
-
//# sourceMappingURL=chunk-
|
|
815
|
+
//# sourceMappingURL=chunk-F32T3DRJ.js.map
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
pickerRootClass,
|
|
12
12
|
quietPickerTriggerClass,
|
|
13
13
|
usePopover
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-4I76LTZS.js";
|
|
15
15
|
import {
|
|
16
16
|
filterCommandPaletteItems
|
|
17
17
|
} from "./chunk-SJWIZT7B.js";
|
|
@@ -273,7 +273,7 @@ import {
|
|
|
273
273
|
} from "react";
|
|
274
274
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
275
275
|
function createLazyMentionEditor() {
|
|
276
|
-
return lazy(() => import("./mention-editor-
|
|
276
|
+
return lazy(() => import("./mention-editor-4PYZJM5A.js").then((m) => m.loadMentionEditor()));
|
|
277
277
|
}
|
|
278
278
|
var MentionEditorBoundary = class extends Component {
|
|
279
279
|
state = { failed: false };
|
|
@@ -1852,4 +1852,4 @@ export {
|
|
|
1852
1852
|
ComposerModeControls,
|
|
1853
1853
|
EntryComposer
|
|
1854
1854
|
};
|
|
1855
|
-
//# sourceMappingURL=chunk-
|
|
1855
|
+
//# sourceMappingURL=chunk-FMEL7VJR.js.map
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
PopoverSurface,
|
|
27
27
|
usePending,
|
|
28
28
|
usePopover
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-4I76LTZS.js";
|
|
30
30
|
import {
|
|
31
31
|
filterCommandPaletteItems,
|
|
32
32
|
groupCommandPaletteItems
|
|
@@ -5959,4 +5959,4 @@ export {
|
|
|
5959
5959
|
useThinkingSeconds,
|
|
5960
5960
|
ChatMessages
|
|
5961
5961
|
};
|
|
5962
|
-
//# sourceMappingURL=chunk-
|
|
5962
|
+
//# sourceMappingURL=chunk-TTYJIMTR.js.map
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "./chunk-L7MB2LLM.js";
|
|
11
11
|
import {
|
|
12
12
|
PopoverSurface
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-4I76LTZS.js";
|
|
14
14
|
import "./chunk-OU3VTK3I.js";
|
|
15
15
|
|
|
16
16
|
// src/web-react/mention-editor.tsx
|
|
@@ -523,4 +523,4 @@ export {
|
|
|
523
523
|
loadMentionEditor,
|
|
524
524
|
loadTiptapModules
|
|
525
525
|
};
|
|
526
|
-
//# sourceMappingURL=mention-editor-
|
|
526
|
+
//# sourceMappingURL=mention-editor-4PYZJM5A.js.map
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
} from "../chunk-TY2DALJG.js";
|
|
39
39
|
import {
|
|
40
40
|
useInfiniteScroll
|
|
41
|
-
} from "../chunk-
|
|
41
|
+
} from "../chunk-F32T3DRJ.js";
|
|
42
42
|
import {
|
|
43
43
|
CheckGlyph,
|
|
44
44
|
ChevronDown,
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
PopoverSurface,
|
|
49
49
|
ProviderLogo,
|
|
50
50
|
usePopover
|
|
51
|
-
} from "../chunk-
|
|
51
|
+
} from "../chunk-4I76LTZS.js";
|
|
52
52
|
import "../chunk-SJWIZT7B.js";
|
|
53
53
|
import "../chunk-OU3VTK3I.js";
|
|
54
54
|
|
package/dist/web-react/index.js
CHANGED
|
@@ -127,14 +127,14 @@ import {
|
|
|
127
127
|
withoutRecordGridCreated,
|
|
128
128
|
withoutRecordGridRemoved,
|
|
129
129
|
withoutRecordGridUpdate
|
|
130
|
-
} from "../chunk-
|
|
130
|
+
} from "../chunk-TTYJIMTR.js";
|
|
131
131
|
import {
|
|
132
132
|
SessionHistoryPanel,
|
|
133
133
|
formatSessionTimestamp,
|
|
134
134
|
useInfiniteScroll,
|
|
135
135
|
useSessionActions,
|
|
136
136
|
useSessionHistory
|
|
137
|
-
} from "../chunk-
|
|
137
|
+
} from "../chunk-F32T3DRJ.js";
|
|
138
138
|
import {
|
|
139
139
|
MENTION_PILL_CLASS
|
|
140
140
|
} from "../chunk-3HUFJ5LO.js";
|
|
@@ -170,7 +170,7 @@ import {
|
|
|
170
170
|
renamePastedImages,
|
|
171
171
|
useComposerAttachments,
|
|
172
172
|
useDictation
|
|
173
|
-
} from "../chunk-
|
|
173
|
+
} from "../chunk-FMEL7VJR.js";
|
|
174
174
|
import "../chunk-L7MB2LLM.js";
|
|
175
175
|
import {
|
|
176
176
|
DEFAULT_EFFORT_LEVELS,
|
|
@@ -188,7 +188,7 @@ import {
|
|
|
188
188
|
reconcileEffortLevels,
|
|
189
189
|
usePending,
|
|
190
190
|
usePopover
|
|
191
|
-
} from "../chunk-
|
|
191
|
+
} from "../chunk-4I76LTZS.js";
|
|
192
192
|
import "../chunk-SJWIZT7B.js";
|
|
193
193
|
import {
|
|
194
194
|
tabTerminalConnectionId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-app",
|
|
3
|
-
"version": "0.47.
|
|
3
|
+
"version": "0.47.12",
|
|
4
4
|
"packageManager": "pnpm@11.24.0",
|
|
5
5
|
"description": "Build agent applications with typed chat, tools, sandboxes, integrations, billing, and evaluation.",
|
|
6
6
|
"keywords": [
|
|
@@ -541,7 +541,7 @@
|
|
|
541
541
|
"@tangle-network/agent-interface": "2.6.0",
|
|
542
542
|
"@tangle-network/agent-knowledge": "15.0.2",
|
|
543
543
|
"@tangle-network/agent-profile-materialize": "0.19.0",
|
|
544
|
-
"@tangle-network/agent-runtime": "0.
|
|
544
|
+
"@tangle-network/agent-runtime": "0.207.0",
|
|
545
545
|
"@tangle-network/brand": "1.5.0",
|
|
546
546
|
"@tangle-network/sandbox": "0.38.2",
|
|
547
547
|
"@tangle-network/sandbox-ui": "0.113.3",
|
|
@@ -601,7 +601,7 @@
|
|
|
601
601
|
"@tangle-network/agent-interface": "^2.6.0",
|
|
602
602
|
"@tangle-network/agent-knowledge": "^15.0.2",
|
|
603
603
|
"@tangle-network/agent-profile-materialize": ">=0.19.0 <0.20.0",
|
|
604
|
-
"@tangle-network/agent-runtime": ">=0.
|
|
604
|
+
"@tangle-network/agent-runtime": ">=0.207.0 <0.208.0",
|
|
605
605
|
"@tangle-network/brand": ">=1.5.0",
|
|
606
606
|
"@tangle-network/sandbox": ">=0.38.2 <0.39.0",
|
|
607
607
|
"@tangle-network/sandbox-ui": ">=0.113.3 <0.114.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/web-react/provider-logo.tsx","../src/web-react/controls.tsx"],"sourcesContent":["/**\n * Provider brand marks — real logo path data (simple-icons / SVG Logos, both\n * CC0) inlined so the picker shows actual provider identity instead of\n * colored-initial monograms. Providers without a usable mark fall back to a\n * tinted monogram chip. Aliases (z-ai/zai, moonshot/moonshotai, deepseek_ai)\n * normalize to one entry.\n */\n\nimport type { ReactNode } from 'react'\n\ninterface LogoDef {\n viewBox: string\n fill: string\n paths: string[]\n}\n\nconst LOGOS: Record<string, LogoDef> = {\n anthropic: { viewBox: '0 0 24 24', fill: '#D97757', paths: [\"M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z\"] },\n google: { viewBox: '0 0 24 24', fill: '#8E75B2', paths: [\"M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81\"] },\n deepseek: { viewBox: '0 0 24 24', fill: '#4D6BFE', paths: [\"M23.748 4.651c-.254-.124-.364.113-.512.233-.051.04-.094.09-.137.137-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.155-.708-.311-.955-.65-.172-.24-.219-.509-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.094.172.187.129.323-.082.28-.18.553-.266.833-.055.179-.137.218-.328.14a5.5 5.5 0 0 1-1.737-1.179c-.857-.828-1.631-1.743-2.597-2.46a12 12 0 0 0-.689-.47c-.985-.957.13-1.743.387-1.836.27-.098.094-.433-.778-.428-.872.003-1.67.295-2.687.685a3 3 0 0 1-.465.136 9.6 9.6 0 0 0-2.883-.101c-1.885.21-3.39 1.1-4.497 2.622C.082 8.776-.231 10.854.152 13.02c.403 2.284 1.568 4.175 3.36 5.653 1.857 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.132-.284 4.994-1.86.47.234.962.328 1.78.398.629.058 1.235-.031 1.705-.129.735-.155.684-.836.418-.961-2.155-1.004-1.682-.595-2.112-.926 1.095-1.295 2.768-3.598 3.284-6.733.05-.346.115-.834.108-1.114-.004-.171.035-.238.23-.257a4.2 4.2 0 0 0 1.545-.475c1.397-.763 1.96-2.016 2.093-3.517.02-.23-.004-.467-.247-.588M11.58 18.168c-2.088-1.642-3.101-2.183-3.52-2.16-.39.024-.32.472-.234.763.09.288.207.487.371.74.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.168-1.361-.801-2.5-1.86-3.301-3.306-.775-1.393-1.225-2.888-1.299-4.482-.02-.385.094-.522.477-.592a4.7 4.7 0 0 1 1.53-.038c2.131.311 3.946 1.264 5.467 2.774.868.86 1.525 1.887 2.202 2.89.72 1.066 1.494 2.082 2.48 2.915.348.291.626.513.892.677-.802.09-2.14.109-3.055-.615zm1.001-6.44a.306.306 0 0 1 .415-.287.3.3 0 0 1 .113.074.3.3 0 0 1 .086.214c0 .17-.136.307-.308.307a.303.303 0 0 1-.306-.307m3.11 1.596c-.2.081-.4.151-.591.16a1.25 1.25 0 0 1-.798-.254c-.274-.23-.47-.358-.551-.758a1.7 1.7 0 0 1 .015-.588c.07-.327-.007-.537-.238-.727-.188-.156-.426-.199-.689-.199a.6.6 0 0 1-.254-.078.253.253 0 0 1-.114-.358 1 1 0 0 1 .192-.21c.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.392.451.462.576.685.915.176.264.336.536.446.848.066.194-.02.353-.25.45\"] },\n mistral: { viewBox: '0 0 24 24', fill: '#FA520F', paths: [\"M17.143 3.429v3.428h-3.429v3.429h-3.428V6.857H6.857V3.43H3.43v13.714H0v3.428h10.286v-3.428H6.857v-3.429h3.429v3.429h3.429v-3.429h3.428v3.429h-3.428v3.428H24v-3.428h-3.43V3.429z\"] },\n xai: { viewBox: '0 0 24 24', fill: '#000000', paths: [\"M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z\"] },\n nvidia: { viewBox: '0 0 24 24', fill: '#76B900', paths: [\"M8.948 8.798v-1.43a6.7 6.7 0 0 1 .424-.018c3.922-.124 6.493 3.374 6.493 3.374s-2.774 3.851-5.75 3.851c-.398 0-.787-.062-1.158-.185v-4.346c1.528.185 1.837.857 2.747 2.385l2.04-1.714s-1.492-1.952-4-1.952a6.016 6.016 0 0 0-.796.035m0-4.735v2.138l.424-.027c5.45-.185 9.01 4.47 9.01 4.47s-4.08 4.964-8.33 4.964c-.37 0-.733-.035-1.095-.097v1.325c.3.035.61.062.91.062 3.957 0 6.82-2.023 9.593-4.408.459.371 2.34 1.263 2.73 1.652-2.633 2.208-8.772 3.984-12.253 3.984-.335 0-.653-.018-.971-.053v1.864H24V4.063zm0 10.326v1.131c-3.657-.654-4.673-4.46-4.673-4.46s1.758-1.944 4.673-2.262v1.237H8.94c-1.528-.186-2.73 1.245-2.73 1.245s.68 2.412 2.739 3.11M2.456 10.9s2.164-3.197 6.5-3.533V6.201C4.153 6.59 0 10.653 0 10.653s2.35 6.802 8.948 7.42v-1.237c-4.84-.6-6.492-5.936-6.492-5.936z\"] },\n meta: { viewBox: '0 0 24 24', fill: '#0467DF', paths: [\"M6.915 4.03c-1.968 0-3.683 1.28-4.871 3.113C.704 9.208 0 11.883 0 14.449c0 .706.07 1.369.21 1.973a6.624 6.624 0 0 0 .265.86 5.297 5.297 0 0 0 .371.761c.696 1.159 1.818 1.927 3.593 1.927 1.497 0 2.633-.671 3.965-2.444.76-1.012 1.144-1.626 2.663-4.32l.756-1.339.186-.325c.061.1.121.196.183.3l2.152 3.595c.724 1.21 1.665 2.556 2.47 3.314 1.046.987 1.992 1.22 3.06 1.22 1.075 0 1.876-.355 2.455-.843a3.743 3.743 0 0 0 .81-.973c.542-.939.861-2.127.861-3.745 0-2.72-.681-5.357-2.084-7.45-1.282-1.912-2.957-2.93-4.716-2.93-1.047 0-2.088.467-3.053 1.308-.652.57-1.257 1.29-1.82 2.05-.69-.875-1.335-1.547-1.958-2.056-1.182-.966-2.315-1.303-3.454-1.303zm10.16 2.053c1.147 0 2.188.758 2.992 1.999 1.132 1.748 1.647 4.195 1.647 6.4 0 1.548-.368 2.9-1.839 2.9-.58 0-1.027-.23-1.664-1.004-.496-.601-1.343-1.878-2.832-4.358l-.617-1.028a44.908 44.908 0 0 0-1.255-1.98c.07-.109.141-.224.211-.327 1.12-1.667 2.118-2.602 3.358-2.602zm-10.201.553c1.265 0 2.058.791 2.675 1.446.307.327.737.871 1.234 1.579l-1.02 1.566c-.757 1.163-1.882 3.017-2.837 4.338-1.191 1.649-1.81 1.817-2.486 1.817-.524 0-1.038-.237-1.383-.794-.263-.426-.464-1.13-.464-2.046 0-2.221.63-4.535 1.66-6.088.454-.687.964-1.226 1.533-1.533a2.264 2.264 0 0 1 1.088-.285z\"] },\n moonshotai: { viewBox: '0 0 24 24', fill: '#16191E', paths: [\"m1.053 16.91 9.538 2.55a21 20.981 0 0 0 .06 2.031l5.956 1.592a12 11.99 0 0 1-15.554-6.172m-1.02-5.79 11.352 3.035a21 20.981 0 0 0-.469 2.01l10.817 2.89a12 11.99 0 0 1-1.845 2.004L.658 15.918a12 11.99 0 0 1-.625-4.796m1.593-5.146L13.573 9.17a21 20.981 0 0 0-1.01 1.874l11.297 3.02a21 20.981 0 0 1-.67 2.362l-11.55-3.087L.125 10.26a12 11.99 0 0 1 1.499-4.285ZM6.067 1.58l11.285 3.016a21 20.981 0 0 0-1.688 1.719l7.824 2.091a21 20.981 0 0 1 .513 2.664L2.107 5.218a12 11.99 0 0 1 3.96-3.638M21.68 4.866 7.222 1.003A12 11.99 0 0 1 21.68 4.866\"] },\n openai: { viewBox: '0 0 256 260', fill: '#10A37F', paths: [\"M239.184 106.203a64.72 64.72 0 0 0-5.576-53.103C219.452 28.459 191 15.784 163.213 21.74A65.586 65.586 0 0 0 52.096 45.22a64.72 64.72 0 0 0-43.23 31.36c-14.31 24.602-11.061 55.634 8.033 76.74a64.67 64.67 0 0 0 5.525 53.102c14.174 24.65 42.644 37.324 70.446 31.36a64.72 64.72 0 0 0 48.754 21.744c28.481.025 53.714-18.361 62.414-45.481a64.77 64.77 0 0 0 43.229-31.36c14.137-24.558 10.875-55.423-8.083-76.483m-97.56 136.338a48.4 48.4 0 0 1-31.105-11.255l1.535-.87l51.67-29.825a8.6 8.6 0 0 0 4.247-7.367v-72.85l21.845 12.636c.218.111.37.32.409.563v60.367c-.056 26.818-21.783 48.545-48.601 48.601M37.158 197.93a48.35 48.35 0 0 1-5.781-32.589l1.534.921l51.722 29.826a8.34 8.34 0 0 0 8.441 0l63.181-36.425v25.221a.87.87 0 0 1-.358.665l-52.335 30.184c-23.257 13.398-52.97 5.431-66.404-17.803M23.549 85.38a48.5 48.5 0 0 1 25.58-21.333v61.39a8.29 8.29 0 0 0 4.195 7.316l62.874 36.272l-21.845 12.636a.82.82 0 0 1-.767 0L41.353 151.53c-23.211-13.454-31.171-43.144-17.804-66.405zm179.466 41.695l-63.08-36.63L161.73 77.86a.82.82 0 0 1 .768 0l52.233 30.184a48.6 48.6 0 0 1-7.316 87.635v-61.391a8.54 8.54 0 0 0-4.4-7.213m21.742-32.69l-1.535-.922l-51.619-30.081a8.39 8.39 0 0 0-8.492 0L99.98 99.808V74.587a.72.72 0 0 1 .307-.665l52.233-30.133a48.652 48.652 0 0 1 72.236 50.391zM88.061 139.097l-21.845-12.585a.87.87 0 0 1-.41-.614V65.685a48.652 48.652 0 0 1 79.757-37.346l-1.535.87l-51.67 29.825a8.6 8.6 0 0 0-4.246 7.367zm11.868-25.58L128.067 97.3l28.188 16.218v32.434l-28.086 16.218l-28.188-16.218z\"] },\n}\n\nconst ALIASES: Record<string, string> = {\n moonshot: 'moonshotai',\n deepseek_ai: 'deepseek',\n 'x-ai': 'xai',\n 'meta-llama': 'meta',\n}\n\nconst MONOGRAM: Record<string, { bg: string; fg: string }> = {\n cohere: { bg: '#fae8ff', fg: '#c026d3' },\n groq: { bg: '#fce7f3', fg: '#db2777' },\n cerebras: { bg: '#ccfbf1', fg: '#0d9488' },\n zai: { bg: '#ede9fe', fg: '#7c3aed' },\n 'z-ai': { bg: '#ede9fe', fg: '#7c3aed' },\n tuner: { bg: '#dbeafe', fg: '#2563eb' },\n}\n\nexport interface ProviderLogoProps {\n provider?: string\n size?: number\n}\n\n/** Real brand mark when we have one; tinted monogram otherwise. */\nexport function ProviderLogo({ provider, size = 16 }: ProviderLogoProps): ReactNode {\n const key = ALIASES[provider ?? ''] ?? provider ?? ''\n const logo = LOGOS[key]\n if (logo) {\n return (\n <svg width={size} height={size} viewBox={logo.viewBox} role=\"img\" aria-label={key}>\n {logo.paths.map((d, i) => (\n <path key={i} d={d} fill={logo.fill} />\n ))}\n </svg>\n )\n }\n // Unknown providers fall back to a neutral monogram drawn from theme tokens\n // (secondary tile, muted glyph) — the previous hardcoded grays (#f3f4f6 /\n // #6b7280) were tuned for light mode and read as a washed-out hole on dark.\n // `style` rather than the `fill` attribute so the var() references resolve.\n const mono = MONOGRAM[key]\n return (\n <svg width={size} height={size} viewBox=\"0 0 16 16\" role=\"img\" aria-label={key || 'model'}>\n <rect width=\"16\" height=\"16\" rx=\"4\" style={{ fill: mono ? mono.bg : 'hsl(var(--secondary))' }} />\n <text x=\"8\" y=\"11.6\" textAnchor=\"middle\" style={{ fill: mono ? mono.fg : 'hsl(var(--muted-foreground))' }} fontSize=\"9\" fontWeight=\"700\" fontFamily=\"system-ui, sans-serif\">\n {(key || '?').charAt(0).toUpperCase()}\n </text>\n </svg>\n )\n}\n","/**\n * Shared chat-shell control primitives — the LEAF that both the web-react barrel\n * (`./index`) and the composer children (`./agent-session-controls`,\n * `./seat-paywall`) import directly, so neither child has to reach back through\n * the barrel (which would re-create an import cycle). The barrel re-exports the\n * public names (`usePopover`, `usePending`, `ModelPicker`, `EffortPicker`, …)\n * unchanged, so the published export surface is identical.\n *\n * Styling contract matches the rest of `web-react`: Tailwind classes against the\n * shared design tokens; the glyphs are inline SVGs, no icon-library dependency.\n */\n\nimport {\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type ReactNode,\n type RefObject,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { ProviderLogo } from './provider-logo'\nimport {\n MAX_RECOMMENDED_MODELS,\n sortModelsByFreshness,\n type CatalogModel,\n} from '../runtime/model-catalog'\n\n// ── shared glyphs (no icon-library dependency) ────────────────────────────\n\nexport function ChevronDown({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n )\n}\n\nfunction SearchGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </svg>\n )\n}\n\nfunction SparkleGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M12 3v3m0 12v3M3 12h3m12 0h3M5.6 5.6l2.1 2.1m8.6 8.6 2.1 2.1m0-12.8-2.1 2.1M7.7 16.3l-2.1 2.1\" />\n </svg>\n )\n}\n\n/** lucide `brain` (v1.27) inlined — `/web-react` ships no icon-library\n * dependency, so the thinking glyph follows the same pattern as the rest of\n * this set. */\nexport function BrainGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M12 18V5\" />\n <path d=\"M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4\" />\n <path d=\"M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5\" />\n <path d=\"M17.997 5.125a4 4 0 0 1 2.526 5.77\" />\n <path d=\"M18 18a4 4 0 0 0 2-7.464\" />\n <path d=\"M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517\" />\n <path d=\"M6 18a4 4 0 0 1-2-7.464\" />\n <path d=\"M6.003 5.125a4 4 0 0 0-2.526 5.77\" />\n </svg>\n )\n}\n\n/** lucide `check` — the selected-row mark in the picker menus. */\nexport function CheckGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n )\n}\n\n/**\n * Keyboard + pointer model for a trigger-and-popover pair, dependency-free.\n * Outside-mousedown and Escape both close; Escape also returns focus to the\n * trigger so keyboard users aren't dropped at the top of the document. The\n * returned `triggerProps` carry the ARIA contract (`aria-haspopup`/\n * `aria-expanded`); spread them onto the trigger button.\n *\n * `panelRef` belongs to the popover panel and MUST be wired when the panel is\n * rendered through {@link PopoverSurface}: a portaled panel is not inside\n * `containerRef`, so a container-only outside test reads every click on the\n * menu's own rows as an outside click and closes before the row's handler runs.\n */\nexport function usePopover(open: boolean, setOpen: (open: boolean) => void) {\n const containerRef = useRef<HTMLDivElement>(null)\n const triggerRef = useRef<HTMLButtonElement>(null)\n const panelRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (!open) return\n function onMouseDown(e: MouseEvent) {\n const target = e.target as Node\n if (containerRef.current?.contains(target)) return\n const panel = panelRef.current\n if (panel?.contains(target)) return\n // A popover opened FROM this one portals as a SIBLING at body level, so\n // `contains` cannot see it and a click on its rows would read as outside.\n // Surfaces stamp their ancestor chain, so descendancy survives the portal.\n const ownPath = panel?.getAttribute(POPOVER_SURFACE_ATTR)\n const hitPath =\n target instanceof Element\n ? target.closest(`[${POPOVER_SURFACE_ATTR}]`)?.getAttribute(POPOVER_SURFACE_ATTR)\n : null\n if (ownPath && hitPath && (hitPath === ownPath || hitPath.startsWith(`${ownPath}${POPOVER_PATH_SEPARATOR}`))) return\n setOpen(false)\n }\n function onKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') {\n setOpen(false)\n triggerRef.current?.focus()\n }\n }\n document.addEventListener('mousedown', onMouseDown)\n document.addEventListener('keydown', onKeyDown)\n return () => {\n document.removeEventListener('mousedown', onMouseDown)\n document.removeEventListener('keydown', onKeyDown)\n }\n }, [open, setOpen])\n\n return {\n containerRef,\n triggerRef,\n panelRef,\n triggerProps: {\n ref: triggerRef,\n 'aria-haspopup': true as const,\n 'aria-expanded': open,\n },\n }\n}\n\n// ── PopoverSurface ────────────────────────────────────────────────────────\n\n/** Distance between the trigger and the panel it opens. */\nconst POPOVER_GAP = 8\n/** Minimum distance the panel keeps from every viewport edge. */\nconst POPOVER_VIEWPORT_MARGIN = 16\n/** Floor for the computed max-height, so a cramped side still shows rows\n * rather than collapsing to a sliver the user cannot read. */\nconst POPOVER_MIN_HEIGHT = 120\n\n/**\n * Marks the portaled panel in the DOM. Products and audits (see\n * `playground/scripts/popover-hit-test.mjs`) select on this rather than on a\n * Tailwind class, which is presentation and free to change.\n *\n * Its VALUE is the surface's ancestor path (`outer/inner`), which is what\n * restores \"is this click inside my popover\" after the portal flattens two\n * nested panels into two siblings of `<body>`.\n */\nexport const POPOVER_SURFACE_ATTR = 'data-agent-app-popover'\nconst POPOVER_PATH_SEPARATOR = '/'\n\n/**\n * `PopoverSurface` is now mounted (closed) inside every server-rendered\n * composer, so its hooks run on the server once per composer per request.\n * React 18 logs \"useLayoutEffect does nothing on the server\" for that; React 19\n * does not (measured silent on react-dom 19.2.8). The peer floor is `react >=18`,\n * so bind the synchronous hook only where there is a DOM and the effect hook\n * elsewhere — placement never runs on the server either way.\n */\nconst useBrowserLayoutEffect = typeof document !== 'undefined' ? useLayoutEffect : useEffect\n\nexport interface PopoverSurfaceProps {\n open: boolean\n /** The trigger the panel anchors to — `usePopover`'s `triggerRef`. */\n triggerRef: RefObject<HTMLElement | null>\n /** `usePopover`'s `panelRef`; also what the outside-click test consults. */\n panelRef: RefObject<HTMLDivElement | null>\n /** Presentation classes. Placement and elevation are owned here — a caller\n * must not pass `absolute`/`fixed`/`top-*`/`bottom-*`/`z-*`. */\n className?: string\n role?: string\n id?: string\n /** Make the panel at least as wide as its trigger. A portaled panel has no\n * `w-full` to inherit — the trigger is no longer its offset parent — so a\n * menu that used to stretch to a full-width trigger declares it here. */\n matchTriggerWidth?: boolean\n children: ReactNode\n}\n\n/**\n * The floating panel every canonical picker opens.\n *\n * It renders through a PORTAL to `document.body` and anchors itself to the\n * trigger in viewport coordinates, because an in-place `absolute` panel's\n * visibility is decided by markup this package does not own. Measured in\n * production: the shipped chat composer docks these controls inside a\n * horizontally scrolling rail (`overflow-x-auto`), and a scroll container\n * clips every positioned descendant whose containing block sits inside it —\n * so a correct 420x457 menu with correct coordinates painted zero pixels and\n * could not be clicked. An ancestor `transform`/`filter`/`contain` would trap\n * it the same way through the stacking context instead of the clip. Leaving\n * the DOM subtree is the only placement a host cannot re-break.\n *\n * Placement prefers ABOVE the trigger (these controls dock at the bottom of a\n * composer), flips below when there is more room there, clamps horizontally\n * into the viewport, and caps its own height to the space on the chosen side.\n * The panel is `visibility: hidden` for the measure pass so it never paints at\n * the pre-placement origin.\n */\nexport function PopoverSurface({\n open,\n triggerRef,\n panelRef,\n className,\n role,\n id,\n matchTriggerWidth,\n children,\n}: PopoverSurfaceProps) {\n const surfaceId = useId()\n const [style, setStyle] = useState<CSSProperties>(() => ({\n position: 'fixed',\n top: 0,\n left: 0,\n visibility: 'hidden',\n }))\n\n const place = useCallback(() => {\n const trigger = triggerRef.current\n const panel = panelRef.current\n if (!trigger || !panel) return\n const anchor = trigger.getBoundingClientRect()\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n\n // `scrollHeight` is the panel's CONTENT height, so it does not feed back\n // on the `maxHeight` this function just applied — reading `offsetHeight`\n // here would measure the previous pass's clamp and ratchet the panel\n // smaller on every scroll event.\n const contentHeight = panel.scrollHeight\n const panelWidth = panel.offsetWidth\n\n const roomAbove = anchor.top - POPOVER_GAP - POPOVER_VIEWPORT_MARGIN\n const roomBelow = viewportHeight - anchor.bottom - POPOVER_GAP - POPOVER_VIEWPORT_MARGIN\n const above = contentHeight <= roomAbove || roomAbove >= roomBelow\n const maxHeight = Math.max(POPOVER_MIN_HEIGHT, above ? roomAbove : roomBelow)\n const height = Math.min(contentHeight, maxHeight)\n\n const top = above ? Math.max(POPOVER_VIEWPORT_MARGIN, anchor.top - POPOVER_GAP - height) : anchor.bottom + POPOVER_GAP\n const rightBound = Math.max(POPOVER_VIEWPORT_MARGIN, viewportWidth - panelWidth - POPOVER_VIEWPORT_MARGIN)\n const left = Math.min(Math.max(POPOVER_VIEWPORT_MARGIN, anchor.left), rightBound)\n\n setStyle({\n position: 'fixed',\n top,\n left,\n maxHeight,\n visibility: 'visible',\n ...(matchTriggerWidth ? { minWidth: anchor.width } : {}),\n })\n }, [matchTriggerWidth, panelRef, triggerRef])\n\n // Layout effect: placement is resolved before the browser paints, so the\n // panel is never seen at the origin it mounts at.\n useBrowserLayoutEffect(() => {\n if (!open) {\n setStyle({ position: 'fixed', top: 0, left: 0, visibility: 'hidden' })\n return\n }\n place()\n }, [open, place])\n\n useEffect(() => {\n if (!open) return\n const onViewportChange = () => place()\n // `capture` so the rail's OWN scroll re-anchors the panel — a scroll inside\n // an ancestor does not bubble to window.\n window.addEventListener('scroll', onViewportChange, true)\n window.addEventListener('resize', onViewportChange)\n return () => {\n window.removeEventListener('scroll', onViewportChange, true)\n window.removeEventListener('resize', onViewportChange)\n }\n }, [open, place])\n\n if (!open || typeof document === 'undefined') return null\n\n const ownerPath = triggerRef.current?.closest?.(`[${POPOVER_SURFACE_ATTR}]`)?.getAttribute(POPOVER_SURFACE_ATTR)\n const path = ownerPath ? `${ownerPath}${POPOVER_PATH_SEPARATOR}${surfaceId}` : surfaceId\n\n return createPortal(\n <div\n ref={panelRef}\n id={id}\n role={role}\n style={style}\n {...{ [POPOVER_SURFACE_ATTR]: path }}\n className={`z-[1000] ${className ?? ''}`}\n >\n {children}\n </div>,\n document.body,\n )\n}\n\n/**\n * Focus treatment for a row inside a popover panel.\n *\n * The ring itself now comes from the `:focus-visible` floor in tokens.css, so\n * this no longer restates a width or a colour. What it still has to say is\n * WHERE the ring is drawn: a popover option is a full-width row inside a panel\n * that clips its own corners (`overflow-hidden rounded-xl`), and an outward\n * ring on the first or last row is clipped away by that panel. Pulling the\n * offset negative draws the same ring just inside the row instead.\n */\nexport const POPOVER_OPTION_FOCUS = 'focus-visible:[outline-offset:-2px]'\n\n/**\n * The one overlay elevation for floating surfaces — picker menus, popovers,\n * drawers, modals. Reads the theme's `--shadow-overlay` token, so every overlay\n * lifts with the same shadow and re-themes from one source. The floating\n * composer uses the quieter `shadow-raised` rung instead.\n *\n * Written as an arbitrary value rather than the preset's `shadow-overlay`\n * utility, because that utility only exists where the preset is part of the\n * Tailwind build. A host that gets its tokens through a precompiled bundle —\n * `@tangle-network/sandbox-ui` ships brand's tokens inlined, with no `@theme`\n * block surviving the compile — receives `--shadow-overlay` as a plain custom\n * property, from which no `shadow-overlay` utility can be generated, and these\n * surfaces render flat. The arbitrary form emits from the class alone and works\n * either way.\n */\nexport const OVERLAY_SHADOW = 'shadow-[var(--shadow-overlay)]'\n\n/**\n * Root geometry for a picker — the box that holds the trigger — in one place\n * because every picker in this family has to agree on it.\n *\n * Shrink-wrapping (`inline-flex`) is the default: these controls dock on a\n * composer row where an expanding pill shoves its neighbours around. A STACKED\n * panel wants the opposite — the compact `AgentSessionControls` gear popover\n * lays its controls out in a column, and a shrink-wrapped root there makes a\n * trigger's own `w-full` a no-op, since it fills a box the trigger itself\n * sized. That is what left Agent backend short of the panel edge and Thinking\n * narrower still.\n *\n * The panel is portaled ({@link PopoverSurface}), so widening the root widens\n * the TRIGGER only. A menu that should follow it declares `matchTriggerWidth`.\n */\nexport function pickerRootClass(fullWidth: boolean): string {\n return `relative ${fullWidth ? 'flex w-full' : 'inline-flex'}`\n}\n\n/**\n * How a picker's TRIGGER is drawn. The menu it opens is the same either way.\n *\n * - `chip` (default): the 36px bordered pill — `rounded-full border\n * border-border bg-card font-medium`. A consumer that names no variant\n * renders exactly what it rendered before this prop existed.\n * - `quiet`: a 28px borderless text button — muted label, small glyph, a\n * surface fill on hover and while the menu is open, nothing else. For a\n * composer whose card already draws the border: three pills docked under\n * the input there read as three more cards, not as the input's controls.\n */\nexport type PickerVariant = 'chip' | 'quiet'\n\n/** The quiet trigger at rest: geometry, type, and keyboard focus. */\nconst QUIET_PICKER_TRIGGER_BASE =\n 'inline-flex h-7 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-md bg-transparent px-2 text-sm font-normal text-muted-foreground transition focus:outline-none focus-visible:ring-2 focus-visible:ring-ring'\n\n/** The fills a quiet trigger shows on hover and while its menu is open — the\n * only two states it draws. Reads `data-state`, which every picker trigger\n * in this family stamps. */\nconst QUIET_PICKER_TRIGGER_INTERACTIVE =\n 'hover:bg-accent hover:text-foreground data-[state=open]:bg-accent data-[state=open]:text-foreground'\n\n/**\n * Trigger classes for a `quiet` picker. Height, padding, radius, and type are\n * fixed here so the triggers on one composer row agree; a caller adds only\n * width (`w-full`) and alignment (`justify-between`).\n *\n * The focus ring is drawn on the element rather than left to the tokens.css\n * `:focus-visible` floor: a quiet trigger sits beside the composer's own action\n * buttons (attach, dictate, send), which draw `focus-visible:ring-2\n * focus-visible:ring-ring`, and a row whose controls answer keyboard focus two\n * different ways reads as two families.\n *\n * `interactive: false` is for a PINNED control (see `HarnessPicker`'s\n * `lockReason`): it keeps the resting treatment and draws no hover or open\n * fill, because a fill promises a menu the control will not open.\n */\nexport function quietPickerTriggerClass({ interactive = true }: { interactive?: boolean } = {}): string {\n return interactive\n ? `${QUIET_PICKER_TRIGGER_BASE} ${QUIET_PICKER_TRIGGER_INTERACTIVE}`\n : `${QUIET_PICKER_TRIGGER_BASE} cursor-default`\n}\n\n/**\n * Guard an async action against double-submit. `run` ignores re-entrant calls\n * while a promise is in flight and flips `pending` so the caller can disable\n * the control — the fix for double-charge / double-approve on a slow network.\n * Settles (success or throw) before clearing, and no-ops state updates after\n * unmount.\n */\nexport function usePending(): { pending: boolean; run: (action: () => void | Promise<void>) => void } {\n const [pending, setPending] = useState(false)\n const inFlight = useRef(false)\n const mounted = useRef(true)\n useEffect(() => {\n mounted.current = true\n return () => {\n mounted.current = false\n }\n }, [])\n const run = (action: () => void | Promise<void>) => {\n if (inFlight.current) return\n let result: void | Promise<void>\n try {\n result = action()\n } catch {\n return\n }\n if (!(result instanceof Promise)) return\n inFlight.current = true\n setPending(true)\n void result.finally(() => {\n inFlight.current = false\n if (mounted.current) setPending(false)\n })\n }\n return { pending, run }\n}\n\n// ── ModelPicker ───────────────────────────────────────────────────────────\n\nexport interface ModelPickerProps {\n value: string\n onChange: (id: string) => void\n /** Catalogue models — from `GET`ing the app's catalogue route (see\n * `runtime/model-catalog`), plus any product-specific entries appended. */\n models: CatalogModel[]\n loading?: boolean\n /** Render a provider logo/badge; default is a generic sparkle. */\n renderProviderBadge?: (provider: string) => ReactNode\n /** Section label for `featured` models. */\n recommendedLabel?: string\n /** Pin a labeled section to the TOP of the list (above Recommended) for the\n * models a product wants surfaced first — e.g. a tuner app's own fine-tuned\n * models (`{ label: 'Your Fine-Tuned Models', match: (m) => m.provider === 'tuner' }`).\n * Matching models are shown only in this section, not duplicated below. */\n priorityGroup?: {\n label: string\n match: (model: CatalogModel) => boolean\n }\n /** Trigger treatment — see {@link PickerVariant}. Default `chip`. */\n variant?: PickerVariant\n}\n\nfunction formatPrice(p?: string): string | undefined {\n if (!p) return undefined\n const n = Number(p)\n if (isNaN(n) || n === 0) return undefined\n const perM = n * 1_000_000\n return perM >= 1 ? `$${perM.toFixed(0)}/M` : `$${perM.toFixed(2)}/M`\n}\n\nfunction formatContext(len?: number): string | undefined {\n if (!len) return undefined\n if (len >= 1_000_000) return `${(len / 1_000_000).toFixed(1)}M ctx`\n if (len >= 1_000) return `${Math.round(len / 1_000)}K ctx`\n return `${len} ctx`\n}\n\nfunction SectionHeader({ children }: { children: ReactNode }) {\n return (\n <div className=\"px-3 pb-1 pt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground\">\n {children}\n </div>\n )\n}\n\nfunction ModelRow({\n model,\n selected,\n onSelect,\n renderProviderBadge,\n}: {\n model: CatalogModel\n selected: boolean\n onSelect: () => void\n renderProviderBadge?: (provider: string) => ReactNode\n}) {\n const price = formatPrice(model.pricing?.prompt)\n const ctx = formatContext(model.contextLength)\n return (\n <button\n type=\"button\"\n onClick={onSelect}\n className={`flex w-full items-center gap-2.5 rounded-md px-3 py-2.5 text-left text-sm transition ${POPOVER_OPTION_FOCUS} ${\n selected ? 'bg-primary/10 font-medium' : 'hover:bg-accent'\n }`}\n >\n {renderProviderBadge ? renderProviderBadge(model.provider) : <ProviderLogo provider={model.provider} size={16} />}\n <span className=\"truncate\">{model.name}</span>\n {!model.supportsTools && (\n <span className=\"shrink-0 rounded bg-secondary px-1.5 py-0.5 text-xs font-medium text-muted-foreground\">\n no tools\n </span>\n )}\n <span className=\"ml-auto flex shrink-0 items-center gap-2 text-xs text-muted-foreground\">\n {ctx && <span>{ctx}</span>}\n {price && <span>{price}</span>}\n </span>\n </button>\n )\n}\n\n/**\n * Searchable model picker pill + popover. A featured model is recommended\n * only when it is also that provider's newest entry. Older featured models\n * stay visible in their provider group instead of jumping above new releases.\n *\n * This is the CANONICAL ecosystem model picker (see \"UI chrome ownership\n * (picker canon)\" in AGENTS.md). sandbox-ui's `dashboard/ModelPicker` is\n * legacy — deprecated, frozen, removed at sandbox-ui's next major; new code\n * belongs here.\n */\nexport function ModelPicker({ value, onChange, models, loading, renderProviderBadge, recommendedLabel = 'Recommended', priorityGroup, variant = 'chip' }: ModelPickerProps) {\n const [open, setOpen] = useState(false)\n const [query, setQuery] = useState('')\n const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen)\n const inputRef = useRef<HTMLInputElement>(null)\n const panelId = useId()\n const sortedModels = useMemo(() => sortModelsByFreshness(models), [models])\n\n useEffect(() => {\n if (open) inputRef.current?.focus()\n }, [open])\n\n const selected = sortedModels.find((m) => m.id === value)\n\n const filtered = useMemo(() => {\n const q = query.trim().toLowerCase()\n if (!q) return null\n return sortedModels.filter(\n (m) =>\n m.id.toLowerCase().includes(q) ||\n m.name.toLowerCase().includes(q) ||\n (m.description?.toLowerCase() ?? '').includes(q) ||\n m.provider.toLowerCase().includes(q),\n )\n }, [sortedModels, query])\n\n const sections = useMemo(() => {\n const isPriority = priorityGroup ? (m: CatalogModel) => priorityGroup.match(m) : () => false\n const priority = priorityGroup ? sortedModels.filter(isPriority) : []\n const seenProviders = new Set<string>()\n const newestIds = new Set<string>()\n for (const model of sortedModels) {\n const provider = model.provider.toLowerCase()\n if (seenProviders.has(provider)) continue\n seenProviders.add(provider)\n newestIds.add(model.id)\n }\n const recommended = sortedModels\n .filter((model) => {\n if (!model.featured || isPriority(model)) return false\n return newestIds.has(model.id)\n })\n .slice(0, MAX_RECOMMENDED_MODELS)\n const recommendedIds = new Set(recommended.map((model) => model.id))\n const byProvider: Array<{ provider: string; items: CatalogModel[] }> = []\n for (const m of sortedModels) {\n if (recommendedIds.has(m.id) || isPriority(m)) continue\n const last = byProvider[byProvider.length - 1]\n if (last && last.provider === m.provider) last.items.push(m)\n else byProvider.push({ provider: m.provider, items: [m] })\n }\n return { priority, recommended, byProvider }\n }, [sortedModels, priorityGroup])\n\n const select = (id: string) => {\n onChange(id)\n setOpen(false)\n setQuery('')\n }\n\n return (\n <div ref={containerRef} className=\"relative inline-flex\">\n <button\n type=\"button\"\n {...triggerProps}\n aria-controls={open ? panelId : undefined}\n onClick={() => setOpen(!open)}\n data-state={open ? 'open' : 'closed'}\n className={\n variant === 'quiet'\n ? quietPickerTriggerClass()\n : 'inline-flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent'\n }\n >\n {selected ? (renderProviderBadge ? renderProviderBadge(selected.provider) : <ProviderLogo provider={selected.provider} size={16} />) : <SparkleGlyph className=\"h-3.5 w-3.5 text-muted-foreground\" />}\n <span className=\"max-w-[160px] truncate\">{selected?.name ?? value}</span>\n <ChevronDown className=\"h-3.5 w-3.5 text-muted-foreground\" />\n </button>\n\n <PopoverSurface\n open={open}\n id={panelId}\n triggerRef={triggerRef}\n panelRef={panelRef}\n className={`flex w-[420px] max-w-[calc(100vw-2rem)] flex-col overflow-hidden rounded-xl border border-card-edge bg-popover ${OVERLAY_SHADOW}`}\n >\n <div className=\"shrink-0 border-b border-border px-3 py-2\">\n <div className=\"flex items-center gap-2 rounded-lg border border-strong bg-background px-3 py-2\">\n <SearchGlyph className=\"h-3.5 w-3.5 text-muted-foreground\" />\n <input\n ref={inputRef}\n type=\"text\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search models...\"\n className=\"flex-1 bg-transparent text-sm placeholder:text-muted-foreground\"\n />\n </div>\n </div>\n {/* `min-h-0` is what lets the list absorb the surface's computed\n max-height on a short viewport instead of overflowing the panel. */}\n <div className=\"max-h-[400px] min-h-0 overflow-y-auto p-1 pb-2\">\n {loading && <div className=\"px-3 py-4 text-center text-sm text-muted-foreground\">Loading models...</div>}\n {!loading && filtered && (\n <>\n {filtered.length === 0 && (\n <div className=\"px-3 py-4 text-center text-sm text-muted-foreground\">No models match your search</div>\n )}\n {filtered.map((m) => (\n <ModelRow key={m.id} model={m} selected={m.id === value} onSelect={() => select(m.id)} renderProviderBadge={renderProviderBadge} />\n ))}\n </>\n )}\n {!loading && !filtered && models.length === 0 && (\n <div className=\"px-3 py-4 text-center text-sm text-muted-foreground\">No models available</div>\n )}\n {!loading && !filtered && models.length > 0 && (\n <>\n {priorityGroup && sections.priority.length > 0 && (\n <>\n <SectionHeader>{priorityGroup.label}</SectionHeader>\n {sections.priority.map((m) => (\n <ModelRow key={m.id} model={m} selected={m.id === value} onSelect={() => select(m.id)} renderProviderBadge={renderProviderBadge} />\n ))}\n </>\n )}\n {sections.recommended.length > 0 && (\n <>\n <SectionHeader>{recommendedLabel}</SectionHeader>\n {sections.recommended.map((m) => (\n <ModelRow key={m.id} model={m} selected={m.id === value} onSelect={() => select(m.id)} renderProviderBadge={renderProviderBadge} />\n ))}\n </>\n )}\n {sections.byProvider.map((g) => (\n <div key={g.provider}>\n <SectionHeader>{g.provider}</SectionHeader>\n {g.items.map((m) => (\n <ModelRow key={m.id} model={m} selected={m.id === value} onSelect={() => select(m.id)} renderProviderBadge={renderProviderBadge} />\n ))}\n </div>\n ))}\n </>\n )}\n </div>\n </PopoverSurface>\n </div>\n )\n}\n\n// ── EffortPicker ──────────────────────────────────────────────────────────\n\n/** One reasoning-budget level: the engine `id` is unchanged (the value the\n * product sends to the loop); only the user-facing `label` is renamed to the\n * plainer \"how hard should it think\" vocabulary from docs/product-surfaces.md.\n * `low`→Quick, `medium`→Standard, `high`→Extended. The mapping is overridable\n * via `EffortPickerProps.levels`, so a product can relabel without losing the\n * ids the runtime expects. */\nexport interface EffortLevel {\n id: string\n label: string\n}\n\n/**\n * The engine ids this package NAMES, and the word each one reads as.\n *\n * Deliberately WIDER than {@link DEFAULT_EFFORT_LEVELS}: the default list is\n * what a picker OFFERS when a product declares nothing, while this is the\n * vocabulary — the labels a named id keeps wherever it appears. The two are\n * different questions, and folding them together is what made a real engine\n * rung read as its own id: `xhigh` and `ultracode` are rungs claude-code\n * applies above `high`, so a product declaring them got \"Xhigh\" while every\n * neighbouring rung had a plain English word. Naming them here is what stops\n * each product inventing its own — the drift `effortLevelsFromIds` exists to\n * prevent. They stay OUT of the offered default because most backends do not\n * apply them, and offering a rung the backend ignores is the defect\n * `effortLevels` was added to close.\n */\nconst KNOWN_EFFORT_LABELS = {\n off: 'Off',\n low: 'Quick',\n medium: 'Standard',\n high: 'Extended',\n xhigh: 'Extra',\n ultracode: 'Ultra',\n} as const\n\nexport const DEFAULT_EFFORT_LEVELS: readonly EffortLevel[] = [\n { id: 'off', label: KNOWN_EFFORT_LABELS.off },\n { id: 'low', label: KNOWN_EFFORT_LABELS.low },\n { id: 'medium', label: KNOWN_EFFORT_LABELS.medium },\n { id: 'high', label: KNOWN_EFFORT_LABELS.high },\n]\n\n/**\n * The user-facing label for an engine level id: the canonical vocabulary when\n * the id is one this package names, otherwise the id itself made readable\n * (`auto` -> \"Auto\", `ultra-code` -> \"Ultra code\"). Never invents a depth word,\n * so an id nobody declared a label for still reads as ITSELF and never as some\n * other level.\n */\nexport function effortLevelLabel(id: string): string {\n const known = (KNOWN_EFFORT_LABELS as Record<string, string | undefined>)[id]\n if (known) return known\n const words = id.replace(/[-_]+/g, ' ').trim()\n return words ? words.charAt(0).toUpperCase() + words.slice(1) : id\n}\n\n/**\n * Build a levels list from the engine ids a backend applies — the shape the\n * removed `ComposerAgentControls` took as `reasoning.available`, so a product\n * migrating that list has one call to make instead of a hand-written label map\n * per product (which is how \"Quick\" and \"Low\" drift apart across surfaces).\n */\nexport function effortLevelsFromIds(ids: readonly string[]): readonly EffortLevel[] {\n return ids.map((id) => ({ id, label: effortLevelLabel(id) }))\n}\n\n/**\n * The list {@link EffortPicker} RENDERS for `value` — the declared levels, plus\n * `value` itself when the declaration omits it.\n *\n * A picker cannot honestly resolve a selected value it was not given, and the\n * failure it used to take instead — fall back to the middle entry — renders the\n * session's real depth as a DIFFERENT level's name. That is exactly the defect\n * `levels` was added to prevent: the legacy adapter's `available` list excluded\n * the `auto` sentinel because the old picker injected it, so a product mapping\n * that list straight across ships a session running on `auto` labelled\n * \"Extended\". Admitting the value is not offering a new choice — it is\n * reporting the state the session is already in, and it disappears from the\n * list as soon as the user picks a declared level.\n *\n * A blank value is not admitted (there is no honest label for it); the picker\n * renders no selection instead.\n */\nexport function reconcileEffortLevels(\n value: string,\n levels: readonly EffortLevel[] = DEFAULT_EFFORT_LEVELS,\n): readonly EffortLevel[] {\n if (!value || levels.some((l) => l.id === value)) return levels\n return [{ id: value, label: effortLevelLabel(value) }, ...levels]\n}\n\n// ── effort strength meter ─────────────────────────────────────────────────\n\n/** Segments the meter draws — fixed geometry so the ladder stays tabular\n * across levels (and across the trigger and its menu rows). */\nexport const EFFORT_METER_SEGMENTS = 4\n\n/** Filled-segment opacity ladder: translucent on the left, heavy on the\n * right — the ramp carries strength even at a glance, the count carries it\n * exactly. Unfilled segments sit at a fixed ghost opacity. */\nconst EFFORT_METER_FILL_OPACITY = [0.25, 0.5, 0.75, 1] as const\nconst EFFORT_METER_GHOST_OPACITY = 0.15\n\n/** Level ids that mean \"no reasoning\" — the meter renders all-ghost. */\nconst OFF_LEVEL_IDS: ReadonlySet<string> = new Set(['off', 'none'])\n\n/**\n * Ids that name a POLICY rather than a depth: `auto` means \"let the harness and\n * model decide\", so it has no position on a strength ladder.\n *\n * Without this it lands wherever the declaration puts it and draws a filled\n * meter — measured on a product that offers `auto` first: every harness read\n * `Auto` at a FULL four bars, including `cli-base`, which has no agent to think\n * at all. A meter is a claim about how hard the run will think, and a sentinel\n * cannot make that claim.\n */\nconst UNPLACEABLE_LEVEL_IDS: ReadonlySet<string> = new Set(['auto'])\n\n/**\n * Filled-segment count for a level: 0 for off/none (or an id the levels list\n * does not carry); otherwise the level's position among the non-off choices\n * scaled onto the meter, so the ladder reads low < medium < high and the top\n * level fills the whole scale. The canonical four levels land 0 / 1 / 2 / 4.\n */\nexport function effortMeterFill(\n levelId: string,\n levels: readonly EffortLevel[] = DEFAULT_EFFORT_LEVELS,\n): number {\n if (OFF_LEVEL_IDS.has(levelId) || UNPLACEABLE_LEVEL_IDS.has(levelId)) return 0\n const active = levels.filter((l) => !OFF_LEVEL_IDS.has(l.id) && !UNPLACEABLE_LEVEL_IDS.has(l.id))\n const index = active.findIndex((l) => l.id === levelId)\n if (index < 0 || active.length === 0) return 0\n return Math.max(1, Math.floor(((index + 1) * EFFORT_METER_SEGMENTS) / active.length))\n}\n\n/**\n * The thinking-strength meter: four 12px bars, filled count = level, filled\n * opacity ramping 25→100% left to right (unfilled at a faint ghost). Purely\n * decorative — the level name is always rendered as text beside it, so the\n * meter is `aria-hidden` and adds no second accessible name.\n */\nexport function EffortMeter({ fill, className }: { fill: number; className?: string }) {\n return (\n <span aria-hidden className={`inline-flex items-center gap-[2px] ${className ?? ''}`}>\n {Array.from({ length: EFFORT_METER_SEGMENTS }, (_, i) => (\n <span\n key={i}\n className=\"h-3 w-[3px] rounded-full bg-current\"\n style={{ opacity: i < fill ? EFFORT_METER_FILL_OPACITY[i] : EFFORT_METER_GHOST_OPACITY }}\n />\n ))}\n </span>\n )\n}\n\nexport interface EffortPickerProps {\n value: string\n onChange: (id: string) => void\n /** Selectable levels (engine id + user-facing label). Defaults to the plain\n * \"Thinking\" vocabulary; override to relabel without changing the ids the\n * runtime receives.\n *\n * A list that omits the current `value` is not a rendering error the picker\n * papers over: `value` is reconciled INTO the rendered list under its own\n * name (see {@link reconcileEffortLevels}), because a control must report\n * the depth the session is running at and never some other list entry. */\n levels?: readonly EffortLevel[]\n /** Prefix shown before the active level on the pill — the \"what is this\"\n * context the bare value lacked. Default \"Thinking\". Pass '' to hide it. */\n label?: string\n /** Fill the container instead of shrink-wrapping — opt-in, default `false`;\n * see {@link pickerRootClass} for when and why. */\n fullWidth?: boolean\n /** Trigger treatment — see {@link PickerVariant}. Default `chip`. */\n variant?: PickerVariant\n}\n\n/** Thinking-budget selector pill, styled to match {@link ModelPicker}. Show\n * it only when the selected model `supportsReasoning`. \"Thinking\" is the\n * plain-English name for what was internally called \"effort\".\n *\n * The CANONICAL ecosystem effort picker — sandbox-ui's reasoning menu (inside\n * its `chat/AgentSessionControls`) is legacy and frozen. */\nexport function EffortPicker({ value, onChange, levels = DEFAULT_EFFORT_LEVELS, label = 'Thinking', fullWidth = false, variant = 'chip' }: EffortPickerProps) {\n const [open, setOpen] = useState(false)\n const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen)\n const panelId = useId()\n const rendered = reconcileEffortLevels(value, levels)\n // The strength ladder is computed over the DECLARED levels only, so admitting\n // the selected value cannot shift where the declared ones sit on the meter.\n // A level the declaration does not carry has no position on that ladder, so\n // it renders with NO meter — an all-ghost meter is what `off` looks like, and\n // \"we cannot place this\" is not \"no thinking\".\n const isDeclared = (id: string) => levels.some((l) => l.id === id) && !UNPLACEABLE_LEVEL_IDS.has(id)\n const selected = rendered.find((l) => l.id === value)\n\n return (\n <div ref={containerRef} className={pickerRootClass(fullWidth)}>\n <button\n type=\"button\"\n {...triggerProps}\n aria-controls={open ? panelId : undefined}\n onClick={() => setOpen(!open)}\n title={label ? `${label} — how hard the agent reasons before answering` : 'Reasoning effort'}\n data-state={open ? 'open' : 'closed'}\n className={`${\n variant === 'quiet'\n ? quietPickerTriggerClass()\n : 'inline-flex min-h-[36px] shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent'\n } ${fullWidth ? 'w-full' : ''}`}\n >\n <BrainGlyph className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n {/* Full width gives the label the slack, so the meter and chevron park\n on the trailing edge and the glyph stays against the text. */}\n <span className={fullWidth ? 'flex-1 truncate text-left' : undefined}>\n {label ? <span className=\"text-muted-foreground\">{label}: </span> : null}\n {selected ? selected.label : '—'}\n </span>\n {/* Quiet inherits the trigger's tone, so the meter is muted at rest\n and lifts with the label on hover. */}\n {selected && isDeclared(selected.id) && (\n <EffortMeter\n fill={effortMeterFill(selected.id, levels)}\n className={variant === 'quiet' ? 'shrink-0' : 'shrink-0 text-foreground'}\n />\n )}\n <ChevronDown className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n </button>\n <PopoverSurface\n open={open}\n id={panelId}\n role=\"menu\"\n triggerRef={triggerRef}\n panelRef={panelRef}\n // A portaled panel has no `w-full` to inherit, so a full-width trigger\n // hands its measured width to the panel instead.\n matchTriggerWidth={fullWidth}\n className={`w-44 overflow-y-auto rounded-xl border border-card-edge bg-popover p-1 ${OVERLAY_SHADOW}`}\n >\n {rendered.map((l) => (\n <button\n key={l.id}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={l.id === value}\n onClick={() => {\n onChange(l.id)\n setOpen(false)\n }}\n className={`flex min-h-[40px] w-full items-center gap-2 rounded-md px-3 py-2 text-left text-sm transition ${POPOVER_OPTION_FOCUS} ${\n l.id === value ? 'bg-primary/10 font-medium' : 'hover:bg-accent'\n }`}\n >\n <BrainGlyph className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"truncate\">{l.label}</span>\n {isDeclared(l.id) && (\n <EffortMeter fill={effortMeterFill(l.id, levels)} className=\"ml-auto text-foreground\" />\n )}\n {l.id === value && (\n <CheckGlyph className={`${isDeclared(l.id) ? '' : 'ml-auto '}h-3.5 w-3.5 shrink-0 text-primary`} />\n )}\n </button>\n ))}\n </PopoverSurface>\n </div>\n )\n}\n"],"mappings":"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","names":["jsx","jsxs"]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|