@zooique/memora 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 (239) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -0
  3. package/dist/agent/agent.d.ts +343 -0
  4. package/dist/agent/agent.d.ts.map +1 -0
  5. package/dist/agent/agent.js +893 -0
  6. package/dist/agent/agent.js.map +1 -0
  7. package/dist/agent/assembler.d.ts +77 -0
  8. package/dist/agent/assembler.d.ts.map +1 -0
  9. package/dist/agent/assembler.js +115 -0
  10. package/dist/agent/assembler.js.map +1 -0
  11. package/dist/agent/builtinToolHandlers.d.ts +96 -0
  12. package/dist/agent/builtinToolHandlers.d.ts.map +1 -0
  13. package/dist/agent/builtinToolHandlers.js +388 -0
  14. package/dist/agent/builtinToolHandlers.js.map +1 -0
  15. package/dist/agent/builtinTools.d.ts +35 -0
  16. package/dist/agent/builtinTools.d.ts.map +1 -0
  17. package/dist/agent/builtinTools.js +75 -0
  18. package/dist/agent/builtinTools.js.map +1 -0
  19. package/dist/agent/constants.d.ts +67 -0
  20. package/dist/agent/constants.d.ts.map +1 -0
  21. package/dist/agent/constants.js +67 -0
  22. package/dist/agent/constants.js.map +1 -0
  23. package/dist/agent/contextManager.d.ts +130 -0
  24. package/dist/agent/contextManager.d.ts.map +1 -0
  25. package/dist/agent/contextManager.js +287 -0
  26. package/dist/agent/contextManager.js.map +1 -0
  27. package/dist/agent/loop.d.ts +288 -0
  28. package/dist/agent/loop.d.ts.map +1 -0
  29. package/dist/agent/loop.js +756 -0
  30. package/dist/agent/loop.js.map +1 -0
  31. package/dist/agent/managers/autoConfigRefiner.d.ts +39 -0
  32. package/dist/agent/managers/autoConfigRefiner.d.ts.map +1 -0
  33. package/dist/agent/managers/autoConfigRefiner.js +150 -0
  34. package/dist/agent/managers/autoConfigRefiner.js.map +1 -0
  35. package/dist/agent/managers/configManager.d.ts +114 -0
  36. package/dist/agent/managers/configManager.d.ts.map +1 -0
  37. package/dist/agent/managers/configManager.js +186 -0
  38. package/dist/agent/managers/configManager.js.map +1 -0
  39. package/dist/agent/managers/insightExtractor.d.ts +141 -0
  40. package/dist/agent/managers/insightExtractor.d.ts.map +1 -0
  41. package/dist/agent/managers/insightExtractor.js +420 -0
  42. package/dist/agent/managers/insightExtractor.js.map +1 -0
  43. package/dist/agent/managers/memoryAdvisor.d.ts +96 -0
  44. package/dist/agent/managers/memoryAdvisor.d.ts.map +1 -0
  45. package/dist/agent/managers/memoryAdvisor.js +198 -0
  46. package/dist/agent/managers/memoryAdvisor.js.map +1 -0
  47. package/dist/agent/managers/memoryInspector.d.ts +231 -0
  48. package/dist/agent/managers/memoryInspector.d.ts.map +1 -0
  49. package/dist/agent/managers/memoryInspector.js +327 -0
  50. package/dist/agent/managers/memoryInspector.js.map +1 -0
  51. package/dist/agent/managers/sessionManager.d.ts +89 -0
  52. package/dist/agent/managers/sessionManager.d.ts.map +1 -0
  53. package/dist/agent/managers/sessionManager.js +178 -0
  54. package/dist/agent/managers/sessionManager.js.map +1 -0
  55. package/dist/agent/managers/userFactExtractor.d.ts +25 -0
  56. package/dist/agent/managers/userFactExtractor.d.ts.map +1 -0
  57. package/dist/agent/managers/userFactExtractor.js +81 -0
  58. package/dist/agent/managers/userFactExtractor.js.map +1 -0
  59. package/dist/agent/managers/workProjection.d.ts +117 -0
  60. package/dist/agent/managers/workProjection.d.ts.map +1 -0
  61. package/dist/agent/managers/workProjection.js +290 -0
  62. package/dist/agent/managers/workProjection.js.map +1 -0
  63. package/dist/agent/messageHistory.d.ts +157 -0
  64. package/dist/agent/messageHistory.d.ts.map +1 -0
  65. package/dist/agent/messageHistory.js +288 -0
  66. package/dist/agent/messageHistory.js.map +1 -0
  67. package/dist/agent/toolExecutor.d.ts +137 -0
  68. package/dist/agent/toolExecutor.d.ts.map +1 -0
  69. package/dist/agent/toolExecutor.js +209 -0
  70. package/dist/agent/toolExecutor.js.map +1 -0
  71. package/dist/agent/tracer.d.ts +122 -0
  72. package/dist/agent/tracer.d.ts.map +1 -0
  73. package/dist/agent/tracer.js +64 -0
  74. package/dist/agent/tracer.js.map +1 -0
  75. package/dist/agent/types.d.ts +98 -0
  76. package/dist/agent/types.d.ts.map +1 -0
  77. package/dist/agent/types.js +19 -0
  78. package/dist/agent/types.js.map +1 -0
  79. package/dist/config/loader.d.ts +229 -0
  80. package/dist/config/loader.d.ts.map +1 -0
  81. package/dist/config/loader.js +194 -0
  82. package/dist/config/loader.js.map +1 -0
  83. package/dist/eval/evalTypes.d.ts +118 -0
  84. package/dist/eval/evalTypes.d.ts.map +1 -0
  85. package/dist/eval/evalTypes.js +102 -0
  86. package/dist/eval/evalTypes.js.map +1 -0
  87. package/dist/index.d.ts +61 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +44 -0
  90. package/dist/index.js.map +1 -0
  91. package/dist/llm/embedding.d.ts +62 -0
  92. package/dist/llm/embedding.d.ts.map +1 -0
  93. package/dist/llm/embedding.js +162 -0
  94. package/dist/llm/embedding.js.map +1 -0
  95. package/dist/llm/factory.d.ts +39 -0
  96. package/dist/llm/factory.d.ts.map +1 -0
  97. package/dist/llm/factory.js +108 -0
  98. package/dist/llm/factory.js.map +1 -0
  99. package/dist/llm/openaiCompatible.d.ts +63 -0
  100. package/dist/llm/openaiCompatible.d.ts.map +1 -0
  101. package/dist/llm/openaiCompatible.js +340 -0
  102. package/dist/llm/openaiCompatible.js.map +1 -0
  103. package/dist/llm/provider.d.ts +91 -0
  104. package/dist/llm/provider.d.ts.map +1 -0
  105. package/dist/llm/provider.js +14 -0
  106. package/dist/llm/provider.js.map +1 -0
  107. package/dist/llm/types.d.ts +25 -0
  108. package/dist/llm/types.d.ts.map +1 -0
  109. package/dist/llm/types.js +7 -0
  110. package/dist/llm/types.js.map +1 -0
  111. package/dist/logging/logger.d.ts +39 -0
  112. package/dist/logging/logger.d.ts.map +1 -0
  113. package/dist/logging/logger.js +279 -0
  114. package/dist/logging/logger.js.map +1 -0
  115. package/dist/logging/loggerInterface.d.ts +33 -0
  116. package/dist/logging/loggerInterface.d.ts.map +1 -0
  117. package/dist/logging/loggerInterface.js +2 -0
  118. package/dist/logging/loggerInterface.js.map +1 -0
  119. package/dist/memory/inMemoryRelationStore.d.ts +51 -0
  120. package/dist/memory/inMemoryRelationStore.d.ts.map +1 -0
  121. package/dist/memory/inMemoryRelationStore.js +65 -0
  122. package/dist/memory/inMemoryRelationStore.js.map +1 -0
  123. package/dist/memory/inMemoryStorage.d.ts +97 -0
  124. package/dist/memory/inMemoryStorage.d.ts.map +1 -0
  125. package/dist/memory/inMemoryStorage.js +177 -0
  126. package/dist/memory/inMemoryStorage.js.map +1 -0
  127. package/dist/memory/loader.d.ts +49 -0
  128. package/dist/memory/loader.d.ts.map +1 -0
  129. package/dist/memory/loader.js +93 -0
  130. package/dist/memory/loader.js.map +1 -0
  131. package/dist/memory/projectManager.d.ts +182 -0
  132. package/dist/memory/projectManager.d.ts.map +1 -0
  133. package/dist/memory/projectManager.js +441 -0
  134. package/dist/memory/projectManager.js.map +1 -0
  135. package/dist/memory/recall.d.ts +77 -0
  136. package/dist/memory/recall.d.ts.map +1 -0
  137. package/dist/memory/recall.js +147 -0
  138. package/dist/memory/recall.js.map +1 -0
  139. package/dist/memory/relationStore.d.ts +78 -0
  140. package/dist/memory/relationStore.d.ts.map +1 -0
  141. package/dist/memory/relationStore.js +2 -0
  142. package/dist/memory/relationStore.js.map +1 -0
  143. package/dist/memory/sessionStore.d.ts +84 -0
  144. package/dist/memory/sessionStore.d.ts.map +1 -0
  145. package/dist/memory/sessionStore.js +2 -0
  146. package/dist/memory/sessionStore.js.map +1 -0
  147. package/dist/memory/storageInterface.d.ts +107 -0
  148. package/dist/memory/storageInterface.d.ts.map +1 -0
  149. package/dist/memory/storageInterface.js +2 -0
  150. package/dist/memory/storageInterface.js.map +1 -0
  151. package/dist/memory/store.d.ts +50 -0
  152. package/dist/memory/store.d.ts.map +1 -0
  153. package/dist/memory/store.js +160 -0
  154. package/dist/memory/store.js.map +1 -0
  155. package/dist/memory/types.d.ts +189 -0
  156. package/dist/memory/types.d.ts.map +1 -0
  157. package/dist/memory/types.js +230 -0
  158. package/dist/memory/types.js.map +1 -0
  159. package/dist/memory/userProfile.d.ts +156 -0
  160. package/dist/memory/userProfile.d.ts.map +1 -0
  161. package/dist/memory/userProfile.js +315 -0
  162. package/dist/memory/userProfile.js.map +1 -0
  163. package/dist/memory/vectorStore.d.ts +75 -0
  164. package/dist/memory/vectorStore.d.ts.map +1 -0
  165. package/dist/memory/vectorStore.js +144 -0
  166. package/dist/memory/vectorStore.js.map +1 -0
  167. package/dist/persona/personaManager.d.ts +121 -0
  168. package/dist/persona/personaManager.d.ts.map +1 -0
  169. package/dist/persona/personaManager.js +349 -0
  170. package/dist/persona/personaManager.js.map +1 -0
  171. package/dist/persona/types.d.ts +32 -0
  172. package/dist/persona/types.d.ts.map +1 -0
  173. package/dist/persona/types.js +5 -0
  174. package/dist/persona/types.js.map +1 -0
  175. package/dist/security/pathGuard.d.ts +121 -0
  176. package/dist/security/pathGuard.d.ts.map +1 -0
  177. package/dist/security/pathGuard.js +276 -0
  178. package/dist/security/pathGuard.js.map +1 -0
  179. package/dist/skill/skillManager.d.ts +82 -0
  180. package/dist/skill/skillManager.d.ts.map +1 -0
  181. package/dist/skill/skillManager.js +198 -0
  182. package/dist/skill/skillManager.js.map +1 -0
  183. package/dist/skill/types.d.ts +28 -0
  184. package/dist/skill/types.d.ts.map +1 -0
  185. package/dist/skill/types.js +5 -0
  186. package/dist/skill/types.js.map +1 -0
  187. package/dist/utils/errors.d.ts +86 -0
  188. package/dist/utils/errors.d.ts.map +1 -0
  189. package/dist/utils/errors.js +143 -0
  190. package/dist/utils/errors.js.map +1 -0
  191. package/dist/utils/eventEmitter.d.ts +87 -0
  192. package/dist/utils/eventEmitter.d.ts.map +1 -0
  193. package/dist/utils/eventEmitter.js +79 -0
  194. package/dist/utils/eventEmitter.js.map +1 -0
  195. package/dist/utils/frontmatter.d.ts +24 -0
  196. package/dist/utils/frontmatter.d.ts.map +1 -0
  197. package/dist/utils/frontmatter.js +44 -0
  198. package/dist/utils/frontmatter.js.map +1 -0
  199. package/dist/utils/json.d.ts +20 -0
  200. package/dist/utils/json.d.ts.map +1 -0
  201. package/dist/utils/json.js +65 -0
  202. package/dist/utils/json.js.map +1 -0
  203. package/dist/utils/loggerHolder.d.ts +37 -0
  204. package/dist/utils/loggerHolder.d.ts.map +1 -0
  205. package/dist/utils/loggerHolder.js +49 -0
  206. package/dist/utils/loggerHolder.js.map +1 -0
  207. package/dist/utils/math.d.ts +5 -0
  208. package/dist/utils/math.d.ts.map +1 -0
  209. package/dist/utils/math.js +19 -0
  210. package/dist/utils/math.js.map +1 -0
  211. package/dist/utils/path.d.ts +28 -0
  212. package/dist/utils/path.d.ts.map +1 -0
  213. package/dist/utils/path.js +33 -0
  214. package/dist/utils/path.js.map +1 -0
  215. package/dist/utils/safeTimer.d.ts +26 -0
  216. package/dist/utils/safeTimer.d.ts.map +1 -0
  217. package/dist/utils/safeTimer.js +49 -0
  218. package/dist/utils/safeTimer.js.map +1 -0
  219. package/dist/utils/scanner.d.ts +54 -0
  220. package/dist/utils/scanner.d.ts.map +1 -0
  221. package/dist/utils/scanner.js +115 -0
  222. package/dist/utils/scanner.js.map +1 -0
  223. package/dist/utils/segmenter.d.ts +30 -0
  224. package/dist/utils/segmenter.d.ts.map +1 -0
  225. package/dist/utils/segmenter.js +80 -0
  226. package/dist/utils/segmenter.js.map +1 -0
  227. package/dist/utils/strings.d.ts +18 -0
  228. package/dist/utils/strings.d.ts.map +1 -0
  229. package/dist/utils/strings.js +25 -0
  230. package/dist/utils/strings.js.map +1 -0
  231. package/dist/utils/time.d.ts +23 -0
  232. package/dist/utils/time.d.ts.map +1 -0
  233. package/dist/utils/time.js +31 -0
  234. package/dist/utils/time.js.map +1 -0
  235. package/dist/utils/toError.d.ts +13 -0
  236. package/dist/utils/toError.d.ts.map +1 -0
  237. package/dist/utils/toError.js +22 -0
  238. package/dist/utils/toError.js.map +1 -0
  239. package/package.json +73 -0
