@astro-minimax/ai 0.9.0 → 0.9.3

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 (251) hide show
  1. package/README.md +108 -18
  2. package/dist/cache/global-cache.d.ts +6 -2
  3. package/dist/cache/global-cache.d.ts.map +1 -1
  4. package/dist/cache/global-cache.js +24 -9
  5. package/dist/cache/index.d.ts +7 -6
  6. package/dist/cache/index.d.ts.map +1 -1
  7. package/dist/cache/index.js +12 -4
  8. package/dist/cache/injection-cache.d.ts +36 -0
  9. package/dist/cache/injection-cache.d.ts.map +1 -0
  10. package/dist/cache/injection-cache.js +90 -0
  11. package/dist/cache/kv-adapter.d.ts.map +1 -1
  12. package/dist/cache/kv-adapter.js +2 -1
  13. package/dist/cache/memory-adapter.d.ts.map +1 -1
  14. package/dist/cache/memory-adapter.js +2 -1
  15. package/dist/cache/response-cache.d.ts +10 -5
  16. package/dist/cache/response-cache.d.ts.map +1 -1
  17. package/dist/cache/response-cache.js +18 -6
  18. package/dist/components/AIChatContainer.d.ts +2 -2
  19. package/dist/components/AIChatContainer.d.ts.map +1 -1
  20. package/dist/components/AIChatContainer.js +8 -920
  21. package/dist/components/ChatInput.d.ts +15 -0
  22. package/dist/components/ChatInput.d.ts.map +1 -0
  23. package/dist/components/ChatInput.js +72 -0
  24. package/dist/components/ChatPanel.d.ts +1 -1
  25. package/dist/components/ChatPanel.d.ts.map +1 -1
  26. package/dist/components/ChatPanel.js +210 -672
  27. package/dist/components/CodeBlock.d.ts +31 -0
  28. package/dist/components/CodeBlock.d.ts.map +1 -0
  29. package/dist/components/CodeBlock.js +143 -0
  30. package/dist/components/MarkmapBlock.d.ts +4 -0
  31. package/dist/components/MarkmapBlock.d.ts.map +1 -0
  32. package/dist/components/MarkmapBlock.js +180 -0
  33. package/dist/components/MermaidBlock.d.ts +4 -0
  34. package/dist/components/MermaidBlock.d.ts.map +1 -0
  35. package/dist/components/MermaidBlock.js +193 -0
  36. package/dist/components/MessageBubble.d.ts +21 -0
  37. package/dist/components/MessageBubble.d.ts.map +1 -0
  38. package/dist/components/MessageBubble.js +233 -0
  39. package/dist/components/ReasoningBlock.d.ts +6 -0
  40. package/dist/components/ReasoningBlock.d.ts.map +1 -0
  41. package/dist/components/ReasoningBlock.js +11 -0
  42. package/dist/components/RichText.d.ts +41 -0
  43. package/dist/components/RichText.d.ts.map +1 -0
  44. package/dist/components/RichText.js +202 -0
  45. package/dist/components/VizShared.d.ts +57 -0
  46. package/dist/components/VizShared.d.ts.map +1 -0
  47. package/dist/components/VizShared.js +233 -0
  48. package/dist/components/tool-auto-continue.d.ts +5 -0
  49. package/dist/components/tool-auto-continue.d.ts.map +1 -0
  50. package/dist/components/tool-auto-continue.js +33 -0
  51. package/dist/constants.d.ts +61 -0
  52. package/dist/constants.d.ts.map +1 -0
  53. package/dist/constants.js +72 -0
  54. package/dist/data/index.d.ts +4 -3
  55. package/dist/data/index.d.ts.map +1 -1
  56. package/dist/data/index.js +4 -10
  57. package/dist/data/knowledge-types.d.ts +8 -0
  58. package/dist/data/knowledge-types.d.ts.map +1 -0
  59. package/dist/data/knowledge-types.js +14 -0
  60. package/dist/data/metadata-loader.d.ts +4 -28
  61. package/dist/data/metadata-loader.d.ts.map +1 -1
  62. package/dist/data/metadata-loader.js +11 -34
  63. package/dist/data/types.d.ts +17 -2
  64. package/dist/data/types.d.ts.map +1 -1
  65. package/dist/extensions/index.d.ts +5 -0
  66. package/dist/extensions/index.d.ts.map +1 -0
  67. package/dist/extensions/index.js +24 -0
  68. package/dist/extensions/injector.d.ts +14 -0
  69. package/dist/extensions/injector.d.ts.map +1 -0
  70. package/dist/extensions/injector.js +146 -0
  71. package/dist/extensions/loader.d.ts +5 -0
  72. package/dist/extensions/loader.d.ts.map +1 -0
  73. package/dist/extensions/loader.js +45 -0
  74. package/dist/extensions/registry.d.ts +4 -0
  75. package/dist/extensions/registry.d.ts.map +1 -0
  76. package/dist/extensions/registry.js +144 -0
  77. package/dist/extensions/types.d.ts +126 -0
  78. package/dist/extensions/types.d.ts.map +1 -0
  79. package/dist/extensions/types.js +0 -0
  80. package/dist/fact-registry/prompt-injector.d.ts +1 -1
  81. package/dist/fact-registry/prompt-injector.d.ts.map +1 -1
  82. package/dist/fact-registry/prompt-injector.js +2 -1
  83. package/dist/index.d.ts +3 -2
  84. package/dist/index.d.ts.map +1 -1
  85. package/dist/index.js +3 -2
  86. package/dist/intelligence/citation-guard.d.ts +2 -13
  87. package/dist/intelligence/citation-guard.d.ts.map +1 -1
  88. package/dist/intelligence/citation-guard.js +52 -23
  89. package/dist/intelligence/evidence-analysis.d.ts +24 -16
  90. package/dist/intelligence/evidence-analysis.d.ts.map +1 -1
  91. package/dist/intelligence/evidence-analysis.js +118 -20
  92. package/dist/intelligence/evidence-budget.d.ts +13 -0
  93. package/dist/intelligence/evidence-budget.d.ts.map +1 -0
  94. package/dist/intelligence/evidence-budget.js +49 -0
  95. package/dist/intelligence/index.d.ts +10 -4
  96. package/dist/intelligence/index.d.ts.map +1 -1
  97. package/dist/intelligence/index.js +27 -3
  98. package/dist/intelligence/keyword-extract.d.ts +1 -1
  99. package/dist/intelligence/keyword-extract.d.ts.map +1 -1
  100. package/dist/intelligence/keyword-extract.js +5 -9
  101. package/dist/intelligence/request-interpretation.d.ts +40 -0
  102. package/dist/intelligence/request-interpretation.d.ts.map +1 -0
  103. package/dist/intelligence/request-interpretation.js +71 -0
  104. package/dist/intelligence/response-templates.d.ts +1 -0
  105. package/dist/intelligence/response-templates.d.ts.map +1 -1
  106. package/dist/intelligence/response-templates.js +13 -0
  107. package/dist/prompt/dynamic-layer.d.ts +1 -5
  108. package/dist/prompt/dynamic-layer.d.ts.map +1 -1
  109. package/dist/prompt/dynamic-layer.js +145 -9
  110. package/dist/prompt/prompt-builder.d.ts +1 -1
  111. package/dist/prompt/prompt-builder.d.ts.map +1 -1
  112. package/dist/prompt/prompt-builder.js +5 -1
  113. package/dist/prompt/semi-static-layer.d.ts +1 -1
  114. package/dist/prompt/semi-static-layer.d.ts.map +1 -1
  115. package/dist/prompt/semi-static-layer.js +22 -12
  116. package/dist/prompt/static-layer.d.ts.map +1 -1
  117. package/dist/prompt/static-layer.js +37 -4
  118. package/dist/prompt/types.d.ts +9 -4
  119. package/dist/prompt/types.d.ts.map +1 -1
  120. package/dist/provider-manager/base.d.ts +5 -1
  121. package/dist/provider-manager/base.d.ts.map +1 -1
  122. package/dist/provider-manager/base.js +22 -2
  123. package/dist/provider-manager/config.d.ts.map +1 -1
  124. package/dist/provider-manager/config.js +3 -2
  125. package/dist/provider-manager/index.d.ts +1 -1
  126. package/dist/provider-manager/index.d.ts.map +1 -1
  127. package/dist/provider-manager/index.js +1 -2
  128. package/dist/provider-manager/manager.d.ts +10 -1
  129. package/dist/provider-manager/manager.d.ts.map +1 -1
  130. package/dist/provider-manager/manager.js +26 -10
  131. package/dist/provider-manager/openai.d.ts +2 -2
  132. package/dist/provider-manager/openai.d.ts.map +1 -1
  133. package/dist/provider-manager/openai.js +19 -4
  134. package/dist/provider-manager/types.d.ts +18 -38
  135. package/dist/provider-manager/types.d.ts.map +1 -1
  136. package/dist/provider-manager/workers.d.ts +2 -2
  137. package/dist/provider-manager/workers.d.ts.map +1 -1
  138. package/dist/provider-manager/workers.js +15 -4
  139. package/dist/query/followup.d.ts +7 -0
  140. package/dist/query/followup.d.ts.map +1 -0
  141. package/dist/query/followup.js +46 -0
  142. package/dist/query/intent.d.ts +6 -0
  143. package/dist/query/intent.d.ts.map +1 -0
  144. package/dist/query/intent.js +137 -0
  145. package/dist/query/types.d.ts +8 -0
  146. package/dist/query/types.d.ts.map +1 -0
  147. package/dist/query/types.js +0 -0
  148. package/dist/search/hybrid-search.d.ts +111 -0
  149. package/dist/search/hybrid-search.d.ts.map +1 -0
  150. package/dist/search/hybrid-search.js +326 -0
  151. package/dist/search/index.d.ts +11 -9
  152. package/dist/search/index.d.ts.map +1 -1
  153. package/dist/search/index.js +46 -10
  154. package/dist/search/scoring.d.ts +18 -0
  155. package/dist/search/scoring.d.ts.map +1 -0
  156. package/dist/search/{search-utils.js → scoring.js} +14 -27
  157. package/dist/search/search-api.d.ts +16 -1
  158. package/dist/search/search-api.d.ts.map +1 -1
  159. package/dist/search/search-api.js +118 -15
  160. package/dist/search/search-index.d.ts +2 -2
  161. package/dist/search/search-index.d.ts.map +1 -1
  162. package/dist/search/search-index.js +4 -2
  163. package/dist/search/session-cache.d.ts +4 -10
  164. package/dist/search/session-cache.d.ts.map +1 -1
  165. package/dist/search/session-cache.js +12 -45
  166. package/dist/search/types.d.ts +28 -0
  167. package/dist/search/types.d.ts.map +1 -1
  168. package/dist/search/vector-reranker.d.ts +3 -3
  169. package/dist/search/vector-reranker.d.ts.map +1 -1
  170. package/dist/search/vector-reranker.js +14 -2
  171. package/dist/server/chat-handler.d.ts +86 -1
  172. package/dist/server/chat-handler.d.ts.map +1 -1
  173. package/dist/server/chat-handler.js +835 -401
  174. package/dist/server/chat-message-utils.d.ts +6 -0
  175. package/dist/server/chat-message-utils.d.ts.map +1 -0
  176. package/dist/server/chat-message-utils.js +40 -0
  177. package/dist/server/chat-utils.d.ts +30 -0
  178. package/dist/server/chat-utils.d.ts.map +1 -0
  179. package/dist/server/chat-utils.js +88 -0
  180. package/dist/server/dev-server.js +238 -101
  181. package/dist/server/env-config.d.ts +22 -0
  182. package/dist/server/env-config.d.ts.map +1 -0
  183. package/dist/server/env-config.js +25 -0
  184. package/dist/server/errors.d.ts +1 -0
  185. package/dist/server/errors.d.ts.map +1 -1
  186. package/dist/server/errors.js +14 -7
  187. package/dist/server/index.d.ts +2 -4
  188. package/dist/server/index.d.ts.map +1 -1
  189. package/dist/server/index.js +4 -25
  190. package/dist/server/metadata-init.d.ts +10 -5
  191. package/dist/server/metadata-init.d.ts.map +1 -1
  192. package/dist/server/metadata-init.js +78 -34
  193. package/dist/server/notify.d.ts +12 -11
  194. package/dist/server/notify.d.ts.map +1 -1
  195. package/dist/server/notify.js +46 -48
  196. package/dist/server/prompt-runtime.d.ts +60 -0
  197. package/dist/server/prompt-runtime.d.ts.map +1 -0
  198. package/dist/server/prompt-runtime.js +284 -0
  199. package/dist/server/stream-helpers.d.ts +30 -16
  200. package/dist/server/stream-helpers.d.ts.map +1 -1
  201. package/dist/server/stream-helpers.js +152 -15
  202. package/dist/server/types.d.ts +47 -12
  203. package/dist/server/types.d.ts.map +1 -1
  204. package/dist/structured-output/generator.d.ts +6 -0
  205. package/dist/structured-output/generator.d.ts.map +1 -0
  206. package/dist/structured-output/generator.js +164 -0
  207. package/dist/structured-output/index.d.ts +4 -0
  208. package/dist/structured-output/index.d.ts.map +1 -0
  209. package/dist/structured-output/index.js +6 -0
  210. package/dist/structured-output/schemas/evidence.d.ts +88 -0
  211. package/dist/structured-output/schemas/evidence.d.ts.map +1 -0
  212. package/dist/structured-output/schemas/evidence.js +65 -0
  213. package/dist/structured-output/types.d.ts +69 -0
  214. package/dist/structured-output/types.d.ts.map +1 -0
  215. package/dist/structured-output/types.js +0 -0
  216. package/dist/tools/action-tools.d.ts +63 -0
  217. package/dist/tools/action-tools.d.ts.map +1 -0
  218. package/dist/tools/action-tools.js +158 -0
  219. package/dist/tools/index.d.ts +2 -0
  220. package/dist/tools/index.d.ts.map +1 -0
  221. package/dist/tools/index.js +30 -0
  222. package/dist/utils/i18n.d.ts +1 -1
  223. package/dist/utils/i18n.d.ts.map +1 -1
  224. package/dist/utils/i18n.js +1 -1
  225. package/dist/utils/logger.d.ts +11 -0
  226. package/dist/utils/logger.d.ts.map +1 -0
  227. package/dist/utils/logger.js +36 -0
  228. package/dist/utils/text.d.ts +11 -0
  229. package/dist/utils/text.d.ts.map +1 -0
  230. package/dist/utils/text.js +87 -0
  231. package/dist/utils/url.d.ts +19 -0
  232. package/dist/utils/url.d.ts.map +1 -0
  233. package/dist/utils/url.js +13 -0
  234. package/package.json +46 -12
  235. package/dist/intelligence/intent-detect.d.ts +0 -40
  236. package/dist/intelligence/intent-detect.d.ts.map +0 -1
  237. package/dist/intelligence/intent-detect.js +0 -93
  238. package/dist/providers/index.d.ts +0 -2
  239. package/dist/providers/index.d.ts.map +0 -1
  240. package/dist/providers/index.js +0 -5
  241. package/dist/search/search-utils.d.ts +0 -47
  242. package/dist/search/search-utils.d.ts.map +0 -1
  243. package/dist/stream/index.d.ts +0 -3
  244. package/dist/stream/index.d.ts.map +0 -1
  245. package/dist/stream/index.js +0 -8
  246. package/dist/stream/mock-stream.d.ts +0 -12
  247. package/dist/stream/mock-stream.d.ts.map +0 -1
  248. package/dist/stream/mock-stream.js +0 -26
  249. package/dist/stream/response.d.ts +0 -10
  250. package/dist/stream/response.d.ts.map +0 -1
  251. package/dist/stream/response.js +0 -21
