cognova 0.2.12 → 0.2.13

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 (188) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_nuxt/{DwY7rCd_.js → -HePz7lp.js} +2 -2
  3. package/.output/public/_nuxt/{CY-cjAwJ.js → 4ALIM-zZ.js} +1 -1
  4. package/.output/public/_nuxt/{DXdwpJ-I.js → 5sUbkh_6.js} +2 -2
  5. package/.output/public/_nuxt/{_cy8R3nk.js → 6bB8Ev7a.js} +1 -1
  6. package/.output/public/_nuxt/{1zUTf4AP.js → 7rT1DCe2.js} +1 -1
  7. package/.output/public/_nuxt/{vIOxcXKR.js → 9O1MXkck.js} +1 -1
  8. package/.output/public/_nuxt/{7oCGSglN.js → 9kAKMaPC.js} +1 -1
  9. package/.output/public/_nuxt/{CVqlefTY.js → B-DMcEU9.js} +1 -1
  10. package/.output/public/_nuxt/{BS2ZNXI1.js → B0nzD8Sk.js} +1 -1
  11. package/.output/public/_nuxt/B2PqR2Vu.js +1 -0
  12. package/.output/public/_nuxt/{Db4KMnt8.js → B2wI_pYg.js} +1 -1
  13. package/.output/public/_nuxt/{zq-a1TeT.js → B5FuOh7E.js} +1 -1
  14. package/.output/public/_nuxt/B6om4MW2.js +1 -0
  15. package/.output/public/_nuxt/{Dya5oK8u.js → B7ikW4eF.js} +1 -1
  16. package/.output/public/_nuxt/{BYHCP8x7.js → B8DFEjxA.js} +1 -1
  17. package/.output/public/_nuxt/{6boMs_nF.js → B9kWNcU7.js} +1 -1
  18. package/.output/public/_nuxt/BAZ8sewA.js +1 -0
  19. package/.output/public/_nuxt/{BXuWCWsJ.js → BCPwL4ma.js} +1 -1
  20. package/.output/public/_nuxt/{DY3uK7wM.js → BCrlmHh_.js} +1 -1
  21. package/.output/public/_nuxt/{BR8bKz8h.js → BD-AFJWW.js} +1 -1
  22. package/.output/public/_nuxt/{BtHQ1T0f.js → BGcQMReV.js} +1 -1
  23. package/.output/public/_nuxt/{BDyn4ApB.js → BL1mkqgd.js} +3 -3
  24. package/.output/public/_nuxt/BNJJSRKh.js +1 -0
  25. package/.output/public/_nuxt/{D8lwrAYS.js → BNeeERBt.js} +1 -1
  26. package/.output/public/_nuxt/{CVFwOzbl.js → BSJb5amZ.js} +1 -1
  27. package/.output/public/_nuxt/{CEnSeCqn.js → BSsaE9Db.js} +1 -1
  28. package/.output/public/_nuxt/{DzA58_Lm.js → BVO3XpHT.js} +1 -1
  29. package/.output/public/_nuxt/{CuxrHsu-.js → BWuL2CzO.js} +1 -1
  30. package/.output/public/_nuxt/{0yk-pS3R.js → B_9zJTqe.js} +1 -1
  31. package/.output/public/_nuxt/{DcJbYLTp.js → B_Lr1vlV.js} +1 -1
  32. package/.output/public/_nuxt/{CZoEPC_Q.js → Bc8bTnkd.js} +3 -3
  33. package/.output/public/_nuxt/{BKXg-alD.js → BghuwIGa.js} +1 -1
  34. package/.output/public/_nuxt/{PP_4ebzl.js → BjsKx597.js} +1 -1
  35. package/.output/public/_nuxt/{DuvzM-P1.js → Bl0qBhCG.js} +1 -1
  36. package/.output/public/_nuxt/{B_wilgcd.js → Bl43dkDq.js} +1 -1
  37. package/.output/public/_nuxt/{JbHa4oXq.js → BnMTFF5R.js} +1 -1
  38. package/.output/public/_nuxt/{CY-QVcA5.js → BrX-PnSK.js} +2 -2
  39. package/.output/public/_nuxt/{DYbZBZet.js → BtV7oNn3.js} +1 -1
  40. package/.output/public/_nuxt/{apYB9dr5.js → BvFYnRMR.js} +1 -1
  41. package/.output/public/_nuxt/{x6FRJ5ac.js → BvTUBUNN.js} +1 -1
  42. package/.output/public/_nuxt/{wO6z2ugJ.js → ByLsRRoQ.js} +1 -1
  43. package/.output/public/_nuxt/{DC4idAGt.js → C1LcEMwB.js} +1 -1
  44. package/.output/public/_nuxt/{YX8avsvq.js → C2IiXp9N.js} +2 -2
  45. package/.output/public/_nuxt/{fbyIeNkc.js → C6OSRpRd.js} +1 -1
  46. package/.output/public/_nuxt/{3jQMk_5H.js → C796kFT9.js} +1 -1
  47. package/.output/public/_nuxt/{DEd2xVbS.js → C7m9zGMG.js} +1 -1
  48. package/.output/public/_nuxt/C8AtdrMH.js +1 -0
  49. package/.output/public/_nuxt/CAWbHTgy.js +1 -0
  50. package/.output/public/_nuxt/{ixlNW2So.js → CFmvNggn.js} +1 -1
  51. package/.output/public/_nuxt/{gTrVszwd.js → CGplHfmR.js} +1 -1
  52. package/.output/public/_nuxt/CJPrV25_.js +1 -0
  53. package/.output/public/_nuxt/{U1MWjQMi.js → CKKEWapF.js} +1 -1
  54. package/.output/public/_nuxt/{C6qKcgOY.js → CLkkdThv.js} +22 -22
  55. package/.output/public/_nuxt/CNjv28J2.js +1 -0
  56. package/.output/public/_nuxt/{BLnYhy_t.js → CRRw0Thu.js} +1 -1
  57. package/.output/public/_nuxt/{10_wwHSz.js → CT8s4rqa.js} +1 -1
  58. package/.output/public/_nuxt/{C27WoGNZ.js → CZSOrxUy.js} +1 -1
  59. package/.output/public/_nuxt/{DNP5E1bC.js → CaNEL9JC.js} +5 -5
  60. package/.output/public/_nuxt/{DhuOKJda.js → CbTLg9oX.js} +1 -1
  61. package/.output/public/_nuxt/CfCXpVn5.js +1 -0
  62. package/.output/public/_nuxt/{C9WIgRRL.js → ChmNlvWR.js} +1 -1
  63. package/.output/public/_nuxt/{t8aDAkZ5.js → CiNxIhaq.js} +1 -1
  64. package/.output/public/_nuxt/{E3rXPwU8.js → Ck0QYdxe.js} +1 -1
  65. package/.output/public/_nuxt/{DUVzIl3o.js → Ckb0pu4-.js} +1 -1
  66. package/.output/public/_nuxt/{vScW1Zgm.js → CkwPRs1D.js} +1 -1
  67. package/.output/public/_nuxt/CmEJg8C6.js +2 -0
  68. package/.output/public/_nuxt/{CTCcEJU3.js → CmL_vMJD.js} +1 -1
  69. package/.output/public/_nuxt/{Bciqk4dX.js → Cq8zPxkT.js} +1 -1
  70. package/.output/public/_nuxt/{D8M722pn.js → CseYuM6E.js} +1 -1
  71. package/.output/public/_nuxt/{D0ifH682.js → CxRnB4NC.js} +1 -1
  72. package/.output/public/_nuxt/{CVdCqaby.js → D0zMyG8n.js} +1 -1
  73. package/.output/public/_nuxt/{DhI5cA_n.js → D12qPplu.js} +1 -1
  74. package/.output/public/_nuxt/{Beom-INj.js → D1XYB283.js} +1 -1
  75. package/.output/public/_nuxt/{BUghTae1.js → D2NxqyzW.js} +1 -1
  76. package/.output/public/_nuxt/{CZRnNmU8.js → D5xyrvFu.js} +1 -1
  77. package/.output/public/_nuxt/{2dNDtTiv.js → D6tVZcRs.js} +3 -3
  78. package/.output/public/_nuxt/{EgKnQnf-.js → D7N3EZ-I.js} +1 -1
  79. package/.output/public/_nuxt/{C5R5QaCA.js → D8iBB0Py.js} +1 -1
  80. package/.output/public/_nuxt/{XCjS70z4.js → D8oIH8m1.js} +1 -1
  81. package/.output/public/_nuxt/{BA_pRWwX.js → DB2zZev7.js} +1 -1
  82. package/.output/public/_nuxt/{Cl-LOSDV.js → DBrOAqkm.js} +1 -1
  83. package/.output/public/_nuxt/{DO9SFIh1.js → DDXDFweK.js} +1 -1
  84. package/.output/public/_nuxt/{B93pdGAW.js → DFZkCmLQ.js} +1 -1
  85. package/.output/public/_nuxt/{CLfF6dSn.js → DFpmIy6J.js} +1 -1
  86. package/.output/public/_nuxt/{BfcLZ_fC.js → DKZmgHNU.js} +1 -1
  87. package/.output/public/_nuxt/{CPutXj8l.js → DNcOC5zj.js} +1 -1
  88. package/.output/public/_nuxt/{BHtY0l0l.js → DQhm-UPG.js} +1 -1
  89. package/.output/public/_nuxt/{C2FxZbO_.js → DR8tGJhL.js} +1 -1
  90. package/.output/public/_nuxt/{D4UJwDQJ.js → DVAEVTjy.js} +1 -1
  91. package/.output/public/_nuxt/{2nOqGUPr.js → DVqrPkCJ.js} +1 -1
  92. package/.output/public/_nuxt/DWZ9ieYa.js +1 -0
  93. package/.output/public/_nuxt/{nnQqD5pb.js → DWj6VsZv.js} +1 -1
  94. package/.output/public/_nuxt/{C2vq6Te8.js → DXJ9PxCv.js} +1 -1
  95. package/.output/public/_nuxt/{CobqYwkp.js → D_ziPROx.js} +1 -1
  96. package/.output/public/_nuxt/{GtEM7xVU.js → Da2vwoYG.js} +1 -1
  97. package/.output/public/_nuxt/{Cc-2ziaZ.js → Ddz3HcBB.js} +1 -1
  98. package/.output/public/_nuxt/{Di-Nc75e.js → DgYei0bK.js} +1 -1
  99. package/.output/public/_nuxt/{DQh6I9z9.js → Di_3GV_R.js} +1 -1
  100. package/.output/public/_nuxt/{ByYh0uRg.js → Djog1f_e.js} +1 -1
  101. package/.output/public/_nuxt/{C4mwL7SE.js → Dkap2-Pj.js} +2 -2
  102. package/.output/public/_nuxt/{D5q8SnqE.js → DlJe_sHk.js} +1 -1
  103. package/.output/public/_nuxt/DlPOQpH_.js +1 -0
  104. package/.output/public/_nuxt/{DTGenhcA.js → DmYWMtVA.js} +1 -1
  105. package/.output/public/_nuxt/DmxKU7sH.js +1 -0
  106. package/.output/public/_nuxt/{DtjjnHnt.js → DowkFZ2V.js} +1 -1
  107. package/.output/public/_nuxt/{0NJ3PaRM.js → DsodHRrQ.js} +1 -1
  108. package/.output/public/_nuxt/{Bk6JUtIo.js → DuzpliIL.js} +1 -1
  109. package/.output/public/_nuxt/DvHS7_h2.js +1 -0
  110. package/.output/public/_nuxt/DwSY6_2U.js +1 -0
  111. package/.output/public/_nuxt/{Djs0Tlpa.js → DypJaSm-.js} +1 -1
  112. package/.output/public/_nuxt/{C71_a1IX.js → DzKaXH6P.js} +1 -1
  113. package/.output/public/_nuxt/{CBTkrk2M.js → FK-jSuOT.js} +1 -1
  114. package/.output/public/_nuxt/{ILEvizzp.js → Fc2JsQt4.js} +1 -1
  115. package/.output/public/_nuxt/{BIXrSYwR.js → IYCBGuRS.js} +1 -1
  116. package/.output/public/_nuxt/{JX1oqJI9.js → LRO7YHoH.js} +1 -1
  117. package/.output/public/_nuxt/{Kw0zy3FG.js → NrRzUJNY.js} +1 -1
  118. package/.output/public/_nuxt/{DJTCT0bl.js → OeVS0Rsb.js} +1 -1
  119. package/.output/public/_nuxt/{BmOtR1wX.js → OlF0QnKF.js} +1 -1
  120. package/.output/public/_nuxt/{DTAStixR.js → QuAoqY7t.js} +1 -1
  121. package/.output/public/_nuxt/{8q5NepGW.js → RlXHkmOd.js} +2 -2
  122. package/.output/public/_nuxt/{rfGRTJJW.js → TxMdabnL.js} +1 -1
  123. package/.output/public/_nuxt/{CZVzFlpI.js → WZnvL9Dh.js} +1 -1
  124. package/.output/public/_nuxt/ZvG7a1W3.js +1 -0
  125. package/.output/public/_nuxt/{N5XtbYVD.js → aPNZBVrG.js} +1 -1
  126. package/.output/public/_nuxt/builds/latest.json +1 -1
  127. package/.output/public/_nuxt/builds/meta/495aca73-bfa5-456e-b96a-f02e009c72d3.json +1 -0
  128. package/.output/public/_nuxt/entry.C_udkZt9.css +1 -0
  129. package/.output/public/_nuxt/{D_4LPm1U.js → evY81hM3.js} +1 -1
  130. package/.output/public/_nuxt/{DzGy77Vr.js → h_bXa-f2.js} +1 -1
  131. package/.output/public/_nuxt/{D9nmzBAw.js → i6QBzaEi.js} +1 -1
  132. package/.output/public/_nuxt/{BGgwYWjH.js → iTVKJ1kw.js} +1 -1
  133. package/.output/public/_nuxt/{Um1vPiAz.js → j92uR3uR.js} +1 -1
  134. package/.output/public/_nuxt/jdUkeAj_.js +1 -0
  135. package/.output/public/_nuxt/{BmVLxnDU.js → jeRvcMHU.js} +1 -1
  136. package/.output/public/_nuxt/{SrncdpaW.js → kuv0zpKq.js} +1 -1
  137. package/.output/public/_nuxt/{DfF81NlA.js → l3lKQs7b.js} +1 -1
  138. package/.output/public/_nuxt/{4K03TkGA.js → pdYvpiud.js} +3 -3
  139. package/.output/public/_nuxt/{C39dQ88F.js → qIgZ7OXa.js} +1 -1
  140. package/.output/public/_nuxt/{DS2wStH1.js → qcVwZv8e.js} +1 -1
  141. package/.output/public/_nuxt/{g5MjDvm5.js → ru8fqqWs.js} +1 -1
  142. package/.output/public/_nuxt/{CQqCBrXj.js → sBzyvWMJ.js} +1 -1
  143. package/.output/public/_nuxt/{D3AZaldL.js → sgmhgpCS.js} +1 -1
  144. package/.output/public/_nuxt/{ChcO9s3o.js → y2jv0da-.js} +1 -1
  145. package/.output/public/_nuxt/{Dn5a-guE.js → yyS4-kAX.js} +1 -1
  146. package/.output/public/_nuxt/zIoBLBHF.js +1 -0
  147. package/.output/public/_nuxt/zpazwPgx.js +1 -0
  148. package/.output/server/chunks/build/{chat-CR3JIVEq.mjs → chat-m4-n9vC6.mjs} +516 -14
  149. package/.output/server/chunks/build/chat-m4-n9vC6.mjs.map +1 -0
  150. package/.output/server/chunks/build/client.precomputed.mjs +1 -1
  151. package/.output/server/chunks/build/server.mjs +1 -1
  152. package/.output/server/chunks/build/styles.mjs +4 -4
  153. package/.output/server/chunks/nitro/nitro.mjs +875 -863
  154. package/.output/server/chunks/routes/_ws/chat.mjs +39 -5
  155. package/.output/server/chunks/routes/_ws/chat.mjs.map +1 -1
  156. package/Claude/skills/_lib/api.py +3 -2
  157. package/app/components/chat/ChatInput.vue +133 -5
  158. package/app/components/chat/MessageBubble.vue +188 -6
  159. package/app/composables/useAttachments.ts +196 -0
  160. package/app/composables/useChat.ts +14 -2
  161. package/app/pages/chat.vue +4 -2
  162. package/package.json +1 -1
  163. package/server/bridge/adapters/imessage.ts +9 -2
  164. package/server/routes/_ws/chat.ts +61 -7
  165. package/server/utils/chat-session-manager.ts +20 -2
  166. package/shared/types/index.ts +27 -1
  167. package/.output/public/_nuxt/BH0QDWEm.js +0 -1
  168. package/.output/public/_nuxt/BK8S2ony.js +0 -1
  169. package/.output/public/_nuxt/BZrSPX0S.js +0 -1
  170. package/.output/public/_nuxt/BaZwjF8o.js +0 -1
  171. package/.output/public/_nuxt/BkfI94R8.js +0 -1
  172. package/.output/public/_nuxt/C3NST0BU.js +0 -1
  173. package/.output/public/_nuxt/CKxSHyww.js +0 -1
  174. package/.output/public/_nuxt/CSKJ-Ahh.js +0 -1
  175. package/.output/public/_nuxt/CWyMCJQH.js +0 -1
  176. package/.output/public/_nuxt/CYPO5o_C.js +0 -1
  177. package/.output/public/_nuxt/CqNwHCpo.js +0 -1
  178. package/.output/public/_nuxt/CwPdIZ9J.js +0 -1
  179. package/.output/public/_nuxt/D5jZq8b3.js +0 -1
  180. package/.output/public/_nuxt/DH4YkDAi.js +0 -1
  181. package/.output/public/_nuxt/DPklr_tJ.js +0 -2
  182. package/.output/public/_nuxt/DQM4eBdt.js +0 -1
  183. package/.output/public/_nuxt/DUAAXJ6Q.js +0 -1
  184. package/.output/public/_nuxt/DmmdPt_5.js +0 -1
  185. package/.output/public/_nuxt/H6JbrRBU.js +0 -1
  186. package/.output/public/_nuxt/builds/meta/a892969f-e07d-4f44-8d7e-57a4b7f33d94.json +0 -1
  187. package/.output/public/_nuxt/entry.NKPfH2kE.css +0 -1
  188. package/.output/server/chunks/build/chat-CR3JIVEq.mjs.map +0 -1
