glirastes 0.1.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 (424) hide show
  1. package/CHANGELOG.md +468 -0
  2. package/README.md +651 -0
  3. package/dist/cli/bin.d.ts +2 -0
  4. package/dist/cli/bin.js +34 -0
  5. package/dist/cli/bin.js.map +1 -0
  6. package/dist/cli/commands/check-upgrade.d.ts +15 -0
  7. package/dist/cli/commands/check-upgrade.js +138 -0
  8. package/dist/cli/commands/check-upgrade.js.map +1 -0
  9. package/dist/cli/commands/test.d.ts +8 -0
  10. package/dist/cli/commands/test.js +76 -0
  11. package/dist/cli/commands/test.js.map +1 -0
  12. package/dist/cli/index.d.ts +1 -0
  13. package/dist/cli/index.js +609 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/cli/utils/changelog-parser.d.ts +13 -0
  16. package/dist/cli/utils/changelog-parser.js +89 -0
  17. package/dist/cli/utils/changelog-parser.js.map +1 -0
  18. package/dist/cli/utils/commit-parser.d.ts +8 -0
  19. package/dist/cli/utils/commit-parser.js +23 -0
  20. package/dist/cli/utils/commit-parser.js.map +1 -0
  21. package/dist/cli/utils/gap-detector.d.ts +14 -0
  22. package/dist/cli/utils/gap-detector.js +65 -0
  23. package/dist/cli/utils/gap-detector.js.map +1 -0
  24. package/dist/cli/utils/get-cli-version.d.ts +2 -0
  25. package/dist/cli/utils/get-cli-version.js +10 -0
  26. package/dist/cli/utils/get-cli-version.js.map +1 -0
  27. package/dist/codegen/asset-sync.d.ts +20 -0
  28. package/dist/codegen/asset-sync.js +26 -0
  29. package/dist/codegen/asset-sync.js.map +1 -0
  30. package/dist/codegen/coverage.d.ts +66 -0
  31. package/dist/codegen/coverage.js +372 -0
  32. package/dist/codegen/coverage.js.map +1 -0
  33. package/dist/codegen/endpoint-scanner.d.ts +16 -0
  34. package/dist/codegen/endpoint-scanner.js +161 -0
  35. package/dist/codegen/endpoint-scanner.js.map +1 -0
  36. package/dist/codegen/format.d.ts +17 -0
  37. package/dist/codegen/format.js +28 -0
  38. package/dist/codegen/format.js.map +1 -0
  39. package/dist/codegen/fs-utils.d.ts +45 -0
  40. package/dist/codegen/fs-utils.js +155 -0
  41. package/dist/codegen/fs-utils.js.map +1 -0
  42. package/dist/codegen/index.d.ts +13 -0
  43. package/dist/codegen/index.js +13 -0
  44. package/dist/codegen/index.js.map +1 -0
  45. package/dist/codegen/mcp-generator.d.ts +50 -0
  46. package/dist/codegen/mcp-generator.js +801 -0
  47. package/dist/codegen/mcp-generator.js.map +1 -0
  48. package/dist/codegen/module-generator.d.ts +11 -0
  49. package/dist/codegen/module-generator.js +351 -0
  50. package/dist/codegen/module-generator.js.map +1 -0
  51. package/dist/codegen/nestjs-scanner.d.ts +43 -0
  52. package/dist/codegen/nestjs-scanner.js +239 -0
  53. package/dist/codegen/nestjs-scanner.js.map +1 -0
  54. package/dist/codegen/output-recommender.d.ts +23 -0
  55. package/dist/codegen/output-recommender.js +31 -0
  56. package/dist/codegen/output-recommender.js.map +1 -0
  57. package/dist/codegen/scaffolder.d.ts +36 -0
  58. package/dist/codegen/scaffolder.js +259 -0
  59. package/dist/codegen/scaffolder.js.map +1 -0
  60. package/dist/codegen/skill-generator.d.ts +49 -0
  61. package/dist/codegen/skill-generator.js +965 -0
  62. package/dist/codegen/skill-generator.js.map +1 -0
  63. package/dist/codegen/types.d.ts +52 -0
  64. package/dist/codegen/types.js +14 -0
  65. package/dist/codegen/types.js.map +1 -0
  66. package/dist/codegen/ui-scanner.d.ts +24 -0
  67. package/dist/codegen/ui-scanner.js +197 -0
  68. package/dist/codegen/ui-scanner.js.map +1 -0
  69. package/dist/codegen/validator.d.ts +35 -0
  70. package/dist/codegen/validator.js +256 -0
  71. package/dist/codegen/validator.js.map +1 -0
  72. package/dist/openapi/demo-generate.d.ts +1 -0
  73. package/dist/openapi/demo-generate.js +15 -0
  74. package/dist/openapi/demo-generate.js.map +1 -0
  75. package/dist/openapi/index.d.ts +78 -0
  76. package/dist/openapi/index.js +341 -0
  77. package/dist/openapi/index.js.map +1 -0
  78. package/dist/react/audio-worklet-processor.d.ts +9 -0
  79. package/dist/react/audio-worklet-processor.js +28 -0
  80. package/dist/react/audio-worklet-processor.js.map +1 -0
  81. package/dist/react/bridges/rest-session-bridge.d.ts +113 -0
  82. package/dist/react/bridges/rest-session-bridge.js +207 -0
  83. package/dist/react/bridges/rest-session-bridge.js.map +1 -0
  84. package/dist/react/components/ai-chat-panel.d.ts +12 -0
  85. package/dist/react/components/ai-chat-panel.js +65 -0
  86. package/dist/react/components/ai-chat-panel.js.map +1 -0
  87. package/dist/react/components/ai-trigger-button.d.ts +2 -0
  88. package/dist/react/components/ai-trigger-button.js +239 -0
  89. package/dist/react/components/ai-trigger-button.js.map +1 -0
  90. package/dist/react/components/approval-card.d.ts +9 -0
  91. package/dist/react/components/approval-card.js +22 -0
  92. package/dist/react/components/approval-card.js.map +1 -0
  93. package/dist/react/components/bulk-approval-card.d.ts +9 -0
  94. package/dist/react/components/bulk-approval-card.js +34 -0
  95. package/dist/react/components/bulk-approval-card.js.map +1 -0
  96. package/dist/react/components/chat-input.d.ts +10 -0
  97. package/dist/react/components/chat-input.js +58 -0
  98. package/dist/react/components/chat-input.js.map +1 -0
  99. package/dist/react/components/chat-window.d.ts +2 -0
  100. package/dist/react/components/chat-window.js +132 -0
  101. package/dist/react/components/chat-window.js.map +1 -0
  102. package/dist/react/components/confirm-dialog.d.ts +32 -0
  103. package/dist/react/components/confirm-dialog.js +46 -0
  104. package/dist/react/components/confirm-dialog.js.map +1 -0
  105. package/dist/react/components/floating-chat-ui.d.ts +84 -0
  106. package/dist/react/components/floating-chat-ui.js +161 -0
  107. package/dist/react/components/floating-chat-ui.js.map +1 -0
  108. package/dist/react/components/mention-chip.d.ts +16 -0
  109. package/dist/react/components/mention-chip.js +39 -0
  110. package/dist/react/components/mention-chip.js.map +1 -0
  111. package/dist/react/components/mention-input.d.ts +8 -0
  112. package/dist/react/components/mention-input.js +115 -0
  113. package/dist/react/components/mention-input.js.map +1 -0
  114. package/dist/react/components/message-bubble.d.ts +11 -0
  115. package/dist/react/components/message-bubble.js +123 -0
  116. package/dist/react/components/message-bubble.js.map +1 -0
  117. package/dist/react/components/message-list.d.ts +8 -0
  118. package/dist/react/components/message-list.js +50 -0
  119. package/dist/react/components/message-list.js.map +1 -0
  120. package/dist/react/components/pipeline-timeline.d.ts +7 -0
  121. package/dist/react/components/pipeline-timeline.js +70 -0
  122. package/dist/react/components/pipeline-timeline.js.map +1 -0
  123. package/dist/react/components/recording-bar.d.ts +2 -0
  124. package/dist/react/components/recording-bar.js +81 -0
  125. package/dist/react/components/recording-bar.js.map +1 -0
  126. package/dist/react/components/recording-controls.d.ts +18 -0
  127. package/dist/react/components/recording-controls.js +35 -0
  128. package/dist/react/components/recording-controls.js.map +1 -0
  129. package/dist/react/components/rich-mention-input.d.ts +2 -0
  130. package/dist/react/components/rich-mention-input.js +569 -0
  131. package/dist/react/components/rich-mention-input.js.map +1 -0
  132. package/dist/react/components/session-switcher.d.ts +14 -0
  133. package/dist/react/components/session-switcher.js +131 -0
  134. package/dist/react/components/session-switcher.js.map +1 -0
  135. package/dist/react/components/suggestion-bar.d.ts +9 -0
  136. package/dist/react/components/suggestion-bar.js +45 -0
  137. package/dist/react/components/suggestion-bar.js.map +1 -0
  138. package/dist/react/components/suggestion-chip.d.ts +9 -0
  139. package/dist/react/components/suggestion-chip.js +12 -0
  140. package/dist/react/components/suggestion-chip.js.map +1 -0
  141. package/dist/react/components/voice-input-addon.d.ts +13 -0
  142. package/dist/react/components/voice-input-addon.js +29 -0
  143. package/dist/react/components/voice-input-addon.js.map +1 -0
  144. package/dist/react/components/voice-input-button.d.ts +2 -0
  145. package/dist/react/components/voice-input-button.js +53 -0
  146. package/dist/react/components/voice-input-button.js.map +1 -0
  147. package/dist/react/hooks/use-ai-chat.d.ts +22 -0
  148. package/dist/react/hooks/use-ai-chat.js +49 -0
  149. package/dist/react/hooks/use-ai-chat.js.map +1 -0
  150. package/dist/react/hooks/use-approvals.d.ts +23 -0
  151. package/dist/react/hooks/use-approvals.js +61 -0
  152. package/dist/react/hooks/use-approvals.js.map +1 -0
  153. package/dist/react/hooks/use-deepgram-transcription.d.ts +2 -0
  154. package/dist/react/hooks/use-deepgram-transcription.js +327 -0
  155. package/dist/react/hooks/use-deepgram-transcription.js.map +1 -0
  156. package/dist/react/hooks/use-drag-resize-panel.d.ts +48 -0
  157. package/dist/react/hooks/use-drag-resize-panel.js +306 -0
  158. package/dist/react/hooks/use-drag-resize-panel.js.map +1 -0
  159. package/dist/react/hooks/use-draggable-position.d.ts +25 -0
  160. package/dist/react/hooks/use-draggable-position.js +132 -0
  161. package/dist/react/hooks/use-draggable-position.js.map +1 -0
  162. package/dist/react/hooks/use-keyboard-shortcut.d.ts +20 -0
  163. package/dist/react/hooks/use-keyboard-shortcut.js +91 -0
  164. package/dist/react/hooks/use-keyboard-shortcut.js.map +1 -0
  165. package/dist/react/hooks/use-mentions.d.ts +23 -0
  166. package/dist/react/hooks/use-mentions.js +40 -0
  167. package/dist/react/hooks/use-mentions.js.map +1 -0
  168. package/dist/react/hooks/use-suggestions.d.ts +22 -0
  169. package/dist/react/hooks/use-suggestions.js +37 -0
  170. package/dist/react/hooks/use-suggestions.js.map +1 -0
  171. package/dist/react/index.d.ts +43 -0
  172. package/dist/react/index.js +53 -0
  173. package/dist/react/index.js.map +1 -0
  174. package/dist/react/provider/ai-chat-provider.d.ts +45 -0
  175. package/dist/react/provider/ai-chat-provider.js +1021 -0
  176. package/dist/react/provider/ai-chat-provider.js.map +1 -0
  177. package/dist/react/provider/chat-context.d.ts +84 -0
  178. package/dist/react/provider/chat-context.js +10 -0
  179. package/dist/react/provider/chat-context.js.map +1 -0
  180. package/dist/react/styles.css +897 -0
  181. package/dist/react/template.d.ts +84 -0
  182. package/dist/react/template.js +83 -0
  183. package/dist/react/template.js.map +1 -0
  184. package/dist/react/themes.d.ts +24 -0
  185. package/dist/react/themes.js +269 -0
  186. package/dist/react/themes.js.map +1 -0
  187. package/dist/react/transports/langgraph/index.d.ts +2 -0
  188. package/dist/react/transports/langgraph/index.js +3 -0
  189. package/dist/react/transports/langgraph/index.js.map +1 -0
  190. package/dist/react/transports/langgraph/langgraph-ai-chat.d.ts +62 -0
  191. package/dist/react/transports/langgraph/langgraph-ai-chat.js +92 -0
  192. package/dist/react/transports/langgraph/langgraph-ai-chat.js.map +1 -0
  193. package/dist/react/transports/langgraph.d.ts +71 -0
  194. package/dist/react/transports/langgraph.js +366 -0
  195. package/dist/react/transports/langgraph.js.map +1 -0
  196. package/dist/react/transports/vercel/index.d.ts +2 -0
  197. package/dist/react/transports/vercel/index.js +3 -0
  198. package/dist/react/transports/vercel/index.js.map +1 -0
  199. package/dist/react/transports/vercel/vercel-ai-chat.d.ts +49 -0
  200. package/dist/react/transports/vercel/vercel-ai-chat.js +79 -0
  201. package/dist/react/transports/vercel/vercel-ai-chat.js.map +1 -0
  202. package/dist/react/transports/vercel.d.ts +30 -0
  203. package/dist/react/transports/vercel.js +67 -0
  204. package/dist/react/transports/vercel.js.map +1 -0
  205. package/dist/react/types.d.ts +750 -0
  206. package/dist/react/types.js +2 -0
  207. package/dist/react/types.js.map +1 -0
  208. package/dist/react/ui.d.ts +73 -0
  209. package/dist/react/ui.js +170 -0
  210. package/dist/react/ui.js.map +1 -0
  211. package/dist/react/utils/create-approval-description.d.ts +53 -0
  212. package/dist/react/utils/create-approval-description.js +120 -0
  213. package/dist/react/utils/create-approval-description.js.map +1 -0
  214. package/dist/react/utils/create-tool-result-handler.d.ts +90 -0
  215. package/dist/react/utils/create-tool-result-handler.js +166 -0
  216. package/dist/react/utils/create-tool-result-handler.js.map +1 -0
  217. package/dist/react/utils/mention-markup.d.ts +13 -0
  218. package/dist/react/utils/mention-markup.js +111 -0
  219. package/dist/react/utils/mention-markup.js.map +1 -0
  220. package/dist/react/utils/merge-pipeline-steps.d.ts +19 -0
  221. package/dist/react/utils/merge-pipeline-steps.js +79 -0
  222. package/dist/react/utils/merge-pipeline-steps.js.map +1 -0
  223. package/dist/react/utils/sanitize-stored-messages.d.ts +23 -0
  224. package/dist/react/utils/sanitize-stored-messages.js +50 -0
  225. package/dist/react/utils/sanitize-stored-messages.js.map +1 -0
  226. package/dist/server/adapters/nestjs/chat/ai-chat-auth.guard.d.ts +10 -0
  227. package/dist/server/adapters/nestjs/chat/ai-chat-auth.guard.js +40 -0
  228. package/dist/server/adapters/nestjs/chat/ai-chat-auth.guard.js.map +1 -0
  229. package/dist/server/adapters/nestjs/chat/ai-chat-module-options.interface.d.ts +32 -0
  230. package/dist/server/adapters/nestjs/chat/ai-chat-module-options.interface.js +2 -0
  231. package/dist/server/adapters/nestjs/chat/ai-chat-module-options.interface.js.map +1 -0
  232. package/dist/server/adapters/nestjs/chat/ai-chat.controller.d.ts +11 -0
  233. package/dist/server/adapters/nestjs/chat/ai-chat.controller.js +78 -0
  234. package/dist/server/adapters/nestjs/chat/ai-chat.controller.js.map +1 -0
  235. package/dist/server/adapters/nestjs/chat/ai-chat.module.d.ts +9 -0
  236. package/dist/server/adapters/nestjs/chat/ai-chat.module.js +116 -0
  237. package/dist/server/adapters/nestjs/chat/ai-chat.module.js.map +1 -0
  238. package/dist/server/adapters/nestjs/chat/ai-chat.service.d.ts +13 -0
  239. package/dist/server/adapters/nestjs/chat/ai-chat.service.js +129 -0
  240. package/dist/server/adapters/nestjs/chat/ai-chat.service.js.map +1 -0
  241. package/dist/server/adapters/nestjs/chat/dto/ai-chat-request.dto.d.ts +7 -0
  242. package/dist/server/adapters/nestjs/chat/dto/ai-chat-request.dto.js +49 -0
  243. package/dist/server/adapters/nestjs/chat/dto/ai-chat-request.dto.js.map +1 -0
  244. package/dist/server/adapters/nestjs/chat/dto/chat-message-part.dto.d.ts +19 -0
  245. package/dist/server/adapters/nestjs/chat/dto/chat-message-part.dto.js +105 -0
  246. package/dist/server/adapters/nestjs/chat/dto/chat-message-part.dto.js.map +1 -0
  247. package/dist/server/adapters/nestjs/chat/dto/chat-message.dto.d.ts +8 -0
  248. package/dist/server/adapters/nestjs/chat/dto/chat-message.dto.js +56 -0
  249. package/dist/server/adapters/nestjs/chat/dto/chat-message.dto.js.map +1 -0
  250. package/dist/server/adapters/nestjs/chat/dto/index.d.ts +3 -0
  251. package/dist/server/adapters/nestjs/chat/dto/index.js +4 -0
  252. package/dist/server/adapters/nestjs/chat/dto/index.js.map +1 -0
  253. package/dist/server/adapters/nestjs/chat/index.d.ts +3 -0
  254. package/dist/server/adapters/nestjs/chat/index.js +3 -0
  255. package/dist/server/adapters/nestjs/chat/index.js.map +1 -0
  256. package/dist/server/adapters/nestjs/chat/speech-stream.gateway.d.ts +4 -0
  257. package/dist/server/adapters/nestjs/chat/speech-stream.gateway.js +69 -0
  258. package/dist/server/adapters/nestjs/chat/speech-stream.gateway.js.map +1 -0
  259. package/dist/server/adapters/nestjs/decorators/ai-module.decorator.d.ts +6 -0
  260. package/dist/server/adapters/nestjs/decorators/ai-module.decorator.js +11 -0
  261. package/dist/server/adapters/nestjs/decorators/ai-module.decorator.js.map +1 -0
  262. package/dist/server/adapters/nestjs/decorators/ai-param.decorator.d.ts +5 -0
  263. package/dist/server/adapters/nestjs/decorators/ai-param.decorator.js +13 -0
  264. package/dist/server/adapters/nestjs/decorators/ai-param.decorator.js.map +1 -0
  265. package/dist/server/adapters/nestjs/decorators/ai-tool.decorator.d.ts +6 -0
  266. package/dist/server/adapters/nestjs/decorators/ai-tool.decorator.js +20 -0
  267. package/dist/server/adapters/nestjs/decorators/ai-tool.decorator.js.map +1 -0
  268. package/dist/server/adapters/nestjs/decorators/constants.d.ts +4 -0
  269. package/dist/server/adapters/nestjs/decorators/constants.js +5 -0
  270. package/dist/server/adapters/nestjs/decorators/constants.js.map +1 -0
  271. package/dist/server/adapters/nestjs/index.d.ts +14 -0
  272. package/dist/server/adapters/nestjs/index.js +20 -0
  273. package/dist/server/adapters/nestjs/index.js.map +1 -0
  274. package/dist/server/adapters/nestjs/metadata.d.ts +39 -0
  275. package/dist/server/adapters/nestjs/metadata.js +30 -0
  276. package/dist/server/adapters/nestjs/metadata.js.map +1 -0
  277. package/dist/server/adapters/nestjs/module/ai-tools-explorer.service.d.ts +36 -0
  278. package/dist/server/adapters/nestjs/module/ai-tools-explorer.service.js +156 -0
  279. package/dist/server/adapters/nestjs/module/ai-tools-explorer.service.js.map +1 -0
  280. package/dist/server/adapters/nestjs/module/ai-tools.module.d.ts +37 -0
  281. package/dist/server/adapters/nestjs/module/ai-tools.module.js +42 -0
  282. package/dist/server/adapters/nestjs/module/ai-tools.module.js.map +1 -0
  283. package/dist/server/adapters/nestjs/module/ai-tools.service.d.ts +28 -0
  284. package/dist/server/adapters/nestjs/module/ai-tools.service.js +38 -0
  285. package/dist/server/adapters/nestjs/module/ai-tools.service.js.map +1 -0
  286. package/dist/server/adapters/nestjs/scanner/nestjs-scanner.d.ts +16 -0
  287. package/dist/server/adapters/nestjs/scanner/nestjs-scanner.js +115 -0
  288. package/dist/server/adapters/nestjs/scanner/nestjs-scanner.js.map +1 -0
  289. package/dist/server/adapters/nestjs/scanner/schema-builder.d.ts +26 -0
  290. package/dist/server/adapters/nestjs/scanner/schema-builder.js +255 -0
  291. package/dist/server/adapters/nestjs/scanner/schema-builder.js.map +1 -0
  292. package/dist/server/adapters/nestjs/swagger.d.ts +7 -0
  293. package/dist/server/adapters/nestjs/swagger.js +37 -0
  294. package/dist/server/adapters/nestjs/swagger.js.map +1 -0
  295. package/dist/server/adapters/nextjs/context-helpers.d.ts +22 -0
  296. package/dist/server/adapters/nextjs/context-helpers.js +55 -0
  297. package/dist/server/adapters/nextjs/context-helpers.js.map +1 -0
  298. package/dist/server/adapters/nextjs/create-ai-chat-handler.d.ts +78 -0
  299. package/dist/server/adapters/nextjs/create-ai-chat-handler.js +950 -0
  300. package/dist/server/adapters/nextjs/create-ai-chat-handler.js.map +1 -0
  301. package/dist/server/adapters/nextjs/index.d.ts +8 -0
  302. package/dist/server/adapters/nextjs/index.js +9 -0
  303. package/dist/server/adapters/nextjs/index.js.map +1 -0
  304. package/dist/server/adapters/nextjs/prepare-model-messages.d.ts +58 -0
  305. package/dist/server/adapters/nextjs/prepare-model-messages.js +111 -0
  306. package/dist/server/adapters/nextjs/prepare-model-messages.js.map +1 -0
  307. package/dist/server/adapters/nextjs/sanitize-model-messages.d.ts +64 -0
  308. package/dist/server/adapters/nextjs/sanitize-model-messages.js +487 -0
  309. package/dist/server/adapters/nextjs/sanitize-model-messages.js.map +1 -0
  310. package/dist/server/adapters/nextjs/server-action-helper.d.ts +7 -0
  311. package/dist/server/adapters/nextjs/server-action-helper.js +38 -0
  312. package/dist/server/adapters/nextjs/server-action-helper.js.map +1 -0
  313. package/dist/server/adapters/nextjs/types.d.ts +246 -0
  314. package/dist/server/adapters/nextjs/types.js +2 -0
  315. package/dist/server/adapters/nextjs/types.js.map +1 -0
  316. package/dist/server/adapters/nextjs/with-ai-tool.d.ts +9 -0
  317. package/dist/server/adapters/nextjs/with-ai-tool.js +10 -0
  318. package/dist/server/adapters/nextjs/with-ai-tool.js.map +1 -0
  319. package/dist/server/core/followup-tool.d.ts +9 -0
  320. package/dist/server/core/followup-tool.js +80 -0
  321. package/dist/server/core/followup-tool.js.map +1 -0
  322. package/dist/server/core/index.d.ts +139 -0
  323. package/dist/server/core/index.js +787 -0
  324. package/dist/server/core/index.js.map +1 -0
  325. package/dist/server/core/intent-classifier.d.ts +94 -0
  326. package/dist/server/core/intent-classifier.js +314 -0
  327. package/dist/server/core/intent-classifier.js.map +1 -0
  328. package/dist/server/core/model-selector.d.ts +12 -0
  329. package/dist/server/core/model-selector.js +45 -0
  330. package/dist/server/core/model-selector.js.map +1 -0
  331. package/dist/server/core/module-router.d.ts +14 -0
  332. package/dist/server/core/module-router.js +107 -0
  333. package/dist/server/core/module-router.js.map +1 -0
  334. package/dist/server/core/zod-compact.d.ts +18 -0
  335. package/dist/server/core/zod-compact.js +127 -0
  336. package/dist/server/core/zod-compact.js.map +1 -0
  337. package/dist/server/index.d.ts +5 -0
  338. package/dist/server/index.js +8 -0
  339. package/dist/server/index.js.map +1 -0
  340. package/dist/server/lancer/cache.d.ts +9 -0
  341. package/dist/server/lancer/cache.js +30 -0
  342. package/dist/server/lancer/cache.js.map +1 -0
  343. package/dist/server/lancer/client.d.ts +2 -0
  344. package/dist/server/lancer/client.js +277 -0
  345. package/dist/server/lancer/client.js.map +1 -0
  346. package/dist/server/lancer/errors.d.ts +13 -0
  347. package/dist/server/lancer/errors.js +18 -0
  348. package/dist/server/lancer/errors.js.map +1 -0
  349. package/dist/server/lancer/index.d.ts +3 -0
  350. package/dist/server/lancer/index.js +3 -0
  351. package/dist/server/lancer/index.js.map +1 -0
  352. package/dist/server/lancer/telemetry-buffer.d.ts +15 -0
  353. package/dist/server/lancer/telemetry-buffer.js +61 -0
  354. package/dist/server/lancer/telemetry-buffer.js.map +1 -0
  355. package/dist/server/lancer/types.d.ts +201 -0
  356. package/dist/server/lancer/types.js +5 -0
  357. package/dist/server/lancer/types.js.map +1 -0
  358. package/dist/server/pii-shield/aegis-detector.d.ts +26 -0
  359. package/dist/server/pii-shield/aegis-detector.js +24 -0
  360. package/dist/server/pii-shield/aegis-detector.js.map +1 -0
  361. package/dist/server/pii-shield/create-pii-shield.d.ts +2 -0
  362. package/dist/server/pii-shield/create-pii-shield.js +189 -0
  363. package/dist/server/pii-shield/create-pii-shield.js.map +1 -0
  364. package/dist/server/pii-shield/deep-walk.d.ts +1 -0
  365. package/dist/server/pii-shield/deep-walk.js +17 -0
  366. package/dist/server/pii-shield/deep-walk.js.map +1 -0
  367. package/dist/server/pii-shield/fake-data.d.ts +5 -0
  368. package/dist/server/pii-shield/fake-data.js +168 -0
  369. package/dist/server/pii-shield/fake-data.js.map +1 -0
  370. package/dist/server/pii-shield/index.d.ts +4 -0
  371. package/dist/server/pii-shield/index.js +5 -0
  372. package/dist/server/pii-shield/index.js.map +1 -0
  373. package/dist/server/pii-shield/leakage.d.ts +1 -0
  374. package/dist/server/pii-shield/leakage.js +13 -0
  375. package/dist/server/pii-shield/leakage.js.map +1 -0
  376. package/dist/server/pii-shield/session-mapping.d.ts +12 -0
  377. package/dist/server/pii-shield/session-mapping.js +68 -0
  378. package/dist/server/pii-shield/session-mapping.js.map +1 -0
  379. package/dist/server/pipeline.d.ts +26 -0
  380. package/dist/server/pipeline.js +125 -0
  381. package/dist/server/pipeline.js.map +1 -0
  382. package/dist/server/testing/approvals.d.ts +11 -0
  383. package/dist/server/testing/approvals.js +39 -0
  384. package/dist/server/testing/approvals.js.map +1 -0
  385. package/dist/server/testing/combination.d.ts +3 -0
  386. package/dist/server/testing/combination.js +81 -0
  387. package/dist/server/testing/combination.js.map +1 -0
  388. package/dist/server/testing/create-test-suite.d.ts +29 -0
  389. package/dist/server/testing/create-test-suite.js +79 -0
  390. package/dist/server/testing/create-test-suite.js.map +1 -0
  391. package/dist/server/testing/edge-cases.d.ts +8 -0
  392. package/dist/server/testing/edge-cases.js +275 -0
  393. package/dist/server/testing/edge-cases.js.map +1 -0
  394. package/dist/server/testing/guardrails.d.ts +14 -0
  395. package/dist/server/testing/guardrails.js +150 -0
  396. package/dist/server/testing/guardrails.js.map +1 -0
  397. package/dist/server/testing/helpers.d.ts +14 -0
  398. package/dist/server/testing/helpers.js +114 -0
  399. package/dist/server/testing/helpers.js.map +1 -0
  400. package/dist/server/testing/index.d.ts +12 -0
  401. package/dist/server/testing/index.js +21 -0
  402. package/dist/server/testing/index.js.map +1 -0
  403. package/dist/server/testing/mock-executor.d.ts +8 -0
  404. package/dist/server/testing/mock-executor.js +38 -0
  405. package/dist/server/testing/mock-executor.js.map +1 -0
  406. package/dist/server/testing/regression.d.ts +7 -0
  407. package/dist/server/testing/regression.js +25 -0
  408. package/dist/server/testing/regression.js.map +1 -0
  409. package/dist/server/testing/routing.d.ts +12 -0
  410. package/dist/server/testing/routing.js +61 -0
  411. package/dist/server/testing/routing.js.map +1 -0
  412. package/dist/server/testing/schema-consistency.d.ts +6 -0
  413. package/dist/server/testing/schema-consistency.js +54 -0
  414. package/dist/server/testing/schema-consistency.js.map +1 -0
  415. package/dist/server/testing/smoke.d.ts +11 -0
  416. package/dist/server/testing/smoke.js +62 -0
  417. package/dist/server/testing/smoke.js.map +1 -0
  418. package/dist/server/testing/types.d.ts +156 -0
  419. package/dist/server/testing/types.js +2 -0
  420. package/dist/server/testing/types.js.map +1 -0
  421. package/dist/types.d.ts +696 -0
  422. package/dist/types.js +84 -0
  423. package/dist/types.js.map +1 -0
  424. package/package.json +187 -0