@@ -0,0 +1,6 @@
1
+ import type { UIMessage } from 'ai';
2
+ export declare function getMessageText(message: UIMessage): string;
3
+ export declare function hasContent(message: UIMessage): boolean;
4
+ export declare function filterValidMessages(messages: UIMessage[]): UIMessage[];
5
+ export declare function getLatestUserText(messages: UIMessage[]): string;
6
+ //# sourceMappingURL=chat-message-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-message-utils.d.ts","sourceRoot":"","sources":["../../src/server/chat-message-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAEpC,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,GAAG,MAAM,CAQzD;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,SAAS,GAAG,OAAO,CAOtD;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAYtE;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,CAQ/D"}
@@ -0,0 +1,40 @@
1
+ function getMessageText(message) {
2
+ if (Array.isArray(message.parts)) {
3
+ return message.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
4
+ }
5
+ return "";
6
+ }
7
+ function hasContent(message) {
8
+ const text = getMessageText(message);
9
+ if (text.trim()) return true;
10
+ if (Array.isArray(message.parts)) {
11
+ return message.parts.some((p) => p.type !== "text");
12
+ }
13
+ return false;
14
+ }
15
+ function filterValidMessages(messages) {
16
+ const filtered = [];
17
+ let lastRole = null;
18
+ for (const msg of messages) {
19
+ if (!hasContent(msg)) continue;
20
+ if (msg.role === lastRole) continue;
21
+ filtered.push(msg);
22
+ lastRole = msg.role;
23
+ }
24
+ return filtered;
25
+ }
26
+ function getLatestUserText(messages) {
27
+ for (let i = messages.length - 1; i >= 0; i--) {
28
+ const msg = messages[i];
29
+ if (msg?.role !== "user") continue;
30
+ const text = getMessageText(msg);
31
+ if (text.trim()) return text;
32
+ }
33
+ return "";
34
+ }
35
+ export {
36
+ filterValidMessages,
37
+ getLatestUserText,
38
+ getMessageText,
39
+ hasContent
40
+ };
@@ -0,0 +1,30 @@
1
+ import type { UIMessage } from "ai";
2
+ import type { ChatContext, NotifyModelInfo as ModelInfo, NotifyTokenUsage as TokenUsage, PhaseTiming } from "./types.js";
3
+ export declare function buildArticleContextPrompt(context: ChatContext): string;
4
+ export interface SendNotificationArgs {
5
+ env: Record<string, unknown>;
6
+ messages: UIMessage[];
7
+ responseText: string;
8
+ relatedArticles: Array<{
9
+ title: string;
10
+ url?: string;
11
+ }>;
12
+ model?: ModelInfo;
13
+ usage?: TokenUsage;
14
+ timing: PhaseTiming;
15
+ cacheKey?: string | null;
16
+ waitUntil?: (promise: Promise<unknown>) => void;
17
+ }
18
+ export declare function sendNotification(args: SendNotificationArgs): void;
19
+ export declare function parseNum(val: unknown, defaultVal: number): number;
20
+ export declare function getTimeoutConfig(env: Record<string, unknown>): {
21
+ request: number;
22
+ keywordExtraction: number;
23
+ evidenceAnalysis: number;
24
+ llmStreaming: number;
25
+ };
26
+ export declare function getHealthConfig(env: Record<string, unknown>): {
27
+ unhealthyThreshold: number;
28
+ recoveryTtl: number;
29
+ };
30
+ //# sourceMappingURL=chat-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-utils.d.ts","sourceRoot":"","sources":["../../src/server/chat-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,EACV,WAAW,EAEX,eAAe,IAAI,SAAS,EAC5B,gBAAgB,IAAI,UAAU,EAC9B,WAAW,EACZ,MAAM,YAAY,CAAC;AAIpB,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAiBtE;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;CACjD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI,CAqCjE;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAQjE;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;EAa5D;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;EAQ3D"}
@@ -0,0 +1,88 @@
1
+ import { notifyAiChat } from "./notify.js";
2
+ import { NOTIFICATION, TIMEOUTS, HEALTH } from "../constants.js";
3
+ function buildArticleContextPrompt(context) {
4
+ if (context.scope !== "article" || !context.article) return "";
5
+ const a = context.article;
6
+ const parts = ["\n[\u5F53\u524D\u9605\u8BFB\u6587\u7AE0]", `\u7528\u6237\u6B63\u5728\u9605\u8BFB\uFF1A\u300A${a.title}\u300B`];
7
+ if (a.categories?.length) parts.push(`\u5206\u7C7B\uFF1A${a.categories.join("\u3001")}`);
8
+ parts.push(
9
+ "",
10
+ "\u4F60\u6B63\u5728\u966A\u7528\u6237\u9605\u8BFB\u8FD9\u7BC7\u6587\u7AE0\u3002\u4F18\u5148\u56F4\u7ED5\u8FD9\u7BC7\u6587\u7AE0\u7684\u5185\u5BB9\u56DE\u7B54\u95EE\u9898\u3002",
11
+ "\u5F53\u7528\u6237\u7684\u95EE\u9898\u4E0E\u5F53\u524D\u6587\u7AE0\u76F8\u5173\u65F6\uFF0C\u4F18\u5148\u4F7F\u7528\u5F53\u524D\u6587\u7AE0\u539F\u6587\u6BB5\u843D\u4F5C\u7B54\uFF0C\u800C\u4E0D\u662F\u53EA\u590D\u8FF0\u6458\u8981\u3002",
12
+ "\u5982\u679C\u95EE\u9898\u662F\u5728\u95EE\u201C\u524D\u9762/\u540E\u9762\u662F\u4EC0\u4E48\u201D\u201C\u8FD9\u4E00\u8282\u8BB2\u4E86\u4EC0\u4E48\u201D\u201C\u8FD9\u4E00\u9879\u540E\u7EED\u5185\u5BB9\u662F\u4EC0\u4E48\u201D\uFF0C\u9ED8\u8BA4\u4F18\u5148\u4F9D\u636E\u5F53\u524D\u6587\u7AE0\u5DF2\u6CE8\u5165\u7684\u539F\u6587\u6BB5\u843D\u56DE\u7B54\u3002",
13
+ "\u5F53\u7528\u6237\u60F3\u8981\u5EF6\u4F38\u65F6\uFF0C\u63A8\u8350\u76F8\u5173\u7684\u535A\u5BA2\u6587\u7AE0\u3002"
14
+ );
15
+ return parts.join("\n");
16
+ }
17
+ function sendNotification(args) {
18
+ const {
19
+ env,
20
+ messages,
21
+ responseText,
22
+ relatedArticles,
23
+ model,
24
+ usage,
25
+ timing,
26
+ cacheKey,
27
+ waitUntil
28
+ } = args;
29
+ const sessionId = cacheKey || `dev-${Date.now().toString(36)}`;
30
+ const notifyArticles = relatedArticles.slice(0, NOTIFICATION.MAX_REFERENCED_ARTICLES).map((a) => ({
31
+ title: a.title,
32
+ url: a.url
33
+ }));
34
+ const notifyPromise = notifyAiChat({
35
+ env,
36
+ sessionId,
37
+ messages,
38
+ aiResponse: responseText,
39
+ referencedArticles: notifyArticles,
40
+ model,
41
+ usage,
42
+ timing
43
+ });
44
+ if (waitUntil) {
45
+ waitUntil(notifyPromise);
46
+ } else {
47
+ void notifyPromise;
48
+ }
49
+ }
50
+ function parseNum(val, defaultVal) {
51
+ if (val === void 0) return defaultVal;
52
+ if (typeof val === "number") return val;
53
+ if (typeof val === "string") {
54
+ const num = parseInt(val, 10);
55
+ return isNaN(num) ? defaultVal : num;
56
+ }
57
+ return defaultVal;
58
+ }
59
+ function getTimeoutConfig(env) {
60
+ return {
61
+ request: parseNum(env.AI_TIMEOUT_REQUEST, TIMEOUTS.REQUEST),
62
+ keywordExtraction: parseNum(
63
+ env.AI_TIMEOUT_KEYWORD,
64
+ TIMEOUTS.KEYWORD_EXTRACTION
65
+ ),
66
+ evidenceAnalysis: parseNum(
67
+ env.AI_TIMEOUT_EVIDENCE,
68
+ TIMEOUTS.EVIDENCE_ANALYSIS
69
+ ),
70
+ llmStreaming: parseNum(env.AI_TIMEOUT_LLM, TIMEOUTS.LLM_STREAMING)
71
+ };
72
+ }
73
+ function getHealthConfig(env) {
74
+ return {
75
+ unhealthyThreshold: parseNum(
76
+ env.AI_HEALTH_THRESHOLD,
77
+ HEALTH.UNHEALTHY_THRESHOLD
78
+ ),
79
+ recoveryTtl: parseNum(env.AI_HEALTH_RECOVERY_TTL, HEALTH.RECOVERY_TTL)
80
+ };
81
+ }
82
+ export {
83
+ buildArticleContextPrompt,
84
+ getHealthConfig,
85
+ getTimeoutConfig,
86
+ parseNum,
87
+ sendNotification
88
+ };
@@ -1,20 +1,62 @@
1
1
  #!/usr/bin/env node