@@ -1,9 +1,10 @@
1
1
  import { _ as _sfc_main$1$1, a as _sfc_main$6 } from './DashboardNavbar-Cpq8yKA0.mjs';
2
- import { Q as useRoute, A as useRouter, g as _sfc_main$d, _ as _sfc_main$8 } from './server.mjs';
3
- import { defineComponent, ref, watch, nextTick, computed, mergeProps, withCtx, unref, createVNode, createBlock, createCommentVNode, openBlock, Fragment, renderList, createTextVNode, readonly, useSSRContext } from 'vue';
4
- import { ssrRenderAttrs, ssrRenderComponent, ssrRenderList, ssrRenderClass, ssrInterpolate, ssrIncludeBooleanAttr } from 'vue/server-renderer';
2
+ import { Q as useRoute, A as useRouter, g as _sfc_main$d, _ as _sfc_main$8, T as __nuxt_component_12, i as useToast } from './server.mjs';
3
+ import { defineComponent, ref, watch, nextTick, computed, mergeProps, withCtx, unref, createVNode, createBlock, createCommentVNode, openBlock, Fragment, renderList, createTextVNode, readonly, isRef, toDisplayString, useSSRContext } from 'vue';
4
+ import { ssrRenderAttrs, ssrRenderComponent, ssrRenderList, ssrRenderClass, ssrInterpolate, ssrRenderAttr, ssrIncludeBooleanAttr } from 'vue/server-renderer';
5
5
  import { _ as _sfc_main$7 } from './Badge-C1RKkIgG.mjs';
