@renxqoo/renx-code 0.0.4 → 0.0.6

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 (210) hide show
  1. package/README.md +82 -51
  2. package/bin/renx.cjs +16 -0
  3. package/package.json +2 -45
  4. package/src/agent/runtime/runtime.context-usage.test.ts +4 -5
  5. package/src/agent/runtime/runtime.error-handling.test.ts +4 -5
  6. package/src/agent/runtime/runtime.test.ts +7 -4
  7. package/src/agent/runtime/runtime.ts +3 -9
  8. package/src/agent/runtime/runtime.usage-forwarding.test.ts +4 -5
  9. package/src/agent/runtime/source-modules.test.ts +16 -35
  10. package/src/agent/runtime/source-modules.ts +17 -0
  11. package/vendor/agent-root/src/agent/ENTERPRISE_ACCEPTANCE_CHECKLIST.md +95 -0
  12. package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.html +1345 -0
  13. package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.md +1353 -0
  14. package/vendor/agent-root/src/agent/ERROR_CONTRACT.md +60 -0
  15. package/vendor/agent-root/src/agent/TEST_COVERAGE_ANALYSIS.md +278 -0
  16. package/vendor/agent-root/src/agent/__test__/error-contract.test.ts +72 -0
  17. package/vendor/agent-root/src/agent/__test__/types.test.ts +137 -0
  18. package/vendor/agent-root/src/agent/agent/__test__/abort-runtime.test.ts +83 -0
  19. package/vendor/agent-root/src/agent/agent/__test__/callback-safety.test.ts +34 -0
  20. package/vendor/agent-root/src/agent/agent/__test__/compaction.test.ts +323 -0
  21. package/vendor/agent-root/src/agent/agent/__test__/concurrency.test.ts +290 -0
  22. package/vendor/agent-root/src/agent/agent/__test__/error-normalizer.test.ts +377 -0
  23. package/vendor/agent-root/src/agent/agent/__test__/error.test.ts +212 -0
  24. package/vendor/agent-root/src/agent/agent/__test__/fault-injection.test.ts +295 -0
  25. package/vendor/agent-root/src/agent/agent/__test__/index.test.ts +3607 -0
  26. package/vendor/agent-root/src/agent/agent/__test__/logger.test.ts +35 -0
  27. package/vendor/agent-root/src/agent/agent/__test__/message-utils.test.ts +517 -0
  28. package/vendor/agent-root/src/agent/agent/__test__/telemetry.test.ts +97 -0
  29. package/vendor/agent-root/src/agent/agent/__test__/timeout-budget.test.ts +479 -0
  30. package/vendor/agent-root/src/agent/agent/__test__/tool-call-merge.test.ts +80 -0
  31. package/vendor/agent-root/src/agent/agent/__test__/tool-execution-ledger.test.ts +76 -0
  32. package/vendor/agent-root/src/agent/agent/__test__/write-buffer.test.ts +173 -0
  33. package/vendor/agent-root/src/agent/agent/__test__/write-file-session.test.ts +109 -0
  34. package/vendor/agent-root/src/agent/agent/abort-runtime.ts +71 -0
  35. package/vendor/agent-root/src/agent/agent/callback-safety.ts +33 -0
  36. package/vendor/agent-root/src/agent/agent/compaction.ts +291 -0
  37. package/vendor/agent-root/src/agent/agent/concurrency.ts +103 -0
  38. package/vendor/agent-root/src/agent/agent/error-normalizer.ts +190 -0
  39. package/vendor/agent-root/src/agent/agent/error.ts +198 -0
  40. package/vendor/agent-root/src/agent/agent/index.ts +1772 -0
  41. package/vendor/agent-root/src/agent/agent/logger.ts +65 -0
  42. package/vendor/agent-root/src/agent/agent/message-utils.ts +101 -0
  43. package/vendor/agent-root/src/agent/agent/stream-events.ts +61 -0
  44. package/vendor/agent-root/src/agent/agent/telemetry.ts +123 -0
  45. package/vendor/agent-root/src/agent/agent/timeout-budget.ts +227 -0
  46. package/vendor/agent-root/src/agent/agent/tool-call-merge.ts +111 -0
  47. package/vendor/agent-root/src/agent/agent/tool-execution-ledger.ts +164 -0
  48. package/vendor/agent-root/src/agent/agent/write-buffer.ts +188 -0
  49. package/vendor/agent-root/src/agent/agent/write-file-session.ts +238 -0
  50. package/vendor/agent-root/src/agent/app/__test__/agent-app-service.test.ts +1053 -0
  51. package/vendor/agent-root/src/agent/app/__test__/minimal-agent-application.test.ts +158 -0
  52. package/vendor/agent-root/src/agent/app/__test__/sqlite-agent-app-store.test.ts +437 -0
  53. package/vendor/agent-root/src/agent/app/agent-app-service.ts +748 -0
  54. package/vendor/agent-root/src/agent/app/contracts.ts +109 -0
  55. package/vendor/agent-root/src/agent/app/index.ts +5 -0
  56. package/vendor/agent-root/src/agent/app/minimal-agent-application.ts +151 -0
  57. package/vendor/agent-root/src/agent/app/ports.ts +72 -0
  58. package/vendor/agent-root/src/agent/app/sqlite-agent-app-store.ts +1182 -0
  59. package/vendor/agent-root/src/agent/app/sqlite-client.ts +177 -0
  60. package/vendor/agent-root/src/agent/docs/cli-app-layer/00-README.md +36 -0
  61. package/vendor/agent-root/src/agent/docs/cli-app-layer/01-scope-and-goals.md +33 -0
  62. package/vendor/agent-root/src/agent/docs/cli-app-layer/02-architecture-overview.md +40 -0
  63. package/vendor/agent-root/src/agent/docs/cli-app-layer/03-domain-model-and-contracts.md +91 -0
  64. package/vendor/agent-root/src/agent/docs/cli-app-layer/04-ports-and-interfaces.md +116 -0
  65. package/vendor/agent-root/src/agent/docs/cli-app-layer/05-run-orchestration-and-state-machine.md +52 -0
  66. package/vendor/agent-root/src/agent/docs/cli-app-layer/06-cli-commands-and-ux.md +53 -0
  67. package/vendor/agent-root/src/agent/docs/cli-app-layer/07-storage-design-local.md +52 -0
  68. package/vendor/agent-root/src/agent/docs/cli-app-layer/08-error-and-observability.md +40 -0
  69. package/vendor/agent-root/src/agent/docs/cli-app-layer/09-security-and-policy-boundary.md +19 -0
  70. package/vendor/agent-root/src/agent/docs/cli-app-layer/10-test-plan-and-acceptance.md +28 -0
  71. package/vendor/agent-root/src/agent/docs/cli-app-layer/11-implementation-phases.md +26 -0
  72. package/vendor/agent-root/src/agent/docs/cli-app-layer/12-open-questions-and-risks.md +30 -0
  73. package/vendor/agent-root/src/agent/docs/cli-app-layer/13-sqlite-schema-fields-and-rationale.md +567 -0
  74. package/vendor/agent-root/src/agent/docs/cli-app-layer/14-project-flow-mermaid.md +583 -0
  75. package/vendor/agent-root/src/agent/docs/cli-app-layer/15-openclaw-style-project-blueprint.md +972 -0
  76. package/vendor/agent-root/src/agent/error-contract.ts +154 -0
  77. package/vendor/agent-root/src/agent/prompts/system.ts +246 -0
  78. package/vendor/agent-root/src/agent/prompts/system1.ts +208 -0
  79. package/vendor/agent-root/src/agent/storage/__test__/file-history-store.test.ts +98 -0
  80. package/vendor/agent-root/src/agent/storage/file-history-store.ts +313 -0
  81. package/vendor/agent-root/src/agent/storage/file-storage-config.ts +94 -0
  82. package/vendor/agent-root/src/agent/storage/file-system.ts +31 -0
  83. package/vendor/agent-root/src/agent/storage/file-write-service.ts +21 -0
  84. package/vendor/agent-root/src/agent/tool/__test__/base-tool.test.ts +413 -0
  85. package/vendor/agent-root/src/agent/tool/__test__/bash-policy.test.ts +356 -0
  86. package/vendor/agent-root/src/agent/tool/__test__/bash.mocked-coverage.test.ts +375 -0
  87. package/vendor/agent-root/src/agent/tool/__test__/bash.test.ts +372 -0
  88. package/vendor/agent-root/src/agent/tool/__test__/error.test.ts +108 -0
  89. package/vendor/agent-root/src/agent/tool/__test__/file-edit-tool.test.ts +258 -0
  90. package/vendor/agent-root/src/agent/tool/__test__/file-history-tools.test.ts +121 -0
  91. package/vendor/agent-root/src/agent/tool/__test__/file-read-tool.test.ts +210 -0
  92. package/vendor/agent-root/src/agent/tool/__test__/glob.test.ts +139 -0
  93. package/vendor/agent-root/src/agent/tool/__test__/grep.mocked-coverage.test.ts +456 -0
  94. package/vendor/agent-root/src/agent/tool/__test__/grep.test.ts +192 -0
  95. package/vendor/agent-root/src/agent/tool/__test__/lsp.test.ts +300 -0
  96. package/vendor/agent-root/src/agent/tool/__test__/outside-workspace-confirmation.test.ts +214 -0
  97. package/vendor/agent-root/src/agent/tool/__test__/path-security.test.ts +336 -0
  98. package/vendor/agent-root/src/agent/tool/__test__/skill-loader.test.ts +494 -0
  99. package/vendor/agent-root/src/agent/tool/__test__/skill-parser.test.ts +543 -0
  100. package/vendor/agent-root/src/agent/tool/__test__/skill-tool.test.ts +172 -0
  101. package/vendor/agent-root/src/agent/tool/__test__/task-concurrency-and-version.test.ts +116 -0
  102. package/vendor/agent-root/src/agent/tool/__test__/task-create-get-list-update.test.ts +267 -0
  103. package/vendor/agent-root/src/agent/tool/__test__/task-create.test.ts +519 -0
  104. package/vendor/agent-root/src/agent/tool/__test__/task-errors.test.ts +225 -0
  105. package/vendor/agent-root/src/agent/tool/__test__/task-output-blocking.test.ts +223 -0
  106. package/vendor/agent-root/src/agent/tool/__test__/task-output.test.ts +184 -0
  107. package/vendor/agent-root/src/agent/tool/__test__/task-parent-abort.test.ts +287 -0
  108. package/vendor/agent-root/src/agent/tool/__test__/task-real-runner-adapter.test.ts +190 -0
  109. package/vendor/agent-root/src/agent/tool/__test__/task-run-lifecycle.test.ts +352 -0
  110. package/vendor/agent-root/src/agent/tool/__test__/task-store-runner-branches.test.ts +395 -0
  111. package/vendor/agent-root/src/agent/tool/__test__/task-store.test.ts +391 -0
  112. package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config-integration.test.ts +176 -0
  113. package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config.test.ts +68 -0
  114. package/vendor/agent-root/src/agent/tool/__test__/task-tools-core-edges.test.ts +630 -0
  115. package/vendor/agent-root/src/agent/tool/__test__/task-tools-runtime-edges.test.ts +732 -0
  116. package/vendor/agent-root/src/agent/tool/__test__/task-types.test.ts +494 -0
  117. package/vendor/agent-root/src/agent/tool/__test__/task-utils-branches.test.ts +175 -0
  118. package/vendor/agent-root/src/agent/tool/__test__/tool-manager.test.ts +505 -0
  119. package/vendor/agent-root/src/agent/tool/__test__/types.test.ts +55 -0
  120. package/vendor/agent-root/src/agent/tool/__test__/web-fetch.test.ts +244 -0
  121. package/vendor/agent-root/src/agent/tool/__test__/web-search.test.ts +290 -0
  122. package/vendor/agent-root/src/agent/tool/__test__/write-file.test.ts +368 -0
  123. package/vendor/agent-root/src/agent/tool/base-tool.ts +345 -0
  124. package/vendor/agent-root/src/agent/tool/bash-policy.ts +636 -0
  125. package/vendor/agent-root/src/agent/tool/bash.ts +688 -0
  126. package/vendor/agent-root/src/agent/tool/error.ts +131 -0
  127. package/vendor/agent-root/src/agent/tool/file-edit-tool.ts +264 -0
  128. package/vendor/agent-root/src/agent/tool/file-history-list.ts +103 -0
  129. package/vendor/agent-root/src/agent/tool/file-history-restore.ts +149 -0
  130. package/vendor/agent-root/src/agent/tool/file-read-tool.ts +211 -0
  131. package/vendor/agent-root/src/agent/tool/glob.ts +171 -0
  132. package/vendor/agent-root/src/agent/tool/grep.ts +496 -0
  133. package/vendor/agent-root/src/agent/tool/lsp.ts +481 -0
  134. package/vendor/agent-root/src/agent/tool/path-security.ts +117 -0
  135. package/vendor/agent-root/src/agent/tool/search/common.ts +153 -0
  136. package/vendor/agent-root/src/agent/tool/skill/index.ts +13 -0
  137. package/vendor/agent-root/src/agent/tool/skill/loader.ts +229 -0
  138. package/vendor/agent-root/src/agent/tool/skill/parser.ts +124 -0
  139. package/vendor/agent-root/src/agent/tool/skill/types.ts +27 -0
  140. package/vendor/agent-root/src/agent/tool/skill-tool.ts +143 -0
  141. package/vendor/agent-root/src/agent/tool/task-create.ts +186 -0
  142. package/vendor/agent-root/src/agent/tool/task-errors.ts +42 -0
  143. package/vendor/agent-root/src/agent/tool/task-get.ts +116 -0
  144. package/vendor/agent-root/src/agent/tool/task-graph.ts +78 -0
  145. package/vendor/agent-root/src/agent/tool/task-list.ts +141 -0
  146. package/vendor/agent-root/src/agent/tool/task-mock-runner-adapter.ts +232 -0
  147. package/vendor/agent-root/src/agent/tool/task-output.ts +223 -0
  148. package/vendor/agent-root/src/agent/tool/task-parent-abort.ts +115 -0
  149. package/vendor/agent-root/src/agent/tool/task-real-runner-adapter.ts +336 -0
  150. package/vendor/agent-root/src/agent/tool/task-runner-adapter.ts +55 -0
  151. package/vendor/agent-root/src/agent/tool/task-stop.ts +187 -0
  152. package/vendor/agent-root/src/agent/tool/task-store.ts +217 -0
  153. package/vendor/agent-root/src/agent/tool/task-subagent-config.ts +149 -0
  154. package/vendor/agent-root/src/agent/tool/task-types.ts +264 -0
  155. package/vendor/agent-root/src/agent/tool/task-update.ts +315 -0
  156. package/vendor/agent-root/src/agent/tool/task.ts +209 -0
  157. package/vendor/agent-root/src/agent/tool/tool-manager.ts +362 -0
  158. package/vendor/agent-root/src/agent/tool/tool-prompts.ts +242 -0
  159. package/vendor/agent-root/src/agent/tool/types.ts +116 -0
  160. package/vendor/agent-root/src/agent/tool/web-fetch.ts +227 -0
  161. package/vendor/agent-root/src/agent/tool/web-search.ts +208 -0
  162. package/vendor/agent-root/src/agent/tool/write-file.ts +497 -0
  163. package/vendor/agent-root/src/agent/types.ts +232 -0
  164. package/vendor/agent-root/src/agent/utils/__tests__/index.test.ts +18 -0
  165. package/vendor/agent-root/src/agent/utils/__tests__/message-utils.test.ts +610 -0
  166. package/vendor/agent-root/src/agent/utils/__tests__/message.test.ts +223 -0
  167. package/vendor/agent-root/src/agent/utils/__tests__/token.test.ts +42 -0
  168. package/vendor/agent-root/src/agent/utils/index.ts +16 -0
  169. package/vendor/agent-root/src/agent/utils/message.ts +171 -0
  170. package/vendor/agent-root/src/agent/utils/token.ts +28 -0
  171. package/vendor/agent-root/src/config/__tests__/load-config-to-env.test.ts +129 -0
  172. package/vendor/agent-root/src/config/__tests__/loader.test.ts +247 -0
  173. package/vendor/agent-root/src/config/__tests__/runtime.test.ts +88 -0
  174. package/vendor/agent-root/src/config/index.ts +54 -0
  175. package/vendor/agent-root/src/config/loader.ts +431 -0
  176. package/vendor/agent-root/src/config/paths.ts +30 -0
  177. package/vendor/agent-root/src/config/runtime.ts +163 -0
  178. package/vendor/agent-root/src/config/types.ts +70 -0
  179. package/vendor/agent-root/src/logger/index.ts +57 -0
  180. package/vendor/agent-root/src/logger/logger.ts +819 -0
  181. package/vendor/agent-root/src/logger/types.ts +150 -0
  182. package/vendor/agent-root/src/providers/__tests__/errors.test.ts +441 -0
  183. package/vendor/agent-root/src/providers/__tests__/index.test.ts +16 -0
  184. package/vendor/agent-root/src/providers/__tests__/openai-compatible.options.test.ts +318 -0
  185. package/vendor/agent-root/src/providers/__tests__/openai-compatible.test.ts +600 -0
  186. package/vendor/agent-root/src/providers/__tests__/registry.test.ts +449 -0
  187. package/vendor/agent-root/src/providers/__tests__/responses-adapter.test.ts +298 -0
  188. package/vendor/agent-root/src/providers/adapters/__tests__/anthropic.test.ts +354 -0
  189. package/vendor/agent-root/src/providers/adapters/__tests__/kimi.test.ts +58 -0
  190. package/vendor/agent-root/src/providers/adapters/__tests__/standard.test.ts +261 -0
  191. package/vendor/agent-root/src/providers/adapters/anthropic.ts +572 -0
  192. package/vendor/agent-root/src/providers/adapters/base.ts +131 -0
  193. package/vendor/agent-root/src/providers/adapters/kimi.ts +48 -0
  194. package/vendor/agent-root/src/providers/adapters/responses.ts +732 -0
  195. package/vendor/agent-root/src/providers/adapters/standard.ts +120 -0
  196. package/vendor/agent-root/src/providers/http/__tests__/client.timeout.test.ts +313 -0
  197. package/vendor/agent-root/src/providers/http/client.ts +289 -0
  198. package/vendor/agent-root/src/providers/http/stream-parser.ts +109 -0
  199. package/vendor/agent-root/src/providers/index.ts +76 -0
  200. package/vendor/agent-root/src/providers/kimi-headers.ts +177 -0
  201. package/vendor/agent-root/src/providers/openai-compatible.ts +387 -0
  202. package/vendor/agent-root/src/providers/registry/model-config.ts +230 -0
  203. package/vendor/agent-root/src/providers/registry/provider-factory.ts +123 -0
  204. package/vendor/agent-root/src/providers/registry.ts +135 -0
  205. package/vendor/agent-root/src/providers/types/api.ts +284 -0
  206. package/vendor/agent-root/src/providers/types/config.ts +58 -0
  207. package/vendor/agent-root/src/providers/types/errors.ts +323 -0
  208. package/vendor/agent-root/src/providers/types/index.ts +72 -0
  209. package/vendor/agent-root/src/providers/types/provider.ts +45 -0
  210. package/vendor/agent-root/src/providers/types/registry.ts +88 -0
