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,950 @@
1
+ import { toolsToAiTools, createFollowupTool } from '../../core/index.js';
2
+ import { applyPromptOverride } from '../../../types.js';
3
+ import { streamText, createUIMessageStream, createUIMessageStreamResponse, } from 'ai';
4
+ import { buildToolContext, createInternalApiCallerFromRequest, } from './context-helpers.js';
5
+ import { prepareModelMessages, wrapToolsForVercelAi } from './prepare-model-messages.js';
6
+ const DEFAULT_SAFETY_MAX_STEPS = 24;
7
+ function asPositiveInt(value) {
8
+ if (typeof value !== 'number' || !Number.isFinite(value))
9
+ return null;
10
+ const normalized = Math.floor(value);
11
+ return normalized > 0 ? normalized : null;
12
+ }
13
+ function resolveStepLimit(options) {
14
+ const moduleMaxSteps = asPositiveInt(options.moduleMaxSteps);
15
+ if (moduleMaxSteps) {
16
+ return { maxSteps: moduleMaxSteps, stepLimitSource: 'module' };
17
+ }
18
+ const configuredMaxSteps = asPositiveInt(options.configuredMaxSteps);
19
+ if (configuredMaxSteps) {
20
+ return { maxSteps: configuredMaxSteps, stepLimitSource: 'explicit' };
21
+ }
22
+ return {
23
+ maxSteps: asPositiveInt(options.safetyMaxSteps) ?? DEFAULT_SAFETY_MAX_STEPS,
24
+ stepLimitSource: 'safety',
25
+ };
26
+ }
27
+ function compactToolNames(toolCalls) {
28
+ const unique = new Set();
29
+ for (const call of toolCalls) {
30
+ if (typeof call.toolName === 'string' && call.toolName.length > 0) {
31
+ unique.add(call.toolName);
32
+ }
33
+ }
34
+ return Array.from(unique);
35
+ }
36
+ function shorten(text, maxLength = 120) {
37
+ const normalized = text.trim().replace(/\s+/g, ' ');
38
+ if (normalized.length <= maxLength)
39
+ return normalized;
40
+ return `${normalized.slice(0, maxLength - 1)}…`;
41
+ }
42
+ function buildStepSummary(args) {
43
+ if (args.requiresApproval) {
44
+ if (args.toolNames.length > 0) {
45
+ return `Awaiting approval: ${args.toolNames.join(', ')}`;
46
+ }
47
+ return 'Awaiting approval.';
48
+ }
49
+ if (args.toolCallCount > 0) {
50
+ const label = args.toolNames.length > 0
51
+ ? args.toolNames.join(', ')
52
+ : `${args.toolCallCount} tool call(s)`;
53
+ return `Executed tools: ${label}`;
54
+ }
55
+ if (args.text.trim().length > 0) {
56
+ return shorten(args.text);
57
+ }
58
+ return `Finished step (${args.finishReason}).`;
59
+ }
60
+ function buildStepReport(step) {
61
+ const toolNames = compactToolNames(step.toolCalls);
62
+ const toolCallCount = step.toolCalls.length;
63
+ const toolResultCount = step.toolResults.length;
64
+ const pendingApprovals = Math.max(toolCallCount - toolResultCount, 0);
65
+ const requiresApproval = step.finishReason === 'tool-calls' && pendingApprovals > 0;
66
+ return {
67
+ stepNumber: step.stepNumber,
68
+ finishReason: step.finishReason,
69
+ toolCalls: toolNames,
70
+ toolResults: toolResultCount,
71
+ requiresApproval,
72
+ pendingApprovals,
73
+ summary: buildStepSummary({
74
+ finishReason: step.finishReason,
75
+ text: step.text,
76
+ toolNames,
77
+ toolCallCount,
78
+ toolResultCount,
79
+ requiresApproval,
80
+ }),
81
+ usage: {
82
+ inputTokens: step.usage.inputTokens ?? 0,
83
+ outputTokens: step.usage.outputTokens ?? 0,
84
+ totalTokens: step.usage.totalTokens ?? 0,
85
+ },
86
+ createdAt: new Date().toISOString(),
87
+ };
88
+ }
89
+ function createPipelineState(options) {
90
+ return {
91
+ status: options.status,
92
+ totalSteps: options.totalSteps,
93
+ finishReason: options.finishReason,
94
+ maxSteps: options.maxSteps,
95
+ stepLimitSource: options.stepLimitSource,
96
+ message: options.message,
97
+ updatedAt: new Date().toISOString(),
98
+ };
99
+ }
100
+ /**
101
+ * Built-in default stream handler.
102
+ *
103
+ * Converts UI messages → model messages, wraps tools, calls streamText,
104
+ * and returns a UI message stream response.
105
+ */
106
+ async function defaultStreamHandler(ctx, onFinish) {
107
+ const vercelTools = wrapToolsForVercelAi(ctx.tools);
108
+ const modelMessages = await prepareModelMessages(ctx.messages, { maxContextMessages: ctx.maxContextMessages });
109
+ let wasTruncated = false;
110
+ let stoppedByLoop = false;
111
+ // Stop condition: step count OR consecutive identical tool calls (loop detection).
112
+ const LOOP_REPEAT_THRESHOLD = 3;
113
+ const shouldStop = (event) => {
114
+ if (event.steps.length >= ctx.maxSteps)
115
+ return true;
116
+ if (event.steps.length >= LOOP_REPEAT_THRESHOLD) {
117
+ const recent = event.steps.slice(-LOOP_REPEAT_THRESHOLD);
118
+ const signatures = recent.map((s) => s.toolCalls
119
+ .map((c) => c.toolName)
120
+ .sort()
121
+ .join(','));
122
+ if (signatures[0].length > 0 &&
123
+ signatures.every((sig) => sig === signatures[0])) {
124
+ stoppedByLoop = true;
125
+ return true;
126
+ }
127
+ }
128
+ return false;
129
+ };
130
+ const stream = createUIMessageStream({
131
+ execute: async ({ writer }) => {
132
+ let totalSteps = 0;
133
+ let finalStateWritten = false;
134
+ const writePipelineState = (state, transient = false) => {
135
+ writer.write({
136
+ type: 'data-pipeline-state',
137
+ data: state,
138
+ transient,
139
+ });
140
+ };
141
+ writePipelineState(createPipelineState({
142
+ status: 'running',
143
+ totalSteps: 0,
144
+ maxSteps: ctx.maxSteps,
145
+ stepLimitSource: ctx.stepLimitSource,
146
+ }), true);
147
+ const result = streamText({
148
+ model: ctx.model,
149
+ messages: modelMessages,
150
+ system: ctx.systemPrompt,
151
+ tools: vercelTools,
152
+ maxOutputTokens: ctx.maxOutputTokens,
153
+ temperature: ctx.temperature,
154
+ stopWhen: shouldStop,
155
+ onStepFinish: (event) => {
156
+ const report = buildStepReport({
157
+ stepNumber: event.stepNumber,
158
+ finishReason: event.finishReason,
159
+ toolCalls: event.toolCalls.map((call) => ({
160
+ toolName: call.toolName,
161
+ })),
162
+ toolResults: event.toolResults,
163
+ text: event.text,
164
+ usage: {
165
+ inputTokens: event.usage.inputTokens,
166
+ outputTokens: event.usage.outputTokens,
167
+ totalTokens: event.usage.totalTokens,
168
+ },
169
+ });
170
+ totalSteps = Math.max(totalSteps, report.stepNumber + 1);
171
+ if (ctx.emitStepReports) {
172
+ writer.write({
173
+ type: 'data-step-report',
174
+ data: report,
175
+ });
176
+ }
177
+ ctx.onStepReport?.(report);
178
+ },
179
+ onAbort: (event) => {
180
+ if (finalStateWritten)
181
+ return;
182
+ totalSteps = Math.max(totalSteps, event.steps.length);
183
+ writePipelineState(createPipelineState({
184
+ status: 'aborted',
185
+ totalSteps,
186
+ finishReason: 'stop',
187
+ maxSteps: ctx.maxSteps,
188
+ stepLimitSource: ctx.stepLimitSource,
189
+ message: 'Stopped by user.',
190
+ }));
191
+ finalStateWritten = true;
192
+ },
193
+ onFinish: (event) => {
194
+ wasTruncated =
195
+ event.finishReason === 'tool-calls' &&
196
+ (event.steps.length >= ctx.maxSteps || stoppedByLoop);
197
+ totalSteps = Math.max(totalSteps, event.steps.length);
198
+ const isSafetyStop = wasTruncated && ctx.stepLimitSource === 'safety' && !stoppedByLoop;
199
+ const status = stoppedByLoop
200
+ ? 'safety-stop'
201
+ : isSafetyStop
202
+ ? 'safety-stop'
203
+ : event.finishReason === 'error'
204
+ ? 'error'
205
+ : 'completed';
206
+ if (!finalStateWritten) {
207
+ writePipelineState(createPipelineState({
208
+ status,
209
+ totalSteps,
210
+ finishReason: event.finishReason,
211
+ maxSteps: ctx.maxSteps,
212
+ stepLimitSource: ctx.stepLimitSource,
213
+ message: stoppedByLoop
214
+ ? 'Stopped: repeated tool call loop detected.'
215
+ : wasTruncated
216
+ ? isSafetyStop
217
+ ? 'Paused at step safety cap. You can continue or stop.'
218
+ : 'Paused at configured step cap.'
219
+ : undefined,
220
+ }));
221
+ finalStateWritten = true;
222
+ }
223
+ onFinish?.({
224
+ totalSteps: event.steps.length,
225
+ finishReason: event.finishReason,
226
+ usage: {
227
+ inputTokens: event.totalUsage.inputTokens ?? 0,
228
+ outputTokens: event.totalUsage.outputTokens ?? 0,
229
+ totalTokens: event.totalUsage.totalTokens ?? 0,
230
+ },
231
+ wasTruncated,
232
+ maxSteps: ctx.maxSteps,
233
+ stepLimitSource: ctx.stepLimitSource,
234
+ });
235
+ },
236
+ });
237
+ writer.merge(result.toUIMessageStream());
238
+ try {
239
+ await result.response;
240
+ }
241
+ catch (error) {
242
+ if (finalStateWritten)
243
+ return;
244
+ writePipelineState(createPipelineState({
245
+ status: 'error',
246
+ totalSteps,
247
+ finishReason: 'error',
248
+ maxSteps: ctx.maxSteps,
249
+ stepLimitSource: ctx.stepLimitSource,
250
+ message: 'Pipeline failed.',
251
+ }));
252
+ finalStateWritten = true;
253
+ throw error;
254
+ }
255
+ },
256
+ });
257
+ return createUIMessageStreamResponse({ stream });
258
+ }
259
+ /**
260
+ * Creates a complete Next.js App Router POST handler for AI chat.
261
+ *
262
+ * Supports two modes:
263
+ *
264
+ * **Pipeline mode** (Pro): When `pipeline` is provided, uses the server-pro
265
+ * pipeline for guardrails, intent classification, tool selection, and model
266
+ * selection.
267
+ *
268
+ * **Legacy mode**: When no `pipeline` is provided, uses the original
269
+ * `guardrails` + `intentRouter` flow.
270
+ *
271
+ * The SDK does not perform authentication or authorization. Tools forward the
272
+ * caller's cookies to backend APIs via `runtime.cookieHeader`; permission
273
+ * checks happen on the backend.
274
+ */
275
+ export function createAiChatHandler(config) {
276
+ const { tools: staticTools, pipeline, followups, loadTools,
277
+ // PII Shield
278
+ piiShield,
279
+ // Audit & Telemetry
280
+ onAudit, telemetry,
281
+ // Lancer (Pro: runtime prompt + model overrides)
282
+ lancer, modelDefaults, modelInstanceFactory,
283
+ // Shared
284
+ model: modelConfig, systemPrompt: systemPromptConfig, locale = 'en-US', uiActionSchema, maxOutputTokens = 600, temperature = 0.2, maxSteps: configuredMaxSteps, safetyMaxSteps = DEFAULT_SAFETY_MAX_STEPS, emitStepReports = true, maxContextMessages = 12, maxConversationHistoryPairs = 4, guardrails, intentRouter, wrapHandler, onError, onToolError, onPipelineResult, onStepReport, onFinish, streamHandler: customStreamHandler, } = config;
285
+ // Report model defaults to Glirastes (fire-and-forget, once)
286
+ let defaultsReported = false;
287
+ function reportDefaultsOnce() {
288
+ if (defaultsReported || !lancer || !modelDefaults)
289
+ return;
290
+ defaultsReported = true;
291
+ lancer.config.reportModels(modelDefaults).catch(() => { });
292
+ }
293
+ // Build stream handler factory — per-request to allow session.ended audit
294
+ function createStreamHandler(auditContext) {
295
+ const wrappedOnFinish = (event) => {
296
+ onFinish?.(event);
297
+ if (auditContext && (onAudit || telemetry)) {
298
+ const sessionEndEvent = {
299
+ type: 'session.ended',
300
+ timestamp: new Date().toISOString(),
301
+ sessionId: auditContext.sessionId,
302
+ source: 'adapter',
303
+ details: {
304
+ totalSteps: event.totalSteps,
305
+ totalTokens: event.usage.totalTokens,
306
+ durationMs: Date.now() - auditContext.requestStart,
307
+ },
308
+ };
309
+ onAudit?.(sessionEndEvent);
310
+ try {
311
+ telemetry?.emit({
312
+ eventType: 'session.ended',
313
+ traceId: auditContext.sessionId,
314
+ tokensIn: event.usage.inputTokens,
315
+ tokensOut: event.usage.outputTokens,
316
+ latencyMs: Date.now() - auditContext.requestStart,
317
+ modelId: auditContext.modelId,
318
+ timestamp: new Date().toISOString(),
319
+ payload: sessionEndEvent.details,
320
+ actor: { sessionId: auditContext.sessionId },
321
+ });
322
+ void telemetry?.flush();
323
+ }
324
+ catch {
325
+ // Telemetry is fire-and-forget
326
+ }
327
+ }
328
+ };
329
+ return customStreamHandler
330
+ ? customStreamHandler
331
+ : (ctx) => defaultStreamHandler(ctx, wrappedOnFinish);
332
+ }
333
+ if (!staticTools && !loadTools) {
334
+ throw new Error('createAiChatHandler: either tools or loadTools must be provided');
335
+ }
336
+ async function handler(req) {
337
+ reportDefaultsOnce();
338
+ try {
339
+ const { messages } = await req.json();
340
+ if (!Array.isArray(messages)) {
341
+ return new Response(JSON.stringify({ error: 'messages must be an array' }), { status: 400, headers: { 'Content-Type': 'application/json' } });
342
+ }
343
+ // Build tool context
344
+ const toolContext = buildToolContext(req, { locale });
345
+ const requestStart = Date.now();
346
+ // Derive session ID — stable per conversation turn (groups approval flows)
347
+ const sessionId = (onAudit || piiShield || telemetry) ? deriveSessionId(messages) : '';
348
+ const toolOptions = {
349
+ uiActionSchema,
350
+ onError: onToolError,
351
+ onAudit,
352
+ sessionId,
353
+ traceId: sessionId || undefined,
354
+ telemetry,
355
+ };
356
+ // Emit session.started for audit + telemetry
357
+ if (sessionId && (onAudit || telemetry)) {
358
+ const sessionStartEvent = {
359
+ type: 'session.started',
360
+ timestamp: new Date().toISOString(),
361
+ sessionId,
362
+ source: 'adapter',
363
+ details: { locale },
364
+ };
365
+ onAudit?.(sessionStartEvent);
366
+ try {
367
+ telemetry?.emit({
368
+ eventType: 'session.started',
369
+ traceId: sessionId,
370
+ timestamp: new Date().toISOString(),
371
+ payload: sessionStartEvent.details,
372
+ actor: { sessionId },
373
+ });
374
+ }
375
+ catch {
376
+ // Telemetry is fire-and-forget
377
+ }
378
+ }
379
+ // ================================================================
380
+ // Pipeline mode
381
+ // ================================================================
382
+ if (pipeline) {
383
+ // Create callEndpoint for endpoint tools (needed regardless of static/dynamic)
384
+ const callEndpoint = createInternalApiCallerFromRequest(req);
385
+ const endpointToolContext = { ...toolContext, callEndpoint };
386
+ // Get tools (static or dynamic)
387
+ let registry;
388
+ if (staticTools) {
389
+ registry = staticTools;
390
+ }
391
+ else {
392
+ registry = await loadTools(endpointToolContext);
393
+ }
394
+ // Add followup tool if configured
395
+ if (followups) {
396
+ const followupTool = createFollowupTool(followups);
397
+ if (followupTool) {
398
+ registry = { ...registry, [followupTool.id]: followupTool };
399
+ }
400
+ }
401
+ // Extract user input for pipeline
402
+ let userText = extractLastUserText(messages);
403
+ if (piiShield) {
404
+ userText = await piiShield.outbound(userText, sessionId);
405
+ }
406
+ // Build lightweight conversation history for intent classification.
407
+ // Include the last few user/assistant text exchanges (excluding the
408
+ // current message) so the classifier can understand follow-ups.
409
+ const conversationHistory = extractConversationHistory(messages, maxConversationHistoryPairs);
410
+ // Run pipeline: guardrails + classification + routing + model selection
411
+ const pipelineResult = await pipeline.process(userText, toolContext, conversationHistory.length > 0 ? conversationHistory : undefined);
412
+ // Notify consumer about pipeline decision
413
+ onPipelineResult?.(pipelineResult);
414
+ // Emit pipeline-stage telemetry events for request trace
415
+ if (telemetry && sessionId) {
416
+ const pipelineActor = { sessionId };
417
+ try {
418
+ // Use explicit blocked flag from pipeline instead of heuristic
419
+ const wardenBlocked = pipelineResult.blocked === true;
420
+ telemetry.emit({
421
+ eventType: wardenBlocked ? 'warden.block' : 'warden.pass',
422
+ traceId: sessionId,
423
+ timestamp: new Date().toISOString(),
424
+ payload: { blocked: wardenBlocked, inputLength: userText.length },
425
+ actor: pipelineActor,
426
+ });
427
+ // Primus classification
428
+ telemetry.emit({
429
+ eventType: 'primus.classify',
430
+ traceId: sessionId,
431
+ timestamp: new Date().toISOString(),
432
+ payload: {
433
+ moduleId: pipelineResult.intent.intent,
434
+ confidence: pipelineResult.intent.confidence,
435
+ module: pipelineResult.module?.id ?? null,
436
+ },
437
+ actor: pipelineActor,
438
+ });
439
+ // Tool routing
440
+ telemetry.emit({
441
+ eventType: 'pipeline.routing',
442
+ traceId: sessionId,
443
+ timestamp: new Date().toISOString(),
444
+ payload: {
445
+ toolCount: pipelineResult.tools.length,
446
+ tools: pipelineResult.tools,
447
+ module: pipelineResult.module?.id ?? null,
448
+ modelId: pipelineResult.model.modelId,
449
+ },
450
+ actor: pipelineActor,
451
+ });
452
+ }
453
+ catch {
454
+ // Telemetry is fire-and-forget
455
+ }
456
+ }
457
+ // Convert all tools to AI tools
458
+ let aiTools = await toolsToAiTools(registry, endpointToolContext, toolOptions);
459
+ // Scope tools to pipeline selection
460
+ if (pipelineResult.blocked) {
461
+ // Guardrails blocked — no tools allowed
462
+ aiTools = {};
463
+ }
464
+ else if (pipelineResult.tools.length > 0) {
465
+ const scoped = {};
466
+ for (const name of pipelineResult.tools) {
467
+ if (aiTools[name])
468
+ scoped[name] = aiTools[name];
469
+ }
470
+ if (Object.keys(scoped).length > 0)
471
+ aiTools = scoped;
472
+ }
473
+ // Resolve model — config callback > pipeline instance > error
474
+ let model;
475
+ if (modelConfig) {
476
+ model =
477
+ typeof modelConfig === 'function'
478
+ ? modelConfig({ pipelineResult })
479
+ : modelConfig;
480
+ }
481
+ else if (pipelineResult.model.instance) {
482
+ model = pipelineResult.model.instance;
483
+ }
484
+ else {
485
+ return new Response(JSON.stringify({
486
+ error: 'No model configured. Provide model on handler config or as instance on ModelSelectorConfig.',
487
+ }), { status: 500, headers: { 'Content-Type': 'application/json' } });
488
+ }
489
+ // Resolve system prompt
490
+ let systemPrompt = typeof systemPromptConfig === 'function'
491
+ ? systemPromptConfig({
492
+ pipelineResult,
493
+ currentDate: new Date(),
494
+ })
495
+ : systemPromptConfig;
496
+ // Track the actual model ID used (may be overridden by Glirastes config)
497
+ let resolvedModelId = pipelineResult.model.modelId;
498
+ // Apply runtime prompt + model overrides from Glirastes (Pro feature)
499
+ if (lancer) {
500
+ try {
501
+ const configResult = await lancer.config.fetch(['prompts', 'models']);
502
+ // Prompt overrides
503
+ if (pipelineResult.module) {
504
+ const prompts = configResult.prompts;
505
+ if (prompts) {
506
+ const override = prompts.find((p) => p.moduleId === pipelineResult.module.id);
507
+ if (override) {
508
+ systemPrompt = applyPromptOverride(systemPrompt, override);
509
+ }
510
+ }
511
+ }
512
+ // Model overrides — resolve tier from pipeline, apply override if configured
513
+ if (modelInstanceFactory) {
514
+ const modelOverrides = configResult.models;
515
+ if (modelOverrides) {
516
+ const tier = pipelineResult.module?.executionDefaults?.modelTier ?? 'standard';
517
+ const overrideModelId = modelOverrides[tier];
518
+ if (overrideModelId) {
519
+ resolvedModelId = overrideModelId;
520
+ model = modelInstanceFactory(overrideModelId);
521
+ }
522
+ }
523
+ }
524
+ }
525
+ catch {
526
+ // Graceful degradation: use local prompt/model if Glirastes is unreachable
527
+ }
528
+ }
529
+ const stepLimit = resolveStepLimit({
530
+ moduleMaxSteps: pipelineResult.module?.executionDefaults?.maxSteps,
531
+ configuredMaxSteps,
532
+ safetyMaxSteps,
533
+ });
534
+ const contextWindow = pipelineResult.module?.executionDefaults?.contextWindow ??
535
+ maxContextMessages;
536
+ let recentMessages = messages.slice(-contextWindow);
537
+ // PII Shield: anonymize message history + wrap tools
538
+ if (piiShield) {
539
+ recentMessages = await anonymizeMessages(recentMessages, piiShield, sessionId);
540
+ aiTools = wrapToolsWithShield(aiTools, piiShield, sessionId);
541
+ }
542
+ // Lancer Approvals: delegate approval decisions to Glirastes
543
+ if (lancer?.approvals) {
544
+ aiTools = wrapToolsWithLancerApprovals(aiTools, lancer.approvals, sessionId);
545
+ }
546
+ const pipelineStreamHandler = createStreamHandler((onAudit || telemetry) ? {
547
+ sessionId,
548
+ requestStart,
549
+ modelId: resolvedModelId,
550
+ } : undefined);
551
+ return pipelineStreamHandler({
552
+ tools: aiTools,
553
+ messages: recentMessages,
554
+ systemPrompt,
555
+ model,
556
+ maxSteps: stepLimit.maxSteps,
557
+ stepLimitSource: stepLimit.stepLimitSource,
558
+ emitStepReports,
559
+ onStepReport,
560
+ maxOutputTokens,
561
+ temperature,
562
+ maxContextMessages,
563
+ modelTier: pipelineResult.model.modelId,
564
+ pipelineResult,
565
+ piiShield: piiShield ? { shield: piiShield, sessionId } : undefined,
566
+ });
567
+ }
568
+ // ================================================================
569
+ // Legacy mode (without pipeline)
570
+ // ================================================================
571
+ // Guardrails
572
+ let processedMessages = messages;
573
+ if (guardrails) {
574
+ const check = await guardrails(messages);
575
+ if (!check.ok) {
576
+ return new Response(JSON.stringify({ error: check.reason ?? 'Invalid input' }), { status: 400, headers: { 'Content-Type': 'application/json' } });
577
+ }
578
+ if (check.sanitizedMessages) {
579
+ processedMessages = check.sanitizedMessages;
580
+ }
581
+ }
582
+ // Create callEndpoint for endpoint tools (needed regardless of static/dynamic)
583
+ const callEndpoint = createInternalApiCallerFromRequest(req);
584
+ const endpointToolContext = { ...toolContext, callEndpoint };
585
+ // Load tools
586
+ let registry;
587
+ if (staticTools) {
588
+ registry = staticTools;
589
+ }
590
+ else {
591
+ registry = await loadTools(endpointToolContext);
592
+ }
593
+ const allToolNames = Object.keys(registry);
594
+ // PII Shield: anonymize for legacy mode
595
+ const legacySessionId = piiShield ? deriveSessionId(processedMessages) : '';
596
+ if (piiShield) {
597
+ const lastUserText = extractLastUserText(processedMessages);
598
+ await piiShield.outbound(lastUserText, legacySessionId);
599
+ }
600
+ // Intent routing
601
+ let routing;
602
+ if (intentRouter) {
603
+ const text = extractLastUserText(processedMessages);
604
+ routing = await intentRouter(text, allToolNames);
605
+ }
606
+ // Convert to AI tools
607
+ let aiTools = await toolsToAiTools(registry, endpointToolContext, toolOptions);
608
+ // Scope tools by intent
609
+ if (routing?.toolNames && routing.toolNames.length > 0) {
610
+ const scoped = {};
611
+ for (const name of routing.toolNames) {
612
+ if (aiTools[name])
613
+ scoped[name] = aiTools[name];
614
+ }
615
+ if (Object.keys(scoped).length > 0)
616
+ aiTools = scoped;
617
+ }
618
+ // Resolve model + system prompt (legacy mode — no pipeline fallback)
619
+ if (!modelConfig) {
620
+ return new Response(JSON.stringify({
621
+ error: 'No model configured. In legacy mode (without pipeline), model is required.',
622
+ }), { status: 500, headers: { 'Content-Type': 'application/json' } });
623
+ }
624
+ const model = typeof modelConfig === 'function'
625
+ ? modelConfig({ routing })
626
+ : modelConfig;
627
+ const systemPrompt = typeof systemPromptConfig === 'function'
628
+ ? systemPromptConfig({
629
+ routing,
630
+ currentDate: new Date(),
631
+ })
632
+ : systemPromptConfig;
633
+ const stepLimit = resolveStepLimit({
634
+ configuredMaxSteps: routing?.maxSteps ?? configuredMaxSteps,
635
+ safetyMaxSteps,
636
+ });
637
+ const contextWindow = routing?.contextWindow ?? maxContextMessages;
638
+ let recentMessages = processedMessages.slice(-contextWindow);
639
+ // PII Shield: anonymize message history + wrap tools (legacy mode)
640
+ if (piiShield) {
641
+ recentMessages = await anonymizeMessages(recentMessages, piiShield, legacySessionId);
642
+ aiTools = wrapToolsWithShield(aiTools, piiShield, legacySessionId);
643
+ }
644
+ // Lancer Approvals: delegate approval decisions to Glirastes (legacy mode)
645
+ if (lancer?.approvals) {
646
+ aiTools = wrapToolsWithLancerApprovals(aiTools, lancer.approvals, legacySessionId || sessionId);
647
+ }
648
+ const legacyStreamHandler = createStreamHandler((onAudit || telemetry) ? {
649
+ sessionId: legacySessionId || sessionId,
650
+ requestStart,
651
+ } : undefined);
652
+ // Delegate streaming to consumer's handler
653
+ return legacyStreamHandler({
654
+ tools: aiTools,
655
+ messages: recentMessages,
656
+ systemPrompt,
657
+ model,
658
+ maxSteps: stepLimit.maxSteps,
659
+ stepLimitSource: stepLimit.stepLimitSource,
660
+ emitStepReports,
661
+ onStepReport,
662
+ maxOutputTokens,
663
+ temperature,
664
+ maxContextMessages,
665
+ modelTier: routing?.modelTier,
666
+ routing,
667
+ piiShield: piiShield ? { shield: piiShield, sessionId: legacySessionId } : undefined,
668
+ });
669
+ }
670
+ catch (error) {
671
+ onError?.(error, req);
672
+ return new Response(JSON.stringify({ error: 'AI request failed' }), { status: 500, headers: { 'Content-Type': 'application/json' } });
673
+ }
674
+ }
675
+ if (wrapHandler) {
676
+ return async (req) => wrapHandler(() => handler(req), req);
677
+ }
678
+ return handler;
679
+ }
680
+ // ============================================================================
681
+ // PII Shield Helpers
682
+ // ============================================================================
683
+ function deriveSessionId(messages) {
684
+ // Use the last user message's ID — groups approval continuations (same
685
+ // last user message) but separates distinct questions (new user message).
686
+ for (let i = messages.length - 1; i >= 0; i--) {
687
+ const msg = messages[i];
688
+ if (msg?.role === 'user' && msg?.id && typeof msg.id === 'string') {
689
+ return `ai-${msg.id}`;
690
+ }
691
+ }
692
+ return `ai-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
693
+ }
694
+ async function anonymizeMessages(messages, shield, sessionId) {
695
+ const result = [];
696
+ for (const msg of messages) {
697
+ if (typeof msg !== 'object' || msg === null) {
698
+ result.push(msg);
699
+ continue;
700
+ }
701
+ const record = msg;
702
+ // Only anonymize user messages
703
+ if (record.role !== 'user') {
704
+ result.push(msg);
705
+ continue;
706
+ }
707
+ // Anonymize string content
708
+ if (typeof record.content === 'string') {
709
+ const anonymized = await shield.outbound(record.content, sessionId);
710
+ result.push({ ...record, content: anonymized });
711
+ continue;
712
+ }
713
+ // Anonymize parts array
714
+ if (Array.isArray(record.parts)) {
715
+ const anonParts = await Promise.all(record.parts.map(async (part) => {
716
+ if (typeof part === 'object' && part !== null &&
717
+ part.type === 'text') {
718
+ const p = part;
719
+ if (typeof p.text === 'string') {
720
+ const anonymized = await shield.outbound(p.text, sessionId);
721
+ return { ...p, text: anonymized };
722
+ }
723
+ }
724
+ return part;
725
+ }));
726
+ result.push({ ...record, parts: anonParts });
727
+ continue;
728
+ }
729
+ result.push(msg);
730
+ }
731
+ return result;
732
+ }
733
+ function wrapToolsWithShield(aiTools, shield, sessionId) {
734
+ const wrapped = {};
735
+ for (const [name, raw] of Object.entries(aiTools)) {
736
+ const sdkTool = raw;
737
+ const originalExecute = sdkTool.execute;
738
+ wrapped[name] = {
739
+ ...sdkTool,
740
+ execute: async (...executeArgs) => {
741
+ // Rehydrate args (first argument is the tool input).
742
+ // Uses the async path for Lancer Aegis rehydration.
743
+ // The sync rehydrateArgs is a legacy no-op kept for backward compat.
744
+ let args = executeArgs[0];
745
+ if (args && typeof args === 'object' && !Array.isArray(args)) {
746
+ if (shield.rehydrateArgsAsync) {
747
+ args = await shield.rehydrateArgsAsync(args, sessionId);
748
+ }
749
+ else {
750
+ args = shield.rehydrateArgs(args, sessionId);
751
+ }
752
+ }
753
+ // Execute with real args
754
+ const result = await originalExecute(args, ...executeArgs.slice(1));
755
+ // Anonymize result before LLM sees it
756
+ return shield.anonymizeResult(result, sessionId);
757
+ },
758
+ };
759
+ }
760
+ return wrapped;
761
+ }
762
+ /**
763
+ * Wrap tool `needsApproval` with Lancer approval checks.
764
+ *
765
+ * When Lancer approvals are configured, each tool's approval decision is
766
+ * delegated to Glirastes instead of relying on the local `needsApproval` flag.
767
+ * If Lancer is unreachable, falls back to the existing local approval check.
768
+ *
769
+ * When a tool requires approval (Lancer returns `required: true`), the
770
+ * requestId is stored so that `decide()` can be called when the user
771
+ * approves and the tool's `execute` fires.
772
+ */
773
+ function wrapToolsWithLancerApprovals(aiTools, approvals, traceId) {
774
+ // Map toolName → requestId for pending approvals (cleared after decide)
775
+ const pendingRequestIds = new Map();
776
+ // Track tools that actually required approval (survives cross-request boundary via resolve fallback)
777
+ const approvalRequired = new Set();
778
+ const wrapped = {};
779
+ for (const [name, raw] of Object.entries(aiTools)) {
780
+ const sdkTool = raw;
781
+ const originalNeedsApproval = sdkTool.needsApproval;
782
+ const originalExecute = sdkTool.execute;
783
+ // Respect local needsApproval: false — never delegate to Lancer for these tools
784
+ if (originalNeedsApproval === false) {
785
+ wrapped[name] = sdkTool;
786
+ continue;
787
+ }
788
+ wrapped[name] = {
789
+ ...sdkTool,
790
+ // Override needsApproval with Lancer check
791
+ needsApproval: async (input) => {
792
+ try {
793
+ const inputHash = approvals.hashInput((input && typeof input === 'object' ? input : {}));
794
+ const check = await approvals.check({
795
+ toolId: sdkTool._toolId ?? name,
796
+ inputHash,
797
+ ...(traceId ? { traceId } : {}),
798
+ });
799
+ if (check.required) {
800
+ // Store requestId for later decide() call
801
+ if (check.requestId) {
802
+ pendingRequestIds.set(name, check.requestId);
803
+ }
804
+ approvalRequired.add(name);
805
+ return true;
806
+ }
807
+ // Lancer says no approval required (auto-approved or no matching flow)
808
+ return false;
809
+ }
810
+ catch {
811
+ // Graceful degradation: fall back to local needsApproval
812
+ if (typeof originalNeedsApproval === 'function') {
813
+ return originalNeedsApproval(input);
814
+ }
815
+ return originalNeedsApproval === true;
816
+ }
817
+ },
818
+ // Wrap execute to call decide() when approved.
819
+ // The requestId may be missing because needsApproval and execute run in
820
+ // different HTTP requests (Vercel AI SDK approval flow), so the in-memory
821
+ // pendingRequestIds map is recreated empty on the second request.
822
+ // Fallback: resolve by toolId + inputHash via the /v1/approvals/resolve endpoint.
823
+ execute: async (...executeArgs) => {
824
+ const requestId = pendingRequestIds.get(name);
825
+ const toolId = sdkTool._toolId ?? name;
826
+ const decidedBy = 'unknown';
827
+ if (requestId) {
828
+ pendingRequestIds.delete(name);
829
+ try {
830
+ await approvals.decide(requestId, {
831
+ decision: 'approved',
832
+ decidedBy,
833
+ });
834
+ }
835
+ catch {
836
+ // Fire-and-forget: don't block tool execution if decide fails
837
+ }
838
+ }
839
+ else if (approvalRequired.has(name)) {
840
+ // Cross-request fallback: resolve pending approval by toolId + inputHash.
841
+ // Only attempt when needsApproval previously returned true (the requestId
842
+ // may be missing because needsApproval and execute run in different HTTP
843
+ // requests, recreating the in-memory map).
844
+ approvalRequired.delete(name);
845
+ try {
846
+ const input = executeArgs[0];
847
+ const inputHash = approvals.hashInput((input && typeof input === 'object' ? input : {}));
848
+ await approvals.resolve({
849
+ toolId,
850
+ inputHash,
851
+ decision: 'approved',
852
+ decidedBy,
853
+ });
854
+ }
855
+ catch {
856
+ // Fire-and-forget: don't block tool execution if resolve fails
857
+ }
858
+ }
859
+ return originalExecute(...executeArgs);
860
+ },
861
+ };
862
+ }
863
+ return wrapped;
864
+ }
865
+ function extractLastUserText(messages) {
866
+ for (let i = messages.length - 1; i >= 0; i--) {
867
+ const msg = messages[i];
868
+ if (typeof msg !== 'object' || msg === null)
869
+ continue;
870
+ const record = msg;
871
+ if (record.role !== 'user')
872
+ continue;
873
+ if (typeof record.content === 'string')
874
+ return record.content;
875
+ if (Array.isArray(record.parts)) {
876
+ for (const part of record.parts) {
877
+ if (typeof part === 'object' &&
878
+ part !== null &&
879
+ part.type === 'text') {
880
+ const text = part.text;
881
+ if (typeof text === 'string')
882
+ return text;
883
+ }
884
+ }
885
+ }
886
+ if (Array.isArray(record.content)) {
887
+ for (const part of record.content) {
888
+ if (typeof part === 'object' &&
889
+ part !== null &&
890
+ part.type === 'text') {
891
+ const text = part.text;
892
+ if (typeof text === 'string')
893
+ return text;
894
+ }
895
+ }
896
+ }
897
+ }
898
+ return '';
899
+ }
900
+ /**
901
+ * Extract a lightweight conversation history from UIMessages for intent
902
+ * classification. Returns the last `maxPairs` user/assistant text exchanges
903
+ * EXCLUDING the current (latest) user message.
904
+ *
905
+ * Tool calls/results are stripped — only human-readable text is included
906
+ * to keep the classification prompt small and fast.
907
+ */
908
+ function extractConversationHistory(messages, maxPairs) {
909
+ // Collect text from all messages except the last user message
910
+ const textMessages = [];
911
+ for (let i = 0; i < messages.length; i++) {
912
+ const msg = messages[i];
913
+ if (typeof msg !== 'object' || msg === null)
914
+ continue;
915
+ const record = msg;
916
+ const role = record.role;
917
+ if (role !== 'user' && role !== 'assistant')
918
+ continue;
919
+ const text = extractTextFromMessage(record);
920
+ if (!text.trim())
921
+ continue;
922
+ textMessages.push({ role: role, content: text });
923
+ }
924
+ // Remove the last user message (that's the current input, not history)
925
+ if (textMessages.length > 0 && textMessages[textMessages.length - 1].role === 'user') {
926
+ textMessages.pop();
927
+ }
928
+ // Return the last N messages (up to maxPairs * 2 for user+assistant pairs)
929
+ return textMessages.slice(-(maxPairs * 2));
930
+ }
931
+ function extractTextFromMessage(msg) {
932
+ if (typeof msg.content === 'string')
933
+ return msg.content;
934
+ const parts = Array.isArray(msg.parts)
935
+ ? msg.parts
936
+ : Array.isArray(msg.content)
937
+ ? msg.content
938
+ : [];
939
+ const texts = [];
940
+ for (const part of parts) {
941
+ if (typeof part === 'object' && part !== null) {
942
+ const p = part;
943
+ if (p.type === 'text' && typeof p.text === 'string') {
944
+ texts.push(p.text);
945
+ }
946
+ }
947
+ }
948
+ return texts.join(' ');
949
+ }
950
+ //# sourceMappingURL=create-ai-chat-handler.js.map