@datalayer/agent-runtimes 1.3.29 → 1.3.32

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.
Files changed (107) hide show
  1. package/lib/AgentNode.js +14 -33
  2. package/lib/chat/ChatFloating.js +40 -8
  3. package/lib/chat/assistant/AssistantStage.d.ts +26 -7
  4. package/lib/chat/assistant/AssistantStage.js +115 -8
  5. package/lib/chat/assistant/SpeechBalloon.js +7 -3
  6. package/lib/chat/assistant/characters.d.ts +32 -1
  7. package/lib/chat/assistant/characters.js +180 -15
  8. package/lib/chat/assistant/state.d.ts +28 -0
  9. package/lib/chat/assistant/state.js +31 -0
  10. package/lib/chat/base/ChatBase.js +74 -50
  11. package/lib/chat/base/modelChoice.d.ts +40 -1
  12. package/lib/chat/base/modelChoice.js +42 -15
  13. package/lib/chat/prompt/InputPrompt.d.ts +7 -1
  14. package/lib/chat/prompt/InputPrompt.js +2 -2
  15. package/lib/chat/prompt/InputPromptBase.js +1 -1
  16. package/lib/chat/prompt/menus/ModelSelector.d.ts +13 -1
  17. package/lib/chat/prompt/menus/ModelSelector.js +17 -5
  18. package/lib/chat/useViewportDrag.d.ts +9 -1
  19. package/lib/chat/useViewportDrag.js +4 -4
  20. package/lib/components/a2ui/index.d.ts +2 -0
  21. package/lib/components/a2ui/index.js +2 -0
  22. package/lib/components/a2ui/visibility.d.ts +15 -0
  23. package/lib/components/a2ui/visibility.js +24 -0
  24. package/lib/components/a2ui/visibleWhen.d.ts +17 -0
  25. package/lib/components/a2ui/visibleWhen.js +54 -0
  26. package/lib/examples/ChatAssistantExample.d.ts +4 -0
  27. package/lib/examples/ChatAssistantExample.js +26 -5
  28. package/lib/examples/utils/owlCharacterPlugin.d.ts +7 -0
  29. package/lib/examples/utils/owlCharacterPlugin.js +44 -0
  30. package/lib/loop/apps/AppFeedback.d.ts +27 -0
  31. package/lib/loop/apps/AppFeedback.js +78 -0
  32. package/lib/loop/apps/AppRenderer.d.ts +33 -1
  33. package/lib/loop/apps/AppRenderer.js +111 -29
  34. package/lib/loop/apps/agent.d.ts +15 -0
  35. package/lib/loop/apps/agent.js +42 -0
  36. package/lib/loop/apps/appspec.js +6 -3
  37. package/lib/loop/apps/checks.d.ts +10 -2
  38. package/lib/loop/apps/checks.js +21 -10
  39. package/lib/loop/apps/feedback.d.ts +51 -0
  40. package/lib/loop/apps/feedback.js +61 -0
  41. package/lib/loop/apps/index.d.ts +3 -0
  42. package/lib/loop/apps/index.js +3 -0
  43. package/lib/loop/apps/rules.d.ts +14 -0
  44. package/lib/loop/apps/rules.js +24 -0
  45. package/lib/loop/core/canvasBlocks.d.ts +16 -0
  46. package/lib/loop/core/canvasBlocks.js +13 -0
  47. package/lib/loop/core/index.d.ts +15 -0
  48. package/lib/loop/core/index.js +3 -0
  49. package/lib/loop/embed/AppEmbed.d.ts +42 -0
  50. package/lib/loop/embed/AppEmbed.js +205 -0
  51. package/lib/loop/embed/datalayer-app.d.ts +1 -0
  52. package/lib/loop/embed/datalayer-app.js +16 -0
  53. package/lib/loop/embed/element.d.ts +57 -0
  54. package/lib/loop/embed/element.js +405 -0
  55. package/lib/loop/embed/embedConfig.d.ts +120 -0
  56. package/lib/loop/embed/embedConfig.js +148 -0
  57. package/lib/loop/embed/embedTheme.d.ts +24 -0
  58. package/lib/loop/embed/embedTheme.js +83 -0
  59. package/lib/loop/index.d.ts +6 -2
  60. package/lib/loop/index.js +8 -2
  61. package/lib/loop/plugins/a2ui/A2uiView.js +2 -3
  62. package/lib/loop/plugins/a2ui-surface/InlineSurface.d.ts +23 -3
  63. package/lib/loop/plugins/a2ui-surface/InlineSurface.js +36 -9
  64. package/lib/loop/plugins/agent-capacity/index.d.ts +4 -0
  65. package/lib/loop/plugins/agent-capacity/index.js +3 -1
  66. package/lib/loop/plugins/agents/switchable.d.ts +7 -0
  67. package/lib/loop/plugins/agents/switchable.js +91 -88
  68. package/lib/loop/plugins/app-page/AppPage.d.ts +16 -0
  69. package/lib/loop/plugins/app-page/AppPage.js +53 -0
  70. package/lib/loop/plugins/app-page/appPageModel.d.ts +180 -0
  71. package/lib/loop/plugins/app-page/appPageModel.js +443 -0
  72. package/lib/loop/plugins/app-page/index.d.ts +8 -0
  73. package/lib/loop/plugins/app-page/index.js +34 -0
  74. package/lib/loop/plugins/canvas-blocks/index.d.ts +63 -0
  75. package/lib/loop/plugins/canvas-blocks/index.js +118 -0
  76. package/lib/loop/plugins/chat/ChatView.js +52 -26
  77. package/lib/loop/plugins/chat/turnState.d.ts +5 -2
  78. package/lib/loop/plugins/chat/turnState.js +2 -1
  79. package/lib/loop/plugins/page-layout/SplitLayout.d.ts +31 -0
  80. package/lib/loop/plugins/page-layout/SplitLayout.js +129 -0
  81. package/lib/loop/plugins/page-layout/index.d.ts +13 -0
  82. package/lib/loop/plugins/page-layout/index.js +10 -1
  83. package/lib/loop/presets.d.ts +12 -0
  84. package/lib/loop/presets.js +5 -3
  85. package/lib/specs/actions.js +9 -0
  86. package/lib/specs/agents/agents.js +20 -4
  87. package/lib/specs/apps.d.ts +10 -1
  88. package/lib/specs/apps.js +1779 -154
  89. package/lib/specs/appspecSchema.js +14 -8
  90. package/lib/specs/models.d.ts +1 -1
  91. package/lib/specs/models.js +8 -8
  92. package/lib/specs/tools.d.ts +1 -0
  93. package/lib/specs/tools.js +19 -0
  94. package/lib/stories/loop/LoopReference.stories.d.ts +21 -0
  95. package/lib/stories/loop/LoopReference.stories.js +31 -0
  96. package/lib/stories/loop/ReferenceScreens.d.ts +53 -0
  97. package/lib/stories/loop/ReferenceScreens.js +256 -0
  98. package/lib/stories/loop/pictures-main.d.ts +1 -0
  99. package/lib/stories/loop/pictures-main.js +64 -0
  100. package/lib/types/agentspecs.d.ts +17 -1
  101. package/lib/types/chat.d.ts +5 -0
  102. package/lib/types/config.d.ts +20 -0
  103. package/package.json +10 -6
  104. package/scripts/check-cloudflare-models.py +2 -2
  105. package/scripts/codegen/generate_agents.py +50 -2
  106. package/scripts/codegen/generate_apps.py +38 -7
  107. package/scripts/codegen/generate_models.py +4 -4
