webaiapi 0.0.0-stage → 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 (205) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +184 -2
  3. package/bin/webapi.mjs +45 -0
  4. package/dist/browser/auth-capture.d.ts +110 -0
  5. package/dist/browser/auth-capture.d.ts.map +1 -0
  6. package/dist/browser/auth-capture.js +487 -0
  7. package/dist/browser/auth-capture.js.map +1 -0
  8. package/dist/browser/credentials.d.ts +102 -0
  9. package/dist/browser/credentials.d.ts.map +1 -0
  10. package/dist/browser/credentials.js +209 -0
  11. package/dist/browser/credentials.js.map +1 -0
  12. package/dist/browser/js-eval.d.ts +44 -0
  13. package/dist/browser/js-eval.d.ts.map +1 -0
  14. package/dist/browser/js-eval.js +20 -0
  15. package/dist/browser/js-eval.js.map +1 -0
  16. package/dist/browser/login-flow.d.ts +171 -0
  17. package/dist/browser/login-flow.d.ts.map +1 -0
  18. package/dist/browser/login-flow.js +606 -0
  19. package/dist/browser/login-flow.js.map +1 -0
  20. package/dist/browser/manager.d.ts +144 -0
  21. package/dist/browser/manager.d.ts.map +1 -0
  22. package/dist/browser/manager.js +586 -0
  23. package/dist/browser/manager.js.map +1 -0
  24. package/dist/browser/platforms.d.ts +96 -0
  25. package/dist/browser/platforms.d.ts.map +1 -0
  26. package/dist/browser/platforms.js +288 -0
  27. package/dist/browser/platforms.js.map +1 -0
  28. package/dist/browser/sse-capture.d.ts +23 -0
  29. package/dist/browser/sse-capture.d.ts.map +1 -0
  30. package/dist/browser/sse-capture.js +199 -0
  31. package/dist/browser/sse-capture.js.map +1 -0
  32. package/dist/browser/stealth.d.ts +12 -0
  33. package/dist/browser/stealth.d.ts.map +1 -0
  34. package/dist/browser/stealth.js +12 -0
  35. package/dist/browser/stealth.js.map +1 -0
  36. package/dist/cli.d.ts +12 -0
  37. package/dist/cli.d.ts.map +1 -0
  38. package/dist/cli.js +441 -0
  39. package/dist/cli.js.map +1 -0
  40. package/dist/config.d.ts +90 -0
  41. package/dist/config.d.ts.map +1 -0
  42. package/dist/config.js +246 -0
  43. package/dist/config.js.map +1 -0
  44. package/dist/controllers/history-db.d.ts +56 -0
  45. package/dist/controllers/history-db.d.ts.map +1 -0
  46. package/dist/controllers/history-db.js +260 -0
  47. package/dist/controllers/history-db.js.map +1 -0
  48. package/dist/controllers/request-pool.d.ts +78 -0
  49. package/dist/controllers/request-pool.d.ts.map +1 -0
  50. package/dist/controllers/request-pool.js +222 -0
  51. package/dist/controllers/request-pool.js.map +1 -0
  52. package/dist/controllers/router.d.ts +172 -0
  53. package/dist/controllers/router.d.ts.map +1 -0
  54. package/dist/controllers/router.js +569 -0
  55. package/dist/controllers/router.js.map +1 -0
  56. package/dist/index.d.ts +72 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +61 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/log/api-logger.d.ts +55 -0
  61. package/dist/log/api-logger.d.ts.map +1 -0
  62. package/dist/log/api-logger.js +264 -0
  63. package/dist/log/api-logger.js.map +1 -0
  64. package/dist/log/debug-logger.d.ts +49 -0
  65. package/dist/log/debug-logger.d.ts.map +1 -0
  66. package/dist/log/debug-logger.js +285 -0
  67. package/dist/log/debug-logger.js.map +1 -0
  68. package/dist/log/logger.d.ts +16 -0
  69. package/dist/log/logger.d.ts.map +1 -0
  70. package/dist/log/logger.js +35 -0
  71. package/dist/log/logger.js.map +1 -0
  72. package/dist/postinstall.d.ts +3 -0
  73. package/dist/postinstall.d.ts.map +1 -0
  74. package/dist/postinstall.js +90 -0
  75. package/dist/postinstall.js.map +1 -0
  76. package/dist/providers/base.d.ts +83 -0
  77. package/dist/providers/base.d.ts.map +1 -0
  78. package/dist/providers/base.js +51 -0
  79. package/dist/providers/base.js.map +1 -0
  80. package/dist/providers/chatglm-dom-extract.d.ts +24 -0
  81. package/dist/providers/chatglm-dom-extract.d.ts.map +1 -0
  82. package/dist/providers/chatglm-dom-extract.js +175 -0
  83. package/dist/providers/chatglm-dom-extract.js.map +1 -0
  84. package/dist/providers/chatglm-dom.d.ts +110 -0
  85. package/dist/providers/chatglm-dom.d.ts.map +1 -0
  86. package/dist/providers/chatglm-dom.js +384 -0
  87. package/dist/providers/chatglm-dom.js.map +1 -0
  88. package/dist/providers/chatglm-sse.d.ts +119 -0
  89. package/dist/providers/chatglm-sse.d.ts.map +1 -0
  90. package/dist/providers/chatglm-sse.js +241 -0
  91. package/dist/providers/chatglm-sse.js.map +1 -0
  92. package/dist/providers/chatglm.d.ts +288 -0
  93. package/dist/providers/chatglm.d.ts.map +1 -0
  94. package/dist/providers/chatglm.js +1631 -0
  95. package/dist/providers/chatglm.js.map +1 -0
  96. package/dist/routes/chat.d.ts +117 -0
  97. package/dist/routes/chat.d.ts.map +1 -0
  98. package/dist/routes/chat.js +1346 -0
  99. package/dist/routes/chat.js.map +1 -0
  100. package/dist/routes/compress.d.ts +142 -0
  101. package/dist/routes/compress.d.ts.map +1 -0
  102. package/dist/routes/compress.js +551 -0
  103. package/dist/routes/compress.js.map +1 -0
  104. package/dist/routes/failover.d.ts +34 -0
  105. package/dist/routes/failover.d.ts.map +1 -0
  106. package/dist/routes/failover.js +221 -0
  107. package/dist/routes/failover.js.map +1 -0
  108. package/dist/routes/helpers.d.ts +174 -0
  109. package/dist/routes/helpers.d.ts.map +1 -0
  110. package/dist/routes/helpers.js +525 -0
  111. package/dist/routes/helpers.js.map +1 -0
  112. package/dist/routes/meta.d.ts +31 -0
  113. package/dist/routes/meta.d.ts.map +1 -0
  114. package/dist/routes/meta.js +184 -0
  115. package/dist/routes/meta.js.map +1 -0
  116. package/dist/routes/sse.d.ts +82 -0
  117. package/dist/routes/sse.d.ts.map +1 -0
  118. package/dist/routes/sse.js +77 -0
  119. package/dist/routes/sse.js.map +1 -0
  120. package/dist/server/app.d.ts +24 -0
  121. package/dist/server/app.d.ts.map +1 -0
  122. package/dist/server/app.js +292 -0
  123. package/dist/server/app.js.map +1 -0
  124. package/dist/server/middleware/api-key.d.ts +61 -0
  125. package/dist/server/middleware/api-key.d.ts.map +1 -0
  126. package/dist/server/middleware/api-key.js +95 -0
  127. package/dist/server/middleware/api-key.js.map +1 -0
  128. package/dist/server/middleware/rate-limit.d.ts +67 -0
  129. package/dist/server/middleware/rate-limit.d.ts.map +1 -0
  130. package/dist/server/middleware/rate-limit.js +134 -0
  131. package/dist/server/middleware/rate-limit.js.map +1 -0
  132. package/dist/server/middleware/timeout.d.ts +34 -0
  133. package/dist/server/middleware/timeout.d.ts.map +1 -0
  134. package/dist/server/middleware/timeout.js +64 -0
  135. package/dist/server/middleware/timeout.js.map +1 -0
  136. package/dist/server/types.d.ts +20 -0
  137. package/dist/server/types.d.ts.map +1 -0
  138. package/dist/server/types.js +2 -0
  139. package/dist/server/types.js.map +1 -0
  140. package/dist/tools/build.d.ts +14 -0
  141. package/dist/tools/build.d.ts.map +1 -0
  142. package/dist/tools/build.js +105 -0
  143. package/dist/tools/build.js.map +1 -0
  144. package/dist/tools/clean.d.ts +32 -0
  145. package/dist/tools/clean.d.ts.map +1 -0
  146. package/dist/tools/clean.js +65 -0
  147. package/dist/tools/clean.js.map +1 -0
  148. package/dist/tools/convert.d.ts +50 -0
  149. package/dist/tools/convert.d.ts.map +1 -0
  150. package/dist/tools/convert.js +289 -0
  151. package/dist/tools/convert.js.map +1 -0
  152. package/dist/tools/names.d.ts +138 -0
  153. package/dist/tools/names.d.ts.map +1 -0
  154. package/dist/tools/names.js +578 -0
  155. package/dist/tools/names.js.map +1 -0
  156. package/dist/tools/parse.d.ts +31 -0
  157. package/dist/tools/parse.d.ts.map +1 -0
  158. package/dist/tools/parse.js +273 -0
  159. package/dist/tools/parse.js.map +1 -0
  160. package/dist/tools/placeholder.d.ts +21 -0
  161. package/dist/tools/placeholder.d.ts.map +1 -0
  162. package/dist/tools/placeholder.js +135 -0
  163. package/dist/tools/placeholder.js.map +1 -0
  164. package/dist/tools/prompts.d.ts +42 -0
  165. package/dist/tools/prompts.d.ts.map +1 -0
  166. package/dist/tools/prompts.js +69 -0
  167. package/dist/tools/prompts.js.map +1 -0
  168. package/dist/tools/protocol.d.ts +58 -0
  169. package/dist/tools/protocol.d.ts.map +1 -0
  170. package/dist/tools/protocol.js +287 -0
  171. package/dist/tools/protocol.js.map +1 -0
  172. package/dist/tools/repair.d.ts +83 -0
  173. package/dist/tools/repair.d.ts.map +1 -0
  174. package/dist/tools/repair.js +510 -0
  175. package/dist/tools/repair.js.map +1 -0
  176. package/dist/tools/workspace.d.ts +40 -0
  177. package/dist/tools/workspace.d.ts.map +1 -0
  178. package/dist/tools/workspace.js +224 -0
  179. package/dist/tools/workspace.js.map +1 -0
  180. package/dist/types/message.d.ts +87 -0
  181. package/dist/types/message.d.ts.map +1 -0
  182. package/dist/types/message.js +85 -0
  183. package/dist/types/message.js.map +1 -0
  184. package/dist/types/openai.d.ts +100 -0
  185. package/dist/types/openai.d.ts.map +1 -0
  186. package/dist/types/openai.js +66 -0
  187. package/dist/types/openai.js.map +1 -0
  188. package/dist/utils/errors.d.ts +82 -0
  189. package/dist/utils/errors.d.ts.map +1 -0
  190. package/dist/utils/errors.js +115 -0
  191. package/dist/utils/errors.js.map +1 -0
  192. package/dist/utils/mutex.d.ts +31 -0
  193. package/dist/utils/mutex.d.ts.map +1 -0
  194. package/dist/utils/mutex.js +61 -0
  195. package/dist/utils/mutex.js.map +1 -0
  196. package/dist/utils/prompt.d.ts +150 -0
  197. package/dist/utils/prompt.d.ts.map +1 -0
  198. package/dist/utils/prompt.js +514 -0
  199. package/dist/utils/prompt.js.map +1 -0
  200. package/dist/utils/text.d.ts +30 -0
  201. package/dist/utils/text.d.ts.map +1 -0
  202. package/dist/utils/text.js +70 -0
  203. package/dist/utils/text.js.map +1 -0
  204. package/package.json +67 -4
  205. package/postinstall.mjs +34 -0
