@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,355 +0,0 @@
1
- // createCardRegistry: the one place an app writes down which cards it renders.
2
- //
3
- // WHY THIS EXISTS, AND WHY IT IS NOT "A WAY TO REGISTER CUSTOM CARDS"
4
- // ------------------------------------------------------------------
5
- // Registering a custom card already worked: `chat.cardTypes = { 'pricing-table':
6
- // 'my-pricing-table' }` goes through `mergeCardTags` and has since the card contract
7
- // landed, and `cardTools({ 'pricing-table': schema }, { provider })` already emitted
8
- // `kai_pricing-table` before this file existed. Measured on 4b33cd8, both halves of
9
- // the custom round trip passed already. Nothing here unlocks them.
10
- //
11
- // Two things did not work, and they are what this file is for.
12
- //
13
- // 1. NOTHING TIED THE TWO ENDS TOGETHER. `cardTypes` is a per-element PROP, so there
14
- // is no ambient registry a backend route could consult. The developer wrote their
15
- // card types on the client, wrote them again in the tool definitions, and nothing
16
- // made the two agree. This is the fifth-copy problem the emit contract exists to
17
- // kill, one layer up from the schema itself.
18
- //
19
- // 2. THE MODEL WAS TOLD ABOUT ALL SEVEN BUILT-INS REGARDLESS. `cardTools({ provider })`
20
- // has no way to say "this app renders confirm and choice, do not offer the model an
21
- // artifact card". Every request paid for seven tool definitions, five of which the
22
- // app had no intention of using, and the model could pick one of them.
23
- //
24
- // So the goal is not the seam, which existed. It is to make the NORMAL path go through
25
- // the seam, so it cannot rot the way it did once already: the only end-to-end user of
26
- // `cardTypes` was a workaround in the conformance spike that registered `spike-artifact`
27
- // because the kit had no artifact card, and when the kit grew one the workaround was
28
- // correctly deleted and the coverage went with it. Coverage that exists only because
29
- // something is missing is coverage on a timer.
30
- //
31
- // WHAT `use` DOES AND DOES NOT NARROW
32
- // -----------------------------------
33
- // `use` narrows what the MODEL IS TOLD ABOUT. It does not narrow what renders, and it
34
- // must not be read as if it did. `mergeCardTags`/`mergeCardComponents` union the seven
35
- // built-ins in unconditionally (consumer overrides win), so an app declaring
36
- // `use: ['confirm']` still renders a `choice` envelope if one arrives. That is the
37
- // right behaviour: an envelope that turns up from somewhere else should draw, not
38
- // degrade to a fallback because it was left off a tool list. Narrowing rendering would
39
- // be a `primitives/card-registry.tsx` change, and a worse product.
40
- //
41
- // Likewise `registry.validate()` covers all seven built-ins regardless of `use`.
42
- // Validation is about what ARRIVED, not about what was offered.
43
- //
44
- // NO `toolPrefix`, DELIBERATELY
45
- // -----------------------------
46
- // The plan reserves `createCardRegistry({ toolPrefix })` and this file does not ship
47
- // it, for the reason tool-defs.ts already gives: the inverse (`cardTypeFromToolName`)
48
- // hard-codes `kai_`, so a prefix honoured on the emit side alone would generate tools
49
- // the loop's parser cannot recognise, and the card would vanish into `runTool` with no
50
- // error anywhere. Worse than not having the option. It lands in both directions in one
51
- // change, or not at all.
52
- //
53
- // SERVER-SAFE
54
- // -----------
55
- // This module is imported by a backend route (it is half the point) so it stays free
56
- // of DOM and of the Solid runtime. `CardComponentMap`/`CardTagMap` are TYPE imports
57
- // and erase completely; the values in `components` are passed through untouched and
58
- // never called here. `verify:ssr` imports the built entry under the `node` condition
59
- // and proves the runtime half.
60
- //
61
- // It does NOT prove the compile-time half, and the two imports below are deliberately
62
- // aimed at `.ts` modules rather than at primitives/card-registry.tsx for a reason no
63
- // runtime guard can see. A type import still has to RESOLVE, and a Node/no-DOM project
64
- // (tsconfig.mcp.json: `lib: ["ESNext"]`, no `jsx`) cannot resolve a `.tsx` at all:
65
- // pointing either of these back at card-registry.tsx puts TS6142 on this exact line on
66
- // any unbuilt tree. Both types are re-exported from card-registry.tsx, so importing
67
- // them from there LOOKS equivalent and compiles everywhere else. It is not. The check
68
- // that tells the difference is `tsc --noEmit -p tsconfig.mcp.json` with no dist/
69
- // present; see the header of primitives/card-component-types.ts.
70
-
71
- import type { CardComponentMap } from '../primitives/card-component-types';
72
- import type { CardTagMap } from '../primitives/card-tags';
73
- import type { JsonSchema } from '../primitives/card-validate';
74
- import {
75
- validateCardData,
76
- type CardValidationReport,
77
- } from '../primitives/card-validate-cards';
78
- import { cardSchemas, isCardSchemaName, type CardSchema, type CardSchemaName } from './index';
79
- import type { CardToolSource } from './tool-defs';
80
-
81
- /**
82
- * One custom card type: what the model should be told, and what draws it.
83
- *
84
- * Every member is optional because the useful combinations genuinely differ. A
85
- * web-component consumer supplies `tag`; a Solid consumer supplies `component`; a
86
- * backend-only registry (a route that builds tool definitions and never renders)
87
- * supplies neither. Only `schema` carries a warning when absent, and the reason is on
88
- * {@link CardRegistrySpec.onIncomplete}.
89
- */
90
- export interface CustomCardSpec {
91
- /**
92
- * The JSON Schema for this card type's `data` payload.
93
- *
94
- * Used for BOTH ends: `cardTools()` projects it into a tool definition, and
95
- * `registry.validate()` checks arriving data against it. Authored form is fine, with
96
- * the descriptions left in: the projection strips what a provider cannot take, and
97
- * the validator ignores keywords it does not implement.
98
- *
99
- * That last clause is a real limit, not a formality, and it is the same one the
100
- * built-ins carry. `validateAgainstSchema` has no applicators, so `allOf`, `anyOf`,
101
- * `oneOf`, `if`/`then`, `$ref` and `additionalProperties` in a custom schema are
102
- * carried faithfully to the model and NOT enforced on the way back. See the
103
- * NOT_ENFORCED table at the top of primitives/card-validate-schemas.ts.
104
- */
105
- readonly schema?: CardSchema | JsonSchema;
106
- /** The custom element that renders it, e.g. `'my-pricing-table'`. Feeds `mergeCardTags`. */
107
- readonly tag?: string;
108
- /** The Solid component that renders it. Feeds `mergeCardComponents`. */
109
- readonly component?: CardComponentMap[string];
110
- /**
111
- * One sentence of PURPOSE, addressed to the model: when should it reach for this
112
- * card? Not a restatement of the shape, which the schema already carries.
113
- *
114
- * Falls back to the schema's own `description`, then to a generated stub. See
115
- * `describe()` in tool-defs.ts.
116
- */
117
- readonly description?: string;
118
- }
119
-
120
- /** What to do about a custom card type registered with no schema. */
121
- export type IncompletePolicy = 'warn' | 'throw' | 'silent';
122
-
123
- export interface CardRegistrySpec {
124
- /**
125
- * Which BUILT-IN card types this app renders, and therefore which ones the model is
126
- * offered.
127
- *
128
- * Omitted means all seven, which is what `cardTools({ provider })` already does and
129
- * what `<kai-chat>` actually renders, so the default describes reality rather than
130
- * quietly shrinking it. `use: []` means none of ours: an app whose generative UI is
131
- * entirely its own.
132
- */
133
- readonly use?: readonly CardSchemaName[];
134
- /** This app's own card types, keyed by `CardEnvelope.type`. */
135
- readonly custom?: Readonly<Record<string, CustomCardSpec>>;
136
- /**
137
- * How a schema-less custom type is reported. Default `'warn'`.
138
- *
139
- * `'throw'` for a build or a CI check that wants the hole to be fatal; `'silent'` for
140
- * a card type your own code populates and a model never emits, where the warning is
141
- * noise. `'silent'` is deliberately a word you have to type, so the acknowledgement is
142
- * greppable instead of implied.
143
- */
144
- readonly onIncomplete?: IncompletePolicy;
145
- }
146
-
147
- /**
148
- * An app's card types, in the one shape both ends take.
149
- *
150
- * ```ts
151
- * // cards.ts, imported by the client AND the route
152
- * export const cards = createCardRegistry({
153
- * use: ['confirm', 'choice'],
154
- * custom: { 'pricing-table': { schema: pricingSchema, tag: 'my-pricing-table' } },
155
- * });
156
- *
157
- * // client
158
- * chat.cardTypes = cards.tags;
159
- * // server
160
- * const tools = cardTools(cards, { provider: 'anthropic' });
161
- * ```
162
- *
163
- * Extends {@link CardToolSource}, so `cardTools(registry, opts)` takes it with no
164
- * signature change on that side. That interface was left open for exactly this.
165
- */
166
- export interface CardRegistry extends CardToolSource {
167
- /**
168
- * The card types the model is offered, keyed by type. `use`d built-ins plus every
169
- * custom type that HAS a schema. What `cardTools()` reads.
170
- */
171
- readonly schemas: Readonly<Record<string, CardSchema>>;
172
- /** Purpose sentences for custom types (and for any built-in a custom entry overrode). */
173
- readonly descriptions: Readonly<Record<string, string>>;
174
- /**
175
- * Custom `type -> tag`, for `chat.cardTypes` / `mergeCardTags`.
176
- *
177
- * Custom entries ONLY. The built-in tags are not restated here because
178
- * `mergeCardTags` adds all seven itself; listing the `use`d ones would read as if the
179
- * others had been excluded, which is not what happens.
180
- */
181
- readonly tags: CardTagMap;
182
- /** Custom `type -> Solid component`, for `<CardRenderer types>` / `mergeCardComponents`. */
183
- readonly components: CardComponentMap;
184
- /** Every type this registry declares, schema-less ones included. Built-ins first. */
185
- readonly types: readonly string[];
186
- /** The built-in types in `use`, in `cardSchemas` order. */
187
- readonly builtIn: readonly CardSchemaName[];
188
- /** The custom types, in declaration order, schema-less ones included. */
189
- readonly custom: readonly string[];
190
- /** Custom types with no schema: registered, renderable, invisible to the model. */
191
- readonly incomplete: readonly string[];
192
- /**
193
- * Custom schemas in the shape `validateCardData`'s third argument takes, so a caller
194
- * that already has a `validateCardData` call can widen it without going through
195
- * {@link CardRegistry.validate}.
196
- */
197
- readonly validationSchemas: Readonly<Record<string, JsonSchema>>;
198
- /**
199
- * Validate an envelope's `data` against this registry's schema for `type`.
200
- *
201
- * Custom schemas win over a built-in of the same name, matching `mergeCardTags`'s
202
- * consumer-wins rule. `null` means there was nothing to check (a type with no
203
- * schema anywhere), which is kept distinguishable from a clean pass so a caller
204
- * cannot report the second as the first.
205
- *
206
- * Covers all seven built-ins regardless of `use`: see the module header.
207
- */
208
- validate(type: string, data: unknown): CardValidationReport | null;
209
- }
210
-
211
- const isRecord = (v: unknown): v is Record<string, unknown> =>
212
- typeof v === 'object' && v !== null && !Array.isArray(v);
213
-
214
- function warnIncomplete(incomplete: readonly string[]): string {
215
- const names = incomplete.map((t) => `"${t}"`).join(', ');
216
- const plural = incomplete.length === 1 ? 'type' : 'types';
217
- return [
218
- `createCardRegistry: ${incomplete.length} custom card ${plural} registered with no \`schema\`: ${names}.`,
219
- ' They will still RENDER (their tag/component is registered), but:',
220
- ' - cardTools() skips them, so the model is never told the type exists and will never emit one;',
221
- ' - registry.validate() returns null for them, so nothing checks what does arrive.',
222
- ' A card type the model is never told about and that nothing validates is a silent hole.',
223
- ' Fix: give each one a `schema`. If the type is populated by your own code and never by a',
224
- " model, say so with `onIncomplete: 'silent'`; use `onIncomplete: 'throw'` to make it fatal.",
225
- ].join('\n');
226
- }
227
-
228
- /**
229
- * Declare the card types this app renders, once, for both ends.
230
- *
231
- * @throws {TypeError} if `use` names something that is not a built-in card type (a
232
- * typo, or a custom type that belongs in `custom`), if a custom key is empty, or if
233
- * `onIncomplete: 'throw'` and a custom type has no schema.
234
- */
235
- export function createCardRegistry(spec: CardRegistrySpec = {}): CardRegistry {
236
- // A plain typeof check rather than the `isRecord` predicate used everywhere else in
237
- // this file. `isRecord` narrows to `Record<string, unknown>`, and intersecting that
238
- // with `CardRegistrySpec` makes the INDEX SIGNATURE win over the declared members:
239
- // `spec.use` becomes `unknown`, `spec.use ?? […]` becomes `{}`, and the rest of the
240
- // function loses its types while still compiling in places. Measured, not guessed —
241
- // it produced seven `tsc` errors on the first pass of this file.
242
- if (typeof spec !== 'object' || spec === null || Array.isArray(spec)) {
243
- throw new TypeError('createCardRegistry: expected a spec object, e.g. createCardRegistry({ use: ["confirm"] })');
244
- }
245
-
246
- // `cardSchemas` is read HERE, inside the function, for the reason `builtInSchemas()`
247
- // in tool-defs.ts spells out: ./index re-exports this module and this module imports
248
- // back out of it, a real ESM cycle that is safe only while the read happens after
249
- // both module bodies have evaluated. Do not hoist it to a module-scope const.
250
- const builtInSource = cardSchemas;
251
-
252
- const useList = spec.use ?? (Object.keys(builtInSource) as CardSchemaName[]);
253
- const unknownUse = useList.filter((t) => !isCardSchemaName(t));
254
- if (unknownUse.length > 0) {
255
- throw new TypeError(
256
- `createCardRegistry: \`use\` names ${unknownUse.length} type(s) that are not built in: ` +
257
- `${unknownUse.map((t) => `"${t}"`).join(', ')}. ` +
258
- `The built-in types are ${Object.keys(builtInSource).join(', ')}. ` +
259
- 'A card type of your own goes in `custom`, with its schema, not in `use`.',
260
- );
261
- }
262
-
263
- // Deduped and put back into cardSchemas order, so two registries listing the same
264
- // types in a different order produce byte-identical tool arrays.
265
- const used = new Set(useList);
266
- const builtIn = (Object.keys(builtInSource) as CardSchemaName[]).filter((t) => used.has(t));
267
-
268
- const customSpecs = spec.custom ?? {};
269
- const customNames = Object.keys(customSpecs);
270
- const emptyKey = customNames.find((n) => n.trim().length === 0);
271
- if (emptyKey !== undefined) {
272
- throw new TypeError('createCardRegistry: a custom card type name must be a non-empty string; it becomes `CardEnvelope.type` and the `kai_<type>` tool name.');
273
- }
274
-
275
- const schemas: Record<string, CardSchema> = {};
276
- for (const type of builtIn) schemas[type] = builtInSource[type];
277
-
278
- const descriptions: Record<string, string> = {};
279
- const tags: CardTagMap = {};
280
- const components: CardComponentMap = {};
281
- const validationSchemas: Record<string, JsonSchema> = {};
282
- const incomplete: string[] = [];
283
-
284
- for (const type of customNames) {
285
- const entry: CustomCardSpec = customSpecs[type];
286
- // Same reason as the `spec` check above: narrowing with `isRecord` here would swap
287
- // `CustomCardSpec`'s members for an index signature and lose `component`'s type.
288
- if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {
289
- throw new TypeError(`createCardRegistry: custom card type "${type}" must be an object, e.g. { schema, tag }.`);
290
- }
291
- // A custom entry OVERRIDES a built-in of the same name rather than colliding with
292
- // it, matching mergeCardTags/mergeCardComponents where the consumer wins. That is
293
- // how you replace our confirm card with yours and still get one tool definition.
294
- if (isRecord(entry.schema)) {
295
- schemas[type] = entry.schema as CardSchema;
296
- validationSchemas[type] = entry.schema as JsonSchema;
297
- } else {
298
- // No schema: keep it out of `schemas` so `cardTools` skips it with no special
299
- // case over there, and record it so the policy below can speak up.
300
- //
301
- // The `delete` is not dead code. It fires when a custom entry SHADOWS a `use`d
302
- // built-in without supplying a schema (`use: ['confirm']` plus
303
- // `custom: { confirm: { tag: 'my-confirm' } }`). Keeping our confirm schema there
304
- // would hand the model a shape describing OUR card while the developer's card
305
- // renders it, which is the drift this whole contract exists to prevent. Dropping
306
- // it instead puts the type in `incomplete`, where it gets said out loud.
307
- delete schemas[type];
308
- incomplete.push(type);
309
- }
310
- if (typeof entry.tag === 'string' && entry.tag.length > 0) tags[type] = entry.tag;
311
- if (typeof entry.component === 'function') components[type] = entry.component;
312
- if (typeof entry.description === 'string' && entry.description.length > 0) {
313
- descriptions[type] = entry.description;
314
- }
315
- }
316
-
317
- if (incomplete.length > 0) {
318
- const policy: IncompletePolicy = spec.onIncomplete ?? 'warn';
319
- const message = warnIncomplete(incomplete);
320
- if (policy === 'throw') throw new TypeError(message);
321
- // WHY THIS WARNS UNCONDITIONALLY RATHER THAN ONLY IN DEV.
322
- // ------------------------------------------------------
323
- // There is no `process.env.NODE_ENV` / `import.meta.env` convention anywhere in
324
- // this package's src/, and the emit-contract plan rejected introducing one for
325
- // exactly this shape of thing: a stripping contract has to hold across seven
326
- // consumer bundlers on a PRE-BUILT dist, where substitution into node_modules is
327
- // not guaranteed, and getting it wrong means the developer's laptop looks fine
328
- // while production is silently the broken one. The same argument applies here,
329
- // and the cost side is far smaller than it was there: a registry is built ONCE at
330
- // module load, not per render, so this is one line per process and not a hot path.
331
- // `onIncomplete: 'silent'` is the escape hatch, and it is a word you have to type.
332
- //
333
- // `!== 'silent'` rather than `=== 'warn'`, so an unrecognised policy is LOUD.
334
- // TypeScript rejects one, but this is shipped JS a consumer can call untyped, and
335
- // `onIncomplete: 'quiet'` reaching the silent branch would be a typo that disables
336
- // the warning about a silent hole. Defaulting the unknown case to noise is the only
337
- // direction that fails safe.
338
- if (policy !== 'silent') console.warn(message);
339
- }
340
-
341
- const frozenValidationSchemas = Object.freeze({ ...validationSchemas });
342
-
343
- return Object.freeze({
344
- schemas: Object.freeze(schemas),
345
- descriptions: Object.freeze(descriptions),
346
- tags: Object.freeze(tags),
347
- components: Object.freeze(components),
348
- types: Object.freeze([...builtIn, ...customNames]),
349
- builtIn: Object.freeze(builtIn),
350
- custom: Object.freeze([...customNames]),
351
- incomplete: Object.freeze([...incomplete]),
352
- validationSchemas: frozenValidationSchemas,
353
- validate: (type: string, data: unknown) => validateCardData(type, data, frozenValidationSchemas),
354
- });
355
- }