6
6
  import { _ as _sfc_main$9 } from './MDC-Dx0YPDhe.mjs';
7
+ import { _ as _sfc_main$a } from './Modal-Z_SoWhh-.mjs';
7
8
  import './DashboardSidebarToggle-Chnqv04k.mjs';
8
9
  import '@vueuse/core';
9
10
  import './cookie-C_iulBi6.mjs';
@@ -260,6 +261,12 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
260
261
  function getTextContent(blocks) {
261
262
  return blocks.filter((b) => b.type === "text").map((b) => b.text).join("\n");
262
263
  }
264
+ function getImageBlocks(blocks) {
265
+ return blocks.filter((b) => b.type === "image");
266
+ }
267
+ function getDocumentBlocks(blocks) {
268
+ return blocks.filter((b) => b.type === "document");
269
+ }
263
270
  function getToolPairs(blocks) {
264
271
  const tools = [];
265
272
  for (const block of blocks) {
@@ -275,6 +282,78 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
275
282
  }
276
283
  return tools;
277
284
  }
285
+ function getDocIcon(doc) {
286
+ if (doc.source.media_type === "application/pdf") return "i-lucide-file-text";
287
+ return "i-lucide-file-code";
288
+ }
289
+ const previewImage = ref(null);
290
+ const previewOpen = computed({
291
+ get: () => previewImage.value !== null,
292
+ set: (v) => {
293
+ if (!v) previewImage.value = null;
294
+ }
295
+ });
296
+ const previewDoc = ref(null);
297
+ const codePreviewOpen = computed({
298
+ get: () => previewDoc.value !== null,
299
+ set: (v) => {
300
+ if (!v) previewDoc.value = null;
301
+ }
302
+ });
303
+ const codePreviewContent = computed(() => previewDoc.value?.source.data || "");
304
+ const extToLang = {
305
+ md: "markdown",
306
+ js: "javascript",
307
+ mjs: "javascript",
308
+ cjs: "javascript",
309
+ jsx: "javascript",
310
+ ts: "typescript",
311
+ tsx: "typescript",
312
+ mts: "typescript",
313
+ json: "json",
314
+ html: "html",
315
+ htm: "html",
316
+ css: "css",
317
+ scss: "css",
318
+ sass: "css",
319
+ less: "css",
320
+ vue: "vue",
321
+ svelte: "html",
322
+ py: "python",
323
+ sql: "sql",
324
+ yaml: "yaml",
325
+ yml: "yaml",
326
+ sh: "bash",
327
+ bash: "bash",
328
+ zsh: "bash",
329
+ fish: "bash",
330
+ go: "go",
331
+ rs: "rust",
332
+ dockerfile: "dockerfile",
333
+ java: "java",
334
+ kt: "java",
335
+ c: "cpp",
336
+ cpp: "cpp",
337
+ h: "cpp",
338
+ hpp: "cpp",
339
+ cs: "cpp",
340
+ xml: "xml",
341
+ graphql: "plaintext",
342
+ gql: "plaintext",
343
+ toml: "plaintext",
344
+ ini: "plaintext",
345
+ csv: "plaintext",
346
+ txt: "plaintext",
347
+ log: "plaintext",
348
+ env: "plaintext",
349
+ prisma: "plaintext",
350
+ proto: "plaintext"
351
+ };
352
+ const codePreviewLang = computed(() => {
353
+ if (!previewDoc.value?.title) return "plaintext";
354
+ const ext = previewDoc.value.title.split(".").pop()?.toLowerCase() || "";
355
+ return extToLang[ext] || "plaintext";
356
+ });
278
357
  const sourceIconMap = {
279
358
  telegram: "i-simple-icons-telegram",
280
359
  discord: "i-simple-icons-discord",
@@ -302,6 +381,8 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
302
381
  const _component_UIcon = _sfc_main$d;
303
382
  const _component_MDC = _sfc_main$9;
304
383
  const _component_ChatToolCallBlock = __nuxt_component_1;
384
+ const _component_UModal = _sfc_main$a;
385
+ const _component_EditorCodeEditor = __nuxt_component_12;
305
386
  _push(`<div${ssrRenderAttrs(mergeProps({
306
387
  class: ["flex", __props.message.role === "user" ? "justify-end" : "justify-start"]
307
388
  }, _attrs))}>`);
@@ -315,7 +396,45 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
315
396
  }
