@kitn.ai/ui 0.28.0 → 0.29.0

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 (376) hide show
  1. package/README.md +1 -1
  2. package/dist/agent-tooling/construct/public.d.ts +15 -0
  3. package/dist/agent-tooling/construct/schema.d.ts +111 -0
  4. package/dist/construct-cli.es.js +3 -3
  5. package/dist/construct.d.ts +5 -0
  6. package/dist/construct.js +327 -0
  7. package/dist/core-C8fzo39E.js +1 -12
  8. package/dist/engine-javascript-C1x7zo1_.js +1 -141
  9. package/dist/mcp.es.js +1 -1
  10. package/package.json +16 -16
  11. package/bin/route.test.js +0 -58
  12. package/src/agent-tooling/README.md +0 -192
  13. package/src/agent-tooling/archetypes.ts +0 -205
  14. package/src/agent-tooling/catalog/README.md +0 -676
  15. package/src/agent-tooling/catalog/catalog-types.ts +0 -231
  16. package/src/agent-tooling/catalog/fabrications.ts +0 -96
  17. package/src/agent-tooling/catalog/invariants.ts +0 -284
  18. package/src/agent-tooling/catalog/labs-titles.ts +0 -114
  19. package/src/agent-tooling/catalog/scenarios.ts +0 -87
  20. package/src/agent-tooling/catalog/surfaces.ts +0 -347
  21. package/src/agent-tooling/construct/cli-entry.ts +0 -8
  22. package/src/agent-tooling/construct/cli.ts +0 -147
  23. package/src/agent-tooling/construct/codegen.ts +0 -1635
  24. package/src/agent-tooling/construct/construct.v1.schema.json +0 -319
  25. package/src/agent-tooling/construct/dev.ts +0 -148
  26. package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +0 -7
  27. package/src/agent-tooling/construct/fixtures/ops-console.construct.json +0 -44
  28. package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +0 -32
  29. package/src/agent-tooling/construct/schema.ts +0 -452
  30. package/src/agent-tooling/integrations/anthropic.ts +0 -442
  31. package/src/agent-tooling/integrations/cloudflare.ts +0 -218
  32. package/src/agent-tooling/integrations/langgraph.ts +0 -133
  33. package/src/agent-tooling/integrations/mastra.ts +0 -182
  34. package/src/agent-tooling/integrations/mock.ts +0 -148
  35. package/src/agent-tooling/integrations/ollama.ts +0 -97
  36. package/src/agent-tooling/integrations/openai.ts +0 -95
  37. package/src/agent-tooling/integrations/openrouter.ts +0 -82
  38. package/src/agent-tooling/integrations/pi.ts +0 -176
  39. package/src/agent-tooling/integrations/pydantic-ai.ts +0 -108
  40. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +0 -398
  41. package/src/agent-tooling/mcp/css-raw.d.ts +0 -12
  42. package/src/agent-tooling/mcp/manifest.ts +0 -422
  43. package/src/agent-tooling/mcp/server.ts +0 -116
  44. package/src/agent-tooling/mcp/stdio.ts +0 -18
  45. package/src/agent-tooling/mcp/tools/construct.ts +0 -130
  46. package/src/agent-tooling/mcp/tools/debug.ts +0 -621
  47. package/src/agent-tooling/mcp/tools/reference.ts +0 -980
  48. package/src/agent-tooling/mcp/tools/scaffold.ts +0 -6708
  49. package/src/agent-tooling/mcp/tools/theme.ts +0 -456
  50. package/src/agent-tooling/mcp/tools/types.ts +0 -14
  51. package/src/agent-tooling/mcp/validate-args.ts +0 -141
  52. package/src/agent-tooling/recipes/composed-thread.ts +0 -714
  53. package/src/agent-tooling/recipes/index.ts +0 -22
  54. package/src/agent-tooling/recipes/types.ts +0 -32
  55. package/src/agent-tooling/registry.ts +0 -132
  56. package/src/agent-tooling/route-emit.ts +0 -305
  57. package/src/agent-tooling/types.ts +0 -390
  58. package/src/components/artifact-card.tsx +0 -120
  59. package/src/components/artifact.tsx +0 -914
  60. package/src/components/attachment-types.ts +0 -66
  61. package/src/components/attachments.tsx +0 -536
  62. package/src/components/audio-visualizer/audio-visualizer.voice-fixture.ts +0 -257
  63. package/src/components/audio-visualizer/aurora.glsl.ts +0 -330
  64. package/src/components/audio-visualizer/fit-scale.ts +0 -112
  65. package/src/components/audio-visualizer/index.tsx +0 -528
  66. package/src/components/audio-visualizer/labs/lab-choreography.ts +0 -187
  67. package/src/components/audio-visualizer/labs/lab-shaders.ts +0 -363
  68. package/src/components/audio-visualizer/labs/lab-visualizer.tsx +0 -102
  69. package/src/components/audio-visualizer/shader-canvas.tsx +0 -876
  70. package/src/components/audio-visualizer/sizes.ts +0 -54
  71. package/src/components/audio-visualizer/variant-aurora.tsx +0 -305
  72. package/src/components/audio-visualizer/variant-bar.tsx +0 -175
  73. package/src/components/audio-visualizer/variant-custom.tsx +0 -344
  74. package/src/components/audio-visualizer/variant-grid.tsx +0 -175
  75. package/src/components/audio-visualizer/variant-radial.tsx +0 -163
  76. package/src/components/audio-visualizer/variant-wave.tsx +0 -130
  77. package/src/components/audio-visualizer/wave.glsl.ts +0 -130
  78. package/src/components/card-fallback.tsx +0 -60
  79. package/src/components/card-renderer.tsx +0 -220
  80. package/src/components/card.tsx +0 -212
  81. package/src/components/chain-of-thought.tsx +0 -348
  82. package/src/components/chat-container.tsx +0 -89
  83. package/src/components/chat-scope-picker.tsx +0 -57
  84. package/src/components/chat-thread.tsx +0 -1014
  85. package/src/components/checkpoint.tsx +0 -88
  86. package/src/components/choice-card.tsx +0 -743
  87. package/src/components/coachmark.tsx +0 -249
  88. package/src/components/code-block.tsx +0 -181
  89. package/src/components/composer-dom.ts +0 -159
  90. package/src/components/composer-highlight.ts +0 -242
  91. package/src/components/composer-history.ts +0 -82
  92. package/src/components/composer.tsx +0 -1075
  93. package/src/components/confirm-card.tsx +0 -402
  94. package/src/components/context.tsx +0 -377
  95. package/src/components/conversation-item.tsx +0 -241
  96. package/src/components/conversation-list.tsx +0 -429
  97. package/src/components/conversation-panel.tsx +0 -118
  98. package/src/components/dismissed-stub.tsx +0 -80
  99. package/src/components/embed.tsx +0 -200
  100. package/src/components/empty.tsx +0 -177
  101. package/src/components/feedback-bar.tsx +0 -166
  102. package/src/components/file-tree.tsx +0 -530
  103. package/src/components/file-upload.tsx +0 -167
  104. package/src/components/form-widgets.tsx +0 -525
  105. package/src/components/form.tsx +0 -1296
  106. package/src/components/home-panel.tsx +0 -159
  107. package/src/components/image.tsx +0 -65
  108. package/src/components/link-preview.tsx +0 -195
  109. package/src/components/loader.tsx +0 -367
  110. package/src/components/markdown.tsx +0 -162
  111. package/src/components/message-skills.tsx +0 -40
  112. package/src/components/message.tsx +0 -765
  113. package/src/components/model-switcher.tsx +0 -132
  114. package/src/components/prompt-input.tsx +0 -188
  115. package/src/components/prompt-suggestion.tsx +0 -150
  116. package/src/components/reasoning.tsx +0 -293
  117. package/src/components/response-compare-types.ts +0 -152
  118. package/src/components/response-compare.tsx +0 -455
  119. package/src/components/response-stream.tsx +0 -109
  120. package/src/components/screen.tsx +0 -181
  121. package/src/components/scroll-button.tsx +0 -93
  122. package/src/components/source.tsx +0 -192
  123. package/src/components/tasks-card.tsx +0 -801
  124. package/src/components/text-shimmer.tsx +0 -37
  125. package/src/components/thinking-bar.tsx +0 -50
  126. package/src/components/thread.tsx +0 -228
  127. package/src/components/toast.tsx +0 -503
  128. package/src/components/tool-classify.ts +0 -26
  129. package/src/components/tool-types.ts +0 -49
  130. package/src/components/tool.tsx +0 -190
  131. package/src/components/use-card-resolution.ts +0 -44
  132. package/src/components/voice-input.tsx +0 -222
  133. package/src/components/voice-output.tsx +0 -242
  134. package/src/components/widget-tab-bar.tsx +0 -73
  135. package/src/components/workspace-shell.tsx +0 -285
  136. package/src/diagnostics/hook.ts +0 -352
  137. package/src/diagnostics/index.ts +0 -82
  138. package/src/diagnostics/report-request.ts +0 -296
  139. package/src/elements/agent-card.tsx +0 -67
  140. package/src/elements/artifact.tsx +0 -194
  141. package/src/elements/attachments.tsx +0 -140
  142. package/src/elements/audio-visualizer.tsx +0 -227
  143. package/src/elements/autoloader.ts +0 -89
  144. package/src/elements/avatar.tsx +0 -33
  145. package/src/elements/badge.tsx +0 -32
  146. package/src/elements/button.tsx +0 -149
  147. package/src/elements/card.tsx +0 -133
  148. package/src/elements/cards.tsx +0 -266
  149. package/src/elements/chain-of-thought.tsx +0 -141
  150. package/src/elements/chat-scope-picker.tsx +0 -65
  151. package/src/elements/chat-types.ts +0 -102
  152. package/src/elements/chat-workspace.tsx +0 -188
  153. package/src/elements/chat.tsx +0 -304
  154. package/src/elements/checkbox-group.tsx +0 -164
  155. package/src/elements/checkbox.tsx +0 -134
  156. package/src/elements/checkpoint.tsx +0 -47
  157. package/src/elements/choice.tsx +0 -100
  158. package/src/elements/coachmark.tsx +0 -90
  159. package/src/elements/code-block.tsx +0 -60
  160. package/src/elements/command.tsx +0 -197
  161. package/src/elements/compare.tsx +0 -111
  162. package/src/elements/compiled.css +0 -2
  163. package/src/elements/composer.tsx +0 -162
  164. package/src/elements/confirm-card.tsx +0 -76
  165. package/src/elements/context-meter.tsx +0 -107
  166. package/src/elements/conversation-item.tsx +0 -120
  167. package/src/elements/conversation-list.tsx +0 -203
  168. package/src/elements/css.ts +0 -5
  169. package/src/elements/default-input.tsx +0 -392
  170. package/src/elements/define-entry.ts +0 -12
  171. package/src/elements/define.tsx +0 -563
  172. package/src/elements/diagnostic-events.ts +0 -114
  173. package/src/elements/dialog.tsx +0 -145
  174. package/src/elements/disclosure.ts +0 -95
  175. package/src/elements/dock.tsx +0 -215
  176. package/src/elements/dropdown.tsx +0 -123
  177. package/src/elements/editable-label.tsx +0 -140
  178. package/src/elements/element-data-types.ts +0 -152
  179. package/src/elements/element-diagnostics.ts +0 -392
  180. package/src/elements/element-manifest.json +0 -354
  181. package/src/elements/element-nonscalar.json +0 -187
  182. package/src/elements/element-types.d.ts +0 -4353
  183. package/src/elements/embed.tsx +0 -35
  184. package/src/elements/empty.tsx +0 -29
  185. package/src/elements/feedback-bar.tsx +0 -66
  186. package/src/elements/file-tree.tsx +0 -62
  187. package/src/elements/file-upload.tsx +0 -44
  188. package/src/elements/form.tsx +0 -94
  189. package/src/elements/hover-card.tsx +0 -80
  190. package/src/elements/icon.tsx +0 -41
  191. package/src/elements/image.tsx +0 -32
  192. package/src/elements/input.tsx +0 -492
  193. package/src/elements/kbd.tsx +0 -45
  194. package/src/elements/link-preview.tsx +0 -34
  195. package/src/elements/loader.tsx +0 -25
  196. package/src/elements/markdown.tsx +0 -38
  197. package/src/elements/menu.tsx +0 -241
  198. package/src/elements/message-skills.tsx +0 -83
  199. package/src/elements/message.tsx +0 -361
  200. package/src/elements/model-switcher.tsx +0 -121
  201. package/src/elements/nav.tsx +0 -87
  202. package/src/elements/notice.tsx +0 -53
  203. package/src/elements/pane-grid.tsx +0 -111
  204. package/src/elements/pane-group.tsx +0 -119
  205. package/src/elements/pane.tsx +0 -129
  206. package/src/elements/popover.tsx +0 -81
  207. package/src/elements/progress-bar.tsx +0 -39
  208. package/src/elements/prompt-dock.tsx +0 -82
  209. package/src/elements/prompt-input.tsx +0 -240
  210. package/src/elements/prompt-suggestions.tsx +0 -113
  211. package/src/elements/radio-group.tsx +0 -129
  212. package/src/elements/reasoning.tsx +0 -71
  213. package/src/elements/register-impl.ts +0 -148
  214. package/src/elements/register.ts +0 -76
  215. package/src/elements/remote.tsx +0 -225
  216. package/src/elements/resizable.globals.d.ts +0 -36
  217. package/src/elements/resizable.tsx +0 -704
  218. package/src/elements/response-stream.tsx +0 -40
  219. package/src/elements/screen.tsx +0 -90
  220. package/src/elements/scroll-area.tsx +0 -33
  221. package/src/elements/scroll-button.tsx +0 -179
  222. package/src/elements/search.tsx +0 -185
  223. package/src/elements/segmented.tsx +0 -129
  224. package/src/elements/select.tsx +0 -165
  225. package/src/elements/separator.tsx +0 -36
  226. package/src/elements/setting-item.tsx +0 -50
  227. package/src/elements/settings-group.tsx +0 -37
  228. package/src/elements/skeleton.tsx +0 -45
  229. package/src/elements/slider.tsx +0 -171
  230. package/src/elements/slot-text.ts +0 -73
  231. package/src/elements/slots.ts +0 -787
  232. package/src/elements/source.tsx +0 -126
  233. package/src/elements/status.tsx +0 -42
  234. package/src/elements/styles.css +0 -328
  235. package/src/elements/switch.tsx +0 -118
  236. package/src/elements/tabs.tsx +0 -95
  237. package/src/elements/tasks.tsx +0 -103
  238. package/src/elements/text-shimmer.tsx +0 -28
  239. package/src/elements/thinking-bar.tsx +0 -43
  240. package/src/elements/thread.tsx +0 -139
  241. package/src/elements/toast.tsx +0 -106
  242. package/src/elements/tool.tsx +0 -78
  243. package/src/elements/tooltip.tsx +0 -85
  244. package/src/elements/validate-messages.ts +0 -76
  245. package/src/elements/voice-input.tsx +0 -100
  246. package/src/elements/voice-output.tsx +0 -82
  247. package/src/index.ts +0 -430
  248. package/src/primitives/audio-bands.ts +0 -174
  249. package/src/primitives/card-component-types.ts +0 -63
  250. package/src/primitives/card-contract.ts +0 -80
  251. package/src/primitives/card-data-types.ts +0 -361
  252. package/src/primitives/card-host.tsx +0 -37
  253. package/src/primitives/card-recovery.ts +0 -160
  254. package/src/primitives/card-registry.tsx +0 -78
  255. package/src/primitives/card-resolution.ts +0 -36
  256. package/src/primitives/card-routing.ts +0 -85
  257. package/src/primitives/card-schemas/artifact.schema.json +0 -92
  258. package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
  259. package/src/primitives/card-schemas/card-event.schema.json +0 -12
  260. package/src/primitives/card-schemas/choice.schema.json +0 -75
  261. package/src/primitives/card-schemas/confirm.schema.json +0 -65
  262. package/src/primitives/card-schemas/embed.schema.json +0 -63
  263. package/src/primitives/card-schemas/form.result.schema.json +0 -7
  264. package/src/primitives/card-schemas/form.schema.json +0 -53
  265. package/src/primitives/card-schemas/link.schema.json +0 -54
  266. package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
  267. package/src/primitives/card-schemas/tasks.schema.json +0 -83
  268. package/src/primitives/card-tags.ts +0 -61
  269. package/src/primitives/card-validate-cards.ts +0 -255
  270. package/src/primitives/card-validate-schemas.ts +0 -58
  271. package/src/primitives/card-validate.ts +0 -131
  272. package/src/primitives/chat-config.tsx +0 -103
  273. package/src/primitives/composer-model.ts +0 -49
  274. package/src/primitives/composer-triggers.ts +0 -35
  275. package/src/primitives/controllable.ts +0 -21
  276. package/src/primitives/conversation-store.ts +0 -248
  277. package/src/primitives/create-kai-chat.ts +0 -66
  278. package/src/primitives/create-tween.ts +0 -266
  279. package/src/primitives/embed-providers.ts +0 -254
  280. package/src/primitives/field-mask.ts +0 -256
  281. package/src/primitives/field-semantics.ts +0 -115
  282. package/src/primitives/highlighter.ts +0 -157
  283. package/src/primitives/input-mask.ts +0 -853
  284. package/src/primitives/link-preview.ts +0 -87
  285. package/src/primitives/message-feedback.ts +0 -124
  286. package/src/primitives/pdf-preview.ts +0 -121
  287. package/src/primitives/toast-store.ts +0 -338
  288. package/src/primitives/url-scheme-policy.ts +0 -70
  289. package/src/primitives/use-audio-analysis.ts +0 -340
  290. package/src/primitives/use-auto-resize.ts +0 -31
  291. package/src/primitives/use-resize-observer.ts +0 -45
  292. package/src/primitives/use-sequencer.ts +0 -72
  293. package/src/primitives/use-speech-recognition.ts +0 -146
  294. package/src/primitives/use-stick-to-bottom.ts +0 -75
  295. package/src/primitives/use-text-stream.ts +0 -143
  296. package/src/primitives/use-voice-recorder.ts +0 -62
  297. package/src/primitives/visualizer-sequences.ts +0 -350
  298. package/src/remote/host-embed.ts +0 -345
  299. package/src/remote/index.ts +0 -2
  300. package/src/remote/origin.ts +0 -30
  301. package/src/remote/provider-runtime.ts +0 -262
  302. package/src/remote/provider.ts +0 -2
  303. package/src/remote/validate.ts +0 -22
  304. package/src/remote/version.ts +0 -12
  305. package/src/remote/wire.ts +0 -48
  306. package/src/schemas/from-tool-call.ts +0 -151
  307. package/src/schemas/index.ts +0 -341
  308. package/src/schemas/provider-subsets.ts +0 -538
  309. package/src/schemas/registry.ts +0 -355
  310. package/src/schemas/tool-defs.ts +0 -793
  311. package/src/solid.ts +0 -173
  312. package/src/state/index.ts +0 -44
  313. package/src/state/messages.ts +0 -53
  314. package/src/state/mock.ts +0 -297
  315. package/src/state/parts.ts +0 -295
  316. package/src/state/persistence.ts +0 -180
  317. package/src/state/stream.ts +0 -246
  318. package/src/state/suggestions.ts +0 -9
  319. package/src/state/threads.ts +0 -142
  320. package/src/test-utils/fake-clock.ts +0 -88
  321. package/src/types.ts +0 -95
  322. package/src/ui/action-icons.ts +0 -53
  323. package/src/ui/agent-card.tsx +0 -218
  324. package/src/ui/avatar.tsx +0 -23
  325. package/src/ui/badge.tsx +0 -21
  326. package/src/ui/button.tsx +0 -49
  327. package/src/ui/card.tsx +0 -245
  328. package/src/ui/checkbox-group.tsx +0 -153
  329. package/src/ui/checkbox.tsx +0 -63
  330. package/src/ui/collapsible.tsx +0 -163
  331. package/src/ui/command.tsx +0 -103
  332. package/src/ui/dialog.tsx +0 -223
  333. package/src/ui/dock.tsx +0 -630
  334. package/src/ui/dropdown.tsx +0 -636
  335. package/src/ui/editable-label.tsx +0 -112
  336. package/src/ui/hover-card.tsx +0 -345
  337. package/src/ui/icon.tsx +0 -167
  338. package/src/ui/input.tsx +0 -391
  339. package/src/ui/kbd.tsx +0 -118
  340. package/src/ui/nav.tsx +0 -282
  341. package/src/ui/notice.tsx +0 -84
  342. package/src/ui/overlay.tsx +0 -277
  343. package/src/ui/pane-grid.tsx +0 -117
  344. package/src/ui/pane-group.tsx +0 -291
  345. package/src/ui/pane.tsx +0 -193
  346. package/src/ui/popover.tsx +0 -106
  347. package/src/ui/progress-bar.tsx +0 -83
  348. package/src/ui/prompt-dock.tsx +0 -145
  349. package/src/ui/radio.tsx +0 -150
  350. package/src/ui/resizable.tsx +0 -693
  351. package/src/ui/scroll-area.tsx +0 -26
  352. package/src/ui/segmented.tsx +0 -109
  353. package/src/ui/select.tsx +0 -168
  354. package/src/ui/separator.tsx +0 -10
  355. package/src/ui/settings-group.tsx +0 -67
  356. package/src/ui/skeleton.tsx +0 -73
  357. package/src/ui/slider.tsx +0 -178
  358. package/src/ui/status.tsx +0 -48
  359. package/src/ui/switch.tsx +0 -119
  360. package/src/ui/tabs.tsx +0 -168
  361. package/src/ui/textarea.tsx +0 -21
  362. package/src/ui/tooltip.tsx +0 -118
  363. package/src/utils/cn.ts +0 -30
  364. package/src/wire/chunk.ts +0 -248
  365. package/src/wire/consume.ts +0 -599
  366. package/src/wire/diagnostics.ts +0 -727
  367. package/src/wire/encode-probe.ts +0 -214
  368. package/src/wire/encode.ts +0 -947
  369. package/src/wire/files.ts +0 -342
  370. package/src/wire/formats/anthropic.ts +0 -274
  371. package/src/wire/formats/openai.ts +0 -228
  372. package/src/wire/index.ts +0 -95
  373. package/src/wire/media-types.ts +0 -344
  374. package/src/wire/read.ts +0 -396
  375. package/src/wire/sink-helpers.ts +0 -50
  376. package/src/wire/sse.ts +0 -153