2
- import { createServer } from "node:http";
2
+ import {
3
+ createServer
4
+ } from "node:http";
3
5
  import { readFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
4
- import { resolve, dirname } from "node:path";
5
- import { fileURLToPath } from "node:url";
6
- const __filename = fileURLToPath(import.meta.url);
7
- const __dirname = dirname(__filename);
8
- const DEFAULT_SUMMARIES = { meta: { lastUpdated: (/* @__PURE__ */ new Date()).toISOString(), model: "none", totalProcessed: 0 }, articles: {} };
6
+ import { resolve } from "node:path";
7
+ import { setLogLevel } from "../utils/logger.js";
8
+ const DEFAULT_SUMMARIES = {
9
+ meta: {
10
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
11
+ model: "none",
12
+ totalProcessed: 0
13
+ },
14
+ articles: {}
15
+ };
9
16
  const DEFAULT_AUTHOR_CONTEXT = { author: {}, posts: [] };
10
17
  const DEFAULT_VOICE_PROFILE = { style: {}, examples: [] };
11
- function extractPostTitle(url) {
12
- const match = url.match(/\/posts\/([^/]+)/);
13
- if (match) {
14
- return decodeURIComponent(match[1].replace(/-/g, " "));
18
+ const DEFAULT_FACT_REGISTRY = {
19
+ $schema: "fact-registry-v1",
20
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
21
+ version: 1,
22
+ facts: [],
23
+ stats: {
24
+ total: 0,
25
+ byCategory: {
26
+ author: 0,
27
+ blog: 0,
28
+ content: 0,
29
+ project: 0,
30
+ tech: 0
31
+ },
32
+ avgConfidence: 0
15
33
  }
16
- return "\u535A\u5BA2\u6587\u7AE0";
17
- }
34
+ };
35
+ const DEFAULT_KNOWLEDGE_BUNDLE = {
36
+ $schema: "knowledge-bundle-v1",
37
+ version: 1,
38
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
39
+ corpusHash: "dev-server-default",
40
+ runtime: {
41
+ summaries: DEFAULT_SUMMARIES,
42
+ authorContext: DEFAULT_AUTHOR_CONTEXT,
43
+ voiceProfile: DEFAULT_VOICE_PROFILE,
44
+ factRegistry: DEFAULT_FACT_REGISTRY,
45
+ vectorIndex: null
46
+ },
47
+ corpus: {
48
+ $schema: "knowledge-corpus-v1",
49
+ version: 1,
50
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
51
+ documents: []
52
+ },
53
+ passages: {
54
+ $schema: "knowledge-passages-v1",
55
+ version: 1,
56
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
57
+ passages: []
58
+ }
59
+ };
18
60
  function findBlogRoot() {
19
61
  let dir = process.cwd();
20
62
  for (let i = 0; i < 10; i++) {
@@ -22,16 +64,21 @@ function findBlogRoot() {
22
64
  return { root: dir, datasDir: resolve(dir, "datas"), hasDatas: true };
23
65
  }
24
66
  if (existsSync(resolve(dir, "apps", "blog", "datas"))) {
25
- return { root: resolve(dir, "apps", "blog"), datasDir: resolve(dir, "apps", "blog", "datas"), hasDatas: true };
26
- }
27
- if (existsSync(resolve(dir, "src", "data"))) {
28
- return { root: dir, datasDir: resolve(dir, "src", "data"), hasDatas: true };
67
+ return {
68
+ root: resolve(dir, "apps", "blog"),
69
+ datasDir: resolve(dir, "apps", "blog", "datas"),
70
+ hasDatas: true
71
+ };
29
72
  }
30
73
  const parent = resolve(dir, "..");
31
74
  if (parent === dir) break;
32
75
  dir = parent;
33
76
  }
34
- return { root: process.cwd(), datasDir: resolve(process.cwd(), "datas"), hasDatas: false };
77
+ return {
78
+ root: process.cwd(),
79
+ datasDir: resolve(process.cwd(), "datas"),
80
+ hasDatas: false
81
+ };
35
82
  }
36
83
  function loadEnv(envPath) {
37
84
  if (!existsSync(envPath)) return;
@@ -55,18 +102,21 @@ function initDatasDirectory(datasDir) {
55
102
  if (!existsSync(datasDir)) {
56
103
  mkdirSync(datasDir, { recursive: true });
57
104
  }
105
+ const runtimeDir = resolve(datasDir, "knowledge", "runtime");
106
+ mkdirSync(runtimeDir, { recursive: true });
58
107
  const files = [
59
- { name: "ai-summaries.json", content: DEFAULT_SUMMARIES },
60
- { name: "author-context.json", content: DEFAULT_AUTHOR_CONTEXT },
61
- { name: "voice-profile.json", content: DEFAULT_VOICE_PROFILE }
108
+ {
109
+ name: resolve(runtimeDir, "knowledge-bundle.json"),
110
+ label: "knowledge/runtime/knowledge-bundle.json",
111
+ content: DEFAULT_KNOWLEDGE_BUNDLE
112
+ }
62
113
  ];
63
114
  for (const file of files) {
64
- const filePath = resolve(datasDir, file.name);
65
- if (!existsSync(filePath)) {
66
- writeFileSync(filePath, JSON.stringify(file.content, null, 2) + "\n");
67
- console.log(` Created ${file.name}`);
115
+ if (!existsSync(file.name)) {
116
+ writeFileSync(file.name, JSON.stringify(file.content, null, 2) + "\n");
117
+ console.log(` Created ${file.label}`);
68
118
  } else {
69
- console.log(` Skipped ${file.name} (already exists)`);
119
+ console.log(` Skipped ${file.label} (already exists)`);
70
120
  }
71
121
  }
72
122
  }
@@ -84,27 +134,51 @@ function loadJson(datasDir, file, defaultValue) {
84
134
  }
85
135
  async function setupHandler(datasDir, hasDatas) {
86
136
  const { handleChatRequest, initializeMetadata } = await import("./index.js");
137
+ const {
138
+ getProviderManager,
139
+ hasAnyProviderConfigured,
140
+ getResponseCacheConfig
141
+ } = await import("../index.js");
87
142
  if (!hasDatas) {
88
- console.log("\n \u26A0\uFE0F No datas/ directory found. AI chat will work with empty context.");
89
- console.log(' Run "pnpm exec astro-ai-dev --init" to create placeholder files.\n');
143
+ console.log(
144
+ "\n \u26A0\uFE0F No datas/ directory found. AI chat will work with empty context."
145
+ );
146
+ console.log(
147
+ ' Run "pnpm exec astro-ai-dev --init" to create placeholder files.\n'
148
+ );
90
149
  } else {
91
- const hasSummaries = existsSync(resolve(datasDir, "ai-summaries.json"));
92
- const hasAuthor = existsSync(resolve(datasDir, "author-context.json"));
93
- if (!hasSummaries || !hasAuthor) {
94
- console.log("\n \u26A0\uFE0F Some metadata files are missing. AI chat may have limited context.\n");
150
+ const hasKnowledgeBundle = existsSync(
151
+ resolve(datasDir, "knowledge", "runtime", "knowledge-bundle.json")
152
+ );
153
+ if (!hasKnowledgeBundle) {
154
+ console.log(
155
+ "\n \u26A0\uFE0F knowledge/runtime/knowledge-bundle.json is missing. AI chat may have limited context.\n"
156
+ );
95
157
  }
96
158
  }
97
- const summaries = loadJson(datasDir, "ai-summaries.json", DEFAULT_SUMMARIES);
98
- const authorContext = loadJson(datasDir, "author-context.json", DEFAULT_AUTHOR_CONTEXT);
99
- const voiceProfile = loadJson(datasDir, "voice-profile.json", DEFAULT_VOICE_PROFILE);
159
+ const knowledgeBundle = loadJson(
160
+ datasDir,
161
+ "knowledge/runtime/knowledge-bundle.json",
162
+ DEFAULT_KNOWLEDGE_BUNDLE
163
+ );
100
164
  const env = { ...process.env };
101
- initializeMetadata({
102
- summaries,
103
- authorContext,
104
- voiceProfile,
105
- siteUrl: process.env.SITE_URL || "http://localhost:4321"
106
- }, env);
107
- return { handleChatRequest, env };
165
+ initializeMetadata(
166
+ {
167
+ knowledgeBundle,
168
+ siteUrl: process.env.SITE_URL || "http://localhost:4321"
169
+ },
170
+ env
171
+ );
172
+ return {
173
+ handleChatRequest,
174
+ initializeMetadata,
175
+ getProviderManager,
176
+ hasAnyProviderConfigured,
177
+ getResponseCacheConfig,
178
+ env,
179
+ knowledgeBundle,
180
+ vectorIndex: knowledgeBundle.runtime.vectorIndex ?? null
181
+ };
108
182
  }
109
183
  function toWebRequest(req) {
110
184
  return new Promise((resolve2, reject) => {
@@ -113,17 +187,23 @@ function toWebRequest(req) {
113
187
  req.on("end", () => {
114
188
  const body = Buffer.concat(chunks);
115
189
  const url = `http://localhost${req.url || "/"}`;
116
- resolve2(new Request(url, {
117
- method: req.method || "GET",
118
- headers: req.headers,
119
- body: req.method !== "GET" && req.method !== "HEAD" ? body : void 0
120
- }));
190
+ resolve2(
191
+ new Request(url, {
192
+ method: req.method || "GET",
193
+ headers: req.headers,
194
+ body: req.method !== "GET" && req.method !== "HEAD" ? body : void 0
195
+ })
196
+ );
121
197
  });
122
198
  req.on("error", reject);
123
199
  });
124
200
  }
125
201
  async function sendWebResponse(webRes, res) {
126
- res.writeHead(webRes.status, Object.fromEntries(webRes.headers));
202
+ const headerEntries = [];
203
+ webRes.headers.forEach((value, key) => {
204
+ headerEntries.push([key, value]);
205
+ });
206
+ res.writeHead(webRes.status, Object.fromEntries(headerEntries));
127
207
  if (!webRes.body) {
128
208
  res.end();
129
209
  return;
@@ -150,17 +230,36 @@ async function main() {
150
230
  console.log("\n\u2705 Done! You can now configure your AI metadata files.\n");
151
231
  process.exit(0);
152
232
  }
233
+ if (process.env.AI_DEBUG) setLogLevel("debug");
234
+ else if (process.env.AI_LOG_LEVEL)
235
+ setLogLevel(
236
+ process.env.AI_LOG_LEVEL
237
+ );
153
238
  const port = parseInt(process.env.AI_DEV_PORT || "8787", 10);
154
239
  const { root: blogRoot, datasDir, hasDatas } = findBlogRoot();
155
240
  loadEnv(resolve(blogRoot, ".env"));
156
241
  console.log("\n\u{1F916} AI Dev Server starting...\n");
157
242
  console.log(` Working directory: ${blogRoot}`);
158
- console.log(` Datas directory: ${datasDir} ${hasDatas ? "\u2713" : "(not found)"}`);
243
+ console.log(
244
+ ` Datas directory: ${datasDir} ${hasDatas ? "\u2713" : "(not found)"}`
245
+ );
159
246
  console.log(` Port: ${port}`);
160
- console.log(` AI_BASE_URL: ${process.env.AI_BASE_URL ? "\u2713 configured" : "\u2717 not set"}`);
161
- console.log(` AI_API_KEY: ${process.env.AI_API_KEY ? "\u2713 configured" : "\u2717 not set"}`);
247
+ console.log(
248
+ ` AI_BASE_URL: ${process.env.AI_BASE_URL ? "\u2713 configured" : "\u2717 not set"}`
249
+ );
250
+ console.log(
251
+ ` AI_API_KEY: ${process.env.AI_API_KEY ? "\u2713 configured" : "\u2717 not set"}`
252
+ );
162
253
  console.log(` AI_MODEL: ${process.env.AI_MODEL || "(default)"}`);
163
- const { handleChatRequest, env } = await setupHandler(datasDir, hasDatas);
254
+ const {
255
+ handleChatRequest,
256
+ getProviderManager,
257
+ hasAnyProviderConfigured,
258
+ getResponseCacheConfig,
259
+ env,
260
+ knowledgeBundle,
261
+ vectorIndex
262
+ } = await setupHandler(datasDir, hasDatas);
164
263
  const server = createServer(async (req, res) => {
165
264
  res.setHeader("Access-Control-Allow-Origin", "*");
166
265
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
@@ -179,58 +278,89 @@ async function main() {
179
278
  return;
180
279
  }
181
280
  if (url.startsWith("/api/notify/comment")) {
182
- const { createNotifier } = await import("@astro-minimax/notify");
281
+ const { handleCommentWebhook } = await import("@astro-minimax/notify");
183
282
  const webReq = await toWebRequest(req);
184
- const body = await webReq.json();
185
- if (body.type !== "new_comment" && body.type !== "new_reply") {
186
- res.writeHead(400, { "Content-Type": "application/json" });
187
- res.end(JSON.stringify({ error: "Unsupported event type" }));
188
- return;
189
- }
190
- const data = body.data || {};
191
- const siteUrl = process.env.SITE_URL || "http://localhost:4321";
192
- const postUrl = data.url?.startsWith("http") ? data.url : `${siteUrl}${data.url || "/"}`;
193
- const notifier = createNotifier({
194
- telegram: process.env.NOTIFY_TELEGRAM_BOT_TOKEN && process.env.NOTIFY_TELEGRAM_CHAT_ID ? {
195
- botToken: process.env.NOTIFY_TELEGRAM_BOT_TOKEN,
196
- chatId: process.env.NOTIFY_TELEGRAM_CHAT_ID
197
- } : void 0,
198
- webhook: process.env.NOTIFY_WEBHOOK_URL ? {
199
- url: process.env.NOTIFY_WEBHOOK_URL
200
- } : void 0,
201
- email: process.env.NOTIFY_RESEND_API_KEY && process.env.NOTIFY_RESEND_FROM && process.env.NOTIFY_RESEND_TO ? {
202
- provider: "resend",
203
- apiKey: process.env.NOTIFY_RESEND_API_KEY,
204
- from: process.env.NOTIFY_RESEND_FROM,
205
- to: process.env.NOTIFY_RESEND_TO
206
- } : void 0
207
- });
208
- const result = await notifier.comment({
209
- author: data.nick || "\u533F\u540D\u7528\u6237",
210
- content: data.comment || "",
211
- postTitle: extractPostTitle(data.url || "/"),
212
- postUrl
213
- });
214
- console.log("[notify] Comment notification sent:", result.success ? "\u2713" : "\u2717", result.results);
215
- res.writeHead(200, { "Content-Type": "application/json" });
216
- res.end(JSON.stringify({
217
- success: result.success,
218
- event: "comment",
219
- channels: result.results.map((r) => ({ channel: r.channel, success: r.success, error: r.error }))
220
- }));
283
+ const webRes = await handleCommentWebhook(webReq, process.env);
284
+ await sendWebResponse(webRes, res);
221
285
  return;
222
286
  }
223
287
  if (url.startsWith("/api/ai-info")) {
224
- res.writeHead(200, { "Content-Type": "application/json" });
225
- res.end(JSON.stringify({
226
- status: "ok",
227
- mode: "dev-server",
228
- datas: { found: hasDatas, path: datasDir },
229
- ai: {
230
- configured: !!(process.env.AI_BASE_URL && process.env.AI_API_KEY),
231
- model: process.env.AI_MODEL || "unknown"
288
+ const manager = getProviderManager(env, { enableMockFallback: true });
289
+ const providerStatus = manager.getProviderStatus();
290
+ const configured = hasAnyProviderConfigured(env);
291
+ const responseCacheConfig = getResponseCacheConfig(env);
292
+ const timeoutConfig = {
293
+ request: env.AI_TIMEOUT_REQUEST ?? 45e3,
294
+ keywordExtraction: env.AI_TIMEOUT_KEYWORD ?? 5e3,
295
+ evidenceAnalysis: env.AI_TIMEOUT_EVIDENCE ?? 8e3,
296
+ llmStreaming: env.AI_TIMEOUT_LLM ?? 3e4
297
+ };
298
+ const healthConfig = {
299
+ unhealthyThreshold: env.AI_HEALTH_THRESHOLD ?? 3,
300
+ recoveryTtl: env.AI_HEALTH_RECOVERY_TTL ?? 6e4
301
+ };
302
+ const dataStatus = {
303
+ knowledgeBundle: {
304
+ loaded: true,
305
+ count: Array.isArray(
306
+ knowledgeBundle?.corpus?.documents
307
+ ) ? knowledgeBundle.corpus.documents.length : void 0,
308
+ lastUpdated: knowledgeBundle?.generatedAt
309
+ },
310
+ vectorIndex: {
311
+ loaded: Boolean(vectorIndex),
312
+ lastUpdated: knowledgeBundle?.generatedAt
232
313
  }
233
- }, null, 2));
314
+ };
315
+ res.writeHead(200, { "Content-Type": "application/json" });
316
+ res.end(
317
+ JSON.stringify(
318
+ {
319
+ status: "ok",
320
+ mode: "dev-server",
321
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
322
+ ai: {
323
+ enabled: true,
324
+ mockMode: !!env.AI_MOCK_MODE,
325
+ configured,
326
+ cache: {
327
+ enabled: responseCacheConfig.enabled,
328
+ ttl: responseCacheConfig.defaultTtl,
329
+ playbackDelay: responseCacheConfig.playbackDelayMs,
330
+ chunkSize: responseCacheConfig.chunkSize,
331
+ thinkingDelay: responseCacheConfig.thinkingPlaybackDelayMs
332
+ },
333
+ timeouts: timeoutConfig,
334
+ health: healthConfig,
335
+ providers: providerStatus.map((p) => ({
336
+ id: p.id,
337
+ type: p.type,
338
+ weight: p.weight,
339
+ healthy: p.health.healthy,
340
+ model: p.model,
341
+ healthDetails: {
342
+ consecutiveFailures: p.health.consecutiveFailures,
343
+ totalRequests: p.health.totalRequests,
344
+ successfulRequests: p.health.successfulRequests,
345
+ lastError: p.health.lastError,
346
+ lastErrorTime: p.health.lastErrorTime,
347
+ lastSuccessTime: p.health.lastSuccessTime
348
+ }
349
+ })),
350
+ dataStatus
351
+ },
352
+ hints: manager.hasProviders() ? [
353
+ `Providers available: ${manager.getProviderCount()}`,
354
+ "Mock fallback: enabled",
355
+ responseCacheConfig.enabled ? "Response cache: enabled" : "Response cache: disabled"
356
+ ] : [
357
+ "No AI providers configured. Set AI_BASE_URL + AI_API_KEY environment variables."
358
+ ]
359
+ },
360
+ null,
361
+ 2
362
+ )
363
+ );
234
364
  return;
235
365
  }
236
366
  res.writeHead(404, { "Content-Type": "application/json" });
@@ -238,7 +368,12 @@ async function main() {
238
368
  } catch (err) {
239
369
  console.error("[AI Dev Server] Error:", err);
240
370
  res.writeHead(500, { "Content-Type": "application/json" });
241
- res.end(JSON.stringify({ error: "Internal server error", detail: err instanceof Error ? err.message : String(err) }));
371
+ res.end(
372
+ JSON.stringify({
373
+ error: "Internal server error",
374
+ detail: err instanceof Error ? err.message : String(err)
375
+ })
376
+ );
242
377
  }
243
378
  });
244
379
  server.listen(port, () => {
@@ -246,9 +381,11 @@ async function main() {
246
381
  \u2705 AI Dev Server running at http://localhost:${port}`);
247
382
  console.log(` POST http://localhost:${port}/api/chat`);
248
383
  console.log(` GET http://localhost:${port}/api/ai-info`);
249
- console.log(`
384
+ console.log(
385
+ `
250
386
  Tip: Run "pnpm exec astro-ai-dev --init" to create datas/ directory.
251
- `);
387
+ `
388
+ );
252
389
  });
253
390
  const shutdown = (signal) => {
254
391
  console.log(`
@@ -0,0 +1,22 @@
1
+ import type { ChatHandlerEnv } from "./types.js";
2
+ export declare function applyAiConfigDefaults(baseEnv: ChatHandlerEnv, aiConfig: {
3
+ cache?: {
4
+ enabled?: boolean;
5
+ ttl?: number;
6
+ playbackDelay?: number;
7
+ chunkSize?: number;
8
+ thinkingDelay?: number;
9
+ };
10
+ timeouts?: {
11
+ request?: number;
12
+ keywordExtraction?: number;
13
+ evidenceAnalysis?: number;
14
+ llmStreaming?: number;
15
+ };
16
+ health?: {
17
+ unhealthyThreshold?: number;
18
+ recoveryTtl?: number;
19
+ };
20
+ mockMode?: boolean;
21
+ } | null | undefined): ChatHandlerEnv;
22
+ //# sourceMappingURL=env-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-config.d.ts","sourceRoot":"","sources":["../../src/server/env-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,cAAc,EACvB,QAAQ,EACJ;IACE,KAAK,CAAC,EAAE;QACN,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,MAAM,CAAC,EAAE;QACP,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GACD,IAAI,GACJ,SAAS,GACZ,cAAc,CA4BhB"}
@@ -0,0 +1,25 @@
1
+ function applyAiConfigDefaults(baseEnv, aiConfig) {
2
+ if (!aiConfig) return { ...baseEnv };
3
+ const envWithConfig = { ...baseEnv };
4
+ const setIfMissing = (envKey, configValue) => {
5
+ if (envWithConfig[envKey] === void 0 && configValue !== void 0) {
6
+ envWithConfig[envKey] = configValue;
7
+ }
8
+ };
9
+ setIfMissing("AI_CACHE_ENABLED", aiConfig.cache?.enabled);
10
+ setIfMissing("AI_CACHE_TTL", aiConfig.cache?.ttl);
11
+ setIfMissing("AI_CACHE_PLAYBACK_DELAY", aiConfig.cache?.playbackDelay);
12
+ setIfMissing("AI_CACHE_CHUNK_SIZE", aiConfig.cache?.chunkSize);
13
+ setIfMissing("AI_CACHE_THINKING_DELAY", aiConfig.cache?.thinkingDelay);
14
+ setIfMissing("AI_TIMEOUT_REQUEST", aiConfig.timeouts?.request);
15
+ setIfMissing("AI_TIMEOUT_KEYWORD", aiConfig.timeouts?.keywordExtraction);
16
+ setIfMissing("AI_TIMEOUT_EVIDENCE", aiConfig.timeouts?.evidenceAnalysis);
17
+ setIfMissing("AI_TIMEOUT_LLM", aiConfig.timeouts?.llmStreaming);
18
+ setIfMissing("AI_HEALTH_THRESHOLD", aiConfig.health?.unhealthyThreshold);
19
+ setIfMissing("AI_HEALTH_RECOVERY_TTL", aiConfig.health?.recoveryTtl);
20
+ setIfMissing("AI_MOCK_MODE", aiConfig.mockMode);
21
+ return envWithConfig;
22
+ }
23
+ export {
24
+ applyAiConfigDefaults
25
+ };
@@ -1,3 +1,4 @@
1
+ export declare function setCorsOrigin(origin: string): void;
1
2
  export declare function chatError(code: string, error: string, status: number, options?: {
2
3
  retryable?: boolean;
3
4
  retryAfter?: number;