316
397
  _push(`<div class="${ssrRenderClass([__props.message.role === "user" ? "bg-primary/5 text-highlighted" : "bg-muted", "max-w-[85%] rounded-xl px-4 py-3"])}">`);
317
398
  if (__props.message.role === "user") {
318
- _push(`<div class="text-sm whitespace-pre-wrap">${ssrInterpolate(getTextContent(__props.message.content))}</div>`);
399
+ _push(`<div>`);
400
+ if (getImageBlocks(__props.message.content).length) {
401
+ _push(`<div class="flex flex-wrap gap-2 mb-2"><!--[-->`);
402
+ ssrRenderList(getImageBlocks(__props.message.content), (img, i) => {
403
+ _push(`<img${ssrRenderAttr("src", `data:${img.source.media_type};base64,${img.source.data}`)} class="max-w-48 max-h-48 rounded-lg object-contain cursor-pointer hover:opacity-80 transition-opacity">`);
404
+ });
405
+ _push(`<!--]--></div>`);
406
+ } else {
407
+ _push(`<!---->`);
408
+ }
409
+ if (getDocumentBlocks(__props.message.content).length) {
410
+ _push(`<div class="flex flex-wrap gap-2 mb-2"><!--[-->`);
411
+ ssrRenderList(getDocumentBlocks(__props.message.content), (doc, i) => {
412
+ _push(`<button class="flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg bg-elevated/50 border border-default text-xs hover:bg-elevated transition-colors cursor-pointer">`);
413
+ _push(ssrRenderComponent(_component_UIcon, {
414
+ name: getDocIcon(doc),
415
+ class: "size-3.5 text-dimmed shrink-0"
416
+ }, null, _parent));
417
+ _push(`<span class="truncate max-w-32">${ssrInterpolate(doc.title || "Document")}</span>`);
418
+ if (doc.source.media_type === "application/pdf") {
419
+ _push(ssrRenderComponent(_component_UIcon, {
420
+ name: "i-lucide-external-link",
421
+ class: "size-3 text-dimmed shrink-0"
422
+ }, null, _parent));
423
+ } else {
424
+ _push(`<!---->`);
425
+ }
426
+ _push(`</button>`);
427
+ });
428
+ _push(`<!--]--></div>`);
429
+ } else {
430
+ _push(`<!---->`);
431
+ }
432
+ if (getTextContent(__props.message.content)) {
433
+ _push(`<div class="text-sm whitespace-pre-wrap">${ssrInterpolate(getTextContent(__props.message.content))}</div>`);
434
+ } else {
435
+ _push(`<!---->`);
436
+ }
437
+ _push(`</div>`);
319
438
  } else {
320
439
  _push(`<!--[-->`);
321
440
  if (getTextContent(__props.message.content)) {
@@ -360,7 +479,87 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
360
479
  } else {
361
480
  _push(`<!---->`);
362
481
  }
363
- _push(`</div></div>`);
482
+ _push(`</div>`);
483
+ _push(ssrRenderComponent(_component_UModal, {
484
+ open: unref(previewOpen),
485
+ "onUpdate:open": ($event) => isRef(previewOpen) ? previewOpen.value = $event : null
486
+ }, {
487
+ content: withCtx((_, _push2, _parent2, _scopeId) => {
488
+ if (_push2) {
489
+ _push2(`<div class="flex items-center justify-center"${_scopeId}>`);
490
+ if (unref(previewImage)) {
491
+ _push2(`<img${ssrRenderAttr("src", `data:${unref(previewImage).source.media_type};base64,${unref(previewImage).source.data}`)} class="max-w-full max-h-[80vh] object-contain rounded-lg"${_scopeId}>`);
492
+ } else {
493
+ _push2(`<!---->`);
494
+ }
495
+ _push2(`</div>`);
496
+ } else {
497
+ return [
498
+ createVNode("div", { class: "flex items-center justify-center" }, [
499
+ unref(previewImage) ? (openBlock(), createBlock("img", {
500
+ key: 0,
501
+ src: `data:${unref(previewImage).source.media_type};base64,${unref(previewImage).source.data}`,
502
+ class: "max-w-full max-h-[80vh] object-contain rounded-lg"
503
+ }, null, 8, ["src"])) : createCommentVNode("", true)
504
+ ])
505
+ ];
506
+ }
507
+ }),
508
+ _: 1
509
+ }, _parent));
510
+ _push(ssrRenderComponent(_component_UModal, {
511
+ open: unref(codePreviewOpen),
512
+ "onUpdate:open": ($event) => isRef(codePreviewOpen) ? codePreviewOpen.value = $event : null
513
+ }, {
514
+ header: withCtx((_, _push2, _parent2, _scopeId) => {
515
+ if (_push2) {
516
+ _push2(`<div class="flex items-center gap-2"${_scopeId}>`);
517
+ _push2(ssrRenderComponent(_component_UIcon, {
518
+ name: "i-lucide-file-code",
519
+ class: "size-4 text-dimmed"
520
+ }, null, _parent2, _scopeId));
521
+ _push2(`<span class="text-sm font-medium truncate"${_scopeId}>${ssrInterpolate(unref(previewDoc)?.title || "File")}</span></div>`);
522
+ } else {
523
+ return [
524
+ createVNode("div", { class: "flex items-center gap-2" }, [
525
+ createVNode(_component_UIcon, {
526
+ name: "i-lucide-file-code",
527
+ class: "size-4 text-dimmed"
528
+ }),
529
+ createVNode("span", { class: "text-sm font-medium truncate" }, toDisplayString(unref(previewDoc)?.title || "File"), 1)
530
+ ])
531
+ ];
532
+ }
533
+ }),
534
+ body: withCtx((_, _push2, _parent2, _scopeId) => {
535
+ if (_push2) {
536
+ _push2(`<div class="h-[60vh] overflow-hidden rounded-lg border border-default"${_scopeId}>`);
537
+ if (unref(previewDoc)) {
538
+ _push2(ssrRenderComponent(_component_EditorCodeEditor, {
539
+ "model-value": unref(codePreviewContent),
540
+ language: unref(codePreviewLang),
541
+ "read-only": ""
542
+ }, null, _parent2, _scopeId));
543
+ } else {
544
+ _push2(`<!---->`);
545
+ }
546
+ _push2(`</div>`);
547
+ } else {
548
+ return [
549
+ createVNode("div", { class: "h-[60vh] overflow-hidden rounded-lg border border-default" }, [
550
+ unref(previewDoc) ? (openBlock(), createBlock(_component_EditorCodeEditor, {
551
+ key: 0,
552
+ "model-value": unref(codePreviewContent),
553
+ language: unref(codePreviewLang),
554
+ "read-only": ""
555
+ }, null, 8, ["model-value", "language"])) : createCommentVNode("", true)
556
+ ])
557
+ ];
558
+ }
559
+ }),
560
+ _: 1
561
+ }, _parent));
562
+ _push(`</div>`);
364
563
  };