@@ -0,0 +1,387 @@
1
+ /**
2
+ * 通用 OpenAI 兼容 Provider 基类
3
+ *
4
+ * 提供统一的请求/流处理逻辑,配合不同 Adapter 与元数据即可支持多家兼容服务。
5
+ *
6
+ * 超时控制说明:
7
+ * - Provider 的 timeout 属性仅作为 Agent.requestTimeout 的默认回退值
8
+ * - 实际超时信号通常由 Agent/LLMCaller 层创建,通过 options.abortSignal 传入
9
+ * - standalone 调用未传 abortSignal 时,HTTPClient 使用 provider timeout 作为兜底
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const provider = new OpenAICompatibleProvider({
14
+ * apiKey: 'sk-xxx',
15
+ * baseURL: 'https://api.example.com',
16
+ * model: 'gpt-4',
17
+ * temperature: 0.7,
18
+ * max_tokens: 4096,
19
+ * LLMMAX_TOKENS: 128000,
20
+ * chatCompletionsPath: '/v1/chat/completions',
21
+ * });
22
+ *
23
+ * const stream = provider.generateStream(messages);
24
+ * for await (const chunk of stream) {
25
+ * // consume chunk
26
+ * }
27
+ * ```
28
+ */
29
+
30
+ import { BaseAPIAdapter } from './adapters/base';
31
+ import { StandardAdapter } from './adapters/standard';
32
+ import { HTTPClient } from './http/client';
33
+ import { StreamParser } from './http/stream-parser';
34
+ import {
35
+ LLMBadRequestError,
36
+ LLMError,
37
+ LLMPermanentError,
38
+ LLMRetryableError,
39
+ isPermanentStreamChunkError,
40
+ } from './types';
41
+ import {
42
+ LLMProvider,
43
+ OpenAICompatibleConfig,
44
+ Chunk,
45
+ LLMGenerateOptions,
46
+ LLMRequestMessage,
47
+ LLMResponse,
48
+ } from './types';
49
+ import type { ProviderLogger } from './types';
50
+
51
+ /** Provider 默认超时时间(毫秒),作为 Agent.requestTimeout 的回退值 */
52
+ const PROVIDER_DEFAULT_TIMEOUT = 1000 * 60 * 10; // 10分钟
53
+
54
+ /**
55
+ * OpenAI 兼容 Provider 基类
56
+ *
57
+ * 支持所有兼容 OpenAI API 格式的服务,包括:
58
+ * - OpenAI 官方 API
59
+ * - Azure OpenAI
60
+ * - 各种兼容第三方服务(如 DeepSeek、Qwen、通义千问等)
61
+ */
62
+ export class OpenAICompatibleProvider extends LLMProvider {
63
+ declare config: OpenAICompatibleConfig;
64
+ readonly httpClient: HTTPClient;
65
+ readonly adapter: BaseAPIAdapter;
66
+ readonly logger?: ProviderLogger;
67
+
68
+ /**
69
+ * 默认请求超时(毫秒)
70
+ * 作为 Agent.requestTimeout 的回退值,实际超时由 Agent 层控制
71
+ */
72
+ private readonly defaultTimeout: number;
73
+
74
+ constructor(config: OpenAICompatibleConfig, adapter?: BaseAPIAdapter) {
75
+ super(config);
76
+
77
+ // 规范化 baseURL(移除末尾斜杠)
78
+ const normalizedBaseURL = config.baseURL.replace(/\/$/, '');
79
+ this.config = { ...config, baseURL: normalizedBaseURL };
80
+ this.logger = config.logger?.child('OpenAICompatibleProvider', {
81
+ model: config.model,
82
+ baseURL: normalizedBaseURL,
83
+ });
84
+
85
+ // 保存默认超时(供 Agent 回退使用)
86
+ this.defaultTimeout = config.timeout ?? PROVIDER_DEFAULT_TIMEOUT;
87
+
88
+ // 初始化 HTTP 客户端(standalone 调用时使用 provider timeout 兜底)
89
+ this.httpClient = new HTTPClient({
90
+ logger: this.logger,
91
+ defaultTimeoutMs: this.defaultTimeout,
92
+ });
93
+
94
+ // 初始化 Adapter(未提供则使用标准适配器)
95
+ this.adapter =
96
+ adapter ??
97
+ new StandardAdapter({
98
+ defaultModel: config.model,
99
+ endpointPath: config.chatCompletionsPath ?? '/chat/completions',
100
+ });
101
+ }
102
+
103
+ /**
104
+ * 生成非流式 LLM 响应
105
+ *
106
+ * @param messages - 对话消息列表
107
+ * @param options - 可选参数(模型、温度等)
108
+ * @returns LLM 响应
109
+ */
110
+ async generate(
111
+ messages: LLMRequestMessage[],
112
+ options?: LLMGenerateOptions
113
+ ): Promise<LLMResponse> {
114
+ this.logger?.debug('generate() called', {
115
+ messageCount: messages.length,
116
+ hasOptions: Boolean(options),
117
+ stream: options?.stream ?? false,
118
+ });
119
+ this.ensureMessages(messages);
120
+ if (options?.stream === true) {
121
+ throw new LLMBadRequestError(
122
+ 'stream=true is not supported in generate(); use generateStream() instead'
123
+ );
124
+ }
125
+
126
+ const requestParams = this.buildRequestParams(messages, options, false);
127
+ return this._generateNonStream(requestParams);
128
+ }
129
+
130
+ /**
131
+ * 生成流式 LLM 响应
132
+ *
133
+ * @param messages - 对话消息列表
134
+ * @param options - 可选参数(模型、温度等)
135
+ * @returns 流式响应生成器
136
+ */
137
+ async *generateStream(
138
+ messages: LLMRequestMessage[],
139
+ options?: LLMGenerateOptions
140
+ ): AsyncGenerator<Chunk> {
141
+ this.logger?.debug('generateStream() called', {
142
+ messageCount: messages.length,
143
+ hasOptions: Boolean(options),
144
+ stream: options?.stream ?? true,
145
+ });
146
+ this.ensureMessages(messages);
147
+ if (options?.stream === false) {
148
+ throw new LLMBadRequestError(
149
+ 'stream=false is not supported in generateStream(); use generate() instead'
150
+ );
151
+ }
152
+
153
+ const requestParams = this.buildRequestParams(messages, options, true);
154
+ yield* this._generateStream(requestParams);
155
+ }
156
+
157
+ private ensureMessages(messages: LLMRequestMessage[]): void {
158
+ if (messages.length === 0) {
159
+ throw new LLMBadRequestError('messages must not be empty', {
160
+ messages: 'at least one message is required',
161
+ });
162
+ }
163
+ }
164
+
165
+ private buildRequestParams(
166
+ messages: LLMRequestMessage[],
167
+ options: LLMGenerateOptions | undefined,
168
+ streamMode: boolean
169
+ ): {
170
+ url: string;
171
+ body: Record<string, unknown>;
172
+ headers: Headers;
173
+ abortSignal?: AbortSignal;
174
+ } {
175
+ const resolvedOptions = this.resolveGenerateOptions({
176
+ ...(options ?? {}),
177
+ stream: streamMode,
178
+ });
179
+ const {
180
+ abortSignal,
181
+ model,
182
+ max_tokens,
183
+ temperature,
184
+ stream,
185
+ tool_stream,
186
+ model_reasoning_effort,
187
+ stream_options,
188
+ tools,
189
+ thinking,
190
+ ...extraOptions
191
+ } = resolvedOptions;
192
+
193
+ const requestBody = this.adapter.transformRequest({
194
+ ...extraOptions,
195
+ model: model ?? this.config.model,
196
+ max_tokens: max_tokens ?? this.config.max_tokens,
197
+ temperature: temperature ?? this.config.temperature,
198
+ messages,
199
+ stream,
200
+ tool_stream: tool_stream ?? this.config.tool_stream,
201
+ model_reasoning_effort: model_reasoning_effort ?? this.config.model_reasoning_effort,
202
+ stream_options,
203
+ tools,
204
+ thinking: thinking ?? this.config.thinking,
205
+ });
206
+
207
+ return {
208
+ url: this._resolveEndpoint(),
209
+ body: requestBody,
210
+ headers: this.adapter.getHeaders(this.config.apiKey),
211
+ abortSignal,
212
+ };
213
+ }
214
+
215
+ /**
216
+ * 统一处理生成选项,补齐流式 usage 配置
217
+ */
218
+ private resolveGenerateOptions(options?: LLMGenerateOptions): LLMGenerateOptions {
219
+ if (!options) return {};
220
+
221
+ const resolved: LLMGenerateOptions = { ...options };
222
+
223
+ if (resolved.stream && this.shouldIncludeStreamUsage(resolved)) {
224
+ resolved.stream_options = {
225
+ ...(resolved.stream_options || {}),
226
+ include_usage: true,
227
+ };
228
+ }
229
+
230
+ return resolved;
231
+ }
232
+
233
+ private shouldIncludeStreamUsage(options: LLMGenerateOptions): boolean {
234
+ if (!options.stream) return false;
235
+ if (options.stream_options?.include_usage === false) return false;
236
+ return this.config.enableStreamUsage !== false;
237
+ }
238
+
239
+ /**
240
+ * 解析完整的端点 URL
241
+ */
242
+ private _resolveEndpoint(): string {
243
+ return `${this.config.baseURL}${this.adapter.getEndpointPath()}`;
244
+ }
245
+
246
+ /**
247
+ * 处理非流式请求
248
+ */
249
+ private async _generateNonStream(params: {
250
+ url: string;
251
+ body: Record<string, unknown>;
252
+ headers: Headers;
253
+ abortSignal?: AbortSignal;
254
+ }): Promise<LLMResponse> {
255
+ this.logger?.debug('Sending non-stream request', {
256
+ url: params.url,
257
+ hasAbortSignal: Boolean(params.abortSignal),
258
+ });
259
+ const response = await this.httpClient.fetch(params.url, {
260
+ method: 'POST',
261
+ headers: params.headers,
262
+ body: JSON.stringify(params.body),
263
+ signal: params.abortSignal,
264
+ });
265
+
266
+ let data: unknown;
267
+ try {
268
+ data = await response.json();
269
+ } catch (error) {
270
+ this.logger?.error('Failed to parse non-stream response JSON', error, {
271
+ url: params.url,
272
+ });
273
+ throw new LLMError(
274
+ `Failed to parse response as JSON: ${error instanceof Error ? error.message : String(error)}`,
275
+ 'INVALID_JSON'
276
+ );
277
+ }
278
+
279
+ this.logger?.debug('Non-stream response parsed', {
280
+ url: params.url,
281
+ });
282
+ return this.adapter.transformResponse(data);
283
+ }
284
+
285
+ /**
286
+ * 处理流式请求
287
+ *
288
+ * 直接返回 AsyncGenerator<Chunk>,由调用者消费流式数据。
289
+ */
290
+ private async *_generateStream(params: {
291
+ url: string;
292
+ body: Record<string, unknown>;
293
+ headers: Headers;
294
+ abortSignal?: AbortSignal;
295
+ }): AsyncGenerator<Chunk> {
296
+ this.logger?.debug('Sending stream request', {
297
+ url: params.url,
298
+ hasAbortSignal: Boolean(params.abortSignal),
299
+ });
300
+ const response = await this.httpClient.fetch(params.url, {
301
+ method: 'POST',
302
+ headers: params.headers,
303
+ body: JSON.stringify(params.body),
304
+ signal: params.abortSignal,
305
+ });
306
+
307
+ if (!response.body) {
308
+ this.logger?.error('Stream response has no readable body', undefined, {
309
+ url: params.url,
310
+ });
311
+ throw new LLMError('Response body is not readable', 'NO_BODY');
312
+ }
313
+
314
+ const streamIterator = this.adapter.parseStreamAsync
315
+ ? this.adapter.parseStreamAsync(response.body.getReader())
316
+ : StreamParser.parseAsync(response.body.getReader());
317
+
318
+ let chunkCount = 0;
319
+ for await (const chunk of streamIterator) {
320
+ chunkCount++;
321
+ const chunkError = this.extractStreamChunkError(chunk);
322
+ if (chunkError) {
323
+ this.logger?.warn('Stream chunk error detected', {
324
+ url: params.url,
325
+ chunkId: chunk.id,
326
+ code: chunkError.code,
327
+ type: chunkError.type,
328
+ });
329
+ throw this.createStreamChunkError(chunkError, chunk.id);
330
+ }
331
+ yield chunk;
332
+ }
333
+
334
+ this.logger?.debug('Stream request completed', {
335
+ url: params.url,
336
+ chunkCount,
337
+ });
338
+ }
339
+
340
+ private extractStreamChunkError(chunk: Chunk): NonNullable<Chunk['error']> | null {
341
+ if (!chunk.error || typeof chunk.error !== 'object') {
342
+ return null;
343
+ }
344
+ return chunk.error;
345
+ }
346
+
347
+ private createStreamChunkError(chunkError: NonNullable<Chunk['error']>, chunkId?: string): Error {
348
+ const rawMessage =
349
+ typeof chunkError.message === 'string' && chunkError.message.trim().length > 0
350
+ ? chunkError.message.trim()
351
+ : 'LLM stream returned an error chunk';
352
+
353
+ const message = chunkId ? `${rawMessage} (chunk: ${chunkId})` : rawMessage;
354
+
355
+ const rawCode =
356
+ typeof chunkError.code === 'string' && chunkError.code
357
+ ? chunkError.code
358
+ : typeof chunkError.type === 'string' && chunkError.type
359
+ ? chunkError.type
360
+ : 'STREAM_CHUNK_ERROR';
361
+
362
+ if (isPermanentStreamChunkError(rawCode, message)) {
363
+ return new LLMPermanentError(message, undefined, rawCode);
364
+ }
365
+ return new LLMRetryableError(message, undefined, rawCode);
366
+ }
367
+
368
+ /**
369
+ * 获取默认请求超时时间
370
+ *
371
+ * 作为 Agent.requestTimeout 的回退值
372
+ */
373
+ getTimeTimeout(): number {
374
+ return this.defaultTimeout;
375
+ }
376
+
377
+ getLLMMaxTokens(): number {
378
+ return this.config.LLMMAX_TOKENS;
379
+ }
380
+
381
+ getMaxOutputTokens(): number {
382
+ return this.config.max_tokens;
383
+ }
384
+ }
385
+
386
+ // 重新导出配置类型
387
+ export type { OpenAICompatibleConfig } from './types';
@@ -0,0 +1,230 @@
1
+ /**
2
+ * 模型配置存储
3
+ *
4
+ * 集中管理所有模型的配置信息,可从外部加载
5
+ */
6
+
7
+ import type { ModelConfig, ModelId } from '../types';
8
+
9
+ /**
10
+ * 模型配置表(以模型 ID 为键,不包含 apiKey 的配置)
11
+ */
12
+ export const MODEL_DEFINITIONS: Record<ModelId, Omit<ModelConfig, 'apiKey'>> = {
13
+ // Anthropic 系列
14
+ 'claude-opus-4.6': {
15
+ id: 'claude-opus-4.6',
16
+ provider: 'anthropic',
17
+ name: 'Claude Opus 4.6',
18
+ baseURL: '',
19
+ endpointPath: '/v1/messages',
20
+ envApiKey: 'ANTHROPIC_API_KEY',
21
+ envBaseURL: 'ANTHROPIC_API_BASE',
22
+ model: 'claude-opus-4-6',
23
+ max_tokens: 16384,
24
+ LLMMAX_TOKENS: 1000 * 1000,
25
+ features: ['streaming', 'function-calling', 'vision'],
26
+ modalities: { image: true },
27
+ },
28
+
29
+ // GLM 系列
30
+ 'glm-4.7': {
31
+ id: 'glm-4.7',
32
+ provider: 'glm',
33
+ name: 'GLM-4.7',
34
+ baseURL: 'https://open.bigmodel.cn/api/paas/v4',
35
+ endpointPath: '/chat/completions',
36
+ envApiKey: 'GLM_API_KEY',
37
+ envBaseURL: 'GLM_API_BASE',
38
+ model: 'GLM-4.7',
39
+ max_tokens: 8000,
40
+ LLMMAX_TOKENS: 200 * 1000,
41
+ features: ['streaming', 'function-calling', 'vision'],
42
+ modalities: { image: true },
43
+ },
44
+ // GLM 系列
45
+ 'glm-5': {
46
+ id: 'glm-5',
47
+ provider: 'glm',
48
+ name: 'GLM-5',
49
+ baseURL: 'https://open.bigmodel.cn/api/paas/v4',
50
+ endpointPath: '/chat/completions',
51
+ envApiKey: 'GLM_API_KEY',
52
+ envBaseURL: 'GLM_API_BASE',
53
+ model: 'glm-5',
54
+ max_tokens: 30000,
55
+ LLMMAX_TOKENS: 200 * 1000,
56
+ features: ['streaming', 'function-calling', 'vision'],
57
+ modalities: { image: true },
58
+ },
59
+ // MiniMax 系列
60
+ 'minimax-2.5': {
61
+ id: 'minimax-2.5',
62
+ provider: 'minimax',
63
+ name: 'MiniMax-2.5',
64
+ baseURL: 'https://api.minimaxi.com/v1',
65
+ endpointPath: '/chat/completions',
66
+ envApiKey: 'MINIMAX_API_KEY',
67
+ envBaseURL: 'MINIMAX_API_URL',
68
+ model: 'MiniMax-M2.5',
69
+ max_tokens: 8000,
70
+ LLMMAX_TOKENS: 200 * 1000,
71
+ features: ['streaming', 'function-calling'],
72
+ },
73
+ // Kimi 系列
74
+ 'kimi-k2.5': {
75
+ id: 'kimi-k2.5',
76
+ provider: 'kimi',
77
+ name: 'Kimi K2.5',
78
+ baseURL: 'https://api.kimi.com/coding/v1',
79
+ endpointPath: '/chat/completions',
80
+ envApiKey: 'KIMI_API_KEY',
81
+ envBaseURL: 'KIMI_API_BASE',
82
+ model: 'kimi-for-coding',
83
+ max_tokens: 10000,
84
+ LLMMAX_TOKENS: 200 * 1000,
85
+ features: ['streaming', 'function-calling', 'reasoning'],
86
+ temperature: 0.6,
87
+ thinking: false,
88
+ },
89
+ // DeepSeek 系列
90
+ 'deepseek-reasoner': {
91
+ id: 'deepseek-reasoner',
92
+ provider: 'deepseek',
93
+ name: 'DeepSeek Reasoner',
94
+ baseURL: 'https://api.deepseek.com/v1',
95
+ endpointPath: '/chat/completions',
96
+ envApiKey: 'DEEPSEEK_API_KEY',
97
+ envBaseURL: 'DEEPSEEK_API_BASE',
98
+ model: 'deepseek-reasoner',
99
+ max_tokens: 8000,
100
+ LLMMAX_TOKENS: 128 * 1000,
101
+ features: ['streaming', 'function-calling'],
102
+ },
103
+ // Qwen 系列
104
+ 'qwen3.5-plus': {
105
+ id: 'qwen3.5-plus',
106
+ provider: 'qwen',
107
+ name: 'Qwen 3.5 Plus',
108
+ baseURL: 'https://coding.dashscope.aliyuncs.com/v1',
109
+ endpointPath: '/chat/completions',
110
+ envApiKey: 'QWEN_API_KEY',
111
+ envBaseURL: 'QWEN_API_BASE',
112
+ model: 'qwen3.5-plus',
113
+ max_tokens: 10000,
114
+ LLMMAX_TOKENS: 200 * 1000,
115
+ features: ['streaming', 'function-calling'],
116
+ modalities: { image: true },
117
+ },
118
+ // Qwen 系列
119
+ 'qwen3.5-max': {
120
+ id: 'qwen3.5-max',
121
+ provider: 'qwen',
122
+ name: 'Qwen 3.5 Max',
123
+ baseURL: 'https://coding.dashscope.aliyuncs.com/v1',
124
+ endpointPath: '/chat/completions',
125
+ envApiKey: 'QWEN_API_KEY',
126
+ envBaseURL: 'QWEN_API_BASE',
127
+ model: 'qwen3-max',
128
+ max_tokens: 1000 * 32,
129
+ LLMMAX_TOKENS: 1024 * 1000,
130
+ features: ['streaming', 'function-calling'],
131
+ },
132
+ 'qwen-kimi-k2.5': {
133
+ id: 'qwen-kimi-k2.5',
134
+ provider: 'qwen',
135
+ name: 'qwen kimi k2.5',
136
+ baseURL: 'https://coding.dashscope.aliyuncs.com/v1',
137
+ endpointPath: '/chat/completions',
138
+ envApiKey: 'QWEN_API_KEY',
139
+ envBaseURL: 'QWEN_API_BASE',
140
+ model: 'kimi-k2.5',
141
+ max_tokens: 8000,
142
+ LLMMAX_TOKENS: 200 * 1000,
143
+ features: ['streaming', 'function-calling'],
144
+ },
145
+ 'qwen-glm-5': {
146
+ id: 'qwen-glm-5',
147
+ provider: 'qwen',
148
+ name: 'Qwen GLM 5',
149
+ baseURL: 'https://coding.dashscope.aliyuncs.com/v1',
150
+ endpointPath: '/chat/completions',
151
+ envApiKey: 'QWEN_API_KEY',
152
+ envBaseURL: 'QWEN_API_BASE',
153
+ model: 'glm-5',
154
+ max_tokens: 8000,
155
+ LLMMAX_TOKENS: 200 * 1000,
156
+ features: ['streaming', 'function-calling'],
157
+ },
158
+ 'qwen-minimax-2.5': {
159
+ id: 'qwen-minimax-2.5',
160
+ provider: 'qwen',
161
+ name: 'Qwen MiniMax 2.5',
162
+ baseURL: 'https://coding.dashscope.aliyuncs.com/v1',
163
+ endpointPath: '/chat/completions',
164
+ envApiKey: 'QWEN_API_KEY',
165
+ envBaseURL: 'QWEN_API_BASE',
166
+ model: 'MiniMax-M2.5',
167
+ max_tokens: 8000,
168
+ LLMMAX_TOKENS: 200 * 1000,
169
+ features: ['streaming', 'function-calling'],
170
+ },
171
+ // 'claude-4.6': {
172
+ // id: 'wr-claude-4.6',
173
+ // provider: 'openai',
174
+ // name: 'Claude Opus 4.6',
175
+ // baseURL: '',
176
+ // endpointPath: '/chat/completions',
177
+ // envApiKey: 'ANTHROPIC_API_KEY',
178
+ // envBaseURL: 'ANTHROPIC_API_BASE',
179
+ // model: 'claude-opus-4-6',
180
+ // max_tokens: 16384,
181
+ // LLMMAX_TOKENS: 1000 * 1000,
182
+ // features: ['streaming', 'function-calling', 'vision'],
183
+ // modalities: { image: true },
184
+ // },
185
+ 'gpt-5.3': {
186
+ id: 'gpt-5.3',
187
+ provider: 'openai',
188
+ name: 'GPT-5.3',
189
+ baseURL: 'https://gmncode.cn/v1',
190
+ endpointPath: '/responses',
191
+ envApiKey: 'OPENAI_API_KEY',
192
+ envBaseURL: 'OPENAI_API_BASE',
193
+ model: 'gpt-5.3-codex',
194
+ max_tokens: 128 * 1000,
195
+ LLMMAX_TOKENS: 400 * 1000,
196
+ model_reasoning_effort: 'high',
197
+ features: ['streaming', 'function-calling', 'reasoning'],
198
+ modalities: { image: true },
199
+ },
200
+ 'gpt-5.4': {
201
+ id: 'gpt-5.4',
202
+ provider: 'openai',
203
+ name: 'GPT-5.4',
204
+ baseURL: 'https://gmncode.cn/v1',
205
+ endpointPath: '/responses',
206
+ envApiKey: 'OPENAI_API_KEY',
207
+ envBaseURL: 'OPENAI_API_BASE',
208
+ model: 'gpt-5.4',
209
+ max_tokens: 10000,
210
+ LLMMAX_TOKENS: 200 * 1000,
211
+ model_reasoning_effort: 'high',
212
+ features: ['streaming', 'function-calling'],
213
+ modalities: { image: true },
214
+ },
215
+ 'openrouter/hunter-alpha': {
216
+ id: 'openrouter/hunter-alpha',
217
+ provider: 'openrouter',
218
+ name: 'OpenRouter Hunter Alpha',
219
+ baseURL: 'https://openrouter.ai/api/v1',
220
+ endpointPath: '/chat/completions',
221
+ envApiKey: 'OPENROUTER_API_KEY',
222
+ envBaseURL: 'OPENROUTER_API_BASE',
223
+ model: 'openrouter/hunter-alpha',
224
+ max_tokens: 32 * 10,
225
+ LLMMAX_TOKENS: 200 * 1000,
226
+ model_reasoning_effort: 'high',
227
+ features: ['streaming', 'function-calling'],
228
+ modalities: { image: true },
229
+ },
230
+ };