@@ -0,0 +1,224 @@
1
+ /**
2
+ * 工作目录与文件路径提取 —— `legacy-python/src/utils/tool_calls.py` 的一部分。
3
+ *
4
+ * ⚠️ 这里是踩坑最密的地方,改动前请读 `docs/hard-constraints.md`「工作目录提取」。
5
+ *
6
+ * 核心结论:方法1(显式声明正则)**必须对所有 role 生效**。
7
+ * CodeBuddy 把 `Workspace Folder: <path>` 放在 **user** 消息的 `<user_info>` 里,
8
+ * 只扫 system 消息会落空 → 回退到 API 进程的 CWD → 工具调用路径全部错误。
9
+ *
10
+ * 与原实现的差异:
11
+ * - Python `re` 的 `\w` 是 Unicode 语义,JS 的 `\w` 只有 ASCII,故统一替换为
12
+ * `PY_W_CHARS`(`\p{L}\p{N}_`)并使用 `u` 标志。
13
+ * - 「目录是否存在」的检查改为可注入({@link ExtractWorkspaceOptions.isDir}),
14
+ * 便于单测与跨平台(Python 直接调 `os.path.isdir`)。
15
+ */
16
+ import { statSync } from 'node:fs';
17
+ import { fileURLToPath } from 'node:url';
18
+ import { logger } from '../log/logger.js';
19
+ import { messageToDict } from '../types/message.js';
20
+ import { PY_W_CHARS } from './repair.js';
21
+ /** AI 不确定路径时常用的编造前缀(必须排除)。 */
22
+ export const FABRICATED_PATH_PREFIXES = [
23
+ '/home/user/',
24
+ '/home/amble/project/',
25
+ '/home/amble/workspace/',
26
+ '/home/project/',
27
+ '/home/workspace/',
28
+ 'C:/Users/user/',
29
+ ];
30
+ /**
31
+ * 匹配显式声明的工作目录。
32
+ *
33
+ * 锚点需覆盖各 IDE 注入 `<user_info>` 的格式差异:
34
+ * - Trae / Cursor: `Working directory:` / `Primary working directory:`
35
+ * - CodeBuddy: `Workspace Folder:`
36
+ * - 通用: `Project root:` / `Project path:` / `工作目录:`
37
+ */
38
+ export const WORKSPACE_PATH_PATTERNS = new RegExp(String.raw `(?:working\s*director|primary\s*working\s*director|` +
39
+ String.raw `workspace\s*folder|project\s*root|project\s*path|project\s*folder|` +
40
+ String.raw `workspace|工作目录)` +
41
+ String.raw `[::]\s*[` +
42
+ '`"\'' +
43
+ String.raw `]*([/${PY_W_CHARS}~.\-]+)`, 'iu');
44
+ /** 匹配 `Working directories:` 之后的列表项。 */
45
+ const WORKING_DIRS_BLOCK = /Working\s+director(?:y|ies)[::]\s*\n((?:\s*-\s+[^\n]+\n?)+)/iu;
46
+ /** 匹配形如 `- /path/to/dir` 的行。 */
47
+ export const PATH_LINE_PATTERN = new RegExp(String.raw `^\s*-\s+([/~${PY_W_CHARS}./-]+)\s*$`, 'gmu');
48
+ /** 路径提取后带的文件扩展名(工作目录是目录,不是文件)。 */
49
+ // ⚠️ 必须写成 `[${PY_W_CHARS}]{n,m}`:直接写 `${PY_W_CHARS}{n,m}` 时量词
50
+ // 只作用于最后一个原子(`_`),而不是整个「字母/数字/下划线」集合。
51
+ const HAS_EXTENSION = new RegExp(String.raw `\.[a-zA-Z][${PY_W_CHARS}]{0,7}$`, 'u');
52
+ /** Java 关键字:被无锚点正则误拼成路径的常见片段。 */
53
+ const JAVA_CLASS_KEYWORDS = new Set([
54
+ 'class', 'function', 'public', 'private', 'protected',
55
+ 'interface', 'extends', 'implements', 'package', 'import',
56
+ 'abstract', 'final', 'static', 'void', 'return', 'new',
57
+ 'super', 'this', 'true', 'false', 'null',
58
+ ]);
59
+ /** 代码示例路径关键词。 */
60
+ const EXAMPLE_KEYWORDS = ['good-example', 'bad-example', 'example', 'demo', 'sample'];
61
+ /** 项目根目录的路径深度上限。 */
62
+ const MAX_PATH_DEPTH = 5;
63
+ /** 路径最短长度(太短不太可能是项目目录)。 */
64
+ const MIN_PATH_LEN = 10;
65
+ /**
66
+ * API 项目自身目录(用于排除 —— 用户项目不可能在这个目录下)。
67
+ *
68
+ * 从模块位置往上两级:`src/tools/` → 仓库根,`dist/tools/` → 仓库根,两者一致。
69
+ */
70
+ export const SELF_PROJECT_DIR = fileURLToPath(new URL('../../', import.meta.url)).replace(/\/$/, '');
71
+ function defaultIsDir(path) {
72
+ try {
73
+ return statSync(path).isDirectory();
74
+ }
75
+ catch {
76
+ return false;
77
+ }
78
+ }
79
+ /**
80
+ * 从消息里提取工作目录 / 项目根路径;找不到返回空字符串。
81
+ *
82
+ * 优先级:user 显式声明(3) > system 显式声明(2) > system 路径推断(1)。
83
+ */
84
+ export function extractWorkspacePath(messages, options = {}) {
85
+ const { isDir = defaultIsDir, selfDir = SELF_PROJECT_DIR } = options;
86
+ let workspacePath = '';
87
+ let systemContent = '';
88
+ let bestPriority = 0;
89
+ for (const raw of messages) {
90
+ const m = messageToDict(raw);
91
+ const role = m.role;
92
+ const content = typeof m.content === 'string' ? m.content : '';
93
+ if (!content)
94
+ continue;
95
+ // ── 方法1(任意 role):匹配显式声明的目录 ──
96
+ const match = WORKSPACE_PATH_PATTERNS.exec(content);
97
+ if (match) {
98
+ const path = match[1].replace(/\/+$/, '');
99
+ const priority = role === 'user' ? 3 : 2;
100
+ if (isDir(path) && priority > bestPriority) {
101
+ workspacePath = path;
102
+ bestPriority = priority;
103
+ logger.info({ role, path }, '[workspace] 从消息提取工作目录');
104
+ }
105
+ }
106
+ if (role !== 'system')
107
+ continue;
108
+ systemContent = content;
109
+ // ── 方法2:`Working directories:` 之后的列表 ──
110
+ const wdMatch = WORKING_DIRS_BLOCK.exec(content);
111
+ if (wdMatch) {
112
+ for (const lineMatch of wdMatch[1].matchAll(new RegExp(PATH_LINE_PATTERN.source, 'gmu'))) {
113
+ const path = lineMatch[1].replace(/\/+$/, '');
114
+ // system 级显式声明优先级 2,**不能覆盖** user 级声明(3)。
115
+ // ⚠️ 与原设计不同处:Python 版写的是 `best_priority < 2`,
116
+ // 一旦第一行把 bestPriority 置成 2,后面更长的候选就永远进不来
117
+ // (列表里有多个目录时等于只取第一个),与「取最长」的意图不符。
118
+ // 这里改成 `< 3`:既不越过 user 级声明,又能继续在 system 级候选里挑最长的。
119
+ if (isDir(path) && bestPriority < 3 && path.length > workspacePath.length) {
120
+ workspacePath = path;
121
+ bestPriority = 2;
122
+ }
123
+ }
124
+ }
125
+ // ── 方法3:在 system 消息里找非编造的真实目录路径 ──
126
+ if (!workspacePath) {
127
+ // lookbehind 排除 XML/HTML 标签误匹配:
128
+ // 系统提示里的 <maximize_context_understanding> 会被无锚点正则误认成路径,
129
+ // 进而作为错误工作目录注入工具描述,导致 AI 把文件写到不存在的目录。
130
+ const pathPattern = new RegExp(String.raw `(?<![\p{L}\p{N}_<])([/~][${PY_W_CHARS}./-]+)`, 'gu');
131
+ for (const pm of content.matchAll(pathPattern)) {
132
+ const path = pm[1].replace(/\/+$/, '');
133
+ if (HAS_EXTENSION.test(path))
134
+ continue; // 带扩展名 → 是文件不是目录
135
+ if (FABRICATED_PATH_PREFIXES.some((p) => path.startsWith(p)))
136
+ continue;
137
+ if (path === selfDir || path.startsWith(`${selfDir}/`))
138
+ continue;
139
+ const parts = path.split('/');
140
+ const last = parts[parts.length - 1];
141
+ if (parts.length >= 2 && JAVA_CLASS_KEYWORDS.has(last))
142
+ continue;
143
+ if (EXAMPLE_KEYWORDS.some((ex) => path.toLowerCase().includes(ex)))
144
+ continue;
145
+ if (path.length < MIN_PATH_LEN)
146
+ continue;
147
+ if ((path.match(/\//g) ?? []).length > MAX_PATH_DEPTH)
148
+ continue;
149
+ // 排除「疑似 JSON 字段名拼接」:所有段都是纯字母且段数 >= 3
150
+ // (真实项目目录几乎都会含下划线/数字/连字符/点之一)
151
+ const nonEmpty = parts.filter(Boolean);
152
+ if (nonEmpty.length >= 3 && nonEmpty.every((p) => /^[A-Za-z]+$/u.test(p)))
153
+ continue;
154
+ // 注意:不再验证目录是否存在 ——
155
+ // 用户的项目目录在用户机器上,不在 API 服务器上
156
+ if (path.length > workspacePath.length) {
157
+ workspacePath = path;
158
+ bestPriority = Math.max(bestPriority, 1);
159
+ }
160
+ }
161
+ }
162
+ }
163
+ // ── 兜底:从 tool 结果的 file_path 反推目录 ──
164
+ if (!workspacePath) {
165
+ for (const raw of messages) {
166
+ const m = messageToDict(raw);
167
+ if (m.role !== 'tool')
168
+ continue;
169
+ const content = typeof m.content === 'string' ? m.content : '';
170
+ for (const pm of content.matchAll(new RegExp(String.raw `(?:file_path|path)[::]\s*([/~][${PY_W_CHARS}./-]+)`, 'gu'))) {
171
+ const path = pm[1];
172
+ const dir = path.slice(0, path.lastIndexOf('/')) || '/';
173
+ if (isDir(dir) && dir.length > workspacePath.length)
174
+ workspacePath = dir;
175
+ }
176
+ }
177
+ }
178
+ if (workspacePath) {
179
+ logger.info({ workspacePath }, '[workspace] 成功提取工作目录');
180
+ }
181
+ else {
182
+ logger.warn('[workspace] 未能从消息中提取工作目录');
183
+ if (systemContent) {
184
+ for (const line of systemContent.split('\n')) {
185
+ if (line.includes('/home/') ||
186
+ line.includes('/Users/') ||
187
+ line.includes('Primary') ||
188
+ line.includes('Working')) {
189
+ logger.warn({ line: line.trim() }, '[workspace] 系统消息路径行');
190
+ }
191
+ }
192
+ }
193
+ }
194
+ return workspacePath;
195
+ }
196
+ /**
197
+ * 从消息历史里提取出现过的真实文件路径。
198
+ *
199
+ * ⚠️ **只从 tool 结果里提取**,不从 AI 的 `tool_calls` 里提取 ——
200
+ * 后者可能是模型编造的。
201
+ */
202
+ export function extractFilePathsFromMessages(messages) {
203
+ const paths = new Set();
204
+ for (const raw of messages) {
205
+ const m = messageToDict(raw);
206
+ if (m.role !== 'tool')
207
+ continue;
208
+ const content = typeof m.content === 'string' ? m.content : '';
209
+ // 模式1: `file_path: /path/to/file` 或 `path: /path/to/file`
210
+ for (const pm of content.matchAll(new RegExp(String.raw `(?:file_path|path)[::]\s*["']*([/~][${PY_W_CHARS}./-]+\.[${PY_W_CHARS}]{1,10})`, 'gu'))) {
211
+ const p = pm[1];
212
+ if (!p.startsWith('http') && p.length < 300)
213
+ paths.add(p);
214
+ }
215
+ // 模式2: 路径出现在文件内容开头(如 Read 工具返回 `# /path/to/file`)
216
+ for (const pm of content.matchAll(new RegExp(String.raw `^#\s*([/~][${PY_W_CHARS}./-]+\.[${PY_W_CHARS}]{1,10})\s*$`, 'gmu'))) {
217
+ const p = pm[1];
218
+ if (!p.startsWith('http') && p.length < 300)
219
+ paths.add(p);
220
+ }
221
+ }
222
+ return [...paths].sort();
223
+ }
224
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/tools/workspace.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * 消息模型 —— `legacy-python/src/models/request.py` 的 TypeScript 移植。
3
+ *
4
+ * 与原实现的差异:
5
+ * - Python 用 pydantic 做校验(role 白名单、messages 非空、首条必须是 system/user)。
6
+ * TS 侧改为 zod(见 `src/types/openai.ts`)在 HTTP 边界校验,本文件只放纯类型与工具函数。
7
+ * - `content` 保持「字符串或多模态数组」的原始形态,不再在读取时提前拍平成字符串,
8
+ * 这样 `formatMessagesAsText` 才能正确处理 `image_url` 项(Python 版对 dict 入参
9
+ * 能正确处理,对 pydantic 入参则因提前拍平而丢失图片标记)。
10
+ */
11
+ /** 允许的消息角色。 */
12
+ export declare const ALLOWED_ROLES: readonly ['system', 'user', 'assistant', 'tool', 'function'];
13
+ export type MessageRole = (typeof ALLOWED_ROLES)[number];
14
+ /** 多模态内容项(OpenAI 格式)。 */
15
+ export interface ContentPart {
16
+ type?: string;
17
+ text?: string;
18
+ [key: string]: unknown;
19
+ }
20
+ export type MessageContent = string | ContentPart[] | null;
21
+ /** OpenAI 兼容的消息。 */
22
+ export interface ChatMessage {
23
+ role: MessageRole | string;
24
+ content?: MessageContent;
25
+ name?: string | null;
26
+ tool_calls?: ToolCallPayload[] | null;
27
+ tool_call_id?: string | null;
28
+ }
29
+ /** OpenAI 工具调用(function 的 arguments 是 JSON 字符串)。 */
30
+ export interface ToolCallPayload {
31
+ id: string;
32
+ type: 'function';
33
+ function: {
34
+ name: string;
35
+ arguments: string;
36
+ };
37
+ }
38
+ /**
39
+ * 工具定义(OpenAI `tools` 数组的元素)。
40
+ *
41
+ * 这里用宽松类型:客户端(CodeBuddy / Trae)实际发来的结构并不总是严格符合规范,
42
+ * Python 版也是把 `tools` 当 `List[Dict[str, Any]]` 用的。
43
+ */
44
+ export interface ToolDefinition {
45
+ type?: string;
46
+ function?: {
47
+ name?: string;
48
+ description?: string;
49
+ parameters?: {
50
+ type?: string;
51
+ properties?: Record<string, unknown>;
52
+ required?: string[];
53
+ [key: string]: unknown;
54
+ };
55
+ [key: string]: unknown;
56
+ };
57
+ [key: string]: unknown;
58
+ }
59
+ /** 消息的「扁平化」视图:所有字段都可选、便于统一取值。 */
60
+ export interface MessageDict {
61
+ role: string;
62
+ content: MessageContent;
63
+ name?: string;
64
+ tool_calls?: ToolCallPayload[];
65
+ tool_call_id?: string;
66
+ }
67
+ /**
68
+ * 取纯文本内容(合并多模态数组里的 text 项)。
69
+ *
70
+ * 与 Python `Message.get_text_content()` 等价。
71
+ */
72
+ export declare function getTextContent(content: MessageContent): string;
73
+ /**
74
+ * 把消息规范化成 `MessageDict`(等价于 Python `_msg_to_dict()`)。
75
+ *
76
+ * 与 Python 的区别:这里永远保留 `content` 的原始形态(字符串或数组),
77
+ * 不再用 `get_text_content()` 提前拍平 —— 拍平会丢掉 `image_url` 标记。
78
+ * 需要纯文本的地方请显式调用 {@link getTextContent}。
79
+ */
80
+ export declare function messageToDict(msg: ChatMessage | Record<string, unknown>): MessageDict;
81
+ /** 取工具定义的名字(容错:客户端结构可能不规范)。 */
82
+ export declare function toolNameOf(tool: ToolDefinition | undefined | null): string;
83
+ /** 取工具定义的参数名列表。 */
84
+ export declare function toolParamNames(tool: ToolDefinition | undefined | null): string[];
85
+ /** 取工具定义的必填参数名列表。 */
86
+ export declare function toolRequiredParams(tool: ToolDefinition | undefined | null): string[];
87
+ //# sourceMappingURL=message.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../src/types/message.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,eAAe;AACf,eAAO,MAAM,aAAa,YAAI,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,CAAU,CAAC;AAE1F,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,yBAAyB;AACzB,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,WAAW,EAAE,GAAG,IAAI,CAAC;AAE3D,oBAAoB;AACpB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,GAAG,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,oDAAoD;AACpD,MAAM,WAAW,eAAe;IAC9B,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;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE;YACX,IAAI,CAAC,EAAE,MAAM,CAAC;YACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACrC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;YACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;SACxB,CAAC;QACF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,iCAAiC;AACjC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAoB9D;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,CAsBrF;AAED,+BAA+B;AAC/B,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAG1E;AAED,mBAAmB;AACnB,wBAAgB,cAAc,CAAC,IAAI,EAAE,cAAc,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,EAAE,CAIhF;AAED,qBAAqB;AACrB,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,EAAE,CAGpF"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * 消息模型 —— `legacy-python/src/models/request.py` 的 TypeScript 移植。
3
+ *
4
+ * 与原实现的差异:
5
+ * - Python 用 pydantic 做校验(role 白名单、messages 非空、首条必须是 system/user)。
6
+ * TS 侧改为 zod(见 `src/types/openai.ts`)在 HTTP 边界校验,本文件只放纯类型与工具函数。
7
+ * - `content` 保持「字符串或多模态数组」的原始形态,不再在读取时提前拍平成字符串,
8
+ * 这样 `formatMessagesAsText` 才能正确处理 `image_url` 项(Python 版对 dict 入参
9
+ * 能正确处理,对 pydantic 入参则因提前拍平而丢失图片标记)。
10
+ */
11
+ /** 允许的消息角色。 */
12
+ export const ALLOWED_ROLES = ['system', 'user', 'assistant', 'tool', 'function'];
13
+ /**
14
+ * 取纯文本内容(合并多模态数组里的 text 项)。
15
+ *
16
+ * 与 Python `Message.get_text_content()` 等价。
17
+ */
18
+ export function getTextContent(content) {
19
+ if (content == null)
20
+ return '';
21
+ if (typeof content === 'string')
22
+ return content;
23
+ const parts = [];
24
+ for (const item of content) {
25
+ if (typeof item === 'string') {
26
+ parts.push(item);
27
+ continue;
28
+ }
29
+ if (item && typeof item === 'object') {
30
+ const rec = item;
31
+ if (rec['type'] === 'text' && 'text' in rec) {
32
+ parts.push(String(rec['text']));
33
+ }
34
+ else if (typeof rec['text'] === 'string') {
35
+ parts.push(rec['text']);
36
+ }
37
+ }
38
+ }
39
+ return parts.join('');
40
+ }
41
+ /**
42
+ * 把消息规范化成 `MessageDict`(等价于 Python `_msg_to_dict()`)。
43
+ *
44
+ * 与 Python 的区别:这里永远保留 `content` 的原始形态(字符串或数组),
45
+ * 不再用 `get_text_content()` 提前拍平 —— 拍平会丢掉 `image_url` 标记。
46
+ * 需要纯文本的地方请显式调用 {@link getTextContent}。
47
+ */
48
+ export function messageToDict(msg) {
49
+ const rec = msg;
50
+ const out = {
51
+ role: typeof rec['role'] === 'string' ? rec['role'] : '',
52
+ content: (rec['content'] ?? ''),
53
+ };
54
+ const toolCalls = rec['tool_calls'];
55
+ if (Array.isArray(toolCalls) && toolCalls.length > 0) {
56
+ out.tool_calls = toolCalls;
57
+ }
58
+ const toolCallId = rec['tool_call_id'];
59
+ if (typeof toolCallId === 'string' && toolCallId) {
60
+ out.tool_call_id = toolCallId;
61
+ }
62
+ const name = rec['name'];
63
+ if (typeof name === 'string' && name) {
64
+ out.name = name;
65
+ }
66
+ return out;
67
+ }
68
+ /** 取工具定义的名字(容错:客户端结构可能不规范)。 */
69
+ export function toolNameOf(tool) {
70
+ const name = tool?.function?.name;
71
+ return typeof name === 'string' ? name : '';
72
+ }
73
+ /** 取工具定义的参数名列表。 */
74
+ export function toolParamNames(tool) {
75
+ const props = tool?.function?.parameters?.properties;
76
+ if (!props || typeof props !== 'object')
77
+ return [];
78
+ return Object.keys(props);
79
+ }
80
+ /** 取工具定义的必填参数名列表。 */
81
+ export function toolRequiredParams(tool) {
82
+ const required = tool?.function?.parameters?.required;
83
+ return Array.isArray(required) ? required : [];
84
+ }
85
+ //# sourceMappingURL=message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.js","sourceRoot":"","sources":["../../src/types/message.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * OpenAI 兼容的请求/响应模型 —— `legacy-python/src/models/{request,response}.py` 的移植。
3
+ *
4
+ * 与原实现的差异:
5
+ * - pydantic → zod。校验规则逐条对齐(role 白名单、messages 非空、
6
+ * 首条必须是 system/user、temperature/max_tokens 等取值范围)。
7
+ * - `EmbeddingRequest` / `ModerationRequest` / `CreateConversationRequest` 不移植:
8
+ * Python 版定义了但**没有任何路由使用它们**(`grep` 可验证)。
9
+ */
10
+ import { z } from 'zod';
11
+ import { type MessageContent } from './message.js';
12
+ export declare const messageSchema: z.ZodObject<{
13
+ role: z.ZodEnum<{
14
+ assistant: "assistant";
15
+ function: "function";
16
+ system: "system";
17
+ tool: "tool";
18
+ user: "user";
19
+ }>;
20
+ content: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodUnknown>, z.ZodNull]>>;
21
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
22
+ tool_calls: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodUnknown>>>;
23
+ tool_call_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
24
+ }, z.core.$strip>;
25
+ export type MessageInput = z.infer<typeof messageSchema>;
26
+ export declare const chatCompletionRequestSchema: z.ZodObject<{
27
+ model: z.ZodString;
28
+ messages: z.ZodArray<z.ZodObject<{
29
+ role: z.ZodEnum<{
30
+ assistant: "assistant";
31
+ function: "function";
32
+ system: "system";
33
+ tool: "tool";
34
+ user: "user";
35
+ }>;
36
+ content: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodUnknown>, z.ZodNull]>>;
37
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
38
+ tool_calls: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodUnknown>>>;
39
+ tool_call_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
40
+ }, z.core.$strip>>;
41
+ stream: z.ZodDefault<z.ZodBoolean>;
42
+ temperature: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
43
+ max_tokens: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
44
+ tools: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodUnknown>>>;
45
+ tool_choice: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>>;
46
+ conversation_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
47
+ workspace_path: z.ZodOptional<z.ZodNullable<z.ZodString>>;
48
+ n: z.ZodDefault<z.ZodOptional<z.ZodNullable<z.ZodNumber>>>;
49
+ top_p: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
50
+ frequency_penalty: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
51
+ presence_penalty: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
52
+ stop: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>>;
53
+ response_format: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
54
+ }, z.core.$strip>;
55
+ export type ChatCompletionRequest = z.infer<typeof chatCompletionRequestSchema>;
56
+ export interface ChatCompletionChoice {
57
+ index: number;
58
+ message: Record<string, unknown>;
59
+ finish_reason: string;
60
+ logprobs?: unknown;
61
+ }
62
+ export interface Usage {
63
+ prompt_tokens: number;
64
+ completion_tokens: number;
65
+ total_tokens: number;
66
+ }
67
+ export interface ChatCompletionResponse {
68
+ id: string;
69
+ object: 'chat.completion';
70
+ created: number;
71
+ model: string;
72
+ choices: ChatCompletionChoice[];
73
+ usage?: Usage | null;
74
+ system_fingerprint?: string | null;
75
+ }
76
+ export interface ModelInfo {
77
+ id: string;
78
+ object: 'model';
79
+ created: number;
80
+ owned_by: string;
81
+ provider: string;
82
+ }
83
+ export interface ModelListResponse {
84
+ object: 'list';
85
+ data: ModelInfo[];
86
+ }
87
+ export interface HealthCheckResponse {
88
+ status: string;
89
+ version: string;
90
+ providers: Record<string, Record<string, string>>;
91
+ }
92
+ /** 当前 Unix 时间戳(秒),等价于 Python `int(datetime.now().timestamp())`。 */
93
+ export declare function nowSeconds(now?: () => number): number;
94
+ /** 模型信息工厂(`created` 可注入,便于测试)。 */
95
+ export declare function makeModelInfo(id: string, provider: string, now?: () => number): ModelInfo;
96
+ /** 构造 OpenAI 格式的错误对象(等价于 `ErrorResponse.from_openai_error`)。 */
97
+ export declare function buildOpenAiError(message: string, errorType?: string, param?: string | null, code?: string | null): Record<string, unknown>;
98
+ /** 取消息内容的纯文本(便捷转发,避免使用方到处 import)。 */
99
+ export type { MessageContent };
100
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/types/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAQlE,eAAO,MAAM,aAAa;;;;;;;;;;;;iBAMxB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEzD,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4BrC,CAAC;AAEJ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAMhF,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,KAAK;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACnD;AAED,mEAAmE;AACnE,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,MAAiB,GAAG,MAAM,CAE/D;AAED,kCAAkC;AAClC,wBAAgB,aAAa,CAC3B,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,MAAM,MAAiB,GAC3B,SAAS,CAEX;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,SAAS,SAA0B,EACnC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,EACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKzB;AAED,sCAAsC;AACtC,YAAY,EAAE,cAAc,EAAE,CAAC"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * OpenAI 兼容的请求/响应模型 —— `legacy-python/src/models/{request,response}.py` 的移植。
3
+ *
4
+ * 与原实现的差异:
5
+ * - pydantic → zod。校验规则逐条对齐(role 白名单、messages 非空、
6
+ * 首条必须是 system/user、temperature/max_tokens 等取值范围)。
7
+ * - `EmbeddingRequest` / `ModerationRequest` / `CreateConversationRequest` 不移植:
8
+ * Python 版定义了但**没有任何路由使用它们**(`grep` 可验证)。
9
+ */
10
+ import { z } from 'zod';
11
+ import { ALLOWED_ROLES } from './message.js';
12
+ /* ------------------------------------------------------------------ */
13
+ /* 请求 */
14
+ /* ------------------------------------------------------------------ */
15
+ const contentSchema = z.union([z.string(), z.array(z.unknown()), z.null()]);
16
+ export const messageSchema = z.object({
17
+ role: z.enum(ALLOWED_ROLES),
18
+ content: contentSchema.optional(),
19
+ name: z.string().nullish(),
20
+ tool_calls: z.array(z.unknown()).nullish(),
21
+ tool_call_id: z.string().nullish(),
22
+ });
23
+ export const chatCompletionRequestSchema = z
24
+ .object({
25
+ model: z.string().min(1),
26
+ messages: z.array(messageSchema).min(1, '消息列表不能为空'),
27
+ stream: z.boolean().default(false),
28
+ temperature: z.number().min(0).max(2).nullish(),
29
+ max_tokens: z.number().int().min(1).nullish(),
30
+ tools: z.array(z.unknown()).nullish(),
31
+ tool_choice: z.union([z.string(), z.record(z.string(), z.unknown())]).nullish(),
32
+ conversation_id: z.string().nullish(),
33
+ workspace_path: z.string().nullish(),
34
+ // OpenAI 兼容参数:接收但不一定使用
35
+ n: z.number().int().nullish().default(1),
36
+ top_p: z.number().min(0).max(1).nullish(),
37
+ frequency_penalty: z.number().min(-2).max(2).nullish(),
38
+ presence_penalty: z.number().min(-2).max(2).nullish(),
39
+ stop: z.union([z.string(), z.array(z.string())]).nullish(),
40
+ response_format: z.record(z.string(), z.unknown()).nullish(),
41
+ })
42
+ .refine((value) => {
43
+ const first = value.messages[0];
44
+ return first !== undefined && (first.role === 'system' || first.role === 'user');
45
+ }, {
46
+ message: '第一条消息必须是 system 或 user',
47
+ path: ['messages'],
48
+ });
49
+ /** 当前 Unix 时间戳(秒),等价于 Python `int(datetime.now().timestamp())`。 */
50
+ export function nowSeconds(now = Date.now) {
51
+ return Math.floor(now() / 1000);
52
+ }
53
+ /** 模型信息工厂(`created` 可注入,便于测试)。 */
54
+ export function makeModelInfo(id, provider, now = Date.now) {
55
+ return { id, object: 'model', created: nowSeconds(now), owned_by: 'ai-api', provider };
56
+ }
57
+ /** 构造 OpenAI 格式的错误对象(等价于 `ErrorResponse.from_openai_error`)。 */
58
+ export function buildOpenAiError(message, errorType = 'invalid_request_error', param, code) {
59
+ const error = { message, type: errorType };
60
+ if (code != null)
61
+ error['code'] = code;
62
+ if (param != null)
63
+ error['param'] = param;
64
+ return error;
65
+ }
66
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/types/openai.ts"],"names":[],"mappings":"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"}