@kitn.ai/ui 0.21.0 → 0.22.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 (243) hide show
  1. package/dist/components/chat-thread.d.ts +9 -0
  2. package/dist/{create-tween-D3Y5qiij.js → create-tween-COnPwAQN.js} +1 -1
  3. package/dist/{create-tween-DGKY1FDY.js → create-tween-DmTUaXWE.js} +1 -1
  4. package/dist/{create-tween-paho5Rh-.js → create-tween-qs-jjvNA.js} +1 -1
  5. package/dist/custom-elements.json +43 -7
  6. package/dist/elements/agent-card.js +1 -1
  7. package/dist/elements/artifact.js +1 -1
  8. package/dist/elements/attachments.js +1 -1
  9. package/dist/elements/audio-visualizer.js +1 -1
  10. package/dist/elements/avatar.js +1 -1
  11. package/dist/elements/badge.js +1 -1
  12. package/dist/elements/button.js +1 -1
  13. package/dist/elements/card.js +1 -1
  14. package/dist/elements/cards.js +1 -1
  15. package/dist/elements/chain-of-thought.js +1 -1
  16. package/dist/elements/chat-scope-picker.js +1 -1
  17. package/dist/elements/chat-workspace.js +1 -1
  18. package/dist/elements/chat.js +1 -1
  19. package/dist/elements/checkpoint.js +1 -1
  20. package/dist/elements/choice.js +1 -1
  21. package/dist/elements/chunks/{Icon-C-2LvGDG.js → Icon-CHG5z5L7.js} +1 -1
  22. package/dist/elements/chunks/{action-icons-CaYoImEk.js → action-icons-BAtCEEgg.js} +1 -1
  23. package/dist/elements/chunks/arrow-left-CFPTeL1Y.js +1 -0
  24. package/dist/elements/chunks/{artifact-BBIscOxJ.js → artifact-fBZOE4SO.js} +1 -1
  25. package/dist/elements/chunks/{attachments-BB56zoji.js → attachments-DpYMe5VQ.js} +1 -1
  26. package/dist/elements/chunks/{audio-visualizer-BxOx4THz.js → audio-visualizer-DFwzAcuL.js} +1 -1
  27. package/dist/elements/chunks/{badge-SxLSZ19R.js → badge-D6zodm6E.js} +1 -1
  28. package/dist/elements/chunks/{button-CmkUkz6c.js → button-C42vrGvO.js} +1 -1
  29. package/dist/elements/chunks/{card-renderer-Db4ffkWv.js → card-renderer-DMZsSuvU.js} +1 -1
  30. package/dist/elements/chunks/{chat-thread-B3Ks-cKr.js → chat-thread-CNNEhol-.js} +1 -1
  31. package/dist/elements/chunks/check-7Q3K-iXE.js +1 -0
  32. package/dist/elements/chunks/chevron-down-CpNYLn7E.js +1 -0
  33. package/dist/elements/chunks/chevron-right-DrH85Fha.js +1 -0
  34. package/dist/elements/chunks/{choice-card-Q9cYYDyM.js → choice-card-YoWjpsFV.js} +1 -1
  35. package/dist/elements/chunks/circle-C9KRjKYv.js +1 -0
  36. package/dist/elements/chunks/circle-check-Dmi7Y4zw.js +1 -0
  37. package/dist/elements/chunks/{circle-x-D0MEfxOM.js → circle-x-QIxXda6k.js} +1 -1
  38. package/dist/elements/chunks/{code-block-C8VzAraE.js → code-block-CqeugReY.js} +1 -1
  39. package/dist/elements/chunks/{collapsible-Cvj61obE.js → collapsible-sTv-_5lF.js} +1 -1
  40. package/dist/elements/chunks/{composer-D86ztyL0.js → composer-ldQyeVEB.js} +1 -1
  41. package/dist/elements/chunks/{confirm-card-BdyDAGLw.js → confirm-card-C0RNOwfn.js} +1 -1
  42. package/dist/elements/chunks/context-5qgypNHC.js +1 -0
  43. package/dist/elements/chunks/conversation-list-DLzOacXz.js +1 -0
  44. package/dist/elements/chunks/{create-tween-C_A_B638.js → create-tween-V4TXZ93X.js} +1 -1
  45. package/dist/elements/chunks/default-input-DeeRSDHc.js +1 -0
  46. package/dist/elements/chunks/{define-BzPnNsXg.js → define-lE-QvQFn.js} +1 -1
  47. package/dist/elements/chunks/{disclosure-DVKsoc1F.js → disclosure-DZSa9jog.js} +1 -1
  48. package/dist/elements/chunks/{download-BjA54IMJ.js → download-B2ZmnGqW.js} +1 -1
  49. package/dist/elements/chunks/{dropdown-BjVVHWXH.js → dropdown-R3B7cSRE.js} +1 -1
  50. package/dist/elements/chunks/{ellipsis-BNedmqfi.js → ellipsis-BmxceY4l.js} +1 -1
  51. package/dist/elements/chunks/{embed-DQsl4XEq.js → embed-BVrtTZPo.js} +1 -1
  52. package/dist/elements/chunks/{external-link-Di-dw2CU.js → external-link-BbdR7YO7.js} +1 -1
  53. package/dist/elements/chunks/{file-text-B3sAODCV.js → file-text-D7dijo1A.js} +1 -1
  54. package/dist/elements/chunks/{file-tree-Dgto-bMn.js → file-tree-0upJ5jeb.js} +1 -1
  55. package/dist/elements/chunks/{folder-D6rMadFV.js → folder-D8z58t7B.js} +1 -1
  56. package/dist/elements/chunks/{form-CILxvhQ7.js → form-p5BKJNw5.js} +1 -1
  57. package/dist/elements/chunks/{hover-card-BtiF4XiU.js → hover-card-CN9s2md5.js} +1 -1
  58. package/dist/elements/chunks/{icon-DKkmze3y.js → icon-CNiKP37E.js} +1 -1
  59. package/dist/elements/chunks/{info-CWRjZkuy.js → info-BSnuJiHI.js} +1 -1
  60. package/dist/elements/chunks/{input--QJBK6BA.js → input-BauDmzxX.js} +1 -1
  61. package/dist/elements/chunks/{kbd-C3zuKh8R.js → kbd-BlHJaP9b.js} +1 -1
  62. package/dist/elements/chunks/{link-BL5JA7Q0.js → link-DEi5iUWC.js} +1 -1
  63. package/dist/elements/chunks/{link-preview-CU37bbXh.js → link-preview-BaHyM6W4.js} +1 -1
  64. package/dist/elements/chunks/{loader-XmpyxyRH.js → loader-CmJG_Fkq.js} +1 -1
  65. package/dist/elements/chunks/{markdown-3Gv5UZ_o.js → markdown-D2jaMpCN.js} +1 -1
  66. package/dist/elements/chunks/{message-X5NZbq-W.js → message-C5UfXZ2Z.js} +1 -1
  67. package/dist/elements/chunks/{message-CnBA2OUt.js → message-CXWLmmLn.js} +1 -1
  68. package/dist/elements/chunks/message-square-hXylwsy0.js +1 -0
  69. package/dist/elements/chunks/{minimize-2-DwyrUTcM.js → minimize-2-C9ytZFMU.js} +1 -1
  70. package/dist/elements/chunks/model-switcher-CivGfD7-.js +1 -0
  71. package/dist/elements/chunks/{overlay-Cepd-KcS.js → overlay-DJL_sbOm.js} +1 -1
  72. package/dist/elements/chunks/{paperclip-CdwKjrlu.js → paperclip-CFaB8naM.js} +1 -1
  73. package/dist/elements/chunks/{progress-bar-DMVXBD3b.js → progress-bar-Br5SksfR.js} +1 -1
  74. package/dist/elements/chunks/{prompt-suggestion-Di_WZE_5.js → prompt-suggestion-CMIvtAhU.js} +1 -1
  75. package/dist/elements/chunks/{reasoning-D0jMch5u.js → reasoning-DpZcNzLq.js} +1 -1
  76. package/dist/elements/chunks/{resizable-1znbL1Gv.js → resizable-Q8i3T9a_.js} +1 -1
  77. package/dist/elements/chunks/{rotate-cw-DVhhgx8n.js → rotate-cw-B5IHCBFV.js} +1 -1
  78. package/dist/elements/chunks/{scroll-area-Bs4bFS1P.js → scroll-area-eLeydBje.js} +1 -1
  79. package/dist/elements/chunks/{scroll-button-Bet5NLc4.js → scroll-button-DWbz0yA1.js} +1 -1
  80. package/dist/elements/chunks/{separator-C5Gh8qGC.js → separator-Xic78AD_.js} +1 -1
  81. package/dist/elements/chunks/{settings-5vmEFg0K.js → settings-B8H51pAx.js} +1 -1
  82. package/dist/elements/chunks/{settings-group-BWLB38kz.js → settings-group-CsG9eYLe.js} +1 -1
  83. package/dist/elements/chunks/{share-BZ3G_DaB.js → share-CNTx0z__.js} +1 -1
  84. package/dist/elements/chunks/{skeleton-DafPJQTp.js → skeleton-CLlHTcMI.js} +1 -1
  85. package/dist/elements/chunks/{source-D_qj_6uJ.js → source-BoVcU5ok.js} +1 -1
  86. package/dist/elements/chunks/{star-Cuv7j2IE.js → star-CxQVTVhI.js} +1 -1
  87. package/dist/elements/chunks/{store-C1StPHfW.js → store-CLtS5CUG.js} +1 -1
  88. package/dist/elements/chunks/{tasks-card-EyoBZfpA.js → tasks-card-CzlkLmUt.js} +1 -1
  89. package/dist/elements/chunks/{text-shimmer-D9gRSh34.js → text-shimmer-D5NhpIQ1.js} +1 -1
  90. package/dist/elements/chunks/{textarea-DuhtHfcm.js → textarea-x5Uxsmtm.js} +1 -1
  91. package/dist/elements/chunks/{thumbs-up-B9hwv43w.js → thumbs-up-UobcJnx9.js} +1 -1
  92. package/dist/elements/chunks/{toast-store-Bm3DUEDe.js → toast-store-BOfs9eXq.js} +1 -1
  93. package/dist/elements/chunks/{tool-CDtW7L0z.js → tool-Be6Dh_dt.js} +1 -1
  94. package/dist/elements/chunks/{tooltip-eB226mGK.js → tooltip-RxMxyCLF.js} +1 -1
  95. package/dist/elements/chunks/{triangle-alert-C1SNzTqK.js → triangle-alert-C4yxH2XN.js} +1 -1
  96. package/dist/elements/chunks/{use-card-resolution-YZh2MvI5.js → use-card-resolution-jva9ehH6.js} +1 -1
  97. package/dist/elements/chunks/{variant-aurora-Cj1F7D0l.js → variant-aurora-Dx4VRcjS.js} +1 -1
  98. package/dist/elements/chunks/{variant-custom-T9gpt7QE.js → variant-custom-Y1ZTWgEa.js} +1 -1
  99. package/dist/elements/chunks/{variant-wave-CxU9z-TE.js → variant-wave-B9gml9Cg.js} +1 -1
  100. package/dist/elements/chunks/{video-CK4R7Rus.js → video-CrPHsytT.js} +1 -1
  101. package/dist/elements/chunks/x-_-OPHept.js +1 -0
  102. package/dist/elements/coachmark.js +1 -1
  103. package/dist/elements/code-block.js +1 -1
  104. package/dist/elements/command.js +1 -1
  105. package/dist/elements/compare.js +1 -1
  106. package/dist/elements/composer.js +1 -1
  107. package/dist/elements/confirm-card.js +1 -1
  108. package/dist/elements/context-meter.js +1 -1
  109. package/dist/elements/conversation-list.js +1 -1
  110. package/dist/elements/default-input.d.ts +27 -0
  111. package/dist/elements/dialog.js +1 -1
  112. package/dist/elements/editable-label.js +1 -1
  113. package/dist/elements/embed.js +1 -1
  114. package/dist/elements/empty.js +1 -1
  115. package/dist/elements/feedback-bar.js +1 -1
  116. package/dist/elements/file-tree.js +1 -1
  117. package/dist/elements/file-upload.js +1 -1
  118. package/dist/elements/form.js +1 -1
  119. package/dist/elements/hover-card.js +1 -1
  120. package/dist/elements/icon.js +1 -1
  121. package/dist/elements/image.js +1 -1
  122. package/dist/elements/input.js +1 -1
  123. package/dist/elements/kbd.js +1 -1
  124. package/dist/elements/link-preview.js +1 -1
  125. package/dist/elements/loader.js +1 -1
  126. package/dist/elements/markdown.js +1 -1
  127. package/dist/elements/menu.js +1 -1
  128. package/dist/elements/message-skills.js +1 -1
  129. package/dist/elements/message.js +1 -1
  130. package/dist/elements/model-switcher.js +1 -1
  131. package/dist/elements/nav.js +1 -1
  132. package/dist/elements/notice.js +1 -1
  133. package/dist/elements/pane-group.js +1 -1
  134. package/dist/elements/pane.js +1 -1
  135. package/dist/elements/popover.js +1 -1
  136. package/dist/elements/progress-bar.js +1 -1
  137. package/dist/elements/prompt-dock.js +1 -1
  138. package/dist/elements/prompt-input.js +1 -1
  139. package/dist/elements/prompt-suggestions.js +1 -1
  140. package/dist/elements/reasoning.js +1 -1
  141. package/dist/elements/remote.js +1 -1
  142. package/dist/elements/resizable.js +1 -1
  143. package/dist/elements/response-stream.js +2 -2
  144. package/dist/elements/screen.js +1 -1
  145. package/dist/elements/scroll-area.js +1 -1
  146. package/dist/elements/scroll-button.js +1 -1
  147. package/dist/elements/search.js +1 -1
  148. package/dist/elements/segmented.js +1 -1
  149. package/dist/elements/separator.js +1 -1
  150. package/dist/elements/setting-item.js +1 -1
  151. package/dist/elements/settings-group.js +1 -1
  152. package/dist/elements/skeleton.js +1 -1
  153. package/dist/elements/slot-text.d.ts +51 -0
  154. package/dist/elements/slots.d.ts +5 -0
  155. package/dist/elements/source.js +1 -1
  156. package/dist/elements/status.js +1 -1
  157. package/dist/elements/switch.js +1 -1
  158. package/dist/elements/tabs.js +1 -1
  159. package/dist/elements/tasks.js +1 -1
  160. package/dist/elements/text-shimmer.js +1 -1
  161. package/dist/elements/thinking-bar.js +1 -1
  162. package/dist/elements/thread.js +1 -1
  163. package/dist/elements/toast.js +1 -1
  164. package/dist/elements/tool.js +1 -1
  165. package/dist/elements/tooltip.js +1 -1
  166. package/dist/elements/voice-input.js +1 -1
  167. package/dist/elements/voice-output.js +1 -1
  168. package/dist/elements.d.ts +12 -6
  169. package/dist/index.js +1535 -1487
  170. package/dist/index.server.js +2330 -2296
  171. package/dist/kai.es.js +1 -1
  172. package/dist/llms/llms-full.txt +12 -3
  173. package/dist/mcp.es.js +809 -75
  174. package/dist/react/index.d.ts +13 -3
  175. package/dist/react.js +14 -14
  176. package/dist/register-impl-AxIlqjo7.js +145 -0
  177. package/dist/{solid-BCJUQqwS.js → solid-BGYSJyHG.js} +4901 -4691
  178. package/dist/{solid-BdENBcEq.js → solid-Dt2nEwfl.js} +4406 -4320
  179. package/dist/solid.js +1 -1
  180. package/dist/solid.server.js +1 -1
  181. package/dist/{variant-aurora-DOb_o4pC.js → variant-aurora-B44X69AG.js} +1 -1
  182. package/dist/{variant-aurora-BKHHiOgL.js → variant-aurora-BRhV8Flk.js} +2 -2
  183. package/dist/{variant-aurora-1wMcXRUS.js → variant-aurora-Ds5ou9BH.js} +2 -2
  184. package/dist/{variant-custom-DWSSgmd2.js → variant-custom-B20FhtYj.js} +2 -2
  185. package/dist/{variant-custom-CJGB0Kbw.js → variant-custom-BvA1Schl.js} +1 -1
  186. package/dist/{variant-custom-Co0CkXJF.js → variant-custom-D6Rtvneb.js} +2 -2
  187. package/dist/{variant-wave-CEODq-9q.js → variant-wave-BUQtkryq.js} +1 -1
  188. package/dist/{variant-wave-C3-45cL6.js → variant-wave-BVYnqy9L.js} +2 -2
  189. package/dist/{variant-wave-jdXBnCUZ.js → variant-wave-DXC6_LcH.js} +2 -2
  190. package/dist/wire/encode.d.ts +79 -6
  191. package/dist/wire/files.d.ts +116 -0
  192. package/dist/wire/index.d.ts +3 -1
  193. package/dist/wire/media-types.d.ts +106 -0
  194. package/dist/wire.js +596 -368
  195. package/frameworks/react/index.tsx +9 -5
  196. package/llms-full.txt +12 -3
  197. package/package.json +2 -1
  198. package/src/agent-tooling/archetypes.ts +43 -12
  199. package/src/agent-tooling/integrations/anthropic.ts +29 -5
  200. package/src/agent-tooling/integrations/cloudflare.ts +5 -0
  201. package/src/agent-tooling/integrations/langgraph.ts +13 -0
  202. package/src/agent-tooling/integrations/mastra.ts +46 -5
  203. package/src/agent-tooling/integrations/mock.ts +4 -0
  204. package/src/agent-tooling/integrations/ollama.ts +7 -0
  205. package/src/agent-tooling/integrations/openai.ts +2 -0
  206. package/src/agent-tooling/integrations/openrouter.ts +2 -0
  207. package/src/agent-tooling/integrations/pi.ts +26 -1
  208. package/src/agent-tooling/integrations/pydantic-ai.ts +37 -3
  209. package/src/agent-tooling/integrations/vercel-ai-sdk.ts +42 -6
  210. package/src/agent-tooling/mcp/tools/scaffold.ts +853 -32
  211. package/src/agent-tooling/registry.ts +57 -0
  212. package/src/agent-tooling/types.ts +132 -0
  213. package/src/components/chat-thread.tsx +10 -1
  214. package/src/components/context.tsx +18 -12
  215. package/src/components/conversation-item.tsx +6 -0
  216. package/src/components/model-switcher.tsx +38 -8
  217. package/src/components/toast.tsx +6 -1
  218. package/src/elements/button.tsx +26 -3
  219. package/src/elements/chat.tsx +28 -2
  220. package/src/elements/default-input.tsx +128 -5
  221. package/src/elements/element-meta.json +30 -4
  222. package/src/elements/element-types.d.ts +12 -6
  223. package/src/elements/menu.tsx +30 -3
  224. package/src/elements/slot-text.ts +73 -0
  225. package/src/elements/slots.ts +10 -0
  226. package/src/index.ts +9 -5
  227. package/src/wire/encode.ts +229 -14
  228. package/src/wire/files.ts +342 -0
  229. package/src/wire/index.ts +21 -0
  230. package/src/wire/media-types.ts +344 -0
  231. package/dist/elements/chunks/arrow-left-Bb46H7w9.js +0 -1
  232. package/dist/elements/chunks/check-C8desc_h.js +0 -1
  233. package/dist/elements/chunks/chevron-down-DKtc2HNB.js +0 -1
  234. package/dist/elements/chunks/chevron-right-Dw4GPhwL.js +0 -1
  235. package/dist/elements/chunks/circle-BeokBsvB.js +0 -1
  236. package/dist/elements/chunks/circle-check-wJSqt859.js +0 -1
  237. package/dist/elements/chunks/context-WHDl-xSx.js +0 -1
  238. package/dist/elements/chunks/conversation-list-CdR14_Y4.js +0 -1
  239. package/dist/elements/chunks/default-input-CSZqUM81.js +0 -1
  240. package/dist/elements/chunks/message-square-CnpAm_P0.js +0 -1
  241. package/dist/elements/chunks/model-switcher-CclaJEHt.js +0 -1
  242. package/dist/elements/chunks/x-D1qx0aLd.js +0 -1
  243. package/dist/register-impl-bzrZ44ft.js +0 -145