@@ -1,293 +0,0 @@
1
- import { type JSX, type Accessor, splitProps, createSignal, createContext, useContext, createEffect, createUniqueId, onCleanup, Show } from 'solid-js';
2
- import { cn } from '../utils/cn';
3
- import { ChevronDown } from 'lucide-solid';
4
- import { Markdown } from './markdown';
5
- import { observeContentHeight } from '../primitives/use-resize-observer';
6
- import { TextShimmer } from './text-shimmer';
7
-
8
- interface ReasoningContextValue {
9
- isOpen: () => boolean;
10
- onOpenChange: (open: boolean) => void;
11
- disabled: () => boolean;
12
- /** Id minted on the root and shared by the trigger's `aria-controls` and the
13
- * content's `id` — the same wiring `Collapsible` uses, so a screen reader can
14
- * name the panel this disclosure toggles. */
15
- contentId: string;
16
- /** ReasoningTrigger registers its button here on mount; the content reads it
17
- * when a panel holding focus collapses, so focus has somewhere to land. */
18
- registerTrigger: (el: HTMLElement | undefined) => void;
19
- /** The registered trigger. Deliberately a plain getter over a mutable
20
- * variable, NOT a signal — registration must not re-run the content effect. */
21
- trigger: () => HTMLElement | undefined;
22
- /** Whether the reasoning is currently streaming — read by `ReasoningTrigger`
23
- * to decide how its own label renders (shimmer while streaming, plain
24
- * neutral text once settled). Kit-decides-HOW: every consumer gets the same
25
- * "Thinking…" shimmer behavior for free, with no prop of their own. */
26
- isStreaming: () => boolean;
27
- }
28
-
29
- /** Imperative open controller, handed to a parent (the kai-reasoning facade) via
30
- * `controllerRef` so it can drive/observe open state — mirrors
31
- * CollapsibleController/HoverCardController. */
32
- export interface ReasoningController { open: Accessor<boolean>; setOpen: (v: boolean) => void; }
33
-
34
- const ReasoningContext = createContext<ReasoningContextValue>();
35
-
36
- function useReasoningContext() {
37
- const context = useContext(ReasoningContext);
38
- if (!context) {
39
- throw new Error('useReasoningContext must be used within a Reasoning provider');
40
- }
41
- return context;
42
- }
43
-
44
- // --- Reasoning (Root) ---
45
-
46
- export interface ReasoningProps {
47
- children: JSX.Element;
48
- class?: string;
49
- open?: boolean;
50
- /** Initial open state (uncontrolled seed). */
51
- defaultOpen?: boolean;
52
- onOpenChange?: (open: boolean) => void;
53
- isStreaming?: boolean;
54
- /** Gate the trigger — programmatic control via the controller still works. */
55
- disabled?: boolean;
56
- /** Receive the open controller (open accessor + setOpen) once mounted. */
57
- controllerRef?: (api: ReasoningController) => void;
58
- /** Keep auto-opening while streaming and auto-closing when it settles (the
59
- * pre-Task-19f `full` behavior). Default false: the panel starts per
60
- * `defaultOpen` and stays exactly where the user leaves it — streaming only
61
- * changes the trigger's label (shimmer), never the open state, matching the
62
- * "closed chip, expand on click" default (owner ruling, 2026-08-26). */
63
- openOnStream?: boolean;
64
- }
65
-
66
- function Reasoning(props: ReasoningProps) {
67
- const [local] = splitProps(props, ['children', 'class', 'open', 'defaultOpen', 'onOpenChange', 'isStreaming', 'disabled', 'controllerRef', 'openOnStream']);
68
- const [internalOpen, setInternalOpen] = createSignal(local.defaultOpen ?? false);
69
- const [wasAutoOpened, setWasAutoOpened] = createSignal(false);
70
-
71
- const isControlled = () => local.open !== undefined;
72
- const isOpen = () => (isControlled() ? local.open! : internalOpen());
73
- const disabled = () => !!local.disabled;
74
-
75
- // The single open-mutate path, shared by the trigger and the imperative
76
- // controller. In controlled mode we don't touch internal state; the consumer
77
- // reflects via the `open` prop and observes via onOpenChange.
78
- const handleOpenChange = (newOpen: boolean) => {
79
- if (isOpen() === newOpen) return;
80
- if (!isControlled()) {
81
- setInternalOpen(newOpen);
82
- }
83
- local.onOpenChange?.(newOpen);
84
- };
85
-
86
- createEffect(() => {
87
- if (!local.openOnStream) return;
88
- const streaming = local.isStreaming;
89
- if (streaming && !wasAutoOpened()) {
90
- if (!isControlled()) setInternalOpen(true);
91
- setWasAutoOpened(true);
92
- }
93
- if (!streaming && wasAutoOpened()) {
94
- if (!isControlled()) setInternalOpen(false);
95
- setWasAutoOpened(false);
96
- }
97
- });
98
-
99
- // Hand the controller up once. setOpen routes through handleOpenChange so it
100
- // notifies onOpenChange and respects controlled/uncontrolled mode. Not gated
101
- // by disabled — the facade's wireDisclosure applies disabled-gating itself.
102
- local.controllerRef?.({ open: isOpen, setOpen: handleOpenChange });
103
-
104
- const contentId = createUniqueId();
105
-
106
- // The trigger element, for the focus hand-off in ReasoningContent. Read once,
107
- // at the moment a panel collapses — a signal would only add a spurious
108
- // dependency to the content effect when the trigger mounts.
109
- let triggerEl: HTMLElement | undefined;
110
-
111
- return (
112
- <ReasoningContext.Provider
113
- value={{
114
- isOpen,
115
- onOpenChange: handleOpenChange,
116
- disabled,
117
- contentId,
118
- registerTrigger: (el) => { triggerEl = el; },
119
- trigger: () => triggerEl,
120
- isStreaming: () => !!local.isStreaming,
121
- }}
122
- >
123
- <div class={local.class}>{local.children}</div>
124
- </ReasoningContext.Provider>
125
- );
126
- }
127
-
128
- // --- ReasoningTrigger ---
129
-
130
- export interface ReasoningTriggerProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
131
- children: JSX.Element;
132
- }
133
-
134
- function ReasoningTrigger(props: ReasoningTriggerProps) {
135
- // `ref` is split out rather than left in `rest`: the trigger takes its own ref
136
- // to register as the panel's focus-return target, and a spread `ref` would
137
- // silently replace it. The consumer's ref is forwarded below instead.
138
- const [local, rest] = splitProps(props, ['children', 'class', 'ref']);
139
- const { isOpen, onOpenChange, disabled, contentId, registerTrigger, isStreaming } = useReasoningContext();
140
-
141
- return (
142
- // The same disclosure contract as CollapsibleTrigger: an explicit
143
- // `type="button"` (so a trigger inside a form never submits it),
144
- // `aria-expanded` + `aria-controls` so assistive tech can read the state and
145
- // find the panel, and the `data-state` / `data-expanded` / `data-closed`
146
- // handles styling and tests hang off. `{...rest}` stays LAST so a consumer
147
- // can still override any of them.
148
- <button
149
- ref={(el) => {
150
- registerTrigger(el);
151
- // Solid hands a component's `ref` down as a callback; tolerate a raw
152
- // element for the hand-written case.
153
- if (typeof local.ref === 'function') (local.ref as (el: HTMLButtonElement) => void)(el);
154
- }}
155
- type="button"
156
- class={cn('flex cursor-pointer items-center gap-2 text-meta', local.class)}
157
- disabled={disabled() || undefined}
158
- aria-expanded={isOpen()}
159
- aria-controls={contentId}
160
- data-expanded={isOpen() ? '' : undefined}
161
- data-closed={isOpen() ? undefined : ''}
162
- data-state={isOpen() ? 'open' : 'closed'}
163
- onClick={() => { if (!disabled()) onOpenChange(!isOpen()); }}
164
- {...rest}
165
- >
166
- {/* Content/chrome, not a control: was `text-primary`, the BRAND token, so
167
- a consumer's branded --kai-color-primary bled onto the "Thinking"
168
- label. `text-foreground` matches the sibling `<Tool>` disclosure
169
- trigger's label (rendered via `Button variant="ghost"`, itself
170
- `text-foreground`) — the established neutral for a disclosure
171
- trigger's own label text in this codebase.
172
- Kit-decides-HOW: while streaming, the label renders with the kit's
173
- own `TextShimmer` (the common "Thinking…" shimmer, already used by
174
- `Loader`'s `text-shimmer` variant) instead of static text; once
175
- settled it's the plain neutral span above. Every consumer gets this
176
- for free — no prop of their own. */}
177
- <Show when={isStreaming()} fallback={<span class="text-foreground">{local.children}</span>}>
178
- <TextShimmer class="font-medium">{local.children}</TextShimmer>
179
- </Show>
180
- <div
181
- class={cn(
182
- 'transform transition-transform',
183
- isOpen() ? 'rotate-180' : ''
184
- )}
185
- >
186
- <ChevronDown class="size-4" />
187
- </div>
188
- </button>
189
- );
190
- }
191
-
192
- // --- ReasoningContent ---
193
-
194
- export interface ReasoningContentProps extends JSX.HTMLAttributes<HTMLDivElement> {
195
- children: JSX.Element;
196
- markdown?: boolean;
197
- contentClass?: string;
198
- }
199
-
200
- function ReasoningContent(props: ReasoningContentProps) {
201
- const [local, rest] = splitProps(props, ['children', 'class', 'contentClass', 'markdown']);
202
- const { isOpen, contentId, trigger } = useReasoningContext();
203
-
204
- let contentRef: HTMLDivElement | undefined;
205
- let innerRef: HTMLDivElement | undefined;
206
-
207
- /** Hand focus back to the trigger when the panel about to go inert is holding
208
- * it. Chromium keeps `activeElement` on the now-inert node for the rest of
209
- * the task and then resets the document's focus to `<body>` — so without this
210
- * a user who was inside the panel loses the focus ring entirely and their
211
- * next Tab restarts from the top. `Collapsible` has exactly this gap: it sets
212
- * `bool:inert` and never looks at where focus was. Runs BEFORE the attribute
213
- * lands, so the move is ours rather than the browser's fallback. */
214
- const releaseFocus = () => {
215
- if (!contentRef) return;
216
- // getRootNode(), not `document`: inside the <kai-reasoning> shadow root
217
- // document.activeElement only ever resolves to the HOST element.
218
- const root = contentRef.getRootNode() as Document | ShadowRoot;
219
- const active = root.activeElement;
220
- // A disabled trigger cannot take focus; the browser then falls back to
221
- // <body>, which is no worse than not trying.
222
- if (active && contentRef.contains(active)) trigger()?.focus();
223
- };
224
-
225
- createEffect(() => {
226
- if (!contentRef || !innerRef) return;
227
-
228
- const dispose = observeContentHeight(innerRef, () => {
229
- if (contentRef && innerRef && isOpen()) {
230
- contentRef.style.maxHeight = `${innerRef.scrollHeight}px`;
231
- }
232
- });
233
-
234
- if (isOpen()) {
235
- contentRef.style.maxHeight = `${innerRef.scrollHeight}px`;
236
- // Dropped in the same tick as the open, NOT on transitionend: the panel is
237
- // interactive from the first frame, so an inert outliving the animation can
238
- // never swallow the first click or Tab into it.
239
- contentRef.removeAttribute('inert');
240
- } else {
241
- contentRef.style.maxHeight = '0px';
242
- releaseFocus();
243
- // Applied in the same tick as the collapse, again NOT on transitionend:
244
- // `inert` has no visual effect of its own, so the 150ms max-height
245
- // transition still runs to completion underneath it (verified in Chromium:
246
- // transitionend fires and the final computed max-height is reached), while
247
- // the a11y tree matches the collapsed intent immediately instead of 150ms
248
- // late. setAttribute rather than the `inert` IDL property because Solid
249
- // routes `inert` through Properties (el.inert = …), which jsdom does not
250
- // reflect back to an attribute — the same reason Collapsible uses `bool:`.
251
- contentRef.setAttribute('inert', '');
252
- }
253
-
254
- onCleanup(dispose);
255
- });
256
-
257
- return (
258
- // `id` matches the trigger's `aria-controls`; `data-state` gives styling and
259
- // tests an attribute handle on the panel instead of forcing them to read the
260
- // animated `max-height`. `inert` while collapsed (as CollapsibleContent does)
261
- // is owned by the effect above, not bound here — it has to be sequenced
262
- // against the focus hand-off, and a second reactive owner would race it.
263
- // `{...rest}` stays LAST so a consumer can still override.
264
- <div
265
- ref={contentRef}
266
- id={contentId}
267
- class={cn(
268
- 'overflow-hidden transition-[max-height] duration-150 ease-out',
269
- local.class
270
- )}
271
- style={{ 'max-height': '0px' }}
272
- data-state={isOpen() ? 'open' : 'closed'}
273
- {...rest}
274
- >
275
- <div
276
- ref={innerRef}
277
- class={cn(
278
- // Markdown content is styled by the token-based `.chat-markdown` (see
279
- // Markdown component), which themes via design tokens — so no Tailwind
280
- // `prose`/`dark:prose-invert` is needed (those wouldn't follow a scoped theme).
281
- 'text-muted-foreground text-body',
282
- local.contentClass
283
- )}
284
- >
285
- <Show when={local.markdown} fallback={local.children}>
286
- <Markdown content={local.children as string} />
287
- </Show>
288
- </div>
289
- </div>
290
- );
291
- }
292
-
293
- export { Reasoning, ReasoningTrigger, ReasoningContent };
@@ -1,152 +0,0 @@
1
- // Types + pure helpers for the dual-response comparison card (`ResponseCompare` /
2
- // `<kai-compare>`). A compare presents exactly TWO assistant candidates for the
3
- // same prompt side-by-side; the user picks the better one (a COMMIT, not a
4
- // Submit), which the consumer turns into a `(prompt, chosen, rejected)`
5
- // preference pair. Kept framework-agnostic and DOM-free so it unit-tests in
6
- // isolation.
7
- import type { ToolPart } from './tool';
8
- import type { AttachmentData } from './attachments';
9
- import type { MessagePart } from '../elements/chat-types';
10
-
11
- // ─────────────────────────────────────────────────────────────────────────────
12
- // Types
13
- // ─────────────────────────────────────────────────────────────────────────────
14
-
15
- /** One assistant response in a comparison. Rendered identically to an assistant
16
- * message (reasoning + tools + attachments + markdown content) via `MessageBody`. */
17
- export interface CompareCandidate {
18
- /** Stable id, unique within the pair; echoed back in the selection. */
19
- id: string;
20
- /** The response text/markdown. */
21
- content: string;
22
- /** Optional collapsible reasoning block. */
23
- reasoning?: { text: string; label?: string };
24
- /** Tool-call parts rendered above the content. */
25
- tools?: ToolPart[];
26
- /** Inline attachment previews rendered above the content. */
27
- attachments?: AttachmentData[];
28
- /** Optional short column label (e.g. "A" / "B" / "Concise"). */
29
- label?: string;
30
- /** Optional model name shown as a sub-label. */
31
- model?: string;
32
- /** When true this candidate is still streaming — its pick control is disabled
33
- * and a per-column shimmer shows until it (and its sibling) settle. */
34
- streaming?: boolean;
35
- }
36
-
37
- /** The two-candidate tuple. Enforced at the type level; validated at runtime by
38
- * `normalizeCandidates`. */
39
- export type ComparePair = [CompareCandidate, CompareCandidate];
40
-
41
- /** How the card collapses once the user picks. `'winner'` (default) shows just the
42
- * chosen candidate's body; `'none'` keeps both columns but marks the choice. */
43
- export type CompareCollapse = 'winner' | 'none';
44
-
45
- /** The compare definition (set as the `data` JS property on `<kai-compare>`). */
46
- export interface ResponseCompareData {
47
- /** Optional prompt/question shown above the two columns. */
48
- prompt?: string;
49
- /** Exactly two candidates: [A, B]. */
50
- candidates: ComparePair;
51
- /** Collapse behaviour after a pick. Default `'winner'`. */
52
- collapse?: CompareCollapse;
53
- }
54
-
55
- /** Emitted (and re-hydratable) when the user picks. The consumer pairs
56
- * `(prompt, chosenId, rejectedIds)` for preference capture / RLHF. */
57
- export interface CompareSelection {
58
- /** The id of the chosen candidate. */
59
- chosenId: string;
60
- /** The id(s) of the rejected candidate(s) — for a pair, the other one. */
61
- rejectedIds: string[];
62
- /** Epoch ms when the pick was made. */
63
- at?: number;
64
- }
65
-
66
- // ─────────────────────────────────────────────────────────────────────────────
67
- // Pure helpers (unit-tested in isolation).
68
- // ─────────────────────────────────────────────────────────────────────────────
69
-
70
- /**
71
- * Validate + normalize the candidate list. A compare requires EXACTLY two
72
- * candidates with unique, non-empty string ids. Returns the usable pair, or an
73
- * error message when the definition is unusable (rendered as an inline error /
74
- * emitted as a `kai-error`). Modeled on `normalizeOptions`.
75
- */
76
- export function normalizeCandidates(candidates: unknown): {
77
- candidates: ComparePair | null;
78
- error?: string;
79
- } {
80
- if (!Array.isArray(candidates)) {
81
- return { candidates: null, error: "This comparison couldn't be displayed." };
82
- }
83
- if (candidates.length !== 2) {
84
- return {
85
- candidates: null,
86
- error: `A comparison needs exactly two candidates (got ${candidates.length}).`,
87
- };
88
- }
89
- const out: CompareCandidate[] = [];
90
- const seen = new Set<string>();
91
- for (const c of candidates) {
92
- if (!c || typeof c !== 'object') {
93
- return { candidates: null, error: "This comparison couldn't be displayed." };
94
- }
95
- const cand = c as Partial<CompareCandidate>;
96
- if (typeof cand.id !== 'string' || cand.id.length === 0) {
97
- return { candidates: null, error: 'Each candidate needs a non-empty id.' };
98
- }
99
- if (seen.has(cand.id)) {
100
- return { candidates: null, error: `Duplicate candidate id "${cand.id}".` };
101
- }
102
- seen.add(cand.id);
103
- out.push({
104
- id: cand.id,
105
- content: typeof cand.content === 'string' ? cand.content : '',
106
- reasoning: cand.reasoning,
107
- tools: Array.isArray(cand.tools) ? cand.tools : undefined,
108
- attachments: Array.isArray(cand.attachments) ? cand.attachments : undefined,
109
- label: typeof cand.label === 'string' ? cand.label : undefined,
110
- model: typeof cand.model === 'string' ? cand.model : undefined,
111
- streaming: cand.streaming === true,
112
- });
113
- }
114
- return { candidates: [out[0], out[1]] };
115
- }
116
-
117
- /** Build the selection payload for choosing `chosenId` out of the pair (the other
118
- * candidate is the rejected one). Stamps `at` with the current time. */
119
- export function buildSelection(pair: ComparePair, chosenId: string): CompareSelection {
120
- const rejectedIds = pair.filter((c) => c.id !== chosenId).map((c) => c.id);
121
- return { chosenId, rejectedIds, at: Date.now() };
122
- }
123
-
124
- /** Whether any candidate in the pair is still streaming (pick stays disabled). */
125
- export function isAnyStreaming(pair: ComparePair | null): boolean {
126
- if (!pair) return false;
127
- return pair.some((c) => c.streaming === true);
128
- }
129
-
130
- /** Map a `CompareCandidate`'s flat legacy fields (content/reasoning/tools/
131
- * attachments) into the ordered `MessagePart[]` `MessageBody` now renders.
132
- * `CompareCandidate` stays its own independent shape (it is `<kai-compare>`'s
133
- * public `data` JSON, not a `ChatMessage`). This is purely a render-time
134
- * adapter, applied at each `MessageBody` call site. Order: reasoning (the
135
- * thinking trace) → tool calls (the actions taken) → attachments (anything
136
- * produced) → the final text answer, mirroring how an assistant turn reads. */
137
- export function candidateToParts(candidate: CompareCandidate): MessagePart[] {
138
- const parts: MessagePart[] = [];
139
- if (candidate.reasoning) {
140
- parts.push({ type: 'reasoning', text: candidate.reasoning.text, label: candidate.reasoning.label });
141
- }
142
- for (const tool of candidate.tools ?? []) {
143
- parts.push({ type: 'tool', tool });
144
- }
145
- for (const attachment of candidate.attachments ?? []) {
146
- parts.push({ type: 'file', attachment });
147
- }
148
- if (candidate.content) {
149
- parts.push({ type: 'text', text: candidate.content });
150
- }
151
- return parts;
152
- }