@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,398 +0,0 @@
1
- import type { Integration } from '../types';
2
-
3
- const vercelAiSdk: Integration = {
4
- id: 'vercel-ai-sdk',
5
- title: 'Vercel AI SDK',
6
- category: 'framework',
7
- language: 'ts',
8
- streamFormat: 'ai-sdk',
9
- envVars: ['AI_GATEWAY_API_KEY'],
10
- // No per-framework templates: the handler below is web-standard, so the
11
- // scaffolder wraps it in the target framework's own route declaration.
12
- routeTemplates: {},
13
- webRoute: `import { dynamicTool, jsonSchema, streamText } from 'ai';
14
- import type {
15
- AssistantContent,
16
- FilePart,
17
- JSONSchema7,
18
- ModelMessage,
19
- SystemModelMessage,
20
- ToolResultPart,
21
- ToolSet,
22
- UserContent,
23
- } from 'ai';
24
-
25
- // Next.js only: add \`export const maxDuration = 30\` to the route file to allow
26
- // long streaming responses. It is a Next route-segment config, not part of the
27
- // handler, so it lives in the file rather than in here.
28
-
29
- /**
30
- * The model, PINNED — and deliberately NOT read off the request body.
31
- *
32
- * Change THIS LINE to change the model; it is the only place one is named. The
33
- * AI Gateway takes a \`creator/model-name\` string, so any id it routes works
34
- * here without touching another import.
35
- *
36
- * Why it is not forwarded from the client, unlike the openai / openrouter /
37
- * anthropic routes:
38
- *
39
- * · Those three POST to ONE host with ONE id space, so the scaffold can seed a
40
- * valid default. The Gateway is a router across every vendor's id space at
41
- * once, so there is no default that is right for it — only one vendor's guess
42
- * baked into a provider-agnostic template.
43
- * · A forwarded model id on a \`needs-proxy\` route is a spend lever handed to
44
- * anything that can POST here, and the Gateway bills per token per model.
45
- *
46
- * WHY THIS ID. It is the one this route has actually been driven against live —
47
- * text, a single tool call and a multi-round tool loop, through the Gateway —
48
- * and, unlike a frontier default, it ANSWERS ON A FREE GATEWAY ACCOUNT. A paid
49
- * id fails a first \`npm run dev\` with
50
- * \`Free tier users do not have access to this model\`, which reads as a broken
51
- * scaffold rather than as a billing setting. It also supports tools and
52
- * reasoning, so the two things this route re-frames are reachable by default,
53
- * and it is cheaper than gpt-4o by roughly two orders of magnitude.
54
- */
55
- const MODEL = 'openai/gpt-oss-120b';
56
-
57
- /**
58
- * One attachment to an AI SDK FilePart.
59
- *
60
- * \`data\` takes the BARE shorthand — a base64 string, or a URL object for a
61
- * remote file — rather than the newer tagged \`{ type: 'data' | 'url' }\` form.
62
- * Both are accepted by the installed SDK; the shorthand is also what AI SDK v5
63
- * and v6 accept, so this route keeps compiling if the app pins an older \`ai\`.
64
- *
65
- * Images arrive as \`image_url\` and become FileParts too. \`ImagePart\` still
66
- * exists but is deprecated in favour of exactly this.
67
- */
68
- function toFilePart(part: Extract<WirePart, { kind: 'file' }>): FilePart {
69
- return {
70
- type: 'file',
71
- mediaType: part.mediaType,
72
- ...(part.filename === undefined ? {} : { filename: part.filename }),
73
- data: part.source.type === 'data' ? part.source.data : new URL(part.source.url),
74
- };
75
- }
76
-
77
- // The kit's wire format is OpenAI-shaped (tool_calls on the assistant message,
78
- // a flat content string on the tool message). The AI SDK's ModelMessage is not:
79
- // a tool call is a CONTENT PART on the assistant message, and a tool result is a
80
- // tagged output union, not a bare string. Converting rather than casting is the
81
- // point — a cast would compile but hand the SDK the wrong shape at runtime.
82
- function toModelMessages(messages: ChatRequestBody['messages']): ModelMessage[] {
83
- return messages.map((message): ModelMessage => {
84
- switch (message.role) {
85
- // A system prompt is text-only on every wire, so the array form collapses.
86
- case 'system':
87
- return { role: 'system', content: wireText(message.content) };
88
- case 'user': {
89
- const parts = wireParts(message.content);
90
- // Plain string for an ordinary turn: identical to what this route sent
91
- // before attachments existed, and the shape the SDK docs lead with.
92
- if (parts.every((p) => p.kind === 'text')) {
93
- return { role: 'user', content: wireText(message.content) };
94
- }
95
- const content: UserContent = parts.map((p) =>
96
- p.kind === 'text' ? { type: 'text' as const, text: p.text } : toFilePart(p),
97
- );
98
- return { role: 'user', content };
99
- }
100
- case 'tool': {
101
- const result: ToolResultPart = {
102
- type: 'tool-result',
103
- toolCallId: message.tool_call_id ?? '',
104
- toolName: message.name ?? '',
105
- output: { type: 'text', value: wireText(message.content) },
106
- };
107
- return { role: 'tool', content: [result] };
108
- }
109
- case 'assistant': {
110
- const text = wireText(message.content);
111
- if (!message.tool_calls?.length) return { role: 'assistant', content: text };
112
- const content: AssistantContent = [];
113
- if (text) content.push({ type: 'text', text });
114
- for (const call of message.tool_calls) {
115
- content.push({
116
- type: 'tool-call',
117
- toolCallId: call.id,
118
- toolName: call.function.name,
119
- input: JSON.parse(call.function.arguments),
120
- });
121
- }
122
- return { role: 'assistant', content };
123
- }
124
- }
125
- });
126
- }
127
-
128
- /** The OpenAI function-calling envelope the front end sends, narrowed from
129
- * \`unknown[]\`. Declared as this integration's \`clientToolFormat\`. */
130
- type OpenAIFunctionTool = {
131
- function?: { name?: string; description?: string; parameters?: unknown };
132
- };
133
-
134
- /**
135
- * OpenAI function schemas -> the AI SDK's own ToolSet.
136
- *
137
- * \`dynamicTool\` is the helper for a schema known only at RUNTIME. The ordinary
138
- * \`tool()\` infers its input type from a Zod schema written in the route, which
139
- * a list arriving in the request body cannot have.
140
- *
141
- * NO \`execute\`, deliberately. A tool the SDK can run makes the ROUTE the loop
142
- * owner: streamText would call it, feed the result back and answer in a single
143
- * response, so the tool call would never reach the browser and \`<kai-tool>\`
144
- * would have nothing to render. Without \`execute\` the SDK emits the call and
145
- * stops, which is the contract the kit's front end already implements — run the
146
- * tool, \`applyToolOutput\`, POST the thread again.
147
- */
148
- function toToolSet(tools: ChatRequestBody['tools']): ToolSet | undefined {
149
- if (!tools?.length) return undefined;
150
- const out: ToolSet = {};
151
- for (const raw of tools) {
152
- const fn = (raw as OpenAIFunctionTool).function;
153
- if (!fn?.name) continue;
154
- out[fn.name] = dynamicTool({
155
- description: fn.description ?? '',
156
- inputSchema: jsonSchema((fn.parameters as JSONSchema7 | undefined) ?? { type: 'object' }),
157
- });
158
- }
159
- return Object.keys(out).length > 0 ? out : undefined;
160
- }
161
-
162
- /** AI SDK finish reasons -> OpenAI's spelling. They agree on 'stop', 'length'
163
- * and 'error' and disagree on the other two, and readOpenAIStream's table reads
164
- * OpenAI's — so an unmapped 'tool-calls' normalises to 'other' and the turn
165
- * stops saying why it stopped. */
166
- const FINISH_REASONS: Record<string, string> = {
167
- 'tool-calls': 'tool_calls',
168
- 'content-filter': 'content_filter',
169
- };
170
-
171
- async function chatHandler(request: Request): Promise<Response> {
172
- let chatBody: ChatRequestBody;
173
- try {
174
- chatBody = await readChatRequest(request);
175
- } catch (error) {
176
- return toChatErrorResponse(error);
177
- }
178
- const { messages, tools } = chatBody;
179
- const toolSet = toToolSet(tools);
180
- const prompt = toModelMessages(messages);
181
-
182
- // THE SYSTEM TURN DOES NOT GO IN \`messages\`, and this is the one that costs a
183
- // live run to find. \`SystemModelMessage\` is still part of the \`ModelMessage\`
184
- // union, so a system entry in this array TYPECHECKS — and then \`ai\` v7's
185
- // \`standardizePrompt\` throws \`InvalidPromptError: System messages are not
186
- // allowed in the prompt or messages fields. Use the instructions option
187
- // instead.\` The kit's own encoder puts the system prompt at \`messages[0]\`, so
188
- // that is every single turn of a scaffolded app, not an edge case.
189
- //
190
- // Hoisted rather than joined into a string: \`instructions\` takes the message
191
- // array, so several system turns keep their order and their count.
192
- //
193
- // On \`ai\` v5/v6 there is no \`instructions\` option and a system message in
194
- // \`messages\` is correct — drop this split and pass \`prompt\` straight through
195
- // if you pin an older SDK.
196
- const instructions = prompt.filter((m): m is SystemModelMessage => m.role === 'system');
197
- const conversation = prompt.filter((m) => m.role !== 'system');
198
-
199
- // \`streamText\` is not awaited: it returns synchronously and does its work as
200
- // the stream is iterated. Prompt validation is part of that work, so an
201
- // invalid prompt surfaces from \`for await (… of result.fullStream)\` below
202
- // rather than from this line — which is why the catch that reports it lives
203
- // in the stream and not around this call. Confirmed by observation: a rejected
204
- // prompt reached the browser as an in-band error frame, not as a 500.
205
- const result = streamText({
206
- model: MODEL, // AI Gateway id; needs AI_GATEWAY_API_KEY
207
- ...(instructions.length > 0 ? { instructions } : {}),
208
- messages: conversation,
209
- ...(toolSet ? { tools: toolSet } : {}),
210
- });
211
-
212
- const encoder = new TextEncoder();
213
-
214
- // OpenAI correlates tool-call fragments by their POSITION in the tool_calls
215
- // array; the SDK identifies each call by id and never sends a position. So one
216
- // is derived from the other, in first-seen order, and every fragment of a call
217
- // carries the same number. Getting this wrong does not throw — the fragments
218
- // land on the wrong call and the arguments come out as spliced JSON.
219
- const toolIndex = new Map<string, number>();
220
- const indexOf = (id: string): number => {
221
- const known = toolIndex.get(id);
222
- if (known !== undefined) return known;
223
- const next = toolIndex.size;
224
- toolIndex.set(id, next);
225
- return next;
226
- };
227
- // How many argument characters a call streamed. \`tool-call\` re-sends the whole
228
- // input at the end, so emitting it unconditionally would DOUBLE the arguments
229
- // of every call that streamed — and skipping it unconditionally would empty
230
- // the arguments of any provider that does not stream them. Neither is safe to
231
- // assume, so the decision is made per call from what actually arrived.
232
- const streamedArgs = new Map<string, number>();
233
-
234
- const sse = new ReadableStream({
235
- async start(controller) {
236
- const send = (chunk: unknown): void => {
237
- controller.enqueue(encoder.encode(\`data: \${JSON.stringify(chunk)}\\n\\n\`));
238
- };
239
- try {
240
- // fullStream, NOT textStream. textStream is text deltas only: a tool call
241
- // or a reasoning block goes past it silently, so a route built on it
242
- // emits a plain answer and nothing else however the model replied.
243
- for await (const part of result.fullStream) {
244
- switch (part.type) {
245
- case 'text-delta':
246
- send({ choices: [{ delta: { content: part.text } }] });
247
- break;
248
-
249
- case 'reasoning-delta':
250
- send({ choices: [{ delta: { reasoning: part.text } }] });
251
- break;
252
-
253
- // The call is ANNOUNCED here, before its arguments exist, which is
254
- // what lets <kai-tool> open a panel with the tool's name in it while
255
- // the arguments are still being written.
256
- case 'tool-input-start':
257
- streamedArgs.set(part.id, 0);
258
- send({
259
- choices: [{
260
- delta: {
261
- tool_calls: [{
262
- index: indexOf(part.id),
263
- id: part.id,
264
- type: 'function',
265
- function: { name: part.toolName, arguments: '' },
266
- }],
267
- },
268
- }],
269
- });
270
- break;
271
-
272
- case 'tool-input-delta':
273
- streamedArgs.set(part.id, (streamedArgs.get(part.id) ?? 0) + part.delta.length);
274
- send({
275
- choices: [{
276
- delta: { tool_calls: [{ index: indexOf(part.id), function: { arguments: part.delta } }] },
277
- }],
278
- });
279
- break;
280
-
281
- case 'tool-call':
282
- // Only when nothing streamed: see \`streamedArgs\`.
283
- if ((streamedArgs.get(part.toolCallId) ?? 0) === 0) {
284
- send({
285
- choices: [{
286
- delta: {
287
- tool_calls: [{
288
- index: indexOf(part.toolCallId),
289
- id: part.toolCallId,
290
- type: 'function',
291
- function: {
292
- name: part.toolName,
293
- arguments: JSON.stringify(part.input ?? {}),
294
- },
295
- }],
296
- },
297
- }],
298
- });
299
- }
300
- break;
301
-
302
- // One frame carries both, the way chat-completions sends them.
303
- // \`reasoning_tokens\` is the number that proves thinking happened even
304
- // when the provider streamed no reasoning text.
305
- case 'finish':
306
- send({
307
- choices: [{
308
- delta: {},
309
- finish_reason: FINISH_REASONS[part.finishReason] ?? part.finishReason,
310
- }],
311
- usage: {
312
- prompt_tokens: part.totalUsage.inputTokens,
313
- completion_tokens: part.totalUsage.outputTokens,
314
- total_tokens: part.totalUsage.totalTokens,
315
- completion_tokens_details: {
316
- reasoning_tokens: part.totalUsage.outputTokenDetails.reasoningTokens,
317
- },
318
- },
319
- });
320
- break;
321
-
322
- // An error the SDK caught mid-stream. The status is long spent, so it
323
- // goes IN BAND like the catch below.
324
- case 'error':
325
- send({
326
- error: {
327
- message: part.error instanceof Error ? part.error.message : String(part.error),
328
- },
329
- });
330
- break;
331
-
332
- // Everything else — text-start/end, tool-input-end, sources, files,
333
- // step boundaries, raw provider frames — has no OpenAI-wire spelling
334
- // and is dropped. \`source\` is the one worth knowing about: map it to
335
- // \`delta.annotations[].url_citation\` if your model cites its sources.
336
- default:
337
- break;
338
- }
339
- }
340
- } catch (err) {
341
- // The status is spent by the time the SDK fails — the headers went out
342
- // with the first byte — so report it IN BAND. readOpenAIStream lands
343
- // this on turn.error and keeps whatever streamed before it. Without it a
344
- // failed key is an empty bubble and nothing in the console.
345
- const message = err instanceof Error ? err.message : 'Model stream failed';
346
- send({ error: { message } });
347
- }
348
- controller.enqueue(encoder.encode('data: [DONE]\\n\\n'));
349
- controller.close();
350
- },
351
- });
352
-
353
- return new Response(sse, {
354
- status: 200,
355
- headers: {
356
- 'Content-Type': 'text/event-stream; charset=utf-8',
357
- // no-transform stops a proxy buffering the stream into one blob.
358
- 'Cache-Control': 'no-cache, no-transform',
359
- Connection: 'keep-alive',
360
- },
361
- });
362
- }`,
363
- streamMapping:
364
- "The Vercel AI SDK's toUIMessageStreamResponse() and toTextStreamResponse() don't emit OpenAI-format SSE, so the route re-frames the stream itself and readOpenAIStream from @kitn.ai/ui/wire parses it exactly as it does every other integration. Iterate result.fullStream, NOT result.textStream: textStream carries text deltas only, so a route built on it emits a plain answer however the model replied and drops every tool call and every reasoning block silently. fullStream yields typed parts: text-delta.text -> delta.content, reasoning-delta.text -> delta.reasoning, tool-input-start plus its tool-input-delta fragments -> delta.tool_calls, finish -> finish_reason plus a usage frame, error -> an in-band {error:{message}}. Two traps. (1) OpenAI correlates tool-call fragments by their POSITION in the tool_calls array and the SDK only ever gives an id, so the route keeps an id -> index map; passing anything else through as the index splices one call's arguments into another. (2) fullStream sends the complete input AGAIN on the tool-call part after streaming it in fragments, so emitting both doubles the arguments — the route tracks how much each call streamed and emits the tool-call part only for a provider that streamed none. Parts with no OpenAI spelling (text-start/end, tool-input-end, step boundaries, raw) are dropped; source parts have one — delta.annotations[].url_citation — and are left unmapped because the SDK's Source union carries document sources a url_citation cannot express. On the REQUEST side the trap that only a live run finds: ai v7 REFUSES a system message inside `messages` (InvalidPromptError, 'Use the instructions option instead') even though SystemModelMessage is still in the ModelMessage union and therefore typechecks — and the kit's encoder puts the system prompt at messages[0], so that is every turn. Hoist system turns into `instructions` and pass the rest as `messages`. That failure arrives from ITERATING fullStream, not from the streamText() call — streamText returns synchronously and validates as the stream is read — so the in-band catch around the loop is what reports it, and it reaches the browser as an error frame rather than as a 500.",
365
- runNote:
366
- "Set AI_GATEWAY_API_KEY for the AI Gateway (string model id form: creator/model-name). The route pins `const MODEL = 'openai/gpt-oss-120b'` — one line, at the top, and any id the Gateway routes works in it. That id is pinned because it answers on a FREE Gateway account: most ids (deepseek/*, meta/*, anthropic/*) return `Free tier users do not have access to this model` or a free-tier rate limit until the account has paid credits, which looks like a broken scaffold rather than a billing setting. For direct provider access, import its provider package (e.g. @ai-sdk/openai) and set the corresponding key (e.g. OPENAI_API_KEY). The tools the front end posts become `dynamicTool`s with NO `execute`, which is what keeps the tool loop in the app: the SDK emits the call and stops, the app runs it, renders it in <kai-tool> and posts the thread back. Give a tool an `execute` and the SDK runs the whole loop server-side, so nothing reaches the browser but the final sentence.",
367
- docsSlug: 'integrations/vercel-ai-sdk',
368
- // `tools` only. `model` is deliberately NOT forwarded — the route pins it in
369
- // one named const, and see that const's comment for why the Gateway is the one
370
- // host where a client-supplied id has no correct default. The catalog check
371
- // agrees from the other direction: `every integration that forwards a model
372
- // emits one valid for the host it POSTs to` reads the host off the route's own
373
- // fetch(), and this route makes no fetch call at all — the SDK owns the
374
- // transport — so a forwarded model here could not be validated against
375
- // anything.
376
- forwardsFromClient: ['tools'],
377
- // 'openai': the ROUTE's request contract, not the SDK's own. `toToolSet` reads
378
- // `raw.function.name` / `.function.parameters` off each entry — the OpenAI
379
- // function-calling envelope — and rebuilds it as a `dynamicTool` with a
380
- // `jsonSchema()` input. Sending the SDK's own tool shape from the client would
381
- // leave `.function` undefined and every tool would arrive nameless.
382
- clientToolFormat: 'openai',
383
- // `ai` only. A direct provider (e.g. @ai-sdk/openai) is the alternative path
384
- // described in runNote, not what this route imports, so it is not listed: the
385
- // rule is what the emitted code actually imports.
386
- deps: { npm: ['ai'], pip: [] },
387
- // Grep the route for a key and you find NOTHING — no header, no process.env.
388
- // The AI SDK reads AI_GATEWAY_API_KEY out of the environment itself, inside
389
- // streamText(). This is the case that makes inference from route source
390
- // unsafe and the declaration necessary; `envVars` is what the schema's safety
391
- // net can still see.
392
- keyExposure: 'needs-proxy',
393
- // The AI Gateway is a remote HTTPS endpoint reached through the `ai` package,
394
- // which is an ordinary npm dependency (see `deps`). Nothing to start.
395
- outOfBand: 'none',
396
- };
397
-
398
- export default vercelAiSdk;
@@ -1,12 +0,0 @@
1
- // `*.css?raw` — Vite inlines the file's TEXT as a string at build time.
2
- //
3
- // tools/theme.ts uses it to read the real `--kai-*` token names out of
4
- // theme.css instead of restating them. The declaration lives here rather than
5
- // coming from `vite/client` because tsconfig.mcp.json deliberately runs with
6
- // `types: ["node"]` and no DOM — this is a Node bundle that emits HTML as
7
- // strings. One narrow module pattern is cheaper than pulling the whole browser
8
- // client typing into that pass.
9
- declare module '*.css?raw' {
10
- const content: string;
11
- export default content;
12
- }