package/src/wire/index.ts CHANGED
@@ -18,13 +18,34 @@ export { applyToolOutput, applyToolFailure, bufferText } from './sink-helpers';
18
18
  export { toOpenAIMessages, toAnthropicMessages, WireEncodeError } from './encode';
19
19
  export type {
20
20
  AnthropicContentBlock,
21
+ AnthropicEncodeOptions,
21
22
  AnthropicWireMessage,
23
+ FileEncodeOptions,
24
+ OpenAIContentPart,
22
25
  OpenAIEncodeOptions,
23
26
  OpenAIReasoningDetail,
24
27
  OpenAIToolCall,
25
28
  OpenAIWireMessage,
29
+ UnencodableFilePolicy,
26
30
  } from './encode';
27
31
 
32
+ // What the encoders CAN represent, published as a value.
33
+ //
34
+ // The point is not introspection. A consumer who wants their own file picker,
35
+ // their own validation and their own error copy can build all three off
36
+ // `encodableMediaTypes()` and `resolveMediaPolicy(...).decide(...)` without
37
+ // using our composer at all -- the kit states a fact about itself and the
38
+ // application decides what to do about it. `<kai-chat accept="...">` is a
39
+ // convenience over exactly this, not a separate mechanism.
40
+ export { encodableMediaTypes, resolveMediaPolicy } from './media-types';
41
+ export type {
42
+ EncodableKind,
43
+ MediaDecision,
44
+ MediaPolicy,
45
+ MediaPolicyOptions,
46
+ MediaTypeFilter,
47
+ } from './media-types';
48
+
28
49
  export { openaiChatFormat } from './formats/openai';