@@ -1,33 +1,198 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- const INK = '#1D1D1F';
2
+ import { loopColors } from '@datalayer/primer-addons/lib/theme';
3
+ const INK = loopColors.ink;
4
+ const INK_DARK = loopColors.inkDark;
3
5
  /** Two eyes with lids that blink and pupils that look about. */
4
- function Eyes({ cx, cy, gap, r, }) {
6
+ function Eyes({ cx, cy, gap, r, colours, }) {
5
7
  const left = cx - gap / 2;
6
8
  const right = cx + gap / 2;
7
- return (_jsxs("g", { children: [_jsx("circle", { cx: left, cy: cy, r: r, fill: "#FFFFFF", stroke: INK, strokeWidth: 1.5 }), _jsx("circle", { cx: right, cy: cy, r: r, fill: "#FFFFFF", stroke: INK, strokeWidth: 1.5 }), _jsxs("g", { className: "assistant-pupils", children: [_jsx("circle", { cx: left + r * 0.15, cy: cy + r * 0.1, r: r * 0.45, fill: INK }), _jsx("circle", { cx: right + r * 0.15, cy: cy + r * 0.1, r: r * 0.45, fill: INK }), _jsx("circle", { cx: left + r * 0.3, cy: cy - r * 0.1, r: r * 0.14, fill: "#FFFFFF" }), _jsx("circle", { cx: right + r * 0.3, cy: cy - r * 0.1, r: r * 0.14, fill: "#FFFFFF" })] }), _jsxs("g", { className: "assistant-lids", children: [_jsx("ellipse", { cx: left, cy: cy, rx: r + 0.5, ry: r + 0.5, fill: "currentColor" }), _jsx("ellipse", { cx: right, cy: cy, rx: r + 0.5, ry: r + 0.5, fill: "currentColor" })] })] }));
9
+ return (_jsxs("g", { children: [_jsx("circle", { cx: left, cy: cy, r: r, fill: colours.white, stroke: colours.ring, strokeWidth: 1.5 }), _jsx("circle", { cx: right, cy: cy, r: r, fill: colours.white, stroke: colours.ring, strokeWidth: 1.5 }), _jsxs("g", { className: "assistant-pupils", children: [_jsx("circle", { cx: left + r * 0.15, cy: cy + r * 0.1, r: r * 0.45, fill: colours.pupil }), _jsx("circle", { cx: right + r * 0.15, cy: cy + r * 0.1, r: r * 0.45, fill: colours.pupil }), _jsx("circle", { cx: left + r * 0.3, cy: cy - r * 0.1, r: r * 0.14, fill: colours.white }), _jsx("circle", { cx: right + r * 0.3, cy: cy - r * 0.1, r: r * 0.14, fill: colours.white })] }), _jsxs("g", { className: "assistant-lids", children: [_jsx("ellipse", { cx: left, cy: cy, rx: r + 0.5, ry: r + 0.5, fill: colours.lid }), _jsx("ellipse", { cx: right, cy: cy, rx: r + 0.5, ry: r + 0.5, fill: colours.lid })] })] }));
8
10
  }
11
+ /**
12
+ * Each drawing's colours, light and dark. The dark ones are drawn for the
13
+ * `loop` theme's dark page (near-black, `loopColors.black`) and not the light
14
+ * drawing on black: lines that were ink turn to the dark mode's ink, the
15
+ * steel and the violets go lighter, outlines that a light page needs give
16
+ * way to the fill's own edge.
17
+ */
18
+ const PAPER_CLIP = {
19
+ light: {
20
+ wire: '#7A808A',
21
+ shine: '#E3E6EB',
22
+ line: INK,
23
+ eye: { white: loopColors.white, ring: INK, pupil: INK, lid: '#B8BDC6' },
24
+ },
25
+ dark: {
26
+ wire: '#C9CED6',
27
+ shine: '#8D93A0',
28
+ line: INK_DARK,
29
+ eye: {
30
+ white: INK_DARK,
31
+ ring: loopColors.grayDark,
32
+ pupil: INK,
33
+ lid: '#8D93A0',
34
+ },
35
+ },
36
+ };
37
+ const WIZARD = {
38
+ light: {
39
+ hat: '#6E5CD6',
40
+ brim: '#4A3C9E',
41
+ robe: '#5B4BB7',
42
+ face: '#F2D3B3',
43
+ faceEdge: '#A0694A',
44
+ beard: '#F4F4F6',
45
+ beardEdge: '#7A808A',
46
+ star: '#F8D469',
47
+ eye: { white: loopColors.white, ring: INK, pupil: INK, lid: '#F2D3B3' },
48
+ },
49
+ dark: {
50
+ hat: '#9C88F0',
51
+ brim: '#7B67DB',
52
+ robe: '#8F7CE8',
53
+ face: '#E8C4A0',
54
+ faceEdge: '#E8C4A0',
55
+ beard: '#E4E4EA',
56
+ beardEdge: loopColors.grayDark,
57
+ star: '#F8D469',
58
+ eye: { white: INK_DARK, ring: INK, pupil: INK, lid: '#E8C4A0' },
59
+ },
60
+ };
61
+ const CAT = {
62
+ light: {
63
+ fur: '#F4A261',
64
+ edge: '#B4571A',
65
+ tail: '#E08A45',
66
+ ear: '#F6A5C1',
67
+ nose: '#B83A6B',
68
+ whiskers: INK,
69
+ eye: { white: loopColors.white, ring: INK, pupil: INK, lid: '#F4A261' },
70
+ },
71
+ dark: {
72
+ fur: '#F4A261',
73
+ edge: '#F4A261',
74
+ tail: '#E08A45',
75
+ ear: '#F6A5C1',
76
+ nose: '#B83A6B',
77
+ whiskers: INK_DARK,
78
+ eye: { white: INK_DARK, ring: INK, pupil: INK, lid: '#F4A261' },
79
+ },
80
+ };
81
+ const LOOP_EYES = {
82
+ light: {
83
+ eye: { white: loopColors.white, ring: INK, pupil: INK, lid: '#E3E6EB' },
84
+ },
85
+ dark: {
86
+ eye: {
87
+ white: INK_DARK,
88
+ ring: INK_DARK,
89
+ pupil: loopColors.black,
90
+ lid: loopColors.grayDark,
91
+ },
92
+ },
93
+ };
9
94
  /** A paper clip of our own: a bent wire with eyes on its upper loop. */
10
- function PaperClip({ size }) {
11
- return (_jsx("svg", { width: size, height: size, viewBox: "0 0 96 96", role: "img", "aria-label": "Paper clip", style: { color: '#B8BDC6' }, children: _jsxs("g", { className: "assistant-body", children: [_jsx("path", { d: "M40 86 L40 30 Q40 14 52 14 Q64 14 64 30 L64 74 Q64 82 56 82 Q48 82 48 74 L48 36", fill: "none", stroke: "#9AA0AA", strokeWidth: 6, strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M40 86 L40 30 Q40 14 52 14 Q64 14 64 30 L64 74 Q64 82 56 82 Q48 82 48 74 L48 36", fill: "none", stroke: "#E3E6EB", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M36 22 Q42 18 47 21", stroke: INK, strokeWidth: 2, fill: "none", strokeLinecap: "round" }), _jsx("path", { d: "M57 21 Q62 18 68 22", stroke: INK, strokeWidth: 2, fill: "none", strokeLinecap: "round" }), _jsx(Eyes, { cx: 52, cy: 30, gap: 16, r: 6.5 }), _jsx("path", { className: "assistant-mouth", d: "M48 44 Q52 47 56 44", stroke: INK, strokeWidth: 2, fill: "none", strokeLinecap: "round" })] }) }));
95
+ function PaperClip({ size, mode = 'light', }) {
96
+ const c = PAPER_CLIP[mode];
97
+ const wire = 'M40 86 L40 30 Q40 14 52 14 Q64 14 64 30 L64 74 Q64 82 56 82 Q48 82 48 74 L48 36';
98
+ return (_jsx("svg", { width: size, height: size, viewBox: "0 0 96 96", role: "img", "aria-label": "Paper clip", "data-assistant-mode": mode, children: _jsxs("g", { className: "assistant-body", children: [_jsx("path", { d: wire, fill: "none", stroke: c.wire, strokeWidth: 6, strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: wire, fill: "none", stroke: c.shine, strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M36 22 Q42 18 47 21", stroke: c.line, strokeWidth: 2, fill: "none", strokeLinecap: "round" }), _jsx("path", { d: "M57 21 Q62 18 68 22", stroke: c.line, strokeWidth: 2, fill: "none", strokeLinecap: "round" }), _jsx(Eyes, { cx: 52, cy: 30, gap: 16, r: 6.5, colours: c.eye }), _jsx("path", { className: "assistant-mouth", d: "M48 44 Q52 47 56 44", stroke: c.line, strokeWidth: 2, fill: "none", strokeLinecap: "round" })] }) }));
12
99
  }
13
100
  /** A wizard: a starred hat, a white beard, kind eyes. */
14
- function Wizard({ size }) {
15
- return (_jsx("svg", { width: size, height: size, viewBox: "0 0 96 96", role: "img", "aria-label": "Wizard", style: { color: '#F2D3B3' }, children: _jsxs("g", { className: "assistant-body", children: [_jsx("path", { d: "M24 92 Q48 58 72 92 Z", fill: "#5B4BB7" }), _jsx("circle", { cx: 48, cy: 48, r: 17, fill: "#F2D3B3" }), _jsx("path", { d: "M31 50 Q48 92 65 50 Q57 60 48 60 Q39 60 31 50 Z", fill: "#F4F4F6", stroke: "#D9DAE0", strokeWidth: 1 }), _jsx("path", { d: "M22 36 L48 2 L74 36 Q48 30 22 36 Z", fill: "#6E5CD6" }), _jsx("path", { d: "M20 37 Q48 29 76 37 Q48 43 20 37 Z", fill: "#4A3C9E" }), _jsx("path", { d: "M52 14 l2 4 4 1 -3 3 1 4 -4 -2 -4 2 1 -4 -3 -3 4 -1 Z", fill: "#F8D469" }), _jsx("circle", { cx: 40, cy: 26, r: 1.8, fill: "#F8D469" }), _jsx(Eyes, { cx: 48, cy: 46, gap: 13, r: 5 }), _jsx("path", { className: "assistant-mouth", d: "M44 58 Q48 61 52 58", stroke: INK, strokeWidth: 2, fill: "none", strokeLinecap: "round" })] }) }));
101
+ function Wizard({ size, mode = 'light', }) {
102
+ const c = WIZARD[mode];
103
+ return (_jsx("svg", { width: size, height: size, viewBox: "0 0 96 96", role: "img", "aria-label": "Wizard", "data-assistant-mode": mode, children: _jsxs("g", { className: "assistant-body", children: [_jsx("path", { d: "M24 92 Q48 58 72 92 Z", fill: c.robe }), _jsx("circle", { cx: 48, cy: 48, r: 17, fill: c.face, stroke: c.faceEdge, strokeWidth: 1.5 }), _jsx("path", { d: "M31 50 Q48 92 65 50 Q57 60 48 60 Q39 60 31 50 Z", fill: c.beard, stroke: c.beardEdge, strokeWidth: 1.2 }), _jsx("path", { d: "M22 36 L48 2 L74 36 Q48 30 22 36 Z", fill: c.hat }), _jsx("path", { d: "M20 37 Q48 29 76 37 Q48 43 20 37 Z", fill: c.brim }), _jsx("path", { d: "M52 14 l2 4 4 1 -3 3 1 4 -4 -2 -4 2 1 -4 -3 -3 4 -1 Z", fill: c.star }), _jsx("circle", { cx: 40, cy: 26, r: 1.8, fill: c.star }), _jsx(Eyes, { cx: 48, cy: 46, gap: 13, r: 5, colours: c.eye }), _jsx("path", { className: "assistant-mouth", d: "M44 58 Q48 61 52 58", stroke: INK, strokeWidth: 2, fill: "none", strokeLinecap: "round" })] }) }));
16
104
  }
17
105
  /** A cat: round, two ears, whiskers, a tail. */
18
- function Cat({ size }) {
19
- return (_jsx("svg", { width: size, height: size, viewBox: "0 0 96 96", role: "img", "aria-label": "Cat", style: { color: '#F4A261' }, children: _jsxs("g", { className: "assistant-body", children: [_jsx("path", { d: "M70 84 Q90 78 84 58", stroke: "#E08A45", strokeWidth: 6, fill: "none", strokeLinecap: "round" }), _jsx("ellipse", { cx: 48, cy: 78, rx: 24, ry: 14, fill: "#F4A261" }), _jsx("path", { d: "M24 30 L28 8 L42 22 Z", fill: "#F4A261" }), _jsx("path", { d: "M72 30 L68 8 L54 22 Z", fill: "#F4A261" }), _jsx("path", { d: "M28 26 L30 14 L38 22 Z", fill: "#F6A5C1" }), _jsx("path", { d: "M68 26 L66 14 L58 22 Z", fill: "#F6A5C1" }), _jsx("circle", { cx: 48, cy: 42, r: 24, fill: "#F4A261" }), _jsx(Eyes, { cx: 48, cy: 38, gap: 18, r: 6.5 }), _jsx("path", { d: "M45 48 L51 48 L48 52 Z", fill: "#B83A6B" }), _jsx("path", { className: "assistant-mouth", d: "M43 55 Q48 58 53 55", stroke: INK, strokeWidth: 2, fill: "none", strokeLinecap: "round" }), _jsx("path", { d: "M30 48 L18 46 M30 52 L18 54 M66 48 L78 46 M66 52 L78 54", stroke: INK, strokeWidth: 1.2, strokeLinecap: "round" })] }) }));
106
+ function Cat({ size, mode = 'light', }) {
107
+ const c = CAT[mode];
108
+ const tail = 'M70 84 Q90 78 84 58';
109
+ return (_jsx("svg", { width: size, height: size, viewBox: "0 0 96 96", role: "img", "aria-label": "Cat", "data-assistant-mode": mode, children: _jsxs("g", { className: "assistant-body", children: [_jsx("path", { d: tail, stroke: c.edge, strokeWidth: 8, fill: "none", strokeLinecap: "round" }), _jsx("path", { d: tail, stroke: c.tail, strokeWidth: 5, fill: "none", strokeLinecap: "round" }), _jsx("ellipse", { cx: 48, cy: 78, rx: 24, ry: 14, fill: c.fur, stroke: c.edge, strokeWidth: 1.5 }), _jsx("path", { d: "M24 30 L28 8 L42 22 Z", fill: c.fur, stroke: c.edge, strokeWidth: 1.5, strokeLinejoin: "round" }), _jsx("path", { d: "M72 30 L68 8 L54 22 Z", fill: c.fur, stroke: c.edge, strokeWidth: 1.5, strokeLinejoin: "round" }), _jsx("path", { d: "M28 26 L30 14 L38 22 Z", fill: c.ear }), _jsx("path", { d: "M68 26 L66 14 L58 22 Z", fill: c.ear }), _jsx("circle", { cx: 48, cy: 42, r: 24, fill: c.fur, stroke: c.edge, strokeWidth: 1.5 }), _jsx(Eyes, { cx: 48, cy: 38, gap: 18, r: 6.5, colours: c.eye }), _jsx("path", { d: "M45 48 L51 48 L48 52 Z", fill: c.nose }), _jsx("path", { className: "assistant-mouth", d: "M43 55 Q48 58 53 55", stroke: INK, strokeWidth: 2, fill: "none", strokeLinecap: "round" }), _jsx("path", { d: "M30 48 L18 46 M30 52 L18 54 M66 48 L78 46 M66 52 L78 54", stroke: c.whiskers, strokeWidth: 1.2, strokeLinecap: "round" })] }) }));
20
110
  }
21
111
  /** The L👀P eyes: the product's own face, two eyes and nothing else. */
22
- function LoopEyes({ size }) {
23
- return (_jsx("svg", { width: size, height: size, viewBox: "0 0 96 96", role: "img", "aria-label": "L\uD83D\uDC40P eyes", style: { color: '#FFFFFF' }, children: _jsxs("g", { className: "assistant-body", children: [_jsx(Eyes, { cx: 48, cy: 50, gap: 40, r: 18 }), _jsx("path", { className: "assistant-mouth", d: "M42 80 Q48 84 54 80", stroke: INK, strokeWidth: 2.5, fill: "none", strokeLinecap: "round", opacity: 0 })] }) }));
112
+ function LoopEyes({ size, mode = 'light', }) {
113
+ const c = LOOP_EYES[mode];
114
+ return (_jsx("svg", { width: size, height: size, viewBox: "0 0 96 96", role: "img", "aria-label": "L\uD83D\uDC40P eyes", "data-assistant-mode": mode, children: _jsxs("g", { className: "assistant-body", children: [_jsx(Eyes, { cx: 48, cy: 50, gap: 40, r: 18, colours: c.eye }), _jsx("path", { className: "assistant-mouth", d: "M42 80 Q48 84 54 80", stroke: mode === 'dark' ? INK_DARK : INK, strokeWidth: 2.5, fill: "none", strokeLinecap: "round", opacity: 0 })] }) }));
24
115
  }
116
+ const eyeOf = (eye, on) => ({
117
+ white: eye.white,
118
+ ring: eye.ring,
119
+ pupil: eye.pupil,
120
+ on,
121
+ });
25
122
  /** The characters Datalayer ships, in the order a picker shows them. */
26
123
  export const ASSISTANT_CHARACTERS = [
27
- { id: 'paperclip', name: 'Paper clip', Drawing: PaperClip },
28
- { id: 'wizard', name: 'Wizard', Drawing: Wizard },
29
- { id: 'cat', name: 'Cat', Drawing: Cat },
30
- { id: 'eyes', name: 'L👀P eyes', Drawing: LoopEyes },
124
+ {
125
+ id: 'paperclip',
126
+ name: 'Paper clip',
127
+ Drawing: PaperClip,
128
+ keyColours: {
129
+ light: {
130
+ edges: [PAPER_CLIP.light.wire, PAPER_CLIP.light.line],
131
+ eye: eyeOf(PAPER_CLIP.light.eye, 'page'),
132
+ },
133
+ dark: {
134
+ edges: [PAPER_CLIP.dark.wire, PAPER_CLIP.dark.line],
135
+ eye: eyeOf(PAPER_CLIP.dark.eye, 'page'),
136
+ },
137
+ },
138
+ },
139
+ {
140
+ id: 'wizard',
141
+ name: 'Wizard',
142
+ Drawing: Wizard,
143
+ keyColours: {
144
+ light: {
145
+ edges: [
146
+ WIZARD.light.hat,
147
+ WIZARD.light.brim,
148
+ WIZARD.light.robe,
149
+ WIZARD.light.faceEdge,
150
+ WIZARD.light.beardEdge,
151
+ ],
152
+ eye: eyeOf(WIZARD.light.eye, WIZARD.light.face),
153
+ },
154
+ dark: {
155
+ edges: [
156
+ WIZARD.dark.hat,
157
+ WIZARD.dark.brim,
158
+ WIZARD.dark.robe,
159
+ WIZARD.dark.faceEdge,
160
+ WIZARD.dark.beardEdge,
161
+ ],
162
+ eye: eyeOf(WIZARD.dark.eye, WIZARD.dark.face),
163
+ },
164
+ },
165
+ },
166
+ {
167
+ id: 'cat',
168
+ name: 'Cat',
169
+ Drawing: Cat,
170
+ keyColours: {
171
+ light: {
172
+ edges: [CAT.light.edge, CAT.light.whiskers],
173
+ eye: eyeOf(CAT.light.eye, CAT.light.fur),
174
+ },
175
+ dark: {
176
+ edges: [CAT.dark.edge, CAT.dark.whiskers],
177
+ eye: eyeOf(CAT.dark.eye, CAT.dark.fur),
178
+ },
179
+ },
180
+ },
181
+ {
182
+ id: 'eyes',
183
+ name: 'L👀P eyes',
184
+ Drawing: LoopEyes,
185
+ keyColours: {
186
+ light: {
187
+ edges: [LOOP_EYES.light.eye.ring],
188
+ eye: eyeOf(LOOP_EYES.light.eye, 'page'),
189
+ },
190
+ dark: {
191
+ edges: [LOOP_EYES.dark.eye.white],
192
+ eye: eyeOf(LOOP_EYES.dark.eye, 'page'),
193
+ },
194
+ },
195
+ },
31
196
  ];
32
197
  /** The character an assistant shows when none is chosen. */
33
198
  export const DEFAULT_ASSISTANT_CHARACTER = 'paperclip';
@@ -60,3 +60,31 @@ export declare const ASSISTANT_AWAY_KEY = "datalayer-assistant-away";
60
60
  export declare function keptAway(): AssistantAway;
61
61
  /** Keep the choice where it lasts as long as it says; `none` forgets it. */
62
62
  export declare function keepAway(away: AssistantAway): void;
63
+ /** A box on the screen, as `getBoundingClientRect` gives it. */
64
+ export interface ScreenBox {
65
+ left: number;
66
+ top: number;
67
+ right: number;
68
+ bottom: number;
69
+ }
70
+ /**
71
+ * What the assistant never sits over (T-27): an open dialog or overlay —
72
+ * Primer's `Dialog`, an `ActionMenu` or `SelectPanel` overlay, a native
73
+ * `<dialog>` — and the composer of a chat.
74
+ */
75
+ export declare const ASSISTANT_OBSTACLES: string;
76
+ /** How near the pointer works, in pixels, before the assistant steps aside. */
77
+ export declare const POINTER_ROOM = 24;
78
+ /** How long the pointer stays away before the assistant comes back, in ms. */
79
+ export declare const POINTER_CALM_MS = 1500;
80
+ /** Whether two boxes share any area, the first grown by `margin`. */
81
+ export declare function boxesMeet(a: ScreenBox, b: ScreenBox, margin?: number): boolean;
82
+ /**
83
+ * Whether the pointer at `point` works where the assistant stands: over it,
84
+ * or within `POINTER_ROOM` of it — a press beside it is aimed at what it
85
+ * hides or crowds.
86
+ */
87
+ export declare function pointerNear(box: ScreenBox, point: {
88
+ x: number;
89
+ y: number;
90
+ }, room?: number): boolean;
@@ -114,3 +114,34 @@ export function keepAway(away) {
114
114
  // Without storage the choice holds for the page.
115
115
  }
116
116
  }
117
+ /**
118
+ * What the assistant never sits over (T-27): an open dialog or overlay —
119
+ * Primer's `Dialog`, an `ActionMenu` or `SelectPanel` overlay, a native
120
+ * `<dialog>` — and the composer of a chat.
121
+ */
122
+ export const ASSISTANT_OBSTACLES = [
123
+ '[role="dialog"]',
124
+ '[role="alertdialog"]',
125
+ 'dialog[open]',
126
+ '[class*="prc-Overlay-Overlay"]',
127
+ '[data-chat-composer]',
128
+ ].join(', ');
129
+ /** How near the pointer works, in pixels, before the assistant steps aside. */
130
+ export const POINTER_ROOM = 24;
131
+ /** How long the pointer stays away before the assistant comes back, in ms. */
132
+ export const POINTER_CALM_MS = 1500;
133
+ /** Whether two boxes share any area, the first grown by `margin`. */
134
+ export function boxesMeet(a, b, margin = 0) {
135
+ return (a.left - margin < b.right &&
136
+ b.left < a.right + margin &&
137
+ a.top - margin < b.bottom &&
138
+ b.top < a.bottom + margin);
139
+ }
140
+ /**
141
+ * Whether the pointer at `point` works where the assistant stands: over it,
142
+ * or within `POINTER_ROOM` of it — a press beside it is aimed at what it
143
+ * hides or crowds.
144
+ */
145
+ export function pointerNear(box, point, room = POINTER_ROOM) {
146
+ return boxesMeet(box, { left: point.x, top: point.y, right: point.x, bottom: point.y }, room);
147
+ }
@@ -48,7 +48,7 @@ import { InputPrompt } from '../prompt/InputPrompt';
48
48
  import { isFloatingChatViewMode } from '../viewModes';
49
49
  import { ToolApprovalBanner, ToolApprovalDialog, } from '../tools';
50
50
  import { EphemeralNotebook } from '../notebook/EphemeralNotebook';
51
- import { initialModelId, isOffered, usableModels } from './modelChoice';
51
+ import { initialModelId, isOffered, offeredModels as offeredModelsFor, } from './modelChoice';
52
52
  // EphemeralDocument statically imports `@datalayer/jupyter-lexical` (which
53
53
  // initialises Lumino-backed nodes on load). Lazy-load it so notebook-only chats
54
54
  // never pull lexical into the bundle or trigger its module side effects.
@@ -1380,37 +1380,46 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
1380
1380
  : undefined;
1381
1381
  const offeredModels = useMemo(() => {
1382
1382
  // Only what can actually be called — see `modelChoice` for the rule.
1383
- const fromConfig = availableModels || configQuery.data?.models;
1384
- if (fromConfig?.length) {
1385
- return usableModels(fromConfig);
1386
- }
1387
- /*
1388
- * The catalogue, filtered to what is worth offering.
1389
- *
1390
- * A server tells the chat which models it can reach and that answer wins.
1391
- * Without one — an in-page agent, or a server that has not answered yet —
1392
- * this used to offer the single model the protocol was built with, which
1393
- * is a menu with nothing to choose.
1394
- *
1395
- * `available` is the filter, not the whole catalogue: twenty-six models,
1396
- * most of them superseded, is a list nobody reads. The specs say which
1397
- * four are current.
1398
- */
1399
- const catalogued = Object.values(AI_MODEL_CATALOGUE)
1400
- // A typed-judgment model answers typed questions, not a chat.
1401
- .filter(model => model.available && isChatModel(model))
1402
- .map(model => ({
1403
- id: model.id,
1404
- name: model.name,
1405
- provider: model.provider,
1406
- }));
1407
- if (catalogued.length > 0) {
1408
- return usableModels(catalogued);
1409
- }
1410
- return browserModel
1411
- ? [{ id: browserModel, name: browserModel, provider: 'inference' }]
1412
- : [];
1413
- }, [availableModels, configQuery.data?.models, browserModel]);
1383
+ // The runtime's answer, when it gave one, is the whole list.
1384
+ // A runtime that was asked and did not answer offers nothing: the
1385
+ // agentspecs catalogue below is not its answer.
1386
+ const fromConfig = availableModels ||
1387
+ configQuery.data?.models ||
1388
+ (configQuery.isError ? [] : undefined);
1389
+ return offeredModelsFor(fromConfig, () => {
1390
+ /*
1391
+ * The catalogue, filtered to what is worth offering.
1392
+ *
1393
+ * A server tells the chat which models it can reach and that answer wins.
1394
+ * Without one — an in-page agent, or a server that has not answered yet —
1395
+ * this used to offer the single model the protocol was built with, which
1396
+ * is a menu with nothing to choose.
1397
+ *
1398
+ * `available` is the filter, not the whole catalogue: twenty-six models,
1399
+ * most of them superseded, is a list nobody reads. The specs say which
1400
+ * four are current.
1401
+ */
1402
+ const catalogued = Object.values(AI_MODEL_CATALOGUE)
1403
+ // A typed-decision model answers typed questions, not a chat.
1404
+ .filter(model => model.available && isChatModel(model))
1405
+ .map(model => ({
1406
+ id: model.id,
1407
+ name: model.name,
1408
+ provider: model.provider,
1409
+ }));
1410
+ if (catalogued.length > 0) {
1411
+ return catalogued;
1412
+ }
1413
+ return browserModel
1414
+ ? [{ id: browserModel, name: browserModel, provider: 'inference' }]
1415
+ : [];
1416
+ });
1417
+ }, [
1418
+ availableModels,
1419
+ configQuery.data?.models,
1420
+ configQuery.isError,
1421
+ browserModel,
1422
+ ]);
1414
1423
  /*
1415
1424
  * Who `@` may address.
1416
1425
  *
@@ -2115,9 +2124,13 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
2115
2124
  const store = useConversationStore.getState();
2116
2125
  const currentlyFetching = store.isFetching(historyScopeId);
2117
2126
  const storedMessages = store.getMessages(historyScopeId);
2118
- // 1) Fast local hydration for view switches in the same browser session.
2127
+ // 1) Fast local hydration for view switches in the same browser session:
2128
+ // only into an empty conversation. The saved copy holds messages, not
2129
+ // tool calls, and this effect runs again on every change of the socket's
2130
+ // state — put over a live conversation, it erased its tool cards, a
2131
+ // pending approval among them, at the socket's first retry.
2119
2132
  if (storedMessages.length > 0) {
2120
- setDisplayItems(storedMessages);
2133
+ setDisplayItems(prev => (prev.length > 0 ? prev : storedMessages));
2121
2134
  setHistoryLoaded(true);
2122
2135
  }
2123
2136
  if (currentlyFetching) {
@@ -2375,16 +2388,24 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
2375
2388
  const incomingId = event.message.id;
2376
2389
  const currentId = currentAssistantMessageRef.current?.id;
2377
2390
  const isNewMessage = !currentId || (incomingId && incomingId !== currentId);
2378
- if (currentAssistantMessageRef.current && !isNewMessage) {
2391
+ if (currentId && !isNewMessage) {
2392
+ /*
2393
+ * The message to write to is the one current now, as the event
2394
+ * arrives — not whichever the ref names when React gets round
2395
+ * to running the updater. A whole answer in one network chunk
2396
+ * queues every delta's updater in the same task, and the turn's
2397
+ * end clears the ref before any of them runs: read lazily, all
2398
+ * but the first found nothing to update, and the conversation
2399
+ * and the balloon showed only the answer's first word.
2400
+ */
2401
+ const rawContent = event.message.content;
2402
+ const sanitizedContent = typeof rawContent === 'string'
2403
+ ? sanitizeAssistantContent(rawContent)
2404
+ : (rawContent ?? '');
2379
2405
  setDisplayItems(prev => {
2380
2406
  const newItems = [...prev];
2381
- const idx = newItems.findIndex(item => !isToolCallMessage(item) &&
2382
- item.id === currentAssistantMessageRef.current?.id);
2407
+ const idx = newItems.findIndex(item => !isToolCallMessage(item) && item.id === currentId);
2383
2408
  if (idx >= 0 && !isToolCallMessage(newItems[idx])) {
2384
- const rawContent = event.message?.content;
2385
- const sanitizedContent = typeof rawContent === 'string'
2386
- ? sanitizeAssistantContent(rawContent)
2387
- : (rawContent ?? '');
2388
2409
  newItems[idx] = {
2389
2410
  ...newItems[idx],
2390
2411
  content: sanitizedContent,
@@ -2392,14 +2413,8 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
2392
2413
  }
2393
2414
  return newItems;
2394
2415
  });
2395
- if (useStoreMode && currentAssistantMessageRef.current) {
2396
- const rawContent = event.message?.content;
2397
- const sanitizedContent = typeof rawContent === 'string'
2398
- ? sanitizeAssistantContent(rawContent)
2399
- : (rawContent ?? '');
2400
- useChatStore
2401
- .getState()
2402
- .updateMessage(currentAssistantMessageRef.current.id, {
2416
+ if (useStoreMode) {
2417
+ useChatStore.getState().updateMessage(currentId, {
2403
2418
  content: sanitizedContent,
2404
2419
  });
2405
2420
  }
@@ -3087,6 +3102,7 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
3087
3102
  // The same reset the header's + performs, for a host whose controls
3088
3103
  // live outside this component — the LOOP prompt's + reaches it here.
3089
3104
  newChat: handleNewChat,
3105
+ thread: () => threadIdRef.current,
3090
3106
  });
3091
3107
  return () => {
3092
3108
  onSendReady(null);
@@ -3481,7 +3497,15 @@ showToolApprovalBanner = true, pendingApprovals: pendingApprovalsProp, onApprove
3481
3497
  promptHistory: configQuery.data?.promptHistory, showTokenUsage: showTokenUsage, showContextRing: showContextRing, agentUsage: agentUsage, showModelSelector: showModelSelector, showToolsMenu: showToolsMenu, showSkillsMenu: showSkillsMenu, codemodeEnabled: codemodeEnabled, onToggleCodemode: onToggleCodemode, isA2AProtocol: isA2AProtocol, showAgentsMenu: showAgentsMenu, agents: footerAgents, selectedAgentId: selectedAgentId ?? footerAgents[0]?.id, onSelectAgent: onSelectAgent, hasConfigData: !!configQuery.data, hasSkillsData: !!skillsQuery.data,
3482
3498
  // So the bar can tell "not here yet" from "not coming": a chat whose
3483
3499
  // agent has no config endpoint waits for ever otherwise.
3484
- configLoading: configQuery.isLoading, models: offeredModels, selectedModel: selectedModel, onModelSelect: setSelectedModel, availableTools: builtinTools, mcpServers: filteredMcpServers, enabledMcpTools: enabledMcpTools, enabledMcpToolCount: getEnabledMcpToolNames().length, onToggleMcpTool: toggleMcpTool, onToggleAllMcpServerTools: toggleAllMcpServerTools, approvedMcpTools: approvedMcpTools, onToggleMcpToolApproval: toggleMcpToolApproval, skills: skillsQuery.data?.skills || [], skillsLoading: !!skillsQuery.isLoading, enabledSkills: enabledSkills, onToggleSkill: toggleSkill, onToggleAllSkills: toggleAllSkills, approvedSkills: approvedSkills, onToggleSkillApproval: toggleSkillApproval, apiBase: indicatorApiBase, authToken: protocol?.authToken, mcpStatusData: effectiveMcpStatusData })) : null;
3500
+ configLoading: configQuery.isLoading, models: offeredModels,
3501
+ // Listed apart and read-only: a typed-decision model is never the
3502
+ // agent's model.
3503
+ decisions: configQuery.data
3504
+ ? {
3505
+ models: configQuery.data.decisionModels,
3506
+ note: configQuery.data.decisionsNote,
3507
+ }
3508
+ : undefined, selectedModel: selectedModel, onModelSelect: setSelectedModel, availableTools: builtinTools, mcpServers: filteredMcpServers, enabledMcpTools: enabledMcpTools, enabledMcpToolCount: getEnabledMcpToolNames().length, onToggleMcpTool: toggleMcpTool, onToggleAllMcpServerTools: toggleAllMcpServerTools, approvedMcpTools: approvedMcpTools, onToggleMcpToolApproval: toggleMcpToolApproval, skills: skillsQuery.data?.skills || [], skillsLoading: !!skillsQuery.isLoading, enabledSkills: enabledSkills, onToggleSkill: toggleSkill, onToggleAllSkills: toggleAllSkills, approvedSkills: approvedSkills, onToggleSkillApproval: toggleSkillApproval, apiBase: indicatorApiBase, authToken: protocol?.authToken, mcpStatusData: effectiveMcpStatusData })) : null;
3485
3509
  // Shared header element. It is rendered either at the top of the chat (when
3486
3510
  // no ephemeral notebook is shown) or INSIDE the chat body column (when the
3487
3511
  // notebook is visible) so the header always follows the chat body across all
@@ -26,6 +26,17 @@ export declare const isUsable: (model: ModelConfig) => boolean;
26
26
  * while the rows and their reasons say which key is missing.
27
27
  */
28
28
  export declare function usableModels(models: ModelConfig[]): ModelConfig[];
29
+ /**
30
+ * The models a chat offers, given what its runtime answered.
31
+ *
32
+ * The runtime's answer is the list: an agent's own models (its `model` and
33
+ * `model_additionals`), each flagged with whether its inference serves it.
34
+ * When the runtime answered, nothing else is added — not even when its list
35
+ * is empty, which says the agent has nothing to switch to. `fallback` is
36
+ * asked only when there is no runtime to answer (an in-page agent) or it
37
+ * has not answered yet.
38
+ */
39
+ export declare function offeredModels(fromRuntime: ModelConfig[] | undefined, fallback: () => ModelConfig[]): ModelConfig[];
29
40
  /** Whether `id` is on offer and usable — the selection may stand. */
30
41
  export declare const isOffered: (offered: ModelConfig[], id?: string) => boolean;
31
42
  /**
@@ -46,9 +57,28 @@ export type ServerCatalogueModel = {
46
57
  name?: string;
47
58
  available?: boolean;
48
59
  missing_env_vars?: string[];
49
- reason?: string;
60
+ reason?: string | null;
50
61
  warning?: string | null;
51
62
  };
63
+ /**
64
+ * The typed-decision models a runtime lists apart (Jev).
65
+ *
66
+ * They answer a decision's typed questions, not a conversation: the menu
67
+ * shows them read-only, under their own heading, with `note` saying so, and
68
+ * never offers one as the agent's model.
69
+ */
70
+ export type Decisions = {
71
+ models: ModelConfig[];
72
+ note: string;
73
+ };
74
+ /** The runtime's `/configure/models` answer, as far as the chat reads it. */
75
+ export type ServerCatalogue = {
76
+ models?: ServerCatalogueModel[];
77
+ source?: string;
78
+ note?: string;
79
+ decision_models: ServerCatalogueModel[];
80
+ decisions_note: string;
81
+ };
52
82
  /**
53
83
  * The server's catalogue in the chat's shape.
54
84
  *
@@ -59,4 +89,13 @@ export type ServerCatalogueModel = {
59
89
  */
60
90
  export declare function readServerCatalogue(payload: {
61
91
  models?: ServerCatalogueModel[];
92
+ source?: string;
93
+ note?: string;
62
94
  } | null | undefined): ModelConfig[];
95
+ /**
96
+ * The typed-decision models of the runtime's answer, in the chat's shape.
97
+ *
98
+ * Read apart from `readServerCatalogue`, so no list a chat picks its model
99
+ * from ever holds one.
100
+ */
101
+ export declare function readServerDecisions(payload: ServerCatalogue): Decisions;
@@ -14,6 +14,19 @@ export function usableModels(models) {
14
14
  const usable = models.filter(isUsable);
15
15
  return usable.length > 0 ? usable : models;
16
16
  }
17
+ /**
18
+ * The models a chat offers, given what its runtime answered.
19
+ *
20
+ * The runtime's answer is the list: an agent's own models (its `model` and
21
+ * `model_additionals`), each flagged with whether its inference serves it.
22
+ * When the runtime answered, nothing else is added — not even when its list
23
+ * is empty, which says the agent has nothing to switch to. `fallback` is
24
+ * asked only when there is no runtime to answer (an in-page agent) or it
25
+ * has not answered yet.
26
+ */
27
+ export function offeredModels(fromRuntime, fallback) {
28
+ return usableModels(fromRuntime ?? fallback());
29
+ }
17
30
  /** Whether `id` is on offer and usable — the selection may stand. */
18
31
  export const isOffered = (offered, id) => Boolean(id) && offered.some(m => m.id === id && isUsable(m));
19
32
  /**
@@ -38,19 +51,33 @@ export function initialModelId(offered, preferred) {
38
51
  * its spec was known went to the first row — Alibaba, and its missing key.
39
52
  */
40
53
  export function readServerCatalogue(payload) {
41
- return (payload?.models ?? []).map(model => {
42
- const missing = model.missing_env_vars ?? [];
43
- const reason = model.reason ??
44
- (missing.length > 0 ? `Set ${missing.join(', ')}` : undefined) ??
45
- model.warning ??
46
- undefined;
47
- return {
48
- id: model.id,
49
- name: model.name ?? model.id,
50
- isAvailable: model.available !== false,
51
- ...(reason && model.available === false
52
- ? { unavailableReason: reason }
53
- : {}),
54
- };
55
- });
54
+ return (payload?.models ?? []).map(readServerModel);
55
+ }
56
+ /**
57
+ * The typed-decision models of the runtime's answer, in the chat's shape.
58
+ *
59
+ * Read apart from `readServerCatalogue`, so no list a chat picks its model
60
+ * from ever holds one.
61
+ */
62
+ export function readServerDecisions(payload) {
63
+ return {
64
+ models: payload.decision_models.map(readServerModel),
65
+ note: payload.decisions_note,
66
+ };
67
+ }
68
+ /** One row of the runtime's answer, in the chat's shape. */
69
+ function readServerModel(model) {
70
+ const missing = model.missing_env_vars ?? [];
71
+ const reason = model.reason ??
72
+ (missing.length > 0 ? `Set ${missing.join(', ')}` : undefined) ??
73
+ model.warning ??
74
+ undefined;
75
+ return {
76
+ id: model.id,
77
+ name: model.name ?? model.id,
78
+ isAvailable: model.available !== false,
79
+ ...(reason && model.available === false
80
+ ? { unavailableReason: reason }
81
+ : {}),
82
+ };
56
83
  }
@@ -16,6 +16,7 @@ import type { PromptSuggestion } from './menus/SuggestionsMenu';
16
16
  import type { MentionableAgent } from './plugins/AgentMentionPlugin';
17
17
  /** One agent the footer may offer. */
18
18
  import type { FooterAgent } from '../../types/chat';
19
+ import type { Decisions } from '../base/modelChoice';
19
20
  export type { FooterAgent };
20
21
  /** Where the prompt stands: in the flow, or in a draggable card over it. */
21
22
  export type InputPromptPlacement = 'docked' | 'floating';
@@ -187,6 +188,11 @@ export interface InputPromptProps {
187
188
  */
188
189
  configLoading?: boolean;
189
190
  models?: ModelConfig[];
191
+ /**
192
+ * The typed-decision models the runtime lists apart (Jev): shown read-only
193
+ * under the models, never one to pick. See `modelChoice`'s `Decisions`.
194
+ */
195
+ decisions?: Decisions;
190
196
  selectedModel?: string;
191
197
  onModelSelect?: (modelId: string) => void;
192
198
  availableTools?: BuiltinTool[];
@@ -214,4 +220,4 @@ export interface InputPromptProps {
214
220
  /** Pre-fetched MCP status from WebSocket — bypasses REST polling */
215
221
  mcpStatusData?: McpToolsetsStatusResponse | null;
216
222
  }
217
- export declare function InputPrompt({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, typingSuggestions, autoFocus, focusTrigger, padding, placement, floatingAnchor, draggable, container, footerExtras, leadingPanel, trailingPanel, onSend, onStop, disableInputPrompt, promptVariant, mentionableAgents, promptHistory, headerContent, showAgentsMenu, showInlineAgentsMenu, agents, selectedAgentId, onSelectAgent, showTokenUsage, showContextRing, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, showSuggestionsMenu, suggestions, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, configLoading, models, selectedModel, onModelSelect, availableTools, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, approvedMcpTools, onToggleMcpToolApproval, skills, skillsLoading, enabledSkills, onToggleSkill, onToggleAllSkills, approvedSkills, onToggleSkillApproval, apiBase, authToken, mcpStatusData, }: InputPromptProps): import("react").JSX.Element;
223
+ export declare function InputPrompt({ input, setInput, isLoading, kernelStatus, connectionConfirmed, placeholder, typingSuggestions, autoFocus, focusTrigger, padding, placement, floatingAnchor, draggable, container, footerExtras, leadingPanel, trailingPanel, onSend, onStop, disableInputPrompt, promptVariant, mentionableAgents, promptHistory, headerContent, showAgentsMenu, showInlineAgentsMenu, agents, selectedAgentId, onSelectAgent, showTokenUsage, showContextRing, agentUsage, showModelSelector, showToolsMenu, showSkillsMenu, showSuggestionsMenu, suggestions, codemodeEnabled, onToggleCodemode, isA2AProtocol, hasConfigData, hasSkillsData, configLoading, models, decisions, selectedModel, onModelSelect, availableTools, mcpServers, enabledMcpTools, enabledMcpToolCount, onToggleMcpTool, onToggleAllMcpServerTools, approvedMcpTools, onToggleMcpToolApproval, skills, skillsLoading, enabledSkills, onToggleSkill, onToggleAllSkills, approvedSkills, onToggleSkillApproval, apiBase, authToken, mcpStatusData, }: InputPromptProps): import("react").JSX.Element;