@@ -0,0 +1,1021 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useState, useRef, useCallback, useMemo, useEffect, } from 'react';
3
+ import { getThemeEffect, getThemeVars } from '../themes.js';
4
+ import { ChatContext } from './chat-context.js';
5
+ import { serializeMentionsForSend } from '../utils/mention-markup.js';
6
+ import { mergePipelineSteps } from '../utils/merge-pipeline-steps.js';
7
+ export const DEFAULT_LOCALE = {
8
+ placeholder: 'Type a message...',
9
+ sendButton: 'Send',
10
+ stopButton: 'Stop',
11
+ clearButton: 'Clear',
12
+ loadMoreButton: 'Load more',
13
+ emptyState: 'Start a conversation',
14
+ errorMessage: 'Something went wrong. Please try again.',
15
+ approveButton: 'Approve',
16
+ rejectButton: 'Reject',
17
+ approveAllButton: 'Approve all',
18
+ rejectAllButton: 'Reject all',
19
+ continueButton: 'Continue',
20
+ dismissButton: 'Dismiss',
21
+ cancelButton: 'Cancel',
22
+ confirmButton: 'Confirm',
23
+ moreItemsLabel: 'more',
24
+ allCountLabel: 'All {count}',
25
+ pipelineTitle: 'Pipeline',
26
+ pipelineRunningLabel: 'Running',
27
+ pipelineCompletedLabel: 'Completed',
28
+ pipelineSafetyStopLabel: 'Safety stop',
29
+ pipelineAbortedLabel: 'Stopped',
30
+ pipelineErrorLabel: 'Error',
31
+ pipelineStepLabel: 'Step',
32
+ pipelineApprovalPendingLabel: 'Approval pending',
33
+ chatTitle: 'AI Assistant',
34
+ closeChatAriaLabel: 'Close chat',
35
+ clearChatAriaLabel: 'Clear conversation',
36
+ confirmClearPrompt: 'Clear this conversation?',
37
+ triggerAriaLabel: 'AI Assistant',
38
+ micAriaLabel: 'Start recording',
39
+ stopRecordingAriaLabel: 'Stop recording',
40
+ cancelRecordingAriaLabel: 'Cancel recording',
41
+ newChatLabel: 'New chat',
42
+ noSessionsLabel: 'No conversations yet',
43
+ sessionsLoadingLabel: 'Loading…',
44
+ deleteSessionAriaLabel: 'Delete conversation',
45
+ confirmDeleteSessionPrompt: 'Delete this conversation?',
46
+ renameSessionAriaLabel: 'Rename conversation',
47
+ renameSessionPlaceholder: 'Conversation title',
48
+ };
49
+ // ============================================================================
50
+ // Helpers
51
+ // ============================================================================
52
+ function isRecord(value) {
53
+ return typeof value === 'object' && value !== null;
54
+ }
55
+ /**
56
+ * Coerce a row returned by `SessionConfig.load` into the SDK's
57
+ * `ChatMessage` shape. Accepts either a full SDK message (already has
58
+ * `parts`) or a flat `{ role, content }` wire message from a typical
59
+ * REST backend. Rows with neither `parts` nor `content` are dropped.
60
+ */
61
+ function coerceLoadedMessages(rows) {
62
+ const result = [];
63
+ for (const row of rows) {
64
+ if (!isRecord(row))
65
+ continue;
66
+ if (Array.isArray(row.parts)) {
67
+ result.push(row);
68
+ continue;
69
+ }
70
+ if (typeof row.content === 'string' && row.content.length > 0) {
71
+ const role = row.role === 'assistant' || row.role === 'system' ? row.role : 'user';
72
+ const createdAtRaw = row.createdAt ?? row.created_at;
73
+ result.push({
74
+ id: typeof row.id === 'string' ? row.id : `msg-${result.length}`,
75
+ role,
76
+ parts: [{ type: 'text', text: row.content }],
77
+ createdAt: createdAtRaw ? new Date(createdAtRaw) : undefined,
78
+ });
79
+ }
80
+ }
81
+ return result;
82
+ }
83
+ function getMentionTypesForTrigger(types, trigger) {
84
+ if (trigger === '/') {
85
+ const slashTypes = types.filter((t) => t === 'task' || t === 'command');
86
+ return slashTypes.length > 0 ? slashTypes : types;
87
+ }
88
+ if (trigger === '@') {
89
+ const atTypes = types.filter((t) => t !== 'command');
90
+ return atTypes.length > 0 ? atTypes : types;
91
+ }
92
+ return types;
93
+ }
94
+ /** Default approval description — returns raw tool name and JSON args */
95
+ function defaultApprovalDescription(toolName, approvalId, args) {
96
+ return {
97
+ id: approvalId,
98
+ toolName,
99
+ args: isRecord(args) ? args : {},
100
+ messageId: '',
101
+ description: toolName,
102
+ };
103
+ }
104
+ /**
105
+ * Remove orphaned tool calls (approval-requested without response)
106
+ * from message history to prevent AI_MissingToolResultsError.
107
+ */
108
+ function sanitizeMessages(msgs) {
109
+ return msgs.map((message) => {
110
+ if (message.role !== 'assistant')
111
+ return message;
112
+ const sanitizedParts = message.parts.filter((part) => {
113
+ if (isRecord(part)) {
114
+ const partType = typeof part.type === 'string' ? part.type : '';
115
+ const partState = typeof part.state === 'string' ? part.state : '';
116
+ if (partType.startsWith('tool-') && partState === 'approval-requested') {
117
+ return false;
118
+ }
119
+ }
120
+ return true;
121
+ });
122
+ return { ...message, parts: sanitizedParts };
123
+ }).filter((message) => {
124
+ if (message.role === 'assistant') {
125
+ const hasContent = message.parts.some((part) => isRecord(part) && typeof part.text === 'string' &&
126
+ part.text.trim().length > 0);
127
+ const hasToolOutput = message.parts.some((part) => {
128
+ if (isRecord(part)) {
129
+ const partType = typeof part.type === 'string' ? part.type : '';
130
+ return partType.startsWith('tool-') && part.state === 'output-available';
131
+ }
132
+ return false;
133
+ });
134
+ return hasContent || hasToolOutput || message.parts.length === 0;
135
+ }
136
+ return true;
137
+ });
138
+ }
139
+ /**
140
+ * Merge consecutive assistant messages by keeping only the last one in each run.
141
+ *
142
+ * When a pipeline resumes after approval, `useChat` creates a new assistant
143
+ * message for each server response. The AI model regenerates cumulative text
144
+ * (all prior context + new content), resulting in multiple bubbles with
145
+ * progressively longer duplicate text.
146
+ *
147
+ * By keeping only the last message in each consecutive assistant run, we show
148
+ * only the most complete version. Tool result processing and suggestion
149
+ * extraction operate on `rawMessages` independently, so no data is lost.
150
+ */
151
+ function consolidateAssistantMessages(messages) {
152
+ if (messages.length <= 1)
153
+ return messages;
154
+ const result = [];
155
+ for (let i = 0; i < messages.length; i++) {
156
+ const msg = messages[i];
157
+ if (msg.role !== 'assistant') {
158
+ result.push(msg);
159
+ continue;
160
+ }
161
+ // Check if this assistant message is followed by another assistant message
162
+ // (without a user message in between). If so, it's intermediate — skip it.
163
+ let isIntermediate = false;
164
+ for (let j = i + 1; j < messages.length; j++) {
165
+ if (messages[j].role === 'user')
166
+ break;
167
+ if (messages[j].role === 'assistant') {
168
+ isIntermediate = true;
169
+ break;
170
+ }
171
+ }
172
+ if (!isIntermediate) {
173
+ result.push(msg);
174
+ }
175
+ }
176
+ return result;
177
+ }
178
+ function normalizePipelineStepReport(data) {
179
+ if (!isRecord(data))
180
+ return null;
181
+ if (typeof data.stepNumber !== 'number' || !Number.isFinite(data.stepNumber)) {
182
+ return null;
183
+ }
184
+ const stepNumber = Math.max(0, Math.floor(data.stepNumber));
185
+ const toolCalls = Array.isArray(data.toolCalls)
186
+ ? data.toolCalls.filter((tool) => typeof tool === 'string')
187
+ : [];
188
+ const toolResults = typeof data.toolResults === 'number' && Number.isFinite(data.toolResults)
189
+ ? Math.max(0, Math.floor(data.toolResults))
190
+ : 0;
191
+ const pendingApprovals = typeof data.pendingApprovals === 'number' && Number.isFinite(data.pendingApprovals)
192
+ ? Math.max(0, Math.floor(data.pendingApprovals))
193
+ : Math.max(toolCalls.length - toolResults, 0);
194
+ const usage = isRecord(data.usage) ? data.usage : {};
195
+ return {
196
+ stepNumber,
197
+ finishReason: typeof data.finishReason === 'string' ? data.finishReason : 'other',
198
+ toolCalls,
199
+ toolResults,
200
+ requiresApproval: data.requiresApproval === true || pendingApprovals > 0,
201
+ pendingApprovals,
202
+ summary: typeof data.summary === 'string' ? data.summary : `Step ${stepNumber + 1}`,
203
+ usage: {
204
+ inputTokens: typeof usage.inputTokens === 'number' && Number.isFinite(usage.inputTokens)
205
+ ? usage.inputTokens
206
+ : 0,
207
+ outputTokens: typeof usage.outputTokens === 'number' && Number.isFinite(usage.outputTokens)
208
+ ? usage.outputTokens
209
+ : 0,
210
+ totalTokens: typeof usage.totalTokens === 'number' && Number.isFinite(usage.totalTokens)
211
+ ? usage.totalTokens
212
+ : 0,
213
+ },
214
+ createdAt: typeof data.createdAt === 'string' ? data.createdAt : new Date().toISOString(),
215
+ };
216
+ }
217
+ function normalizePipelineState(data) {
218
+ if (!isRecord(data))
219
+ return null;
220
+ if (data.status !== 'running' &&
221
+ data.status !== 'completed' &&
222
+ data.status !== 'safety-stop' &&
223
+ data.status !== 'aborted' &&
224
+ data.status !== 'error') {
225
+ return null;
226
+ }
227
+ if (typeof data.maxSteps !== 'number' || !Number.isFinite(data.maxSteps)) {
228
+ return null;
229
+ }
230
+ if (data.stepLimitSource !== 'explicit' &&
231
+ data.stepLimitSource !== 'module' &&
232
+ data.stepLimitSource !== 'safety') {
233
+ return null;
234
+ }
235
+ return {
236
+ status: data.status,
237
+ totalSteps: typeof data.totalSteps === 'number' && Number.isFinite(data.totalSteps)
238
+ ? Math.max(0, Math.floor(data.totalSteps))
239
+ : 0,
240
+ finishReason: typeof data.finishReason === 'string' ? data.finishReason : undefined,
241
+ maxSteps: Math.max(1, Math.floor(data.maxSteps)),
242
+ stepLimitSource: data.stepLimitSource,
243
+ updatedAt: typeof data.updatedAt === 'string' ? data.updatedAt : new Date().toISOString(),
244
+ message: typeof data.message === 'string' ? data.message : undefined,
245
+ };
246
+ }
247
+ /**
248
+ * Provider component that manages chat state and exposes it to child components.
249
+ *
250
+ * Transport-agnostic: pick a transport hook (Vercel, LangGraph, or your own)
251
+ * and pass it via the `transport` prop.
252
+ *
253
+ * Features:
254
+ * - Message sanitization (removes orphaned approval-requested tool parts)
255
+ * - Session persistence (load on mount, save on change)
256
+ * - Approval extraction and response handling
257
+ * - Truncation detection via `data-truncation` data parts
258
+ * - Suggestion extraction from `suggest_followups` tool output
259
+ * - Pagination (visible message count, loadMore)
260
+ *
261
+ * @example
262
+ * ```tsx
263
+ * import { AiChatProvider, AiChatPanel } from 'glirastes/react';
264
+ * import { useVercelAiChatTransport } from 'glirastes/react/vercel';
265
+ *
266
+ * function App() {
267
+ * const transport = useVercelAiChatTransport({ endpoint: '/api/ai/chat' });
268
+ * return (
269
+ * <AiChatProvider transport={transport}>
270
+ * <AiChatPanel />
271
+ * </AiChatProvider>
272
+ * );
273
+ * }
274
+ * ```
275
+ */
276
+ export function AiChatProvider({ transport, mentions, toolResults: userToolResults, voice: userVoice, session, classNames: userClassNames, components: userComponents, suggestions: userSuggestions, locale: userLocale, theme: userTheme, onToolResult, onBeforeSend, approvalDescription: userApprovalDescription, continueMessage = 'Please continue.', toolLabels: userToolLabels, pipelineMessageTranslator, stepSummaryFormatter, children, }) {
277
+ // Merge caller-supplied locale overrides with English defaults.
278
+ const locale = useMemo(() => ({ ...DEFAULT_LOCALE, ...(userLocale ?? {}) }), [userLocale]);
279
+ // Resolve `theme` prop → CSS variables spread onto widget roots.
280
+ const themeVars = useMemo(() => getThemeVars(userTheme), [userTheme]);
281
+ const themeEffect = useMemo(() => getThemeEffect(userTheme), [userTheme]);
282
+ const classNames = useMemo(() => userClassNames ?? {}, [userClassNames]);
283
+ const components = useMemo(() => userComponents ?? {}, [userComponents]);
284
+ const suggestionsConfig = useMemo(() => ({ enabled: true, count: 3, autoSuggest: true, ...userSuggestions }), [userSuggestions]);
285
+ const toolResultConfig = useMemo(() => ({ mode: 'default', allowlist: [], ...userToolResults }), [userToolResults]);
286
+ const voiceConfig = useMemo(() => ({
287
+ enabled: false,
288
+ language: 'de',
289
+ recordingBar: { enabled: true, variant: 'inline', ...(userVoice?.recordingBar ?? {}) },
290
+ ...userVoice,
291
+ }), [userVoice]);
292
+ const toolLabels = useMemo(() => userToolLabels ?? {}, [userToolLabels]);
293
+ const approvalDescriptionFn = userApprovalDescription ?? defaultApprovalDescription;
294
+ // Approvals state (Map for O(1) lookup)
295
+ const [pendingApprovalsMap, setPendingApprovalsMap] = useState(new Map());
296
+ const [processingApprovalId, setProcessingApprovalId] = useState(null);
297
+ const [isInitialized, setIsInitialized] = useState(false);
298
+ // ---------------------------------------------------------------------------
299
+ // Multi-session state
300
+ //
301
+ // `session.activeId` is the controlled form — when the drop-in widget owns
302
+ // the id (so it can feed it to the transport as `threadId`). Otherwise we
303
+ // fall back to an internal `uncontrolledActiveId`, seeded from
304
+ // `defaultActiveId` / `'default'`.
305
+ // ---------------------------------------------------------------------------
306
+ const [uncontrolledActiveId, setUncontrolledActiveId] = useState(() => session?.activeId ?? session?.defaultActiveId ?? 'default');
307
+ const activeSessionId = session?.activeId ?? uncontrolledActiveId;
308
+ const [sessions, setSessions] = useState([]);
309
+ const [isSessionsLoading, setIsSessionsLoading] = useState(false);
310
+ const sessionsSupported = Boolean(session && session.list && session.create && session.remove);
311
+ // Keep a ref so callbacks inside effects read the current session config
312
+ // without re-binding on every render.
313
+ const sessionRef = useRef(session);
314
+ sessionRef.current = session;
315
+ // Truncation
316
+ const [truncation, setTruncation] = useState(null);
317
+ const [pipelineSteps, setPipelineSteps] = useState([]);
318
+ const [pipelineState, setPipelineState] = useState(null);
319
+ // Pagination
320
+ const [visibleMessageCount, setVisibleMessageCount] = useState(30);
321
+ // Suggestions
322
+ const [suggestionChips, setSuggestionChips] = useState(suggestionsConfig.staticChips ?? []);
323
+ const isSuggestionsGenerating = false; // Suggestions come from tool output, not async generation
324
+ // Mentions
325
+ const [mentionQuery, setMentionQuery] = useState('');
326
+ const [mentionTrigger, setMentionTrigger] = useState(null);
327
+ const [mentionResults, setMentionResults] = useState([]);
328
+ const [activeMentions, setActiveMentions] = useState([]);
329
+ const [isMentionSearching, setIsMentionSearching] = useState(false);
330
+ // Refs for deduplication
331
+ const processedToolCallsRef = useRef(new Set());
332
+ const handledApprovalIdsRef = useRef(new Set());
333
+ // Stable refs for callbacks to avoid re-creating transport
334
+ const onToolResultRef = useRef(onToolResult);
335
+ onToolResultRef.current = onToolResult;
336
+ const approvalDescriptionRef = useRef(approvalDescriptionFn);
337
+ approvalDescriptionRef.current = approvalDescriptionFn;
338
+ // Data part handler — processes pipeline and truncation events from any transport
339
+ const handleDataPart = useCallback((dataPart) => {
340
+ if (dataPart.type === 'data-truncation') {
341
+ const data = dataPart.data;
342
+ setTruncation({
343
+ completedTools: data.completedTools,
344
+ message: data.message,
345
+ });
346
+ return;
347
+ }
348
+ if (dataPart.type === 'data-step-report') {
349
+ const report = normalizePipelineStepReport(dataPart.data);
350
+ if (!report)
351
+ return;
352
+ setPipelineSteps((prev) => mergePipelineSteps(prev, [report]));
353
+ setPipelineState((prev) => prev ?? {
354
+ status: 'running',
355
+ totalSteps: report.stepNumber + 1,
356
+ maxSteps: 1,
357
+ stepLimitSource: 'safety',
358
+ updatedAt: new Date().toISOString(),
359
+ });
360
+ return;
361
+ }
362
+ if (dataPart.type === 'data-pipeline-state') {
363
+ const nextState = normalizePipelineState(dataPart.data);
364
+ if (nextState) {
365
+ setPipelineState(nextState);
366
+ }
367
+ }
368
+ }, []);
369
+ const resolvedTransport = transport;
370
+ useEffect(() => {
371
+ return resolvedTransport.subscribeToData?.(handleDataPart);
372
+ }, [resolvedTransport, handleDataPart]);
373
+ const { messages: rawMessages, sendMessage, status, error, stop: transportStop, setMessages, addToolApprovalResponse, } = resolvedTransport;
374
+ const isLoading = status === 'submitted' || status === 'streaming';
375
+ useEffect(() => {
376
+ if (!error)
377
+ return;
378
+ setPipelineState((prev) => ({
379
+ status: 'error',
380
+ totalSteps: prev?.totalSteps ?? pipelineSteps.length,
381
+ finishReason: 'error',
382
+ maxSteps: prev?.maxSteps ?? 1,
383
+ stepLimitSource: prev?.stepLimitSource ?? 'safety',
384
+ updatedAt: new Date().toISOString(),
385
+ message: typeof error.message === 'string' ? error.message : 'Pipeline failed.',
386
+ }));
387
+ }, [error, pipelineSteps.length]);
388
+ // Mark stored messages as already processed (prevents re-dispatching tool results)
389
+ const markStoredMessagesAsProcessed = useCallback((storedMessages) => {
390
+ for (const message of storedMessages) {
391
+ if (!isRecord(message))
392
+ continue;
393
+ const messageId = typeof message.id === 'string' ? message.id : 'stored-message';
394
+ const parts = Array.isArray(message.parts) ? message.parts : [];
395
+ for (const part of parts) {
396
+ if (!isRecord(part))
397
+ continue;
398
+ const partType = typeof part.type === 'string' ? part.type : '';
399
+ if (partType.startsWith('tool-')) {
400
+ const toolCallId = typeof part.toolCallId === 'string'
401
+ ? part.toolCallId
402
+ : `${messageId}-${partType}`;
403
+ processedToolCallsRef.current.add(toolCallId);
404
+ if (part.state === 'approval-requested' && isRecord(part.approval) && typeof part.approval.id === 'string') {
405
+ handledApprovalIdsRef.current.add(part.approval.id);
406
+ }
407
+ if (part.state === 'output-available' && isRecord(part.output) && part.output.success && part.output.taskId) {
408
+ processedToolCallsRef.current.add(`task-${toolCallId}`);
409
+ }
410
+ }
411
+ }
412
+ }
413
+ }, []);
414
+ // Load messages from session whenever the active session changes.
415
+ // Runs on mount and on every switchSession() call.
416
+ useEffect(() => {
417
+ const cfg = sessionRef.current;
418
+ if (!cfg?.load) {
419
+ if (!isInitialized)
420
+ setIsInitialized(true);
421
+ return;
422
+ }
423
+ // Don't try to load the bootstrap sentinel when multi-session mode is
424
+ // active — `'default'` is unlikely to be a valid session id in the
425
+ // consumer's backend, and the auto-select effect (below) will switch
426
+ // us to the first real session as soon as `list()` resolves.
427
+ const isBootstrapSentinel = activeSessionId === 'default' &&
428
+ cfg.list !== undefined &&
429
+ cfg.activeId === undefined;
430
+ if (isBootstrapSentinel) {
431
+ if (!isInitialized)
432
+ setIsInitialized(true);
433
+ return;
434
+ }
435
+ let cancelled = false;
436
+ (async () => {
437
+ try {
438
+ const loaded = await Promise.resolve(cfg.load(activeSessionId));
439
+ if (cancelled)
440
+ return;
441
+ processedToolCallsRef.current.clear();
442
+ handledApprovalIdsRef.current.clear();
443
+ // Coerce wire-shape rows (with `content: string`) into SDK
444
+ // messages (with `parts: [...]`) so bridges don't have to.
445
+ const coerced = loaded ? coerceLoadedMessages(loaded) : [];
446
+ if (coerced.length > 0) {
447
+ markStoredMessagesAsProcessed(coerced);
448
+ const sanitized = sanitizeMessages(coerced);
449
+ setMessages(sanitized);
450
+ }
451
+ else {
452
+ setMessages([]);
453
+ }
454
+ }
455
+ catch (err) {
456
+ if (cancelled)
457
+ return;
458
+ console.warn(`[AiChatProvider] session.load("${activeSessionId}") failed:`, err);
459
+ setMessages([]);
460
+ }
461
+ finally {
462
+ if (!cancelled)
463
+ setIsInitialized(true);
464
+ }
465
+ })();
466
+ return () => {
467
+ cancelled = true;
468
+ };
469
+ // rawMessages intentionally excluded — we only re-load on session switch.
470
+ // eslint-disable-next-line react-hooks/exhaustive-deps
471
+ }, [activeSessionId, setMessages, markStoredMessagesAsProcessed]);
472
+ // Save messages to session on change (scoped to the active session).
473
+ useEffect(() => {
474
+ if (!isInitialized)
475
+ return;
476
+ if (rawMessages.length === 0)
477
+ return;
478
+ const cfg = sessionRef.current;
479
+ if (!cfg?.save)
480
+ return;
481
+ void Promise.resolve(cfg.save(activeSessionId, rawMessages));
482
+ }, [rawMessages, isInitialized, activeSessionId]);
483
+ // Process tool results and approvals from streaming messages
484
+ useEffect(() => {
485
+ if (rawMessages.length === 0)
486
+ return;
487
+ const lastMessage = rawMessages[rawMessages.length - 1];
488
+ if (lastMessage.role !== 'assistant')
489
+ return;
490
+ for (const part of lastMessage.parts) {
491
+ if (!('type' in part))
492
+ continue;
493
+ const partType = part.type;
494
+ if (partType.startsWith('tool-')) {
495
+ const toolPart = part;
496
+ const toolName = partType.replace('tool-', '');
497
+ // Detect approval-requested
498
+ if (toolPart.state === 'approval-requested' &&
499
+ toolPart.approval?.id &&
500
+ !handledApprovalIdsRef.current.has(toolPart.approval.id)) {
501
+ handledApprovalIdsRef.current.add(toolPart.approval.id);
502
+ const pending = approvalDescriptionRef.current(toolName, toolPart.approval.id, toolPart.input);
503
+ setPendingApprovalsMap(prev => new Map(prev).set(toolPart.approval.id, pending));
504
+ }
505
+ // Tool result available — call onToolResult
506
+ if (toolPart.state === 'output-available' && isRecord(toolPart.output)) {
507
+ const toolCallId = toolPart.toolCallId || `${lastMessage.id}-${partType}`;
508
+ if (!processedToolCallsRef.current.has(toolCallId)) {
509
+ processedToolCallsRef.current.add(toolCallId);
510
+ onToolResultRef.current?.(toolName, toolPart.output);
511
+ }
512
+ }
513
+ }
514
+ }
515
+ }, [rawMessages]);
516
+ // Extract suggestions from suggest_followups tool
517
+ useEffect(() => {
518
+ if (rawMessages.length === 0)
519
+ return;
520
+ const count = suggestionsConfig.count ?? 3;
521
+ let latestFollowups = null;
522
+ for (let messageIndex = rawMessages.length - 1; messageIndex >= 0; messageIndex -= 1) {
523
+ const message = rawMessages[messageIndex];
524
+ if (message.role !== 'assistant')
525
+ continue;
526
+ for (const part of message.parts) {
527
+ if (!('type' in part))
528
+ continue;
529
+ const partType = part.type;
530
+ if (partType !== 'tool-suggest_followups')
531
+ continue;
532
+ const toolPart = part;
533
+ if (toolPart.state !== 'output-available' || !isRecord(toolPart.output)) {
534
+ continue;
535
+ }
536
+ const result = toolPart.output;
537
+ if (!Array.isArray(result.followups))
538
+ continue;
539
+ const followups = result.followups.filter((f) => typeof f === 'string' && f.trim().length > 0);
540
+ if (followups.length > 0) {
541
+ latestFollowups = followups.slice(0, count);
542
+ }
543
+ }
544
+ if (latestFollowups && latestFollowups.length > 0) {
545
+ break;
546
+ }
547
+ }
548
+ if (latestFollowups && latestFollowups.length > 0) {
549
+ setSuggestionChips(latestFollowups);
550
+ }
551
+ }, [rawMessages, suggestionsConfig.count]);
552
+ // Fallback to static chips when model doesn't call suggest_followups
553
+ const prevIsLoadingRef = useRef(false);
554
+ useEffect(() => {
555
+ // Trigger when loading transitions from true → false
556
+ if (prevIsLoadingRef.current && !isLoading) {
557
+ // If no dynamic chips were generated, restore static chips
558
+ setSuggestionChips((current) => {
559
+ if (current.length === 0 && suggestionsConfig.staticChips?.length) {
560
+ return suggestionsConfig.staticChips;
561
+ }
562
+ return current;
563
+ });
564
+ }
565
+ prevIsLoadingRef.current = isLoading;
566
+ }, [isLoading, suggestionsConfig.staticChips]);
567
+ // Mention search
568
+ useEffect(() => {
569
+ let cancelled = false;
570
+ const run = async () => {
571
+ if (!mentions || mentionQuery.trim().length === 0) {
572
+ setMentionResults([]);
573
+ setIsMentionSearching(false);
574
+ return;
575
+ }
576
+ setIsMentionSearching(true);
577
+ const query = mentionQuery.trim();
578
+ const searchTypes = getMentionTypesForTrigger(mentions.types, mentionTrigger);
579
+ const grouped = await Promise.all(searchTypes.map(async (type) => {
580
+ try {
581
+ return await mentions.search(query, type);
582
+ }
583
+ catch {
584
+ return [];
585
+ }
586
+ }));
587
+ if (cancelled)
588
+ return;
589
+ const deduped = new Map();
590
+ for (const items of grouped) {
591
+ for (const item of items) {
592
+ deduped.set(`${item.type}:${item.id}`, item);
593
+ }
594
+ }
595
+ setMentionResults(Array.from(deduped.values()));
596
+ setIsMentionSearching(false);
597
+ };
598
+ void run();
599
+ return () => {
600
+ cancelled = true;
601
+ };
602
+ }, [mentionQuery, mentionTrigger, mentions]);
603
+ // Actions
604
+ const send = useCallback(async (message) => {
605
+ // Clear truncation and suggestion chips on new message
606
+ setTruncation(null);
607
+ setSuggestionChips([]);
608
+ setPipelineSteps([]);
609
+ setPipelineState(null);
610
+ // Preprocess message
611
+ let processedMessage = message;
612
+ const mentionSerializeConfig = mentions?.serialize;
613
+ if (mentionSerializeConfig?.enabled !== false) {
614
+ processedMessage = serializeMentionsForSend(processedMessage, activeMentions, mentionSerializeConfig);
615
+ }
616
+ if (onBeforeSend) {
617
+ processedMessage = onBeforeSend(processedMessage, activeMentions);
618
+ }
619
+ // Sanitize messages before sending to prevent AI_MissingToolResultsError
620
+ const currentMessages = rawMessages;
621
+ const sanitized = sanitizeMessages(currentMessages);
622
+ if (sanitized.length !== currentMessages.length || JSON.stringify(sanitized) !== JSON.stringify(currentMessages)) {
623
+ setMessages(sanitized);
624
+ setPendingApprovalsMap(new Map());
625
+ }
626
+ // Auto-reject pending approvals when user sends new message
627
+ if (pendingApprovalsMap.size > 0) {
628
+ const approvalIds = Array.from(pendingApprovalsMap.keys());
629
+ setPendingApprovalsMap(new Map());
630
+ for (const approvalId of approvalIds) {
631
+ await addToolApprovalResponse({
632
+ id: approvalId,
633
+ approved: false,
634
+ reason: 'Auto-rejected: user sent a new message.',
635
+ });
636
+ }
637
+ }
638
+ await sendMessage({ text: processedMessage });
639
+ setActiveMentions([]);
640
+ setMentionQuery('');
641
+ setMentionTrigger(null);
642
+ setMentionResults([]);
643
+ setIsMentionSearching(false);
644
+ }, [
645
+ rawMessages,
646
+ setMessages,
647
+ sendMessage,
648
+ addToolApprovalResponse,
649
+ pendingApprovalsMap,
650
+ mentions,
651
+ onBeforeSend,
652
+ activeMentions,
653
+ ]);
654
+ const stop = useCallback(() => {
655
+ setPipelineState((prev) => ({
656
+ status: 'aborted',
657
+ totalSteps: prev?.totalSteps ?? pipelineSteps.length,
658
+ finishReason: 'stop',
659
+ maxSteps: prev?.maxSteps ?? 1,
660
+ stepLimitSource: prev?.stepLimitSource ?? 'safety',
661
+ updatedAt: new Date().toISOString(),
662
+ message: 'Stopped by user.',
663
+ }));
664
+ transportStop();
665
+ }, [transportStop, pipelineSteps.length]);
666
+ const clear = useCallback(() => {
667
+ setMessages([]);
668
+ void Promise.resolve(sessionRef.current?.clear?.(activeSessionId));
669
+ processedToolCallsRef.current.clear();
670
+ handledApprovalIdsRef.current.clear();
671
+ setPendingApprovalsMap(new Map());
672
+ setVisibleMessageCount(30);
673
+ setTruncation(null);
674
+ setPipelineSteps([]);
675
+ setPipelineState(null);
676
+ setMentionQuery('');
677
+ setMentionTrigger(null);
678
+ setMentionResults([]);
679
+ setActiveMentions([]);
680
+ setIsMentionSearching(false);
681
+ setSuggestionChips(suggestionsConfig.staticChips ?? []);
682
+ }, [setMessages, activeSessionId, suggestionsConfig.staticChips]);
683
+ // ---------------------------------------------------------------------------
684
+ // Multi-session actions
685
+ // ---------------------------------------------------------------------------
686
+ const applyActiveId = useCallback((id) => {
687
+ if (session?.activeId === undefined) {
688
+ // Uncontrolled
689
+ setUncontrolledActiveId(id);
690
+ }
691
+ session?.onActiveIdChange?.(id);
692
+ }, [session]);
693
+ const refreshSessions = useCallback(async () => {
694
+ const cfg = sessionRef.current;
695
+ if (!cfg?.list)
696
+ return;
697
+ setIsSessionsLoading(true);
698
+ try {
699
+ const list = await cfg.list();
700
+ setSessions(list);
701
+ // Auto-select the first session if we're still on the bootstrap
702
+ // sentinel and the consumer doesn't control `activeId` externally.
703
+ if (list.length > 0 &&
704
+ cfg.activeId === undefined &&
705
+ (uncontrolledActiveIdRef.current === 'default' ||
706
+ !list.some((s) => s.id === uncontrolledActiveIdRef.current))) {
707
+ const next = list[0].id;
708
+ setUncontrolledActiveId(next);
709
+ cfg.onActiveIdChange?.(next);
710
+ }
711
+ }
712
+ catch (err) {
713
+ console.warn('[AiChatProvider] session.list failed:', err);
714
+ }
715
+ finally {
716
+ setIsSessionsLoading(false);
717
+ }
718
+ }, []);
719
+ // Mirror state into a ref so refreshSessions doesn't need it as a dep.
720
+ const uncontrolledActiveIdRef = useRef(uncontrolledActiveId);
721
+ uncontrolledActiveIdRef.current = uncontrolledActiveId;
722
+ // Auto-fetch sessions when the consumer supplies a list() function.
723
+ useEffect(() => {
724
+ if (!sessionsSupported)
725
+ return;
726
+ void refreshSessions();
727
+ }, [sessionsSupported, refreshSessions]);
728
+ // Refetch sessions when a streaming response finishes, so backend-generated
729
+ // titles (auto-generated after the first exchange) appear without a reload.
730
+ const wasLoadingRef = useRef(false);
731
+ useEffect(() => {
732
+ if (!sessionsSupported) {
733
+ wasLoadingRef.current = isLoading;
734
+ return;
735
+ }
736
+ if (wasLoadingRef.current && !isLoading) {
737
+ void refreshSessions();
738
+ }
739
+ wasLoadingRef.current = isLoading;
740
+ }, [isLoading, sessionsSupported, refreshSessions]);
741
+ const switchSession = useCallback(async (id) => {
742
+ if (id === activeSessionId)
743
+ return;
744
+ // Reset transient UI state before loading new session
745
+ setPendingApprovalsMap(new Map());
746
+ setTruncation(null);
747
+ setPipelineSteps([]);
748
+ setPipelineState(null);
749
+ setSuggestionChips(suggestionsConfig.staticChips ?? []);
750
+ setVisibleMessageCount(30);
751
+ applyActiveId(id);
752
+ }, [activeSessionId, applyActiveId, suggestionsConfig.staticChips]);
753
+ const createSession = useCallback(async (opts) => {
754
+ const cfg = sessionRef.current;
755
+ if (!cfg?.create)
756
+ return null;
757
+ const created = await cfg.create(opts);
758
+ await refreshSessions();
759
+ await switchSession(created.id);
760
+ return created;
761
+ }, [refreshSessions, switchSession]);
762
+ const removeSession = useCallback(async (id) => {
763
+ const cfg = sessionRef.current;
764
+ if (!cfg?.remove)
765
+ return;
766
+ await cfg.remove(id);
767
+ // Re-fetch first so the fallback target reflects reality
768
+ const cfgList = cfg.list ? await cfg.list() : [];
769
+ setSessions(cfgList);
770
+ if (id === activeSessionId) {
771
+ const next = cfgList.find((s) => s.id !== id);
772
+ if (next) {
773
+ await switchSession(next.id);
774
+ }
775
+ else if (cfg.create) {
776
+ // No sessions left — spin up a fresh one
777
+ const created = await cfg.create();
778
+ const refreshed = cfg.list ? await cfg.list() : [created];
779
+ setSessions(refreshed);
780
+ await switchSession(created.id);
781
+ }
782
+ }
783
+ }, [activeSessionId, switchSession]);
784
+ const renameSession = useCallback(async (id, title) => {
785
+ const cfg = sessionRef.current;
786
+ if (!cfg?.rename)
787
+ return;
788
+ await cfg.rename(id, title);
789
+ await refreshSessions();
790
+ }, [refreshSessions]);
791
+ // Pagination + consolidation (removes duplicate assistant bubbles from pipeline resumes)
792
+ const allMessages = rawMessages;
793
+ const consolidated = consolidateAssistantMessages(allMessages);
794
+ const hasMore = consolidated.length > visibleMessageCount;
795
+ const visibleMessages = hasMore
796
+ ? consolidated.slice(-visibleMessageCount)
797
+ : consolidated;
798
+ const loadMore = useCallback(() => {
799
+ setVisibleMessageCount(prev => prev + 10);
800
+ }, []);
801
+ // Approval handlers
802
+ const approve = useCallback(async (id) => {
803
+ setProcessingApprovalId(id);
804
+ setPendingApprovalsMap(prev => {
805
+ const next = new Map(prev);
806
+ next.delete(id);
807
+ return next;
808
+ });
809
+ await addToolApprovalResponse({ id, approved: true });
810
+ setProcessingApprovalId(null);
811
+ }, [addToolApprovalResponse]);
812
+ const reject = useCallback(async (id) => {
813
+ setProcessingApprovalId(id);
814
+ setPendingApprovalsMap(prev => {
815
+ const next = new Map(prev);
816
+ next.delete(id);
817
+ return next;
818
+ });
819
+ await addToolApprovalResponse({
820
+ id,
821
+ approved: false,
822
+ reason: 'Rejected by user.',
823
+ });
824
+ setProcessingApprovalId(null);
825
+ }, [addToolApprovalResponse]);
826
+ // Truncation
827
+ const continueTruncation = useCallback(async () => {
828
+ setTruncation(null);
829
+ await sendMessage({ text: continueMessage });
830
+ }, [sendMessage, continueMessage]);
831
+ const dismissTruncation = useCallback(() => {
832
+ setTruncation(null);
833
+ }, []);
834
+ // Pending approvals as array (for context consumers)
835
+ const pendingApprovals = useMemo(() => Array.from(pendingApprovalsMap.values()), [pendingApprovalsMap]);
836
+ // Mention actions
837
+ const setMentionSearch = useCallback((query, trigger) => {
838
+ setMentionQuery(query);
839
+ setMentionTrigger(trigger);
840
+ }, []);
841
+ const clearMentionSearch = useCallback(() => {
842
+ setMentionQuery('');
843
+ setMentionTrigger(null);
844
+ setMentionResults([]);
845
+ setIsMentionSearching(false);
846
+ }, []);
847
+ const addActiveMention = useCallback((mention) => {
848
+ const mentionId = typeof mention.id === 'string' ? mention.id : '';
849
+ const mentionType = typeof mention.type === 'string' ? mention.type : '';
850
+ if (!mentionId || !mentionType)
851
+ return;
852
+ setActiveMentions((prev) => {
853
+ const mentionKey = `${mentionType}:${mentionId}`;
854
+ const next = prev.filter((item) => `${item.type}:${item.id}` !== mentionKey);
855
+ next.push(mention);
856
+ return next;
857
+ });
858
+ }, []);
859
+ const removeActiveMention = useCallback((mentionId) => {
860
+ setActiveMentions((prev) => prev.filter((item) => item.id !== mentionId));
861
+ }, []);
862
+ const clearActiveMentions = useCallback(() => {
863
+ setActiveMentions([]);
864
+ }, []);
865
+ const selectMention = useCallback((result) => {
866
+ if (mentions?.resolve) {
867
+ void mentions.resolve(result.id, result.type)
868
+ .then((resolved) => {
869
+ addActiveMention({
870
+ ...resolved,
871
+ id: result.id,
872
+ type: result.type,
873
+ label: typeof resolved.label === 'string' ? resolved.label : result.label,
874
+ displayName: typeof resolved.displayName === 'string'
875
+ ? resolved.displayName
876
+ : result.label,
877
+ });
878
+ })
879
+ .catch(() => {
880
+ addActiveMention({
881
+ id: result.id,
882
+ type: result.type,
883
+ label: result.label,
884
+ displayName: result.label,
885
+ });
886
+ });
887
+ }
888
+ else {
889
+ addActiveMention({
890
+ id: result.id,
891
+ type: result.type,
892
+ label: result.label,
893
+ displayName: result.label,
894
+ });
895
+ }
896
+ setMentionQuery('');
897
+ setMentionTrigger(null);
898
+ setMentionResults([]);
899
+ setIsMentionSearching(false);
900
+ }, [mentions, addActiveMention]);
901
+ const selectSuggestion = useCallback((suggestion) => {
902
+ send(suggestion);
903
+ }, [send]);
904
+ const refreshSuggestions = useCallback(() => {
905
+ // Suggestions are driven by tool output, not manual refresh
906
+ }, []);
907
+ // Build context value
908
+ const contextValue = useMemo(() => ({
909
+ classNames,
910
+ components,
911
+ locale,
912
+ themeVars,
913
+ themeEffect,
914
+ suggestions: suggestionsConfig,
915
+ toolLabels,
916
+ toolResults: toolResultConfig,
917
+ voice: voiceConfig,
918
+ mentionConfig: mentions,
919
+ pipelineMessageTranslator,
920
+ stepSummaryFormatter,
921
+ messages: visibleMessages,
922
+ isLoading,
923
+ error: error ?? null,
924
+ send,
925
+ stop,
926
+ clear,
927
+ loadMore,
928
+ hasMore,
929
+ pipelineSteps,
930
+ pipelineState,
931
+ pendingApprovals,
932
+ approve,
933
+ reject,
934
+ isProcessingApproval: processingApprovalId !== null,
935
+ approvalDescription: approvalDescriptionRef.current,
936
+ truncation,
937
+ continueTruncation,
938
+ dismissTruncation,
939
+ mentionQuery,
940
+ mentionTrigger,
941
+ mentionResults,
942
+ setMentionSearch,
943
+ clearMentionSearch,
944
+ selectMention,
945
+ activeMentions,
946
+ addActiveMention,
947
+ removeActiveMention,
948
+ clearActiveMentions,
949
+ isMentionSearching,
950
+ hasMentions: !!mentions,
951
+ suggestionChips,
952
+ selectSuggestion,
953
+ refreshSuggestions,
954
+ isSuggestionsGenerating,
955
+ sessions,
956
+ activeSessionId,
957
+ sessionsSupported,
958
+ isSessionsLoading,
959
+ switchSession,
960
+ createSession,
961
+ removeSession,
962
+ renameSession,
963
+ refreshSessions,
964
+ }), [
965
+ classNames,
966
+ components,
967
+ locale,
968
+ themeVars,
969
+ themeEffect,
970
+ suggestionsConfig,
971
+ toolLabels,
972
+ toolResultConfig,
973
+ voiceConfig,
974
+ mentions,
975
+ pipelineMessageTranslator,
976
+ stepSummaryFormatter,
977
+ visibleMessages,
978
+ isLoading,
979
+ error,
980
+ send,
981
+ stop,
982
+ clear,
983
+ loadMore,
984
+ hasMore,
985
+ pipelineSteps,
986
+ pipelineState,
987
+ pendingApprovals,
988
+ approve,
989
+ reject,
990
+ processingApprovalId,
991
+ truncation,
992
+ continueTruncation,
993
+ dismissTruncation,
994
+ mentionQuery,
995
+ mentionTrigger,
996
+ mentionResults,
997
+ setMentionSearch,
998
+ clearMentionSearch,
999
+ selectMention,
1000
+ activeMentions,
1001
+ addActiveMention,
1002
+ removeActiveMention,
1003
+ clearActiveMentions,
1004
+ isMentionSearching,
1005
+ suggestionChips,
1006
+ selectSuggestion,
1007
+ refreshSuggestions,
1008
+ isSuggestionsGenerating,
1009
+ sessions,
1010
+ activeSessionId,
1011
+ sessionsSupported,
1012
+ isSessionsLoading,
1013
+ switchSession,
1014
+ createSession,
1015
+ removeSession,
1016
+ renameSession,
1017
+ refreshSessions,
1018
+ ]);
1019
+ return (_jsx(ChatContext.Provider, { value: contextValue, children: children }));
1020
+ }
1021
+ //# sourceMappingURL=ai-chat-provider.js.map