365
564
  }
366
565
  });
@@ -411,6 +610,206 @@ _sfc_main$2.setup = (props, ctx) => {
411
610
  return _sfc_setup$2 ? _sfc_setup$2(props, ctx) : void 0;
412
611
  };
413
612
  const __nuxt_component_7 = Object.assign(_sfc_main$2, { __name: "ChatStreamingMessage" });
613
+ const IMAGE_TYPES = ["image/jpeg", "image/png", "image/gif", "image/webp"];
614
+ const TEXT_MIME_TYPES = /* @__PURE__ */ new Set([
615
+ "application/json",
616
+ "application/javascript",
617
+ "application/typescript",
618
+ "application/xml",
619
+ "application/x-yaml",
620
+ "application/x-sh",
621
+ "application/sql",
622
+ "application/toml",
623
+ "application/x-httpd-php"
624
+ ]);
625
+ const MAX_FILE_SIZE = 20 * 1024 * 1024;
626
+ function generateId$1() {
627
+ if (typeof crypto !== "undefined" && crypto.randomUUID)
628
+ return crypto.randomUUID();
629
+ return Math.random().toString(36).slice(2);
630
+ }
631
+ function readFileAsBase64(file) {
632
+ return new Promise((resolve, reject) => {
633
+ const reader = new FileReader();
634
+ reader.onload = () => {
635
+ const result = reader.result;
636
+ const base64 = result.split(",")[1];
637
+ if (base64) resolve(base64);
638
+ else reject(new Error("Failed to read file as base64"));
639
+ };
640
+ reader.onerror = () => reject(reader.error);
641
+ reader.readAsDataURL(file);
642
+ });
643
+ }
644
+ function readFileAsText(file) {
645
+ return new Promise((resolve, reject) => {
646
+ const reader = new FileReader();
647
+ reader.onload = () => resolve(reader.result);
648
+ reader.onerror = () => reject(reader.error);
649
+ reader.readAsText(file);
650
+ });
651
+ }
652
+ function isImageType(mime) {
653
+ return IMAGE_TYPES.includes(mime);
654
+ }
655
+ function isTextType(mime) {
656
+ return mime.startsWith("text/") || TEXT_MIME_TYPES.has(mime);
657
+ }
658
+ function isPdfType(mime) {
659
+ return mime === "application/pdf";
660
+ }
661
+ function useAttachments() {
662
+ const attachments = ref([]);
663
+ const toast = useToast();
664
+ async function addFiles(files) {
665
+ for (const file of Array.from(files)) {
666
+ if (file.size > MAX_FILE_SIZE) {
667
+ toast.add({ title: "File too large", description: `${file.name} exceeds 20MB limit`, color: "error" });
668
+ continue;
669
+ }
670
+ const mime = file.type || "";
671
+ try {
672
+ if (isImageType(mime)) {
673
+ const base64 = await readFileAsBase64(file);
674
+ const previewUrl = URL.createObjectURL(file);
675
+ attachments.value.push({
676
+ id: generateId$1(),
677
+ kind: "image",
678
+ previewUrl,
679
+ base64,
680
+ mediaType: mime,
681
+ name: file.name
682
+ });
683
+ } else if (isPdfType(mime)) {
684
+ const base64 = await readFileAsBase64(file);
685
+ attachments.value.push({
686
+ id: generateId$1(),
687
+ kind: "document",
688
+ data: base64,
689
+ sourceType: "base64",
690
+ name: file.name
691
+ });
692
+ } else if (isTextType(mime) || isLikelyTextFile(file.name)) {
693
+ const text = await readFileAsText(file);
694
+ attachments.value.push({
695
+ id: generateId$1(),
696
+ kind: "document",
697
+ data: text,
698
+ sourceType: "text",
699
+ name: file.name
700
+ });
701
+ } else {
702
+ toast.add({ title: "Unsupported file type", description: `${file.name} (${mime || "unknown type"})`, color: "error" });
703
+ }
704
+ } catch {
705
+ toast.add({ title: "Failed to read file", description: file.name, color: "error" });
706
+ }
707
+ }
708
+ }
709
+ function removeAttachment(id) {
710
+ const idx = attachments.value.findIndex((a) => a.id === id);
711
+ if (idx !== -1) {
712
+ const att = attachments.value[idx];
713
+ if (att.kind === "image") URL.revokeObjectURL(att.previewUrl);
714
+ attachments.value.splice(idx, 1);
715
+ }
716
+ }
717
+ function clearAttachments() {
718
+ for (const att of attachments.value)
719
+ if (att.kind === "image") URL.revokeObjectURL(att.previewUrl);
720
+ attachments.value = [];
721
+ }
722
+ function toImageBlocks() {
723
+ return attachments.value.filter((a) => a.kind === "image").map((att) => ({
724
+ type: "image",
725
+ source: {
726
+ type: "base64",
727
+ media_type: att.mediaType,
728
+ data: att.base64
729
+ }
730
+ }));
731
+ }
732
+ function toDocumentBlocks() {
733
+ return attachments.value.filter((a) => a.kind === "document").map((att) => ({
734
+ type: "document",
735
+ source: att.sourceType === "base64" ? { type: "base64", media_type: "application/pdf", data: att.data } : { type: "text", media_type: "text/plain", data: att.data },
736
+ title: att.name
737
+ }));
738
+ }
739
+ return {
740
+ attachments: readonly(attachments),
741
+ addFiles,
742
+ removeAttachment,
743
+ clearAttachments,
744
+ toImageBlocks,
745
+ toDocumentBlocks
746
+ };
747
+ }
748
+ function isLikelyTextFile(name) {
749
+ const ext = name.split(".").pop()?.toLowerCase();
750
+ if (!ext) return false;
751
+ const textExtensions = /* @__PURE__ */ new Set([
752
+ "txt",
753
+ "md",
754
+ "js",
755
+ "ts",
756
+ "jsx",
757
+ "tsx",
758
+ "py",
759
+ "rb",
760
+ "rs",
761
+ "go",
762
+ "java",
763
+ "c",
764
+ "cpp",
765
+ "h",
766
+ "hpp",
767
+ "cs",
768
+ "swift",
769
+ "kt",
770
+ "scala",
771
+ "json",
772
+ "yaml",
773
+ "yml",
774
+ "toml",
775
+ "ini",
776
+ "cfg",
777
+ "conf",
778
+ "xml",
779
+ "html",
780
+ "htm",
781
+ "css",
782
+ "scss",
783
+ "sass",
784
+ "less",
785
+ "sh",
786
+ "bash",
787
+ "zsh",
788
+ "fish",
789
+ "ps1",
790
+ "bat",
791
+ "cmd",
792
+ "sql",
793
+ "graphql",
794
+ "gql",
795
+ "proto",
796
+ "csv",
797
+ "tsv",
798
+ "log",
799
+ "env",
800
+ "gitignore",
801
+ "dockerignore",
802
+ "vue",
803
+ "svelte",
804
+ "astro",
805
+ "prisma",
806
+ "tf",
807
+ "r",
808
+ "lua",
809
+ "dart"
810
+ ]);
811
+ return textExtensions.has(ext);
812
+ }
414
813
  const _sfc_main$1 = /* @__PURE__ */ defineComponent({
415
814
  __name: "ChatInput",
416
815
  __ssrInlineRender: true,
@@ -422,28 +821,123 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
422
821
  setup(__props, { emit: __emit }) {
423
822
  const props = __props;
424
823
  const emit = __emit;
824
+ const { attachments, clearAttachments, toImageBlocks, toDocumentBlocks } = useAttachments();
425
825
  const inputText = ref("");
426
826
  const textareaRef = ref(null);
827
+ const fileInputRef = ref(null);
828
+ const isDragging = ref(false);
427
829
  const isStreaming = computed(() => props.sessionStatus === "streaming");
428
830
  const isConnected = computed(() => props.connectionStatus === "connected");
429
- const canSend = computed(() => isConnected.value && !isStreaming.value && inputText.value.trim().length > 0);
831
+ const canSend = computed(
832
+ () => isConnected.value && !isStreaming.value && (inputText.value.trim().length > 0 || attachments.value.length > 0)
833
+ );
430
834
  function handleSend() {
431
835
  if (!canSend.value) return;
432
- emit("send", inputText.value.trim());
836
+ const images = toImageBlocks();
837
+ const docs = toDocumentBlocks();
838
+ emit(
839
+ "send",
840
+ inputText.value.trim(),
841
+ images.length > 0 ? images : void 0,
842
+ docs.length > 0 ? docs : void 0
843
+ );
433
844
  inputText.value = "";
845
+ clearAttachments();
434
846
  nextTick(() => {
435
847
  if (textareaRef.value) textareaRef.value.style.height = "auto";
436
848
  });
437
849
  }
850
+ const FILE_ACCEPT = [
851
+ "image/jpeg",
852
+ "image/png",
853
+ "image/gif",
854
+ "image/webp",
855
+ "application/pdf",
856
+ ".txt",
857
+ ".md",
858
+ ".js",
859
+ ".ts",
860
+ ".jsx",
861
+ ".tsx",
862
+ ".py",
863
+ ".rb",
864
+ ".rs",
865
+ ".go",
866
+ ".java",
867
+ ".c",
868
+ ".cpp",
869
+ ".h",
870
+ ".cs",
871
+ ".swift",
872
+ ".kt",
873
+ ".json",
874
+ ".yaml",
875
+ ".yml",
876
+ ".toml",
877
+ ".ini",
878
+ ".xml",
879
+ ".html",
880
+ ".css",
881
+ ".scss",
882
+ ".sh",
883
+ ".sql",
884
+ ".graphql",
885
+ ".csv",
886
+ ".log",
887
+ ".vue",
888
+ ".svelte",
889
+ ".prisma",
890
+ ".lua",
891
+ ".dart"
892
+ ].join(",");
438
893
  return (_ctx, _push, _parent, _attrs) => {
894
+ const _component_UIcon = _sfc_main$d;
439
895
  const _component_UButton = _sfc_main$8;
440
- _push(`<div${ssrRenderAttrs(mergeProps({ class: "border-t border-default p-4" }, _attrs))}>`);
896
+ _push(`<div${ssrRenderAttrs(mergeProps({ class: "border-t border-default p-4 relative" }, _attrs))}>`);
897
+ if (unref(isDragging)) {
898
+ _push(`<div class="absolute inset-0 bg-primary/10 border-2 border-dashed border-primary rounded-lg flex items-center justify-center z-10"><span class="text-sm text-primary font-medium">Drop files here</span></div>`);
899
+ } else {
900
+ _push(`<!---->`);
901
+ }
441
902
  if (!unref(isConnected)) {
442
903
  _push(`<div class="flex items-center gap-2 mb-2 text-xs text-dimmed"><span class="size-2 rounded-full bg-warning"></span><span>${ssrInterpolate(__props.connectionStatus === "connecting" ? "Connecting..." : "Disconnected")}</span></div>`);
443
904
  } else {
444
905
  _push(`<!---->`);
445
906
  }
446
- _push(`<div class="flex items-start gap-2"><textarea${ssrIncludeBooleanAttr(!unref(isConnected) || unref(isStreaming)) ? " disabled" : ""} placeholder="Send a message..." rows="1" class="flex-1 resize-none bg-elevated/50 border border-default rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary/50 disabled:opacity-50">${ssrInterpolate(unref(inputText))}</textarea>`);
907
+ if (unref(attachments).length) {
908
+ _push(`<div class="flex gap-2 mb-2 flex-wrap"><!--[-->`);
909
+ ssrRenderList(unref(attachments), (att) => {
910
+ _push(`<div class="${ssrRenderClass([att.kind === "image" ? "size-16" : "h-10 px-3 flex items-center gap-1.5 bg-elevated/50", "relative group rounded-lg overflow-hidden border border-default"])}">`);
911
+ if (att.kind === "image") {
912
+ _push(`<img${ssrRenderAttr("src", att.previewUrl)}${ssrRenderAttr("alt", att.name)} class="size-full object-cover">`);
913
+ } else {
914
+ _push(`<!--[-->`);
915
+ _push(ssrRenderComponent(_component_UIcon, {
916
+ name: att.name.endsWith(".pdf") ? "i-lucide-file-text" : "i-lucide-file-code",
917
+ class: "size-4 text-dimmed shrink-0"
918
+ }, null, _parent));
919
+ _push(`<span class="text-xs truncate max-w-24">${ssrInterpolate(att.name)}</span><!--]-->`);
920
+ }
921
+ _push(`<button class="absolute top-0 right-0 p-0.5 bg-error/80 rounded-bl-lg opacity-0 group-hover:opacity-100 transition-opacity">`);
922
+ _push(ssrRenderComponent(_component_UIcon, {
923
+ name: "i-lucide-x",
924
+ class: "size-3 text-white"
925
+ }, null, _parent));
926
+ _push(`</button></div>`);
927
+ });
928
+ _push(`<!--]--></div>`);
929
+ } else {
930
+ _push(`<!---->`);
931
+ }
932
+ _push(`<div class="flex items-start gap-2"><textarea${ssrIncludeBooleanAttr(!unref(isConnected) || unref(isStreaming)) ? " disabled" : ""} placeholder="Send a message..." rows="1" class="flex-1 resize-none bg-elevated/50 border border-default rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary/50 disabled:opacity-50">${ssrInterpolate(unref(inputText))}</textarea><input type="file"${ssrRenderAttr("accept", unref(FILE_ACCEPT))} multiple class="hidden">`);
933
+ _push(ssrRenderComponent(_component_UButton, {
934
+ icon: "i-lucide-paperclip",
935
+ variant: "ghost",
936
+ color: "neutral",
937
+ size: "md",
938
+ disabled: !unref(isConnected) || unref(isStreaming),
939
+ onClick: ($event) => unref(fileInputRef)?.click()
940
+ }, null, _parent));
447
941
  if (unref(isStreaming)) {
448
942
  _push(ssrRenderComponent(_component_UButton, {
449
943
  icon: "i-lucide-square",
@@ -504,18 +998,26 @@ function useChat() {
504
998
  }
505
999
  connectionStatus.value = "disconnected";
506
1000
  }
507
- function sendMessage(message) {
1001
+ function sendMessage(message, attachments, documents) {
508
1002
  if (!ws.value || ws.value.readyState !== WebSocket.OPEN) return;
1003
+ const content = [];
1004
+ if (attachments?.length)
1005
+ for (const img of attachments) content.push(img);
1006
+ if (documents?.length)
1007
+ for (const doc of documents) content.push(doc);
1008
+ if (message) content.push({ type: "text", text: message });
509
1009
  messages.value.push({
510
1010
  id: generateId(),
511
1011
  conversationId: activeConversationId.value || "",
512
1012
  role: "user",
513
- content: [{ type: "text", text: message }],
1013
+ content,
514
1014
  createdAt: /* @__PURE__ */ new Date()
515
1015
  });
516
1016
  ws.value.send(JSON.stringify({
517
1017
  type: "chat:send",
518
1018
  message,
1019
+ attachments: attachments?.length ? attachments : void 0,
1020
+ documents: documents?.length ? documents : void 0,
519
1021
  conversationId: activeConversationId.value
520
1022
  }));
521
1023
  }
@@ -612,8 +1114,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
612
1114
  useRoute();
613
1115
  useRouter();
614
1116
  const messagesContainer = ref(null);
615
- function handleSend(message) {
616
- sendMessage(message);
1117
+ function handleSend(message, attachments, documents) {
1118
+ sendMessage(message, attachments, documents);
617
1119
  nextTick(scrollToBottom);
618
1120
  }
619
1121
  function scrollToBottom() {
@@ -847,4 +1349,4 @@ _sfc_main.setup = (props, ctx) => {
847
1349
  };
848
1350
 
849
1351
  export { _sfc_main as default };
850
- //# sourceMappingURL=chat-CR3JIVEq.mjs.map
1352
+ //# sourceMappingURL=chat-m4-n9vC6.mjs.map