29
50
  export { anthropicMessagesFormat } from './formats/anthropic';
30
51
 
@@ -0,0 +1,344 @@
1
+ // THE media-type declaration. One table, read by every layer that has an
2
+ // opinion about attachments.
3
+ //
4
+ // WHY THIS FILE EXISTS AT ALL. Two features want the same knowledge: the
5
+ // composer needs to know what a user is allowed to stage, and the encoders need
6
+ // to know what they can turn into provider content. Those are the same set. When
7
+ // each grows its own copy they drift, and the drift is not theoretical -- it is
8
+ // the exact defect #186 fixed one layer down, where a composer happily staged a
9
+ // `blob:` URL that the encoder could not represent. So the set is declared ONCE,
10
+ // here, and both layers derive from it rather than restating it.
11
+ //
12
+ // THE BOUNDARY THIS DRAWS. The kit owns "what CAN be encoded" -- a fact about
13
+ // `encode.ts`, not a policy. The developer owns "what I want to ALLOW", and can
14
+ // only ever NARROW the kit's set, never widen it: widening would just move a
15
+ // provider 400 later in the request. That asymmetry is why the filter is a
16
+ // declarative list rather than a hook, and why `encodableMediaTypes()` is public.
17
+ //
18
+ // No I/O, like the rest of `wire/`. Pattern matching and, for text, decoding
19
+ // base64 that is already inline -- computation over bytes already in hand, never
20
+ // a fetch.
21
+
22
+ /** What a media type BECOMES on the wire. Named for the Anthropic block set,
23
+ * which is the narrower of the two: `text` / `image` / `document` and nothing
24
+ * else. There is no arbitrary-file block on either API, which is why a text
25
+ * file has to ride as text content and a `.zip` has no representation at all. */
26
+ export type EncodableKind = 'image' | 'document' | 'text';
27
+
28
+ // WHAT A BROWSER ACTUALLY CALLS A FILE -- ONE OBSERVATION, NOT A STANDING FACT.
29
+ //
30
+ // Observed 2026-08-13 (UTC), Chrome 151.0.7922.137, macOS 26.5 arm64, with the
31
+ // files handed to a real `<input type="file">` so the browser built every `File`
32
+ // itself. Re-run it rather than trusting it:
33
+ // node scripts/probe-file-media-types.mjs
34
+ //
35
+ // .txt text/plain .js text/javascript .png image/png
36
+ // .md text/markdown .css text/css .zip application/zip
37
+ // .csv text/csv .html text/html .pdf application/pdf
38
+ // .json application/json .sh text/x-sh
39
+ // .xml text/xml .py text/x-python-script
40
+ // .yaml application/x-yaml .yml application/x-yaml
41
+ // .ts .tsx .rs .go .sql .toml .log -> "" (the browser could not name them)
42
+ //
43
+ // THESE VALUES ARE PLATFORM-SPECIFIC. Nineteen of the twenty-two match macOS's
44
+ // own `preferredMIMEType`, so the browser is answering out of the OS type
45
+ // database and Linux and Windows will answer differently. Nothing returned
46
+ // `application/octet-stream` -- Chrome's failure mode here is the EMPTY STRING.
47
+ // (`.ts` is not a TypeScript file to macOS: it resolves to an MPEG-2
48
+ // transport-stream UTI, which carries no MIME string at all, which is why it
49
+ // comes back empty rather than as `video/mp2t`.)
50
+ //
51
+ // EXACTLY TWO THINGS BELOW REST ON THIS TABLE, and both survive it being wrong
52
+ // somewhere else:
53
+ // 1. `application/x-yaml` is a row because it was measured here. A platform
54
+ // that says something else does not make this row wrong, only incomplete.
55
+ // 2. Seven of the twenty-two extensions are the ones a developer is likeliest
56
+ // to attach to a coding chat, and the browser names NONE of them. That is
57
+ // why an unnamed file is decided by DECODING its bytes and never by reading
58
+ // its filename -- see `decide()`. Another OS moves WHICH rows come back
59
+ // empty; it cannot move the fact that some do.
60
+ // Anything else read off this table is being read too hard.
61
+
62
+ /**
63
+ * ★ THE DECLARATION. Everything else in this file, and both `accept` surfaces,
64
+ * are derived from this array. Adding a row teaches the encoder AND widens the
65
+ * composer's picker; deleting one narrows both. If you find yourself writing a
66
+ * second list of media types anywhere in this repo, delete it and read this.
67
+ *
68
+ * Patterns are HTML `accept` syntax: an exact type (`image/png`) or a subtype
69
+ * wildcard (`text/*`). File EXTENSIONS (`.md`) are deliberately not supported --
70
+ * they map to media types only by convention, and guessing is how a `.md` full
71
+ * of base64 becomes a 400. An extension in a developer's `accept` THROWS rather
72
+ * than matching nothing; a file the browser could not name is settled by
73
+ * decoding it. Neither path ever consults a filename.
74
+ *
75
+ * On the image list: JPEG, PNG, GIF and WebP are the four formats BOTH APIs
76
+ * document. SVG and BMP are the ones people actually try, and both are a 400 at
77
+ * request time, so they are absent on purpose.
78
+ *
79
+ * On the text list: `text/*` is the core, because a media type in that tree is
80
+ * text by definition of the tree. The `application/` rows are the judgement
81
+ * calls -- textual formats that IANA files outside `text/` for historical
82
+ * reasons, and that people genuinely attach. `application/json` and
83
+ * `application/xml` are the two obvious ones.
84
+ *
85
+ * On YAML, since it is two rows for one format: `application/x-yaml` is what
86
+ * Chrome hands back for a `.yaml` on macOS, MEASURED in the table above.
87
+ * `application/yaml` is the IANA-registered type (RFC 9512, 2024) and is what a
88
+ * correctly configured server sends, so it is here on REGISTRY grounds rather
89
+ * than on a measurement. `text/yaml` and `text/x-yaml` are in the wild too and
90
+ * need no row of their own: `text/*` already covers both.
91
+ */
92
+ const ENCODABLE: readonly { readonly pattern: string; readonly kind: EncodableKind }[] = [
93
+ { pattern: 'image/jpeg', kind: 'image' },
94
+ { pattern: 'image/png', kind: 'image' },
95
+ { pattern: 'image/gif', kind: 'image' },
96
+ { pattern: 'image/webp', kind: 'image' },
97
+ { pattern: 'application/pdf', kind: 'document' },
98
+ { pattern: 'text/*', kind: 'text' },
99
+ { pattern: 'application/json', kind: 'text' },
100
+ { pattern: 'application/xml', kind: 'text' },
101
+ { pattern: 'application/x-yaml', kind: 'text' },
102
+ { pattern: 'application/yaml', kind: 'text' },
103
+ ];
104
+
105
+ /**
106
+ * The media type an unnamed file gets once its BYTES have proven to be UTF-8
107
+ * text, and the type whose presence in the effective policy is what permits that
108
+ * proof to be attempted at all.
109
+ *
110
+ * `text/plain` is not a guess dressed up as a fact. It is the media type for
111
+ * "text, no further structure claimed", which is exactly what a successful
112
+ * decode establishes and the most any decode could ever establish. A `.rs` file
113
+ * arriving as `text/plain` is true; arriving as `text/x-rust` would be the
114
+ * filename talking.
115
+ */
116
+ export const UNNAMED_TEXT_MEDIA_TYPE = 'text/plain';
117
+
118
+ /**
119
+ * Media types that say nothing about the bytes they label.
120
+ *
121
+ * The empty string is what `File.type` is when the OS type database had no
122
+ * answer (seven of the twenty-two rows above). `application/octet-stream` is the
123
+ * same non-answer written down: RFC 2046 defines it as "arbitrary binary data",
124
+ * and it is what `FileReader.readAsDataURL` substitutes for an empty type --
125
+ * measured in Chrome 151 AND in the jsdom the unit suite runs on, both of which
126
+ * produce `data:application/octet-stream;base64,...` for a `File` whose `type`
127
+ * is `''`. So the same typeless file reaches the composer as `''` and reaches
128
+ * the encoder as `application/octet-stream`, and both spellings have to mean the
129
+ * same thing or the two layers disagree about one file.
130
+ */
131
+ const NAMES_NOTHING: readonly string[] = ['', 'application/octet-stream'];
132
+
133
+ /** A developer's narrowing filter. A comma-separated string (so it works as an
134
+ * HTML attribute under the `kai-` contract) or an array (so it composes in JS).
135
+ * Both spell the same thing; the string form is what `<kai-chat accept="...">`
136
+ * takes and what the `kai` MCP scaffolder can emit as data. */
137
+ export type MediaTypeFilter = string | readonly string[];
138
+
139
+ /** One media type, decided against the effective set.
140
+ *
141
+ * `unsupported` and `filtered` are split because the developer needs different
142
+ * things from them: `unsupported` means fix your expectations (no API takes
143
+ * this), `filtered` means fix your `accept` (the kit could have sent it). */
144
+ export type MediaDecision =
145
+ | { status: 'allowed'; kind: EncodableKind }
146
+ | { status: 'unsupported' }
147
+ | { status: 'filtered' }
148
+ /**
149
+ * Nobody named this file, so its media type cannot decide it. LOOK AT THE
150
+ * BYTES: decode them as UTF-8 (`classifyAttachment` does), and it is `text`
151
+ * if they decode and unencodable if they do not. Do not look at the filename.
152
+ *
153
+ * ★ THIS VARIANT IS WHERE THE DEVELOPER'S FILTER IS ENFORCED, so the caller
154
+ * cannot get it wrong by forgetting to check. It is returned ONLY when the
155
+ * effective policy still admits `text/plain` -- the one thing a decode can
156
+ * establish. Narrow `accept` to `image/png` and an unnamed file comes back
157
+ * `unsupported` instead, so the decode path is unreachable and a typeless
158
+ * `.rs` cannot slip past an images-only filter. That is the whole reason the
159
+ * check lives here rather than at each call site: there is one place to get
160
+ * right, and the callers physically cannot reach the bytes without being told
161
+ * to.
162
+ */
163
+ | { status: 'undetermined' };
164
+
165
+ export interface MediaPolicy {
166
+ /** The effective patterns: the kit's capability set narrowed by the
167
+ * developer's filter. Never wider than `encodableMediaTypes()`. */
168
+ readonly types: readonly string[];
169
+ /** The same set as an HTML `accept` attribute value, ready to put on an
170
+ * `<input type="file">`. This is what makes the picker and the encoder
171
+ * provably one thing rather than two lists that agree today. */
172
+ readonly accept: string;
173
+ /**
174
+ * What this policy makes of one media type, including "I cannot tell from
175
+ * this, go and read the bytes" -- see `undetermined`.
176
+ *
177
+ * The primitive behind "expose information, do not make decisions": it answers
178
+ * a question and returns a fact, so a consumer can build their own picker,
179
+ * their own validation and their own error copy on top of it without the kit
180
+ * deciding anything on their behalf.
181
+ */
182
+ decide(mediaType: string | undefined): MediaDecision;
183
+ }
184
+
185
+ export interface MediaPolicyOptions {
186
+ /** Narrow the kit's capability set. Omitted means the full set. Anything here
187
+ * that the kit cannot encode is dropped rather than honoured, because
188
+ * allowing it would only relocate the failure to the provider. */
189
+ accept?: MediaTypeFilter;
190
+ }
191
+
192
+ // NOTE ON WHAT IS DELIBERATELY ABSENT: there is no size cap, no file count, and
193
+ // no truncation path here, and their absence is a decision rather than an
194
+ // omission. How many bytes to send is a cost decision that lands on the
195
+ // consumer's invoice, and a component library that grows a limits engine starts
196
+ // making application choices on their behalf. The kit encodes what it is given.
197
+ // A developer who wants a ceiling has `File.size` and `decide()` and can enforce
198
+ // one in three lines of their own code, where it belongs.
199
+
200
+ const normalize = (value: string): string => value.trim().toLowerCase();
201
+
202
+ /** Does this media type say anything at all about the bytes it labels? Exported
203
+ * so `files.ts` decides "nameless" by the same rule `decide()` does, rather
204
+ * than growing a second opinion about which spellings mean "I don't know". */
205
+ export const namesNothing = (mediaType: string | undefined): boolean =>
206
+ NAMES_NOTHING.includes(mediaType === undefined ? '' : normalize(mediaType));
207
+
208
+ /**
209
+ * A file EXTENSION in `accept` is a hard error, and the loudness is the point.
210
+ *
211
+ * HTML's own `accept` takes extensions, the prop is called `accept`, and it is
212
+ * documented as HTML `accept` syntax -- so `accept=".py"` is a reasonable thing
213
+ * for a developer to write, and it is a trap. Measured on this branch before the
214
+ * throw existed: `.py` alone resolved to zero effective types and a picker with
215
+ * `accept=""`, a composer that silently accepted NOTHING. `".py,text/plain"` was
216
+ * worse, because the half that worked made it read as correct while the `.py`
217
+ * vanished without a word.
218
+ *
219
+ * A silent empty set is the one outcome nobody can debug, so this throws. It is
220
+ * safe to throw: no released version of this kit ships the prop, so no existing
221
+ * app can be relying on the old silence.
222
+ */
223
+ const assertMediaType = (entry: string): string => {
224
+ if (!entry.startsWith('.')) return entry;
225
+ throw new Error(
226
+ `\`accept\` entry "${entry}" is a file extension, and this kit takes media types only. ` +
227
+ `HTML's own accept attribute does take extensions, which is exactly why this throws rather ` +
228
+ `than quietly matching nothing. Use a media type instead -- "text/*" covers source files, ` +
229
+ `"image/*" images, "application/pdf" PDFs, and \`encodableMediaTypes()\` is the full set. ` +
230
+ `You lose nothing by dropping the extension: a file the browser cannot name is decided by ` +
231
+ `decoding its bytes, which is stronger than matching its name.`,
232
+ );
233
+ };
234
+
235
+ const splitFilter = (filter: MediaTypeFilter): string[] =>
236
+ (typeof filter === 'string' ? filter.split(',') : filter)
237
+ .map(normalize)
238
+ .filter((v) => v !== '')
239
+ .map(assertMediaType);
240
+
241
+ /** `image/png` -> `['image','png']`; `text/*` -> `['text','*']`. */
242
+ const parts = (pattern: string): [string, string] => {
243
+ const slash = pattern.indexOf('/');
244
+ return slash === -1 ? [pattern, ''] : [pattern.slice(0, slash), pattern.slice(slash + 1)];
245
+ };
246
+
247
+ const matches = (pattern: string, mediaType: string): boolean => {
248
+ const [pType, pSub] = parts(pattern);
249
+ const [mType, mSub] = parts(mediaType);
250
+ if (pType !== '*' && pType !== mType) return false;
251
+ return pSub === '*' || pSub === mSub;
252
+ };
253
+
254
+ /**
255
+ * The narrower of two patterns, or `undefined` when they do not overlap.
256
+ *
257
+ * This is what "narrow, never widen" means mechanically. `accept: 'image/*'`
258
+ * against a capability of `image/png` yields `image/png`, not `image/*`: the
259
+ * developer asked for images, and the kit's answer is the images it can actually
260
+ * send. Conversely `accept: 'text/markdown'` against a capability of `text/*`
261
+ * yields `text/markdown`, because there the developer is the narrower one.
262
+ */
263
+ const intersect = (capability: string, filter: string): string | undefined => {
264
+ if (matches(capability, filter)) return filter;
265
+ if (matches(filter, capability)) return capability;
266
+ return undefined;
267
+ };
268
+
269
+ /**
270
+ * Every media type this kit's encoders can represent, as HTML `accept` patterns.
271
+ *
272
+ * PUBLIC ON PURPOSE, and not merely for introspection: a consumer who wants
273
+ * their own picker, their own validation and their own error copy can build all
274
+ * three against this without touching `<kai-chat>` at all. That demotes the
275
+ * `accept` prop from "the only door" to a convenience over a published fact,
276
+ * which is the composition-first shape this project already committed to.
277
+ */
278
+ export function encodableMediaTypes(): readonly string[] {
279
+ return ENCODABLE.map((entry) => entry.pattern);
280
+ }
281
+
282
+ /**
283
+ * The effective policy: the kit's capability set narrowed by the developer's
284
+ * filter, plus the text ceiling.
285
+ *
286
+ * BOTH LAYERS CALL THIS. The composer calls it to build its picker `accept`
287
+ * attribute and to filter what actually gets staged; the encoders call it to
288
+ * decide what reaches the wire. That shared call is the whole design -- it is
289
+ * why changing `ENCODABLE` above moves the picker and the encoder together
290
+ * rather than moving one and leaving the other to be noticed in production.
291
+ */
292
+ export function resolveMediaPolicy(options: MediaPolicyOptions = {}): MediaPolicy {
293
+ const filter = options.accept === undefined ? undefined : splitFilter(options.accept);
294
+
295
+ const effective: { pattern: string; kind: EncodableKind }[] = [];
296
+ for (const capability of ENCODABLE) {
297
+ if (filter === undefined) {
298
+ effective.push({ ...capability });
299
+ continue;
300
+ }
301
+ for (const wanted of filter) {
302
+ const overlap = intersect(capability.pattern, wanted);
303
+ // A capability can overlap several filter entries (`text/*` against
304
+ // `text/plain,text/csv`), and each overlap is its own effective pattern.
305
+ if (overlap !== undefined && !effective.some((e) => e.pattern === overlap)) {
306
+ effective.push({ pattern: overlap, kind: capability.kind });
307
+ }
308
+ }
309
+ }
310
+
311
+ return {
312
+ types: effective.map((e) => e.pattern),
313
+ accept: effective.map((e) => e.pattern).join(','),
314
+ decide(mediaType) {
315
+ const type = mediaType === undefined ? '' : normalize(mediaType);
316
+
317
+ if (namesNothing(type)) {
318
+ // Nothing here names the bytes, and the filename is not evidence, so
319
+ // the answer is in the bytes themselves -- but only if the developer's
320
+ // filter would still take what a decode can prove. See the
321
+ // `undetermined` variant: this is the single place that gate exists.
322
+ return effective.some((e) => matches(e.pattern, UNNAMED_TEXT_MEDIA_TYPE))
323
+ ? { status: 'undetermined' }
324
+ : // `unsupported` rather than `filtered`, deliberately: `filtered`
325
+ // claims the kit COULD have encoded this file, and nobody has
326
+ // established what it is. Unread and unnamed, it is not a text
327
+ // file the filter excluded -- it is a file with no known type.
328
+ { status: 'unsupported' };
329
+ }
330
+
331
+ const hit = effective.find((e) => matches(e.pattern, type));
332
+ if (hit) return { status: 'allowed', kind: hit.kind };
333
+ // Distinguishing these two is the point: one is the kit's limit, the
334
+ // other is the developer's own filter looking back at them.
335
+ return ENCODABLE.some((e) => matches(e.pattern, type))
336
+ ? { status: 'filtered' }
337
+ : { status: 'unsupported' };
338
+ },
339
+ };
340
+ }
341
+
342
+ /** The policy every caller gets when nobody narrowed anything: the kit's full
343
+ * capability set. Built once -- it has no inputs. */
344
+ export const DEFAULT_MEDIA_POLICY: MediaPolicy = resolveMediaPolicy();
@@ -1 +0,0 @@
1
- import{I as o}from"./Icon-C-2LvGDG.js";import{c as m,m as r}from"./define-BzPnNsXg.js";var e=[["path",{d:"m12 19-7-7 7-7",key:"1l729n"}],["path",{d:"M19 12H5",key:"x3x0zl"}]],t=a=>m(o,r(a,{name:"ArrowLeft",iconNode:e})),p=t;export{p as a};
@@ -1 +0,0 @@
1
- import{I as m}from"./Icon-C-2LvGDG.js";import{c as o,m as r}from"./define-BzPnNsXg.js";var c=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],e=a=>o(m,r(a,{name:"Check",iconNode:c})),f=e;export{f as c};
@@ -1 +0,0 @@
1
- import{I as r}from"./Icon-C-2LvGDG.js";import{c as a,m}from"./define-BzPnNsXg.js";var e=[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]],n=o=>a(r,m(o,{name:"ChevronDown",iconNode:e})),p=n;export{p as c};
@@ -1 +0,0 @@
1
- import{I as o}from"./Icon-C-2LvGDG.js";import{c as a,m as r}from"./define-BzPnNsXg.js";var t=[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]],e=m=>a(o,r(m,{name:"ChevronRight",iconNode:t})),h=e;export{h as c};
@@ -1 +0,0 @@
1
- import{I as c}from"./Icon-C-2LvGDG.js";import{c as m,m as o}from"./define-BzPnNsXg.js";var a=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],e=r=>m(c,o(r,{name:"Circle",iconNode:a})),i=e;export{i as c};
@@ -1 +0,0 @@
1
- import{I as c}from"./Icon-C-2LvGDG.js";import{c as r,m as a}from"./define-BzPnNsXg.js";var e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],o=m=>r(c,a(m,{name:"CircleCheck",iconNode:e})),i=o;export{i as c};
@@ -1 +0,0 @@
1
- import{l as s,c as n,S as a,i as o,a as d,b as f,n as P,z,A,t as u,d as D,j as E}from"./define-BzPnNsXg.js";import{H,a as O,b as R}from"./hover-card-BtiF4XiU.js";import{c as h}from"./cn-CU7UAWzk.js";import{B as q}from"./button-CmkUkz6c.js";var G=u('<svg aria-label="Model context usage"height=20 role=img viewBox="0 0 24 24"width=20 style=color:currentcolor><circle cx=12 cy=12 fill=none opacity=0.25 r=10 stroke=currentColor stroke-width=2></circle><circle cx=12 cy=12 fill=none opacity=0.7 r=10 stroke=currentColor stroke-linecap=round stroke-width=2 style=transform:rotate(-90deg);transform-origin:center>'),J=u('<span class="font-medium text-muted-foreground">'),K=u('<div class="flex items-center justify-between gap-3 text-xs"><p></p><p class="font-mono text-muted-foreground"> / '),L=u('<div class=space-y-2><div class="h-1.5 w-full rounded-full bg-muted overflow-hidden"><div>'),b=u("<div>"),Q=u("<span class=text-muted-foreground>Total cost"),F=u("<span>"),V=u("<div><span class=text-muted-foreground>Input"),W=u("<div><span class=text-muted-foreground>Output"),X=u("<div><span class=text-muted-foreground>Reasoning"),Y=u("<div><span class=text-muted-foreground>Cache");const Z=10,U=100,y=.7,C=.9;function _(e,t=y,r=C){return e>r?"danger":e>t?"warn":"ok"}const M=z();function g(){const e=A(M);if(!e)throw new Error("Context components must be used within Context");return e}const j=new Intl.NumberFormat("en-US",{notation:"compact"}),N=new Intl.NumberFormat("en-US",{maximumFractionDigits:1,style:"percent"}),ee=new Intl.NumberFormat("en-US",{currency:"USD",style:"currency"});function te(e){const t=s(()=>({usedTokens:e.usedTokens,maxTokens:e.maxTokens,inputTokens:e.inputTokens,outputTokens:e.outputTokens,reasoningTokens:e.reasoningTokens,cacheTokens:e.cacheTokens,estimatedCost:e.estimatedCost,warnThreshold:e.warnThreshold??y,dangerThreshold:e.dangerThreshold??C}));return n(M.Provider,{get value(){return t()},get children(){return n(H,{openDelay:0,get children(){return e.children}})}})}function re(){const e=g(),t=2*Math.PI*Z,r=s(()=>e.usedTokens/e.maxTokens),l=s(()=>t*(1-r()));return(()=>{var i=G(),T=i.firstChild,x=T.nextSibling;return D(x,"stroke-dasharray",`${t} ${t}`),d(()=>D(x,"stroke-dashoffset",l())),i})()}function ne(e){const t=g(),r=s(()=>t.usedTokens/t.maxTokens),l=s(()=>N.format(r()));return n(O,{get children(){return n(a,{get when(){return!e.children},get fallback(){return e.children},get children(){return n(q,{type:"button",variant:"ghost",get class(){return e.class},get children(){return[(()=>{var i=J();return o(i,l),i})(),n(re,{})]}})}})}})}function se(e){return n(R,{get class(){return h("min-w-60 divide-y divide-border overflow-hidden",e.class)},get children(){return e.children}})}function oe(e){const t=g(),r=s(()=>t.usedTokens/t.maxTokens),l=s(()=>N.format(r())),i=s(()=>j.format(t.usedTokens)),T=s(()=>j.format(t.maxTokens)),x=s(()=>`${Math.min(r()*U,U)}%`),$=s(()=>{const c=r();return c>t.dangerThreshold?"danger":c>t.warnThreshold?"warn":"ok"}),B=s(()=>{const c=$();return c==="danger"?"bg-red-400":c==="warn"?"bg-yellow-400":"bg-primary"});return(()=>{var c=b();return o(c,n(a,{get when(){return!e.children},get fallback(){return e.children},get children(){return[(()=>{var w=K(),p=w.firstChild,k=p.nextSibling,m=k.firstChild;return o(p,l),o(k,i,m),o(k,T,null),w})(),(()=>{var w=L(),p=w.firstChild,k=p.firstChild;return d(m=>{var S=h("h-full rounded-full transition-all",B()),I=x();return S!==m.e&&f(k,m.e=S),I!==m.t&&P(k,"width",m.t=I),m},{e:void 0,t:void 0}),w})()]}})),d(()=>f(c,h("w-full space-y-2 p-3",e.class))),c})()}function ae(e){return(()=>{var t=b();return o(t,()=>e.children),d(()=>f(t,h("w-full p-3",e.class))),t})()}function ue(e){const t=g(),r=s(()=>ee.format(t.estimatedCost??0));return(()=>{var l=b();return o(l,n(a,{get when(){return!e.children},get fallback(){return e.children},get children(){return[Q(),(()=>{var i=F();return o(i,r),i})()]}})),d(()=>f(l,h("flex w-full items-center justify-between gap-3 bg-muted p-3 text-xs",e.class))),l})()}function v(e){return(()=>{var t=F();return o(t,(()=>{var r=E(()=>e.tokens===void 0);return()=>r()?"\u2014":j.format(e.tokens)})()),t})()}function ie(e){const t=g();return n(a,{get when(){return e.children||t.inputTokens},get children(){return n(a,{get when(){return!e.children},get fallback(){return e.children},get children(){var r=V();return r.firstChild,o(r,n(v,{get tokens(){return t.inputTokens}}),null),d(()=>f(r,h("flex items-center justify-between text-xs",e.class))),r}})}})}function le(e){const t=g();return n(a,{get when(){return e.children||t.outputTokens},get children(){return n(a,{get when(){return!e.children},get fallback(){return e.children},get children(){var r=W();return r.firstChild,o(r,n(v,{get tokens(){return t.outputTokens}}),null),d(()=>f(r,h("flex items-center justify-between text-xs",e.class))),r}})}})}function ce(e){const t=g();return n(a,{get when(){return e.children||t.reasoningTokens},get children(){return n(a,{get when(){return!e.children},get fallback(){return e.children},get children(){var r=X();return r.firstChild,o(r,n(v,{get tokens(){return t.reasoningTokens}}),null),d(()=>f(r,h("flex items-center justify-between text-xs",e.class))),r}})}})}function de(e){const t=g();return n(a,{get when(){return e.children||t.cacheTokens},get children(){return n(a,{get when(){return!e.children},get fallback(){return e.children},get children(){var r=Y();return r.firstChild,o(r,n(v,{get tokens(){return t.cacheTokens}}),null),d(()=>f(r,h("flex items-center justify-between text-xs",e.class))),r}})}})}export{te as C,y as D,ne as a,se as b,oe as c,ae as d,ie as e,le as f,ue as g,_ as h,ce as i,de as j,C as k};
@@ -1 +0,0 @@
1
- import{c as n,m as L,g as y,s as A,l as m,i as l,S as h,a as v,b as p,d as M,t as c,e as N,o as O,x as D,F as k}from"./define-BzPnNsXg.js";import{c as f}from"./cn-CU7UAWzk.js";import{a as R,b as q,C as E}from"./collapsible-Cvj61obE.js";import{B as C}from"./button-CmkUkz6c.js";import{B as F}from"./badge-SxLSZ19R.js";import{S as P}from"./scroll-area-Bs4bFS1P.js";import{m as U}from"./message-square-CnpAm_P0.js";import{I as G}from"./Icon-C-2LvGDG.js";var H=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M9 3v18",key:"fh3hqa"}],["path",{d:"m14 9 3 3-3 3",key:"8010ee"}]],J=i=>n(G,L(i,{name:"PanelLeftOpen",iconNode:H})),K=J;function Q(i,e){const[d,a]=y(e);return[()=>i()??d(),t=>a(t)]}var $=c('<span part=trailing class="ml-auto shrink-0 text-xs text-muted-foreground">'),V=c('<div class="flex items-center gap-2.5"><span>'),W=c("<button>"),X=c('<div class="flex items-center gap-2"><div>'),Y=c("<div> messages");function Z(i,e=Date.now()){if(!i)return"";const d=Date.parse(i);if(Number.isNaN(d))return"";const a=Math.max(0,Math.round((e-d)/1e3));if(a<60)return"just now";const t=Math.floor(a/60);if(t<60)return`${t}m ago`;const s=Math.floor(t/60);return s<24?`${s}h ago`:`${Math.floor(s/24)}d ago`}function B(i){const[e]=A(i,["conversation","isActive","onSelect","compact","class"]),d=m(()=>e.conversation.trailing??Z(e.conversation.updatedAt??e.conversation.lastMessageAt));return(()=>{var a=W();return a.$$click=()=>e.onSelect(e.conversation.id),l(a,n(h,{get when(){return e.compact},get fallback(){return[(()=>{var t=X(),s=t.firstChild;return l(s,()=>e.conversation.title),l(t,n(h,{get when(){return d()},get children(){var g=$();return l(g,d),g}}),null),v(()=>p(s,f("min-w-0 flex-1 truncate text-sm",e.isActive?"font-medium text-foreground":"text-foreground/80"))),t})(),(()=>{var t=Y(),s=t.firstChild;return l(t,()=>e.conversation.messageCount,s),v(()=>p(t,f("mt-0.5 truncate text-xs",e.isActive?"text-foreground/70":"text-muted-foreground"))),t})()]},get children(){var t=V(),s=t.firstChild;return l(t,n(U,{get class(){return f("size-3.5 shrink-0",e.isActive?"text-foreground":"text-muted-foreground")}}),s),l(s,()=>e.conversation.title),l(t,n(h,{get when(){return d()},get children(){var g=$();return l(g,d),g}}),null),v(()=>p(s,f("min-w-0 flex-1 truncate text-sm",e.isActive?"font-medium text-foreground":"text-foreground/80"))),t}})),v(t=>{var s=e.conversation.id,g=f("w-full rounded-lg text-left transition-colors",e.compact?"px-2.5 py-1.5":"px-2.5 py-2",e.isActive?"bg-muted":"hover:bg-muted/50",e.class);return s!==t.e&&M(a,"data-conversation-id",t.e=s),g!==t.t&&p(a,t.t=g),t},{e:void 0,t:void 0}),a})()}N(["click"]);var _=c('<div class="px-3 pb-2"><div class="flex items-center gap-2 rounded-md bg-surface-strong px-2.5 py-1.5"><svg width=13 height=13 viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2 class=text-muted-foreground><circle cx=11 cy=11 r=8></circle><line x1=21 y1=21 x2=16.65 y2=16.65></line></svg><input type=text placeholder="Search chats..."aria-label="Search chats"class="bg-transparent text-[13px] text-foreground placeholder:text-muted-foreground rounded-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring w-full">'),ee=c('<div class="space-y-0.5 py-1">'),te=c('<div class="shrink-0 border-t border-border">'),re=c("<div>"),ne=c('<svg width=16 height=16 viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2><line x1=3 y1=12 x2=21 y2=12></line><line x1=3 y1=6 x2=21 y2=6></line><line x1=3 y1=18 x2=21 y2=18>'),oe=c('<svg width=16 height=16 viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2><line x1=12 y1=5 x2=12 y2=19></line><line x1=5 y1=12 x2=19 y2=12>'),ae=c('<div class="flex items-center justify-between p-3 pb-2"><div class="flex items-center gap-2"><span class="text-sm font-semibold text-foreground">Chats'),ie=c('<div class="flex flex-1 flex-col items-center justify-center gap-1 p-6 text-center text-sm text-muted-foreground">No conversations yet'),se=c('<svg width=10 height=10 viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2><polyline points="6 9 12 15 18 9">'),le=c("<span>"),ce=c('<div class="pl-2 mt-0.5 space-y-0.5">');function ue(i){return n(C,{variant:"ghost",size:"icon-sm","aria-label":"Open sidebar",get class(){return f("rounded-full bg-card/80 shadow-sm backdrop-blur",i.class)},get onClick(){return i.onExpand},get children(){return n(K,{class:"size-4"})}})}function de(i){const[e]=A(i,["groups","conversations","activeId","onSelect","onNewChat","onToggleSidebar","header","footer","empty","compact","onSearchChange","controllerRef","class"]),[d,a]=y(""),t=m(()=>e.conversations.length===0);let s;const g=o=>{var r;a(o),(r=e.onSearchChange)==null||r.call(e,o)};O(()=>{var o;(o=e.controllerRef)==null||o.call(e,{focus:r=>s?.focus(r),clearSearch:()=>g("")})});const S=m(()=>{const o=d().toLowerCase();return o?e.conversations.filter(r=>r.title.toLowerCase().includes(o)):e.conversations}),T=m(()=>{const o=new Map;for(const r of S()){const u=r.groupId;o.has(u)||o.set(u,[]),o.get(u).push(r)}return o}),x=m(()=>{const o=new Set((e.groups??[]).map(r=>r.id));return S().filter(r=>r.groupId==null||!o.has(r.groupId))});return(()=>{var o=re();return l(o,n(h,{get when(){return e.header},get fallback(){return(()=>{var r=ae(),u=r.firstChild,b=u.firstChild;return l(u,n(C,{variant:"ghost",size:"icon-sm","aria-label":"Toggle sidebar",get onClick(){return e.onToggleSidebar},get children(){return ne()}}),b),l(r,n(C,{variant:"ghost",size:"icon-sm","aria-label":"New chat",get onClick(){return e.onNewChat},get children(){return oe()}}),null),r})()},get children(){return e.header}}),null),l(o,n(h,{get when(){return!t()},get children(){var r=_(),u=r.firstChild,b=u.firstChild,w=b.nextSibling;w.$$input=j=>g(j.currentTarget.value);var I=s;return typeof I=="function"?D(I,w):s=w,v(()=>w.value=d()),r}}),null),l(o,n(h,{get when(){return!t()},get fallback(){return n(h,{get when(){return e.empty},get fallback(){return ie()},get children(){return e.empty}})},get children(){return n(P,{class:"flex-1 px-2",get children(){return[n(k,{get each(){return e.groups},children:r=>{const u=m(()=>T().get(r.id)??[]);return n(h,{get when(){return u().length>0},get children(){return n(z,{get name(){return r.name},get count(){return u().length},get conversations(){return u()},get activeId(){return e.activeId},get onSelect(){return e.onSelect},get compact(){return e.compact}})}})}}),n(h,{get when(){return x().length>0},get children(){return n(h,{get when(){return e.compact},get fallback(){return n(z,{name:"Ungrouped",get count(){return x().length},get conversations(){return x()},get activeId(){return e.activeId},get onSelect(){return e.onSelect}})},get children(){var r=ee();return l(r,n(k,{get each(){return x()},children:u=>n(B,{conversation:u,get isActive(){return u.id===e.activeId},get onSelect(){return e.onSelect},compact:!0})})),r}})}})]}})}}),null),l(o,n(h,{get when(){return e.footer},get children(){var r=te();return l(r,()=>e.footer),r}}),null),v(()=>p(o,f("flex flex-col h-full bg-sidebar",e.class))),o})()}function z(i){const[e,d]=y(!0);return n(E,{get open(){return e()},onOpenChange:d,get children(){return[n(R,{class:"flex items-center gap-1.5 w-full px-1.5 py-1 rounded-md text-[13px] text-muted-foreground font-medium hover:bg-muted/30 transition-colors cursor-pointer mt-1.5",get children(){return[(()=>{var a=se();return v(()=>M(a,"class",f("transition-transform",!e()&&"-rotate-90"))),a})(),(()=>{var a=le();return l(a,()=>i.name),a})(),n(F,{variant:"count",class:"ml-auto text-[11px]",get children(){return i.count}})]}}),n(q,{get children(){var a=ce();return l(a,n(k,{get each(){return i.conversations},children:t=>n(B,{conversation:t,get isActive(){return t.id===i.activeId},get onSelect(){return i.onSelect},get compact(){return i.compact}})})),a}})]}})}N(["input"]);export{de as C,ue as a,Q as c};
@@ -1 +0,0 @@
1
- import{c as t,m as x,s as y,y as T,q as I,i as c,g as U,A as H,O as P,t as d,z as j,e as D,F as k,S as g,j as V,u as S,x as _}from"./define-BzPnNsXg.js";import{c as z}from"./cn-CU7UAWzk.js";import{C as q,s as B,n as E}from"./composer-D86ztyL0.js";import{P as M}from"./prompt-suggestion-Di_WZE_5.js";import{B as m}from"./button-CmkUkz6c.js";import{T as O}from"./tooltip-eB226mGK.js";import{A as F,a as N,d as W,e as G,i as J}from"./attachments-BB56zoji.js";import{a as K}from"./action-icons-CaYoImEk.js";import{p as Q,g as X}from"./paperclip-CdwKjrlu.js";import{m as Y}from"./icon-DKkmze3y.js";import{I as Z}from"./Icon-C-2LvGDG.js";var ee=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}]],te=e=>t(Z,x(e,{name:"Square",iconNode:ee})),re=te,ne=d("<div data-prompt-input>"),ae=d("<div>");const L=j();function le(){const e=H(L);if(!e)throw new Error("PromptInput subcomponents must be used within PromptInput");return e}function ie(e){const[r,l]=y(e,["isLoading","value","onValueChange","maxHeight","onSubmit","children","disabled","class","onClick"]),[u,b]=U(r.value??"");let i;const h=s=>{var v;b(s),(v=r.onValueChange)==null||v.call(r,s)},w=s=>{r.disabled||i==null||i.focus(),typeof r.onClick=="function"&&r.onClick(s)};return t(L.Provider,{get value(){return{isLoading:r.isLoading??!1,value:()=>r.value??u(),setValue:r.onValueChange??h,maxHeight:r.maxHeight??240,onSubmit:r.onSubmit,get disabled(){return r.disabled},get textareaRef(){return i},setTextareaRef:s=>{i=s}}},get children(){var s=ne();return s.$$click=w,I(s,x({get class(){return z("bg-surface cursor-text rounded-xl p-2 shadow-xs","focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-0",r.disabled&&"cursor-not-allowed opacity-60",r.class)}},l),!1,!0),c(s,()=>r.children),s}})}function se(e){const[r]=y(e,["class","placeholder","aria-label","triggers","kindIcons","onComposerChange"]),l=le(),u=T(),b=()=>z("text-foreground min-h-[44px] w-full bg-transparent shadow-none outline-none focus-visible:ring-0 focus-visible:ring-offset-0 overflow-y-auto whitespace-pre-wrap break-words",P(u.proseSize()),r.class);return t(q,{bare:!0,get value(){return l.value()},get placeholder(){return r.placeholder},get ariaLabel(){return r["aria-label"]},get disabled(){return l.disabled},get maxHeight(){return l.maxHeight},get editableClass(){return b()},editableRef:i=>l.setTextareaRef(i),get triggers(){return r.triggers},get kindIcons(){return r.kindIcons},onChange:i=>{var h;(h=r.onComposerChange)==null||h.call(r,i),l.setValue(i.text.replace(/^\s+/,""))},onSubmit:()=>{var i;l.disabled||(i=l.onSubmit)==null||i.call(l)}})}function oe(e){const[r,l]=y(e,["children","class"]);return(()=>{var u=ae();return I(u,x({get class(){return z("flex items-center gap-2",r.class)}},l),!1,!0),c(u,()=>r.children),u})()}D(["click"]);var ue=d('<div class="mb-2 flex flex-wrap gap-2">'),ce=d('<div class="px-3 pt-3">'),de=d("<slot name=input-top>"),ge=d("<input type=file multiple class=hidden>"),he=d('<div class="flex items-center gap-2"><slot name=toolbar-start style=display:contents>'),pe=d('<div class="flex items-center gap-2"><slot name=toolbar-end>'),me=d('<span class="px-1 text-xs">'),be=d('<svg width=16 height=16 viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2><line x1=12 y1=19 x2=12 y2=5></line><polyline points="5 12 12 5 19 12">');function fe(e){return{id:typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID():`${e.name}-${e.size}-${e.lastModified}`,type:"file",filename:e.name,mediaType:e.type||void 0,url:e.type.startsWith("image/")?URL.createObjectURL(e):void 0}}function ve(e){let r;const l=()=>e.attachments??[],u=()=>!!e.onAttachmentsChange,b=n=>{!(n!=null&&n.length)||!e.onAttachmentsChange||e.onAttachmentsChange([...l(),...Array.from(n).map(fe)])},i=n=>{var o;return(o=e.onAttachmentsChange)==null?void 0:o.call(e,l().filter(a=>a.id!==n))},h=()=>B(E(e.value)),w=()=>e.disabled||e.loading||!h().trim()&&l().length===0,s=()=>!!e.loading&&!!e.stoppable,v=()=>!!h().trim()||l().length>0,$=()=>{const n=e.submit??"always";return n==="always"||n==="auto"&&v()};return[t(g,{get when(){var n;return(n=e.suggestions)==null?void 0:n.length},get children(){var n=ue();return c(n,t(k,{get each(){return e.suggestions},children:o=>t(M,{onClick:()=>e.onSuggestionClick(o),children:o})})),n}}),t(ie,{get value(){return e.value},get onValueChange(){return e.onValueChange},get onSubmit(){return e.onSubmit},get isLoading(){return e.loading},get disabled(){return e.disabled},class:"relative",get children(){return[t(g,{get when(){return V(()=>!!u())()&&l().length},get children(){var n=ce();return c(n,t(F,{variant:"inline",get children(){return t(k,{get each(){return l()},children:o=>t(N,{data:o,onRemove:()=>i(o.id),get children(){return[t(W,{}),t(G,{}),t(J,{})]}})})}})),n}}),(()=>{var n=de();return n._$owner=S(),n})(),t(se,{get placeholder(){return e.placeholder},get"aria-label"(){return e.placeholder||"Message"},class:"min-h-[44px] pt-3 pl-4",get triggers(){return e.triggers},get kindIcons(){return e.kindIcons},get onComposerChange(){return e.onComposerChange}}),t(oe,{class:"mt-2 flex w-full items-center justify-between gap-2 px-3 pb-0",get children(){return[(()=>{var n=he(),o=n.firstChild;return o._$owner=S(),c(n,t(g,{get when(){return V(()=>!!u())()&&e.attach!==!1},get children(){return[(()=>{var a=ge();a.addEventListener("change",C=>{b(C.currentTarget.files),C.currentTarget.value=""});var f=r;return typeof f=="function"?_(f,a):r=a,a})(),t(m,{type:"button",variant:"outline",size:"icon-sm",class:"rounded-full","aria-label":"Attach files",get disabled(){return e.disabled},onClick:()=>r?.click(),get children(){return t(Q,{class:"size-4"})}})]}}),null),c(n,t(g,{get when(){return e.search},get children(){return t(m,{type:"button",variant:"outline",size:"sm",class:"rounded-full gap-1","aria-label":"Search the web",get disabled(){return e.disabled},onClick:()=>{var a;return(a=e.onSearch)==null?void 0:a.call(e)},get children(){return[t(X,{class:"size-4"}),"Search"]}})}}),null),c(n,t(g,{get when(){return e.voice},get children(){return t(m,{type:"button",variant:"outline",size:"icon-sm",class:"rounded-full","aria-label":"Voice input",get disabled(){return e.disabled},onClick:()=>{var a;return(a=e.onVoice)==null?void 0:a.call(e)},get children(){return t(Y,{class:"size-4"})}})}}),null),c(n,t(k,{get each(){return e.toolbarActions??[]},children:a=>{const f=K(a.icon),C=a.tooltip??a.label,A=t(m,{type:"button",variant:"outline",size:"icon-sm",class:"rounded-full",get"aria-label"(){return a.label},get"data-action"(){return a.id},get disabled(){return e.disabled},onClick:()=>{var p;return(p=e.onAction)==null?void 0:p.call(e,a.id)},get children(){return t(g,{when:f,get fallback(){return(()=>{var p=me();return c(p,()=>a.label),p})()},children:p=>{const R=p();return t(R,{class:"size-4"})}})}});return f?t(O,{content:C,children:A}):A}}),null),n})(),(()=>{var n=pe(),o=n.firstChild;return o._$owner=S(),c(n,t(g,{get when(){return s()},get fallback(){return t(g,{get when(){return $()},get children(){return t(m,{size:"icon-sm",class:"rounded-full",part:"send","data-testid":"send","aria-label":"Send message",get disabled(){return w()},get onClick(){return e.onSubmit},get children(){return be()}})}})},get children(){return t(m,{size:"icon-sm",variant:"outline",class:"rounded-full","data-testid":"stop","aria-label":"Stop",get onClick(){return e.onStop},get children(){return t(re,{class:"size-3"})}})}}),null),n})()]}})]}})]}export{ve as D};
@@ -1 +0,0 @@
1
- import{I as e}from"./Icon-C-2LvGDG.js";import{c as m,m as o}from"./define-BzPnNsXg.js";var r=[["path",{d:"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z",key:"1lielz"}]],s=a=>m(e,o(a,{name:"MessageSquare",iconNode:r})),i=s;export{i as m};
@@ -1 +0,0 @@
1
- import{s as C,c as r,m as I,j as y,F as m,g as k,i as d,S as h,a as p,d as M,b as O,t as a,e as R}from"./define-BzPnNsXg.js";import{c as f}from"./cn-CU7UAWzk.js";import{c as j,D as S,a as $,b as z}from"./dropdown-BjVVHWXH.js";import{B}from"./button-CmkUkz6c.js";var D=a('<svg width=12 height=12 viewBox="0 0 24 24"fill=none stroke=currentColor stroke-width=2><polyline points="6 9 12 15 18 9">'),F=a('<span class="text-caption text-muted-foreground">'),q=a('<div class="flex flex-col"><span>'),E=a("<div class=pl-2>"),P=a('<div><button type=button class="flex w-full items-center justify-between rounded-md px-2 py-1.5 text-body outline-none transition-colors hover:bg-muted focus:bg-muted">');const x=o=>(()=>{var e=D();return p(()=>M(e,"class",o.class)),e})();function b(o){const e=()=>o.model.description??o.model.provider;return r(z,{onSelect:()=>o.onModelChange(o.model.id),get children(){var s=q(),u=s.firstChild;return d(u,()=>o.model.name),d(s,r(h,{get when(){return e()},get children(){var c=F();return d(c,e),c}}),null),p(()=>O(u,f("text-body",o.model.id===o.currentModelId&&"font-medium text-foreground"))),s}})}function _(o){const[e]=C(o,["models","currentModelId","onModelChange","class","defaultOpen","disabled","controllerRef"]),s=()=>e.models.find(t=>t.id===e.currentModelId),u=()=>e.models.filter(t=>!t.group),c=()=>{const t=[],n=new Map;for(const l of e.models)l.group&&(n.has(l.group)||(n.set(l.group,[]),t.push(l.group)),n.get(l.group).push(l));return t.map(l=>({name:l,models:n.get(l)}))};return r(h,{get when(){return e.models.length>1},get children(){return r(j,{get defaultOpen(){return e.defaultOpen},get disabled(){return e.disabled},get controllerRef(){return e.controllerRef},get children(){return[r(S,{as:t=>r(B,I({variant:"ghost",size:"sm",get class(){return f("gap-1 text-meta text-muted-foreground",e.class)}},t,{get children(){return[y(()=>{var n;return((n=s())==null?void 0:n.name)??e.currentModelId}),r(x,{})]}}))}),r($,{get children(){return[r(m,{get each(){return u()},children:t=>r(b,{model:t,get currentModelId(){return e.currentModelId},get onModelChange(){return e.onModelChange}})}),r(m,{get each(){return c()},children:t=>{const[n,l]=k(!1);return(()=>{var g=P(),i=g.firstChild;return i.$$click=()=>l(!n()),d(i,()=>t.name,null),d(i,r(x,{get class(){return f("transition-transform",n()&&"rotate-180")}}),null),d(g,r(h,{get when(){return n()},get children(){var v=E();return d(v,r(m,{get each(){return t.models},children:w=>r(b,{model:w,get currentModelId(){return e.currentModelId},get onModelChange(){return e.onModelChange}})})),v}}),null),p(()=>M(i,"aria-expanded",n())),g})()}})]}})]}})}})}R(["click"]);export{_ as M};
@@ -1 +0,0 @@
1
- import{I as m}from"./Icon-C-2LvGDG.js";import{c as o,m as r}from"./define-BzPnNsXg.js";var e=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],t=a=>o(m,r(a,{name:"X",iconNode:e})),p=t;export{p as x};