@@ -0,0 +1,340 @@
1
+ /**
2
+ * OpenAI Chat Completions 兼容实现
3
+ *
4
+ * 适用于:DeepSeek / 豆包 / 通义 / Ollama / 任何兼容 OpenAI 协议的 API
5
+ * 详见 ADR-003
6
+ */
7
+ import { LlmProvider } from '../llm/provider.js';
8
+ import { llmError, networkError, configError, toError } from '../utils/errors.js';
9
+ import { logger } from '../logging/logger.js';
10
+ /**
11
+ * 通用 OpenAI 兼容 Provider
12
+ * 通过 baseUrl 适配不同厂商
13
+ */
14
+ export class OpenAICompatibleProvider extends LlmProvider {
15
+ config;
16
+ name;
17
+ constructor(name, config) {
18
+ super();
19
+ this.config = config;
20
+ this.name = name;
21
+ }
22
+ /** 默认请求超时:120 秒 */
23
+ static DEFAULT_TIMEOUT_MS = 120_000;
24
+ async *chat(messages, opts = {}) {
25
+ const url = `${this.config.baseUrl}/chat/completions`;
26
+ const model = opts.model ?? this.config.defaultModel;
27
+ // 请求超时控制:默认 120s,可通过 opts.timeoutMs 覆盖
28
+ const timeoutMs = opts.timeoutMs ?? OpenAICompatibleProvider.DEFAULT_TIMEOUT_MS;
29
+ const body = {
30
+ model,
31
+ messages: this.formatMessages(messages),
32
+ temperature: opts.temperature ?? 0.7,
33
+ stream: true,
34
+ };
35
+ if (opts.tools)
36
+ body['tools'] = opts.tools;
37
+ if (opts.maxTokens)
38
+ body['max_tokens'] = opts.maxTokens;
39
+ // 校验 API Key(M-103:缺失时给友好提示,不暴露 undefined 报错)
40
+ if (!this.config.apiKey) {
41
+ throw configError('API Key 未配置', `provider: ${this.name},baseUrl: ${this.config.baseUrl}`, [
42
+ '检查 ~/.memora/config.json 的 llm.apiKey 字段',
43
+ '确认已设置环境变量 MEMORA_LLM_API_KEY',
44
+ '查看文档:config.example.md',
45
+ ]);
46
+ }
47
+ // 合并 AbortSignal:外部取消信号 + 超时信号
48
+ // 确保用户取消和请求超时都能中断 fetch 和流读取
49
+ const abortController = new AbortController();
50
+ const timeoutId = setTimeout(() => abortController.abort(new DOMException('LLM 请求超时', 'TimeoutError')), timeoutMs);
51
+ const { signal: optsSignal } = opts;
52
+ const onOptsAbort = () => abortController.abort(optsSignal?.reason);
53
+ if (optsSignal) {
54
+ if (optsSignal.aborted) {
55
+ abortController.abort(optsSignal.reason);
56
+ }
57
+ else {
58
+ optsSignal.addEventListener('abort', onOptsAbort, { once: true });
59
+ }
60
+ }
61
+ let response;
62
+ try {
63
+ response = await fetch(url, {
64
+ method: 'POST',
65
+ headers: {
66
+ 'Content-Type': 'application/json',
67
+ Authorization: `Bearer ${this.config.apiKey}`,
68
+ },
69
+ body: JSON.stringify(body),
70
+ signal: abortController.signal,
71
+ });
72
+ }
73
+ catch (err) {
74
+ clearTimeout(timeoutId);
75
+ if (optsSignal)
76
+ optsSignal.removeEventListener('abort', onOptsAbort);
77
+ const e = toError(err);
78
+ // 区分超时错误和网络错误
79
+ if (e.name === 'AbortError' || e.name === 'TimeoutError') {
80
+ throw networkError('LLM 请求超时', `${this.config.baseUrl} 请求超过 ${timeoutMs / 1000}s 未响应`, [
81
+ '检查网络连接稳定性',
82
+ '如频繁超时,考虑切换 provider 或在 config.json 调整 timeoutMs',
83
+ '稍后重试',
84
+ ], e);
85
+ }
86
+ throw networkError('LLM 服务连接失败', `无法访问 ${this.config.baseUrl}:${e.message}`, [
87
+ '检查网络连接(是否能访问 baseUrl)',
88
+ '确认 baseUrl 配置正确',
89
+ '如使用 VPN/代理,检查代理设置',
90
+ ], e);
91
+ }
92
+ // fetch 成功后保留 optsSignal 监听:用户在 SSE 流式阶段取消时,
93
+ // 仍需通过 onOptsAbort 触发 abortController.abort() 中断 reader.read()。
94
+ // 注意:{ once: true } 仅在 optsSignal 自身 abort 时移除监听器;
95
+ // 正常完成或异常路径必须显式 removeEventListener,否则监听器常驻泄漏。
96
+ // 下方外层 try-finally 统一清理 timeoutId 与 optsSignal 监听器,覆盖所有抛错路径。
97
+ try {
98
+ if (!response.ok) {
99
+ await this.handleResponseError(response);
100
+ }
101
+ if (!response.body) {
102
+ throw llmError('LLM API 返回空 body', `${this.config.baseUrl} 返回了 200 但无 body`, [
103
+ '重试一次',
104
+ '如持续出现,联系厂商',
105
+ ]);
106
+ }
107
+ try {
108
+ // 将 abortController.signal 传入 SSE 解析器,使超时/取消能中断流读取
109
+ yield* this.parseSseStream(response.body, abortController.signal);
110
+ }
111
+ catch (err) {
112
+ // SSE 解析异常时也要 cancel stream(Node 24 + undici 同上)
113
+ try {
114
+ await response.body?.cancel();
115
+ }
116
+ catch (err) {
117
+ logger.debug({ err: toError(err).message }, 'response.body.cancel 失败');
118
+ }
119
+ throw err;
120
+ }
121
+ }
122
+ finally {
123
+ // 统一清理:覆盖 HTTP 错误、空 body、SSE 异常、正常完成所有路径
124
+ // 修复 LLM-01:原实现仅在 fetch 网络异常 catch 移除监听器,
125
+ // handleResponseError/空body/SSE 抛错路径均泄漏监听器与定时器
126
+ clearTimeout(timeoutId);
127
+ if (optsSignal)
128
+ optsSignal.removeEventListener('abort', onOptsAbort);
129
+ }
130
+ }
131
+ /**
132
+ * 处理 HTTP 错误响应
133
+ *
134
+ * 消费并释放 body,根据状态码抛出相应的错误类型。
135
+ */
136
+ async handleResponseError(response) {
137
+ const errorText = await response.text().catch(() => '<无法读取响应体>');
138
+ try {
139
+ await response.body?.cancel();
140
+ }
141
+ catch (err) {
142
+ logger.debug({ err: toError(err).message }, 'response.body.cancel 失败');
143
+ }
144
+ const status = response.status;
145
+ if (status === 401 || status === 403) {
146
+ throw configError('LLM API Key 无效', `HTTP ${status}:${errorText.slice(0, 200)}`, [
147
+ '检查 API Key 是否正确(注意 ${MEMORA_LLM_API_KEY} 占位符是否已展开)',
148
+ '确认 Key 未过期',
149
+ '如使用 DeepSeek/豆包,确认 Key 来自对应平台',
150
+ ]);
151
+ }
152
+ if (status === 429) {
153
+ throw llmError('LLM 服务限流', `HTTP 429:${errorText.slice(0, 200)}`, [
154
+ '稍后重试',
155
+ '如频繁触发考虑升级套餐或换用其他 provider',
156
+ ]);
157
+ }
158
+ if (status >= 400 && status < 500) {
159
+ throw llmError('LLM 请求格式错误', `HTTP ${status}:${errorText.slice(0, 200)}`, [
160
+ '检查消息内容是否含特殊字符',
161
+ '确认 model 名称正确',
162
+ '如使用 tools,确认 tool schema 有效',
163
+ ]);
164
+ }
165
+ throw llmError('LLM 服务端错误', `HTTP ${status}:${errorText.slice(0, 200)}`, [
166
+ '稍后重试',
167
+ '如持续失败,访问厂商状态页确认服务状态',
168
+ '可在 config.json 切换 provider 兜底',
169
+ ]);
170
+ }
171
+ /**
172
+ * 格式化消息为 OpenAI 协议格式
173
+ *
174
+ * 关键兼容性处理:
175
+ * - assistant 消息带 tool_calls 时,若 content 为空字符串,转为 null
176
+ * (部分 LLM provider 对空字符串 content 处理异常,导致请求挂起或报错)
177
+ * - tool 消息必须包含 tool_call_id 关联对应的工具调用
178
+ */
179
+ formatMessages(messages) {
180
+ return messages.map((m) => {
181
+ if (m.role === 'tool') {
182
+ return { role: 'tool', tool_call_id: m.toolCallId, content: m.content };
183
+ }
184
+ if (m.role === 'assistant' && m.toolCalls) {
185
+ return {
186
+ role: 'assistant',
187
+ // OpenAI 协议:有 tool_calls 时 content 应为 null(而非空字符串),
188
+ // 空字符串会导致部分 provider 请求异常或无响应
189
+ content: m.content && m.content.length > 0 ? m.content : null,
190
+ tool_calls: m.toolCalls,
191
+ };
192
+ }
193
+ return { role: m.role, content: m.content };
194
+ });
195
+ }
196
+ /**
197
+ * 解析 SSE 流
198
+ * OpenAI 协议:data: {...}\n\n
199
+ *
200
+ * 支持解析 tool_calls delta(流式工具调用):
201
+ * OpenAI 协议中 tool_calls 以 delta 形式分片传输,
202
+ * 需要跨 chunk 累积 function.name 和 function.arguments,
203
+ * 在 finish_reason='tool_calls' 或流结束时输出完整的 toolCalls。
204
+ *
205
+ * @param body - SSE 响应流
206
+ * @param signal - 中止信号(超时/用户取消),中断 reader.read() 等待
207
+ */
208
+ async *parseSseStream(body, signal) {
209
+ const reader = body.getReader();
210
+ const decoder = new TextDecoder();
211
+ let buffer = '';
212
+ // 流式 tool_calls 累积器:按 index 分片累积 name + arguments
213
+ // OpenAI 协议:同一个 tool_call 的 name/arguments 可能跨多个 delta 分片到达
214
+ const toolCallAccumulators = new Map();
215
+ // 修复 P1-C:chunk 级读超时
216
+ // 原实现 reader.read() 阻塞时无超时,连接半挂(NAT/代理/服务端慢响应不关 TCP)会永久等待
217
+ // abort signal 也只能在新 chunk 到达后检查,无法中断正在 await 的 read()
218
+ // 改用 setTimeout + reader.cancel:超时则 cancel reader 让 read() reject 退出
219
+ const CHUNK_READ_TIMEOUT_MS = 30_000;
220
+ try {
221
+ while (true) {
222
+ // 检查中止信号:超时或用户取消时立即退出
223
+ if (signal?.aborted) {
224
+ throw new DOMException('LLM 流读取被中止', signal.reason?.name ?? 'AbortError');
225
+ }
226
+ // chunk 级读超时:超时则 cancel reader,让正在 await 的 read() 立即 reject
227
+ // reader.cancel() 会让 pending 的 reader.read() 抛 AbortError(DOMException)
228
+ const chunkTimer = setTimeout(() => {
229
+ // cancel 失败也不影响(reader 可能已 done 或被其他路径 cancel)
230
+ reader.cancel(new DOMException('LLM chunk 读取超时', 'TimeoutError')).catch(() => { });
231
+ }, CHUNK_READ_TIMEOUT_MS);
232
+ let readResult;
233
+ try {
234
+ readResult = await reader.read();
235
+ }
236
+ finally {
237
+ // read 完成(无论成功/失败)都清理 chunk timer,避免泄漏
238
+ clearTimeout(chunkTimer);
239
+ }
240
+ const { done, value } = readResult;
241
+ if (done)
242
+ break;
243
+ buffer += decoder.decode(value, { stream: true });
244
+ const lines = buffer.split('\n');
245
+ buffer = lines.pop() ?? '';
246
+ for (const line of lines) {
247
+ const trimmed = line.trim();
248
+ if (!trimmed.startsWith('data:'))
249
+ continue;
250
+ const data = trimmed.slice(5).trim();
251
+ if (data === '[DONE]') {
252
+ // 流结束:输出累积的 tool_calls(如果有)
253
+ if (toolCallAccumulators.size > 0) {
254
+ yield this.buildToolCallsChunk(toolCallAccumulators);
255
+ }
256
+ return;
257
+ }
258
+ try {
259
+ const json = JSON.parse(data);
260
+ const choice = json.choices?.[0];
261
+ if (!choice)
262
+ continue;
263
+ const chunk = {};
264
+ // delta.content 可能为 null(tool_calls 场景),!= null 排除 null/undefined
265
+ // 空字符串在流式中极少出现,但不影响语义,保持原有 truthy 检查即可
266
+ if (choice.delta?.content)
267
+ chunk.content = choice.delta.content;
268
+ // 累积 tool_calls delta
269
+ if (choice.delta?.tool_calls) {
270
+ for (const tc of choice.delta.tool_calls) {
271
+ const idx = tc.index ?? 0;
272
+ const acc = toolCallAccumulators.get(idx) ?? { id: '', name: '', arguments: '' };
273
+ if (tc.id)
274
+ acc.id = tc.id;
275
+ if (tc.function?.name)
276
+ acc.name += tc.function.name;
277
+ if (tc.function?.arguments)
278
+ acc.arguments += tc.function.arguments;
279
+ toolCallAccumulators.set(idx, acc);
280
+ }
281
+ }
282
+ // finish_reason='tool_calls' 时输出完整的 toolCalls
283
+ if (choice.finish_reason === 'tool_calls') {
284
+ chunk.toolCalls = this.buildToolCallsFromAccumulators(toolCallAccumulators);
285
+ toolCallAccumulators.clear();
286
+ }
287
+ else if (choice.finish_reason && toolCallAccumulators.size > 0) {
288
+ // finish_reason 为 stop/length 等非 tool_calls 值时,清空累积器防止污染下一次调用
289
+ // (某些模型可能在 stop 时残留不完整的 tool_calls 碎片)
290
+ toolCallAccumulators.clear();
291
+ }
292
+ if (choice.finish_reason) {
293
+ chunk.finishReason = choice.finish_reason;
294
+ }
295
+ yield chunk;
296
+ }
297
+ catch (err) {
298
+ logger.debug({ line: line.slice(0, 80), err: toError(err).message }, 'SSE 行解析失败');
299
+ }
300
+ }
301
+ }
302
+ }
303
+ finally {
304
+ // 修复 P1-C:releaseLock 不会取消流,只是释放锁让其他 reader 能 getReader()
305
+ // 改用 reader.cancel() 彻底释放底层 TCP 连接,避免 generator 提前 break 时
306
+ // 底层连接悬挂(CallLlmWithRetry 无 finally 触发 abort 时的兜底)
307
+ // 已 done/cancel 的 reader 调 cancel 是 no-op,安全
308
+ try {
309
+ await reader.cancel();
310
+ }
311
+ catch {
312
+ // cancel 失败不阻塞,reader 会被 GC 回收
313
+ }
314
+ }
315
+ }
316
+ /**
317
+ * 从累积器构建完整的 toolCalls 数组(用于 finish_reason='tool_calls' 场景)
318
+ */
319
+ buildToolCallsFromAccumulators(accs) {
320
+ const calls = [];
321
+ for (const [idx, acc] of accs) {
322
+ calls.push({
323
+ id: acc.id || `call_${idx}`,
324
+ type: 'function',
325
+ function: { name: acc.name, arguments: acc.arguments },
326
+ });
327
+ }
328
+ return calls;
329
+ }
330
+ /**
331
+ * 从累积器构建 LlmChunk(用于流结束时的兜底输出)
332
+ */
333
+ buildToolCallsChunk(accs) {
334
+ return {
335
+ toolCalls: this.buildToolCallsFromAccumulators(accs),
336
+ finishReason: 'tool_calls',
337
+ };
338
+ }
339
+ }
340
+ //# sourceMappingURL=openaiCompatible.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openaiCompatible.js","sourceRoot":"","sources":["../../src/llm/openaiCompatible.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAQ7C;;;GAGG;AACH,MAAM,OAAO,wBAAyB,SAAQ,WAAW;IAKpC;IAJV,IAAI,CAAS;IAEtB,YACE,IAAY,EACK,MAA8B;QAE/C,KAAK,EAAE,CAAC;QAFS,WAAM,GAAN,MAAM,CAAwB;QAG/C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,mBAAmB;IACX,MAAM,CAAU,kBAAkB,GAAG,OAAO,CAAC;IAErD,KAAK,CAAC,CAAC,IAAI,CAAC,QAAmB,EAAE,OAAoB,EAAE;QACrD,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,mBAAmB,CAAC;QACtD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;QACrD,uCAAuC;QACvC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,wBAAwB,CAAC,kBAAkB,CAAC;QAEhF,MAAM,IAAI,GAA4B;YACpC,KAAK;YACL,QAAQ,EAAE,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC;YACvC,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,GAAG;YACpC,MAAM,EAAE,IAAI;SACb,CAAC;QAEF,IAAI,IAAI,CAAC,KAAK;YAAE,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;QAC3C,IAAI,IAAI,CAAC,SAAS;YAAE,IAAI,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;QAExD,8CAA8C;QAC9C,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACxB,MAAM,WAAW,CACf,aAAa,EACb,aAAa,IAAI,CAAC,IAAI,aAAa,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EACxD;gBACE,0CAA0C;gBAC1C,8BAA8B;gBAC9B,wBAAwB;aACzB,CACF,CAAC;QACJ,CAAC;QAED,+BAA+B;QAC/B,6BAA6B;QAC7B,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;QAC9C,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QACnH,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;QACpC,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACpE,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;gBACvB,eAAe,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;YAC3C,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACpE,CAAC;QACH,CAAC;QAED,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAC1B,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;iBAC9C;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;gBAC1B,MAAM,EAAE,eAAe,CAAC,MAAM;aAC/B,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,IAAI,UAAU;gBAAE,UAAU,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YACrE,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;YACvB,cAAc;YACd,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;gBACzD,MAAM,YAAY,CAChB,UAAU,EACV,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,SAAS,SAAS,GAAG,IAAI,OAAO,EACtD;oBACE,WAAW;oBACX,iDAAiD;oBACjD,MAAM;iBACP,EACD,CAAC,CACF,CAAC;YACJ,CAAC;YACD,MAAM,YAAY,CAChB,YAAY,EACZ,QAAQ,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,EAAE,EAC1C;gBACE,uBAAuB;gBACvB,iBAAiB;gBACjB,mBAAmB;aACpB,EACD,CAAC,CACF,CAAC;QACJ,CAAC;QAED,6CAA6C;QAC7C,gEAAgE;QAChE,mDAAmD;QACnD,+CAA+C;QAC/C,6DAA6D;QAE7D,IAAI,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;YAC3C,CAAC;YAED,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnB,MAAM,QAAQ,CAAC,kBAAkB,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,kBAAkB,EAAE;oBAC3E,MAAM;oBACN,YAAY;iBACb,CAAC,CAAC;YACL,CAAC;YAED,IAAI,CAAC;gBACH,mDAAmD;gBACnD,KAAK,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;YACpE,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,iDAAiD;gBACjD,IAAI,CAAC;oBACH,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;gBAChC,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,yBAAyB,CAAC,CAAC;gBACzE,CAAC;gBACD,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,yCAAyC;YACzC,0CAA0C;YAC1C,+CAA+C;YAC/C,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,IAAI,UAAU;gBAAE,UAAU,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,mBAAmB,CAAC,QAAkB;QAClD,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC;QACjE,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,yBAAyB,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;QAE/B,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACrC,MAAM,WAAW,CAAC,gBAAgB,EAAE,QAAQ,MAAM,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE;gBAC/E,oDAAoD;gBACpD,YAAY;gBACZ,+BAA+B;aAChC,CAAC,CAAC;QACL,CAAC;QAED,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACnB,MAAM,QAAQ,CAAC,UAAU,EAAE,YAAY,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE;gBAChE,MAAM;gBACN,2BAA2B;aAC5B,CAAC,CAAC;QACL,CAAC;QAED,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;YAClC,MAAM,QAAQ,CAAC,YAAY,EAAE,QAAQ,MAAM,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE;gBACxE,eAAe;gBACf,eAAe;gBACf,6BAA6B;aAC9B,CAAC,CAAC;QACL,CAAC;QAED,MAAM,QAAQ,CAAC,WAAW,EAAE,QAAQ,MAAM,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE;YACvE,MAAM;YACN,qBAAqB;YACrB,+BAA+B;SAChC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACK,cAAc,CAAC,QAAmB;QACxC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACxB,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACtB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YAC1E,CAAC;YACD,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;gBAC1C,OAAO;oBACL,IAAI,EAAE,WAAW;oBACjB,oDAAoD;oBACpD,8BAA8B;oBAC9B,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;oBAC7D,UAAU,EAAE,CAAC,CAAC,SAAS;iBACxB,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;;;;OAWG;IACK,KAAK,CAAC,CAAC,cAAc,CAAC,IAAgC,EAAE,MAAoB;QAClF,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,kDAAkD;QAClD,4DAA4D;QAC5D,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAA2D,CAAC;QAEhG,qBAAqB;QACrB,0DAA0D;QAC1D,uDAAuD;QACvD,qEAAqE;QACrE,MAAM,qBAAqB,GAAG,MAAM,CAAC;QAErC,IAAI,CAAC;YACH,OAAO,IAAI,EAAE,CAAC;gBACZ,sBAAsB;gBACtB,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;oBACpB,MAAM,IAAI,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,YAAY,CAAC,CAAC;gBAC5E,CAAC;gBAED,4DAA4D;gBAC5D,wEAAwE;gBACxE,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,EAAE;oBACjC,+CAA+C;oBAC/C,MAAM,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACpF,CAAC,EAAE,qBAAqB,CAAC,CAAC;gBAE1B,IAAI,UAAU,CAAC;gBACf,IAAI,CAAC;oBACH,UAAU,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBACnC,CAAC;wBAAS,CAAC;oBACT,uCAAuC;oBACvC,YAAY,CAAC,UAAU,CAAC,CAAC;gBAC3B,CAAC;gBAED,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC;gBACnC,IAAI,IAAI;oBAAE,MAAM;gBAEhB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;gBAClD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACjC,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;gBAE3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;oBAC5B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC;wBAAE,SAAS;oBAC3C,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;oBACrC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;wBACtB,4BAA4B;wBAC5B,IAAI,oBAAoB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;4BAClC,MAAM,IAAI,CAAC,mBAAmB,CAAC,oBAAoB,CAAC,CAAC;wBACvD,CAAC;wBACD,OAAO;oBACT,CAAC;oBAED,IAAI,CAAC;wBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAa3B,CAAC;wBAEF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;wBACjC,IAAI,CAAC,MAAM;4BAAE,SAAS;wBAEtB,MAAM,KAAK,GAAa,EAAE,CAAC;wBAC3B,kEAAkE;wBAClE,uCAAuC;wBACvC,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO;4BAAE,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;wBAEhE,sBAAsB;wBACtB,IAAI,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC;4BAC7B,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;gCACzC,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC;gCAC1B,MAAM,GAAG,GAAG,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;gCACjF,IAAI,EAAE,CAAC,EAAE;oCAAE,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;gCAC1B,IAAI,EAAE,CAAC,QAAQ,EAAE,IAAI;oCAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC;gCACpD,IAAI,EAAE,CAAC,QAAQ,EAAE,SAAS;oCAAE,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;gCACnE,oBAAoB,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;4BACrC,CAAC;wBACH,CAAC;wBAED,8CAA8C;wBAC9C,IAAI,MAAM,CAAC,aAAa,KAAK,YAAY,EAAE,CAAC;4BAC1C,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,8BAA8B,CAAC,oBAAoB,CAAC,CAAC;4BAC5E,oBAAoB,CAAC,KAAK,EAAE,CAAC;wBAC/B,CAAC;6BAAM,IAAI,MAAM,CAAC,aAAa,IAAI,oBAAoB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;4BACjE,8DAA8D;4BAC9D,uCAAuC;4BACvC,oBAAoB,CAAC,KAAK,EAAE,CAAC;wBAC/B,CAAC;wBAED,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;4BACzB,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC,aAAyC,CAAC;wBACxE,CAAC;wBACD,MAAM,KAAK,CAAC;oBACd,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;oBACpF,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,0DAA0D;YAC1D,2DAA2D;YAC3D,mDAAmD;YACnD,6CAA6C;YAC7C,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACP,+BAA+B;YACjC,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACK,8BAA8B,CACpC,IAAkE;QAElE,MAAM,KAAK,GAAe,EAAE,CAAC;QAC7B,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,GAAG,CAAC,EAAE,IAAI,QAAQ,GAAG,EAAE;gBAC3B,IAAI,EAAE,UAAU;gBAChB,QAAQ,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE;aACvD,CAAC,CAAC;QACL,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACK,mBAAmB,CACzB,IAAkE;QAElE,OAAO;YACL,SAAS,EAAE,IAAI,CAAC,8BAA8B,CAAC,IAAI,CAAC;YACpD,YAAY,EAAE,YAAY;SAC3B,CAAC;IACJ,CAAC"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * LLM Provider 抽象接口
3
+ * 所有 LLM 实现(DeepSeek / 豆包 / OpenAI / Mock)必须实现此接口
4
+ * 详见 ADR-003
5
+ */
6
+ import type { LlmChunk } from '../llm/types.js';
7
+ export interface Message {
8
+ role: 'system' | 'user' | 'assistant' | 'tool';
9
+ content: string;
10
+ toolCalls?: Array<{
11
+ id: string;
12
+ type: 'function';
13
+ function: {
14
+ name: string;
15
+ arguments: string;
16
+ };
17
+ }>;
18
+ toolCallId?: string;
19
+ }
20
+ export interface ChatOptions {
21
+ model?: string;
22
+ temperature?: number;
23
+ maxTokens?: number;
24
+ tools?: Array<{
25
+ type: 'function';
26
+ function: {
27
+ name: string;
28
+ description: string;
29
+ parameters: Record<string, unknown>;
30
+ };
31
+ }>;
32
+ /**
33
+ * 结构化输出约束(OpenAI response_format 兼容协议)
34
+ *
35
+ * 当 Provider 支持 structured output 且工具定义标记 strict 时,
36
+ * AgentLoop 自动生成 json_schema 约束,强制 LLM 输出合法 tool_call。
37
+ * 不支持的 Provider 静默跳过,fallback 到纯文本 tool_call 模式。
38
+ */
39
+ response_format?: {
40
+ type: 'json_schema';
41
+ json_schema: {
42
+ name: string;
43
+ strict: boolean;
44
+ schema: Record<string, unknown>;
45
+ };
46
+ };
47
+ stream?: boolean;
48
+ /**
49
+ * LLM 通道选择(多 Provider 路由预留)
50
+ *
51
+ * - 'chat':前台通道,用于用户对话(高质量、低延迟)
52
+ * - 'background':后台通道,用于归档/投影/画像(中等质量、低成本)
53
+ *
54
+ * 不指定时使用默认 chat 通道。
55
+ * 多 Provider 路由功能处于设计阶段,当前所有消费者共用同一 Provider。
56
+ * 详见接入指南 §九
57
+ */
58
+ channel?: 'chat' | 'background';
59
+ /**
60
+ * 中止信号:用于取消正在进行的 LLM 请求
61
+ *
62
+ * AgentLoop 在用户取消对话时传入 AbortSignal,
63
+ * Provider 应将 signal 传给底层 fetch/stream 读取,确保请求可被中断。
64
+ */
65
+ signal?: AbortSignal;
66
+ /**
67
+ * 请求超时(毫秒)。默认 120 秒。
68
+ * 超时后抛出 networkError,由 callLlmWithRetry 决定是否重试。
69
+ */
70
+ timeoutMs?: number;
71
+ }
72
+ /**
73
+ * LLM Provider 抽象类
74
+ * 实现类需实现 chat() 流式方法
75
+ */
76
+ export declare abstract class LlmProvider {
77
+ abstract readonly name: string;
78
+ /**
79
+ * 是否支持结构化输出(response_format json_schema)
80
+ *
81
+ * 默认 false,子类可覆盖。AgentLoop 在构建工具调用时检查此标记,
82
+ * 不支持时自动降级为纯文本 tool_call 模式。
83
+ */
84
+ readonly supportsStructuredOutput: boolean;
85
+ /**
86
+ * 流式对话
87
+ * 返回 AsyncIterable,每项是一个增量块
88
+ */
89
+ abstract chat(messages: Message[], opts?: ChatOptions): AsyncIterable<LlmChunk>;
90
+ }
91
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/llm/provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAEhB,SAAS,CAAC,EAAE,KAAK,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,UAAU,CAAC;QACjB,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC;KAC/C,CAAC,CAAC;IAEH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,KAAK,CAAC,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,UAAU,CAAC;QACjB,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM,CAAC;YACb,WAAW,EAAE,MAAM,CAAC;YACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACrC,CAAC;KACH,CAAC,CAAC;IACH;;;;;;OAMG;IACH,eAAe,CAAC,EAAE;QAChB,IAAI,EAAE,aAAa,CAAC;QACpB,WAAW,EAAE;YACX,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,OAAO,CAAC;YAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACjC,CAAC;KACH,CAAC;IAEF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;IAChC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,8BAAsB,WAAW;IAC/B,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAE/B;;;;;OAKG;IACH,QAAQ,CAAC,wBAAwB,EAAE,OAAO,CAAS;IAEnD;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,aAAa,CAAC,QAAQ,CAAC;CAChF"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * LLM Provider 抽象类
3
+ * 实现类需实现 chat() 流式方法
4
+ */
5
+ export class LlmProvider {
6
+ /**
7
+ * 是否支持结构化输出(response_format json_schema)
8
+ *
9
+ * 默认 false,子类可覆盖。AgentLoop 在构建工具调用时检查此标记,
10
+ * 不支持时自动降级为纯文本 tool_call 模式。
11
+ */
12
+ supportsStructuredOutput = false;
13
+ }
14
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/llm/provider.ts"],"names":[],"mappings":"AA2EA;;;GAGG;AACH,MAAM,OAAgB,WAAW;IAG/B;;;;;OAKG;IACM,wBAAwB,GAAY,KAAK,CAAC;CAOpD"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * LLM 适配层类型定义
3
+ *
4
+ * 详见 ADR-003 · LLM 适配层使用 OpenAI Chat Completions 兼容协议
5
+ */
6
+ /**
7
+ * 工具调用描述
8
+ */
9
+ export interface ToolCall {
10
+ id: string;
11
+ type: 'function';
12
+ function: {
13
+ name: string;
14
+ arguments: string;
15
+ };
16
+ }
17
+ /**
18
+ * LLM 响应块
19
+ */
20
+ export interface LlmChunk {
21
+ content?: string;
22
+ toolCalls?: ToolCall[];
23
+ finishReason?: 'stop' | 'tool_calls' | 'length' | 'error';
24
+ }
25
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/llm/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,QAAQ,GAAG,OAAO,CAAC;CAC3D"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * LLM 适配层类型定义
3
+ *
4
+ * 详见 ADR-003 · LLM 适配层使用 OpenAI Chat Completions 兼容协议
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/llm/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * 结构化日志 — 全局单例 + 可替换 ILogger
3
+ *
4
+ * 内核零第三方依赖:pino 为可选 peerDependency,通过动态 import 加载。
5
+ * 宿主可注入自定义 logger(setLogger),完全绕过 pino。
6
+ *
7
+ * 降级策略:
8
+ * 1. pino 可用 → 双流输出(stderr + 文件日志)
9
+ * 2. pino 不可用 → console 零依赖 fallback(仅 stderr)
10
+ * 3. 宿主注入 → 优先使用宿主实现
11
+ *
12
+ * 使用方式:
13
+ * import { logger } from '../logging/logger.js';
14
+ * logger.info({ key: val }, 'message');
15
+ *
16
+ * 注入自定义 logger:
17
+ * import { setLogger } from '../logging/logger.js';
18
+ * setLogger(myCustomLogger);
19
+ */
20
+ import type { ILogger } from '../logging/loggerInterface.js';
21
+ /**
22
+ * 全局日志访问器
23
+ *
24
+ * 20+ 个内核模块统一通过此变量输出日志。
25
+ * 宿主注入自定义 logger 后,所有模块自动使用新实现。
26
+ */
27
+ export declare const logger: ILogger;
28
+ /**
29
+ * 替换全局日志实现
30
+ *
31
+ * 宿主项目在 Agent 初始化前调用此函数注入自定义 logger。
32
+ * 传入 undefined 则恢复为默认(pino 或 console fallback)。
33
+ *
34
+ * 注意:此函数修改全局状态。在单 Agent 模型下(ADR-011),
35
+ * 同一进程只有一个 Agent 实例,不会冲突。若同一进程创建多个
36
+ * Agent 实例并分别注入 logger,后者会覆盖前者——此时会输出警告。
37
+ */
38
+ export declare function setLogger(newLogger: ILogger | undefined): void;
39
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logging/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAS,MAAM,8BAA8B,CAAC;AAsPnE;;;;;GAKG;AACH,eAAO,MAAM,MAAM,EAAE,OAapB,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAqB9D"}