@ai-zen/agents-sdk 1.0.0-alpha.21 → 1.0.0-alpha.23

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 (47) hide show
  1. package/CHANGELOG.md +223 -171
  2. package/README.md +15 -0
  3. package/README.zh.md +15 -0
  4. package/dist/agent-plugins/AutoMigratePlugin.js +1 -1
  5. package/dist/agent-plugins/UnknownToolHintPlugin.js +4 -4
  6. package/dist/config/constants.js +29 -24
  7. package/dist/config/factory-skills.js +56 -56
  8. package/dist/config/migrate.d.ts +10 -2
  9. package/dist/config/migrate.js +23 -2
  10. package/dist/runtime/HandoffGuardPlugin.js +2 -2
  11. package/dist/runtime/HandoffService.js +22 -22
  12. package/dist/runtime/createAgent.d.ts +7 -3
  13. package/dist/runtime/createAgent.js +7 -5
  14. package/dist/runtime/createModel.js +3 -3
  15. package/dist/scope/PermissionEvaluator.js +1 -1
  16. package/dist/scope/Scope.js +1 -1
  17. package/dist/scope/plugins/builtin/BatchEditTool.js +8 -8
  18. package/dist/scope/plugins/builtin/CopyTool.js +4 -4
  19. package/dist/scope/plugins/builtin/CwdTool.js +1 -1
  20. package/dist/scope/plugins/builtin/DownloadFileTool.js +8 -8
  21. package/dist/scope/plugins/builtin/EditTool.js +9 -9
  22. package/dist/scope/plugins/builtin/ExecTool.js +8 -8
  23. package/dist/scope/plugins/builtin/ExistTool.js +2 -2
  24. package/dist/scope/plugins/builtin/FindTextTool.js +10 -10
  25. package/dist/scope/plugins/builtin/GenerateImageTool.js +13 -13
  26. package/dist/scope/plugins/builtin/GlobTool.js +4 -4
  27. package/dist/scope/plugins/builtin/InspectFileTool.js +7 -7
  28. package/dist/scope/plugins/builtin/LsTool.js +5 -5
  29. package/dist/scope/plugins/builtin/MkdirTool.js +3 -3
  30. package/dist/scope/plugins/builtin/ReadTool.js +8 -8
  31. package/dist/scope/plugins/builtin/RenameTool.js +3 -3
  32. package/dist/scope/plugins/builtin/RmTool.js +3 -3
  33. package/dist/scope/plugins/builtin/SleepTool.js +6 -6
  34. package/dist/scope/plugins/builtin/SpawnTool.js +9 -9
  35. package/dist/scope/plugins/builtin/ViewImageTool.js +12 -12
  36. package/dist/scope/plugins/builtin/WriteTool.js +3 -3
  37. package/dist/scope/plugins/mcp/McpConnectionManager.js +7 -7
  38. package/dist/scope/plugins/mcp/discover.js +1 -1
  39. package/dist/scope/plugins/mcp/mcpTools.js +29 -29
  40. package/dist/scope/plugins/skills/discover.js +7 -7
  41. package/dist/scope/plugins/skills/skillTools.js +17 -17
  42. package/dist/scope/plugins/subagents/subAgentTools.js +2 -2
  43. package/dist/scope/plugins/usertools/discover.js +2 -2
  44. package/dist/shared/content-blocks.js +9 -9
  45. package/dist/shared/errors.js +3 -3
  46. package/dist/types/index.d.ts +22 -1
  47. package/package.json +10 -1
@@ -15,25 +15,25 @@ export class GenerateImageTool extends SdkCallbackTool {
15
15
  }
16
16
  function = {
17
17
  name: "generate_image",
18
- description: "根据文字描述生成图片,返回图片 URL 列表(JSON)。如需查看图片内容,请用 view_image 工具(传入图片 URL);如需保存到本地,用 download_file 下载。",
18
+ description: "Generate an image from a text description and return a list of image URLs (JSON). To inspect the image content, use the view_image tool (pass the image URL); to save it locally, use download_file.",
19
19
  parameters: {
20
20
  type: "object",
21
21
  properties: {
22
22
  prompt: {
23
23
  type: "string",
24
- description: "所需图像的文本描述,应详细描述画面内容、风格、构图等",
24
+ description: "Text description of the desired image; describe the subject, style, composition and other details",
25
25
  },
26
26
  model: {
27
27
  type: "string",
28
- description: "图片模型 ID,不指定则使用配置中的默认图片模型;若指定的模型不存在,本工具会返回当前可用的模型列表。",
28
+ description: "Image model ID. Defaults to the configured default image model; if the given model does not exist, this tool returns the list of currently available models.",
29
29
  },
30
30
  size: {
31
31
  type: "string",
32
- description: '图片尺寸。不指定则使用模型的默认尺寸。cogview系列: 1024x1024, 768x1344, 864x1152, 1344x768, 1152x864, 1440x720, 720x1440。glm-image: 1280x1280, 1568x1056, 1056x1568, 1472x1088, 1088x1472, 1728x960, 960x1728。',
32
+ description: 'Image size. Defaults to the model default size. cogview series: 1024x1024, 768x1344, 864x1152, 1344x768, 1152x864, 1440x720, 720x1440. glm-image: 1280x1280, 1568x1056, 1056x1568, 1472x1088, 1088x1472, 1728x960, 960x1728.',
33
33
  },
34
34
  quality: {
35
35
  type: "string",
36
- description: "图像质量。hd: 精细(约20秒), standard: 快速(约5-10秒)",
36
+ description: "Image quality. hd: fine (about 20 seconds), standard: fast (about 5-10 seconds)",
37
37
  enum: ["hd", "standard"],
38
38
  },
39
39
  },
@@ -49,7 +49,7 @@ export class GenerateImageTool extends SdkCallbackTool {
49
49
  try {
50
50
  const prompt = input.prompt;
51
51
  if (!prompt || !prompt.trim()) {
52
- return JSON.stringify({ success: false, error: "prompt 不能为空" });
52
+ return JSON.stringify({ success: false, error: "prompt must not be empty" });
53
53
  }
54
54
  const config = this.env.config;
55
55
  const imageModels = config.imageModels;
@@ -57,7 +57,7 @@ export class GenerateImageTool extends SdkCallbackTool {
57
57
  if (!imageModels || imageModels.length === 0) {
58
58
  return JSON.stringify({
59
59
  success: false,
60
- error: "未配置图片生成模型。请在配置中添加 imageModels。",
60
+ error: "No image generation model configured. Add imageModels to the configuration.",
61
61
  });
62
62
  }
63
63
  const modelId = input.model || defaultImageModel;
@@ -67,20 +67,20 @@ export class GenerateImageTool extends SdkCallbackTool {
67
67
  if (!imageModel) {
68
68
  return JSON.stringify({
69
69
  success: false,
70
- error: `图片模型 "${modelId}" 不存在。可用的图片模型: ${imageModels.map((m) => m.id).join(", ")}`,
70
+ error: `Image model "${modelId}" does not exist. Available image models: ${imageModels.map((m) => m.id).join(", ")}`,
71
71
  });
72
72
  }
73
73
  const endpoint = config.endpoints.find((e) => e.id === imageModel.endpointId);
74
74
  if (!endpoint) {
75
75
  return JSON.stringify({
76
76
  success: false,
77
- error: `图片模型 "${imageModel.name}" 对应的端点 "${imageModel.endpointId}" 未配置`,
77
+ error: `Endpoint "${imageModel.endpointId}" for image model "${imageModel.name}" is not configured`,
78
78
  });
79
79
  }
80
80
  if (!endpoint.apiKey) {
81
81
  return JSON.stringify({
82
82
  success: false,
83
- error: `端点 "${endpoint.name}" 的 API Key 未设置`,
83
+ error: `API Key for endpoint "${endpoint.name}" is not set`,
84
84
  });
85
85
  }
86
86
  const client = new OpenAI({
@@ -107,7 +107,7 @@ export class GenerateImageTool extends SdkCallbackTool {
107
107
  modelId: imageModel.id,
108
108
  created: result.created,
109
109
  images: urls.map((url, i) => ({ index: i, url })),
110
- note: "图片临时链接有效期为30天。如需查看图片内容,可用 view_image 工具(传入图片 URL);如需保存,可用 download_file 下载。",
110
+ note: "Image links are temporary and expire after 30 days. To inspect the image content, use the view_image tool (pass the image URL); to save it, use download_file.",
111
111
  }, null, 2);
112
112
  }
113
113
  catch (error) {
@@ -116,12 +116,12 @@ export class GenerateImageTool extends SdkCallbackTool {
116
116
  return JSON.stringify({
117
117
  success: false,
118
118
  aborted: true,
119
- error: "图片生成被中断(aborted)",
119
+ error: "Image generation aborted",
120
120
  });
121
121
  }
122
122
  return JSON.stringify({
123
123
  success: false,
124
- error: error instanceof Error ? error.message : "图片生成失败",
124
+ error: error instanceof Error ? error.message : "Image generation failed",
125
125
  });
126
126
  }
127
127
  }
@@ -4,7 +4,7 @@ import { DEFAULT_MAX_TOOL_OUTPUT, guardOutput, headPreview } from "./outputGuard
4
4
  export class GlobTool extends SdkCallbackTool {
5
5
  function = {
6
6
  name: "glob",
7
- description: "使用 glob 模式递归扫描和查找文件。这是进行文件系统搜索的首选工具,功能远优于简单的 'ls' 列表命令。当你需要查找特定类型的文件、遍历目录树或需要排除特定文件时,请优先使用此函数。",
7
+ description: "Recursively scan for and find files using a glob pattern. This is the preferred tool for file system searches, far better than a plain 'ls' listing. Prefer this tool when you need to find files of a specific type, walk a directory tree, or exclude specific files.",
8
8
  parameters: {
9
9
  type: "object",
10
10
  properties: {
@@ -68,9 +68,9 @@ export class GlobTool extends SdkCallbackTool {
68
68
  const preview = headPreview(json);
69
69
  return JSON.stringify({
70
70
  outputTooLarge: true,
71
- warning: `输出过大:匹配结果共 ${json.length} 字符,超过上限 ${limit} 字符。` +
72
- `完整结果已落盘(result.json),可用 read 分批读取;` +
73
- `也可用更精确的 pattern 或 exclude 缩小范围后重新查找。`,
71
+ warning: `Output too large: the matches total ${json.length} characters, exceeding the limit of ${limit} characters. ` +
72
+ `The full result has been written to disk (result.json) and can be read in chunks with read; ` +
73
+ `alternatively, narrow the scope with a more precise pattern or exclude and search again.`,
74
74
  files: ctx.files,
75
75
  chars: json.length,
76
76
  ...preview,
@@ -12,17 +12,17 @@ import { DEFAULT_MAX_TOOL_OUTPUT } from "./outputGuard.js";
12
12
  export class InspectFileTool extends SdkCallbackTool {
13
13
  function = {
14
14
  name: "inspect_file",
15
- description: "勘察文件的结构概况:总行数、总字符数、最长行的列数及其行索引、平均列数、行尾类型(LF/CRLF)。可选返回每行的列数映射。适用于在 read 之前先了解文件规模,再决定用 range 读取哪一段。仅做流式扫描,不受 read 的 300KB 读取阈值限制。",
15
+ description: "Inspect a file's structural overview: total lines, total characters, the longest line's column count and its line index, average column count, and line ending type (LF/CRLF). Optionally returns a per-line column count map. Useful for sizing up a file before reading it, so you can decide which range to read. Streaming scan only, not subject to the 300KB read threshold of read.",
16
16
  parameters: {
17
17
  type: "object",
18
18
  properties: {
19
19
  path: {
20
20
  type: "string",
21
- description: "文件路径",
21
+ description: "File path",
22
22
  },
23
23
  withColCountMap: {
24
24
  type: "boolean",
25
- description: "是否返回每行列数映射(对象:行索引 → 列数,行索引从 0 开始)。默认 false。行数很多时该映射可能过大,此时将只返回概况字段。",
25
+ description: "Whether to return a per-line column count map (object: line index → column count, line index is 0-based). Default false. When there are many lines the map may be too large; in that case only the overview fields are returned.",
26
26
  default: false,
27
27
  },
28
28
  },
@@ -38,7 +38,7 @@ export class InspectFileTool extends SdkCallbackTool {
38
38
  const filePath = this.resolve(input.path);
39
39
  const stats = await fsp.stat(filePath);
40
40
  if (!stats.isFile()) {
41
- return `"${filePath}" 不是文件`;
41
+ return `"${filePath}" is not a file`;
42
42
  }
43
43
  const withColCountMap = input.withColCountMap ?? false;
44
44
  const result = await scan(filePath, withColCountMap);
@@ -61,9 +61,9 @@ export class InspectFileTool extends SdkCallbackTool {
61
61
  return JSON.stringify({
62
62
  ...summary,
63
63
  colCountMapOmitted: true,
64
- warning: `行长度明细过大:概况与 colCountMap 合计 ${payload.length} 字符,` +
65
- `超过上限 ${limit} 字符,未落盘返回。文件规模超出可处理范围,` +
66
- `建议改用 find_text 定位后再按 range 分段读取。`,
64
+ warning: `Line length details too large: overview plus colCountMap total ${payload.length} characters, ` +
65
+ `exceeding the limit of ${limit} characters; not written to disk. The file is beyond the supported size, ` +
66
+ `so use find_text to locate the target and then read it in chunks by range.`,
67
67
  });
68
68
  }
69
69
  return payload;
@@ -4,13 +4,13 @@ import { DEFAULT_MAX_TOOL_OUTPUT, guardOutput, headPreview } from "./outputGuard
4
4
  export class LsTool extends SdkCallbackTool {
5
5
  function = {
6
6
  name: "ls",
7
- description: "列出目录",
7
+ description: "List a directory",
8
8
  parameters: {
9
9
  type: "object",
10
10
  properties: {
11
11
  path: {
12
12
  type: "string",
13
- description: "目录路径",
13
+ description: "Directory path",
14
14
  },
15
15
  },
16
16
  required: ["path"],
@@ -35,9 +35,9 @@ export class LsTool extends SdkCallbackTool {
35
35
  const preview = headPreview(json);
36
36
  return JSON.stringify({
37
37
  outputTooLarge: true,
38
- warning: `输出过大:目录条目共 ${entries.length} 项、${json.length} 字符,超过上限 ${limit} 字符。` +
39
- `完整列表已落盘(result.json),可用 read 分批读取;` +
40
- `也可改用 glob 按模式筛选。`,
38
+ warning: `Output too large: ${entries.length} directory entries, ${json.length} characters in total, exceeding the limit of ${limit} characters. ` +
39
+ `The full list has been written to disk (result.json) and can be read in chunks with read; ` +
40
+ `alternatively, use glob to filter by pattern.`,
41
41
  files: ctx.files,
42
42
  chars: json.length,
43
43
  ...preview,
@@ -3,17 +3,17 @@ import { SdkCallbackTool } from "./SdkCallbackTool.js";
3
3
  export class MkdirTool extends SdkCallbackTool {
4
4
  function = {
5
5
  name: "mkdir",
6
- description: "创建目录",
6
+ description: "Create a directory",
7
7
  parameters: {
8
8
  type: "object",
9
9
  properties: {
10
10
  path: {
11
11
  type: "string",
12
- description: "目录路径",
12
+ description: "Directory path",
13
13
  },
14
14
  recursive: {
15
15
  type: "boolean",
16
- description: "是否递归创建子目录",
16
+ description: "Whether to create parent directories recursively",
17
17
  },
18
18
  },
19
19
  required: ["path"],
@@ -4,18 +4,18 @@ import { DEFAULT_MAX_TOOL_OUTPUT, guardOutput } from "./outputGuard.js";
4
4
  export class ReadTool extends SdkCallbackTool {
5
5
  function = {
6
6
  name: "read",
7
- description: "读取文件",
7
+ description: "Read a file",
8
8
  parameters: {
9
9
  type: "object",
10
10
  properties: {
11
11
  path: {
12
12
  type: "string",
13
- description: "文件路径",
13
+ description: "File path",
14
14
  },
15
15
  range: {
16
16
  type: "array",
17
- description: "读取范围 [起始行, 起始列, 结束行, 结束列],行列均从 0 开始,-1 表示末位;" +
18
- "例如 [0, 0, 100, -1] 表示从第 0 行第 0 列读到第 100 行最后一列。省略则读取整个文件。",
17
+ description: "Read range [startLine, startCol, endLine, endCol]; rows and columns are 0-based, -1 means the last position. " +
18
+ "For example, [0, 0, 100, -1] reads from line 0, column 0 through the last column of line 100; omit it to read the whole file.",
19
19
  items: {
20
20
  type: "number",
21
21
  },
@@ -34,7 +34,7 @@ export class ReadTool extends SdkCallbackTool {
34
34
  const stats = await fsp.stat(filePath);
35
35
  // 读取阈值:文件过大时拒绝读取(与输出阈值 maxToolOutput 无关)
36
36
  if (stats.size > 300 * 1024) {
37
- throw new Error(`文件过大,无法读取,当前文件大小 ${stats.size} 字节`);
37
+ throw new Error(`File too large to read: ${stats.size} bytes`);
38
38
  }
39
39
  const content = await fsp.readFile(filePath, "utf-8");
40
40
  const output = input.range ? sliceByRange(content, input.range) : content;
@@ -44,9 +44,9 @@ export class ReadTool extends SdkCallbackTool {
44
44
  tool: "read",
45
45
  content: output,
46
46
  isOverLimit: (text) => text.length > limit,
47
- buildWarning: () => `读取内容过大:本次输出 ${output.length} 字符,超过上限 ${limit} 字符,未落盘。` +
48
- `文件共 ${countLines(content)} 行、${content.length} 字符,` +
49
- `请用 range 参数分范围读取(形如 [起始行, 起始列, 结束行, 结束列],行列从 0 开始,-1 表示末位)。`,
47
+ buildWarning: () => `Output too large: this read returned ${output.length} characters, exceeding the limit of ${limit} characters; not written to disk. ` +
48
+ `The file has ${countLines(content)} lines and ${content.length} characters. ` +
49
+ `Use the range parameter to read it in chunks (format [startLine, startCol, endLine, endCol], 0-based, -1 means the last position).`,
50
50
  });
51
51
  }
52
52
  catch (error) {
@@ -3,17 +3,17 @@ import { SdkCallbackTool } from "./SdkCallbackTool.js";
3
3
  export class RenameTool extends SdkCallbackTool {
4
4
  function = {
5
5
  name: "rename",
6
- description: "重命名或移动文件/目录(相当于 mv 命令)",
6
+ description: "Rename or move a file/directory (equivalent to the mv command)",
7
7
  parameters: {
8
8
  type: "object",
9
9
  properties: {
10
10
  oldPath: {
11
11
  type: "string",
12
- description: "原路径",
12
+ description: "Original path",
13
13
  },
14
14
  newPath: {
15
15
  type: "string",
16
- description: "新路径",
16
+ description: "New path",
17
17
  },
18
18
  },
19
19
  required: ["oldPath", "newPath"],
@@ -3,17 +3,17 @@ import { SdkCallbackTool } from "./SdkCallbackTool.js";
3
3
  export class RmTool extends SdkCallbackTool {
4
4
  function = {
5
5
  name: "rm",
6
- description: "删除文件或目录",
6
+ description: "Delete a file or directory",
7
7
  parameters: {
8
8
  type: "object",
9
9
  properties: {
10
10
  path: {
11
11
  type: "string",
12
- description: "文件或目录路径",
12
+ description: "File or directory path",
13
13
  },
14
14
  recursive: {
15
15
  type: "boolean",
16
- description: "是否递归删除子目录",
16
+ description: "Whether to delete subdirectories recursively",
17
17
  },
18
18
  },
19
19
  required: ["path"],
@@ -2,13 +2,13 @@ import { SdkCallbackTool } from "./SdkCallbackTool.js";
2
2
  export class SleepTool extends SdkCallbackTool {
3
3
  function = {
4
4
  name: "sleep",
5
- description: "等待指定的时间(毫秒)。用于需要延迟执行的场景,例如等待其他操作完成、操作间隔控制等。注意:过长的等待时间会影响响应速度,建议不超过 30000 毫秒(30 秒)。",
5
+ description: "Wait for the specified time in milliseconds. Use it when a delay is needed, for example to wait for another operation to finish or to space out actions. Note: long waits slow down responses; keep it at or below 30000 milliseconds (30 seconds).",
6
6
  parameters: {
7
7
  type: "object",
8
8
  properties: {
9
9
  ms: {
10
10
  type: "number",
11
- description: "等待的毫秒数(1 秒 = 1000 毫秒)。建议不超过 30000(30 秒)。",
11
+ description: "Milliseconds to wait (1 second = 1000 milliseconds). Values above 30000 (30 seconds) are not recommended.",
12
12
  },
13
13
  },
14
14
  required: ["ms"],
@@ -23,14 +23,14 @@ export class SleepTool extends SdkCallbackTool {
23
23
  if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) {
24
24
  return JSON.stringify({
25
25
  success: false,
26
- error: "ms 必须是正整数",
26
+ error: "ms must be a positive integer",
27
27
  });
28
28
  }
29
29
  if (ms > 300_000) {
30
30
  // 超过 5 分钟给出警告
31
31
  return JSON.stringify({
32
32
  success: false,
33
- error: `等待时间 ${ms}ms 过长,建议不超过 300000ms(5 分钟)。如需长时间等待请分段执行。`,
33
+ error: `Wait time ${ms}ms is too long, keep it at or below 300000ms (5 minutes). For longer waits, split them into shorter steps`,
34
34
  });
35
35
  }
36
36
  // 若 signal 已处于 aborted,直接返回中断结果,避免不必要的等待
@@ -53,14 +53,14 @@ export class SleepTool extends SdkCallbackTool {
53
53
  return JSON.stringify({
54
54
  success: false,
55
55
  aborted: true,
56
- error: "等待被中断(aborted)",
56
+ error: "Wait aborted",
57
57
  });
58
58
  }
59
59
  return JSON.stringify({
60
60
  success: true,
61
61
  waitedMs: ms,
62
62
  waitedSeconds: (ms / 1000).toFixed(1),
63
- message: `已等待 ${ms}ms(${(ms / 1000).toFixed(1)} 秒)`,
63
+ message: `Waited ${ms}ms (${(ms / 1000).toFixed(1)} seconds)`,
64
64
  });
65
65
  }
66
66
  }
@@ -3,21 +3,21 @@ import { SdkCallbackTool } from "./SdkCallbackTool.js";
3
3
  export class SpawnTool extends SdkCallbackTool {
4
4
  function = {
5
5
  name: "spawn",
6
- description: "异步执行命令,启动程序后立即返回,不等待执行结果。适用于启动长期运行的进程(如服务器、监听程序、GUI应用等)或不需要等待结果的命令。注意:该工具本身不捕获命令的输出;若需获取/留存输出,可在命令中使用 shell 重定向写入文件(如 `> /path/file`,支持 `>>` 追加、`|` 管道)。命令经 shell 解析执行。",
6
+ description: "Spawn a command asynchronously and return immediately without waiting for the result. Use it for long-running processes (servers, watchers, GUI apps, etc.) or commands whose result you do not need to wait for. Note: this tool does not capture the command's output itself; to retain or inspect output, use shell redirection to a file inside the command (e.g. `> /path/file`; `>>` append and `|` pipes are supported). The command is parsed and executed by the shell.",
7
7
  parameters: {
8
8
  type: "object",
9
9
  properties: {
10
10
  command: {
11
11
  type: "string",
12
- description: "要执行的命令(含参数)",
12
+ description: "Command to execute (including arguments)",
13
13
  },
14
14
  cwd: {
15
15
  type: "string",
16
- description: "工作目录(可选,默认当前工作目录)",
16
+ description: "Working directory (optional, defaults to the current working directory)",
17
17
  },
18
18
  detached: {
19
19
  type: "boolean",
20
- description: "是否完全脱离当前进程组(可选,默认 false)。设为 true 时,即使当前 Agent 进程退出,启动的程序仍会继续运行。适用于需要独立运行的守护进程或 GUI 程序。",
20
+ description: "Whether to fully detach from the current process group (optional, defaults to false). When true, the spawned program keeps running even after the current Agent process exits. Use it for daemons or GUI programs that must run independently.",
21
21
  },
22
22
  },
23
23
  required: ["command"],
@@ -48,7 +48,7 @@ export class SpawnTool extends SdkCallbackTool {
48
48
  resolve(JSON.stringify({
49
49
  success: false,
50
50
  pid: null,
51
- message: `启动失败: ${err.message}`,
51
+ message: `Failed to start: ${err.message}`,
52
52
  }));
53
53
  });
54
54
  child.on("spawn", () => {
@@ -58,7 +58,7 @@ export class SpawnTool extends SdkCallbackTool {
58
58
  resolve(JSON.stringify({
59
59
  success: true,
60
60
  pid: child.pid ?? null,
61
- message: `进程已启动 (PID: ${child.pid ?? "unknown"})`,
61
+ message: `Process started (PID: ${child.pid ?? "unknown"})`,
62
62
  }));
63
63
  });
64
64
  child.on("exit", (code) => {
@@ -70,8 +70,8 @@ export class SpawnTool extends SdkCallbackTool {
70
70
  pid: child.pid ?? null,
71
71
  exitCode: code,
72
72
  message: code === null
73
- ? `进程已退出 (PID: ${child.pid ?? "unknown"})`
74
- : `进程已退出 (PID: ${child.pid ?? "unknown"}, 退出码: ${code})`,
73
+ ? `Process exited (PID: ${child.pid ?? "unknown"})`
74
+ : `Process exited (PID: ${child.pid ?? "unknown"}, exit code: ${code})`,
75
75
  }));
76
76
  });
77
77
  const timeout = setTimeout(() => {
@@ -81,7 +81,7 @@ export class SpawnTool extends SdkCallbackTool {
81
81
  resolve(JSON.stringify({
82
82
  success: true,
83
83
  pid: child.pid ?? null,
84
- message: `进程已启动 (PID: ${child.pid ?? "unknown"})`,
84
+ message: `Process started (PID: ${child.pid ?? "unknown"})`,
85
85
  }));
86
86
  }, 500);
87
87
  const cleanup = () => {
@@ -35,13 +35,13 @@ export class ViewImageTool extends SdkCallbackTool {
35
35
  }
36
36
  function = {
37
37
  name: "view_image",
38
- description: "查看一张图片并分析其内容。传入本地图片路径或 http(s) 图片 URL。本地图片优先上传(端点支持 Files API 时)否则以 base64 内联引用,网络图片直接引用。不支持本地 URL(如 file:// 协议、指向本机 localhost/127.0.0.1 的 http(s) 地址),本地图片请使用文件路径。适合识别图片文字、描述图片内容、分析图表等。",
38
+ description: "View an image and analyze its content. Pass a local image path or an http(s) image URL. Local images are uploaded when the endpoint supports the Files API and are otherwise referenced as inline base64; remote images are referenced directly. Local URLs are not supported (such as the file:// protocol, or http(s) addresses pointing to localhost/127.0.0.1 on this machine); use a file path for local images. Suitable for reading text in images, describing image content and analyzing charts.",
39
39
  parameters: {
40
40
  type: "object",
41
41
  properties: {
42
42
  path_or_url: {
43
43
  type: "string",
44
- description: "本地图片路径(相对/绝对)或 http(s) 图片 URL。支持的格式:JPEG、PNG、GIF、WebP。不支持本地 URL(如 file:// 协议、指向本机 localhost/127.0.0.1 的 http(s) 地址),本地图片请使用文件路径。",
44
+ description: "Local image path (relative or absolute) or an http(s) image URL. Supported formats: JPEG, PNG, GIF, WebP. Local URLs are not supported (such as the file:// protocol, or http(s) addresses pointing to localhost/127.0.0.1 on this machine); use a file path for local images.",
45
45
  },
46
46
  },
47
47
  required: ["path_or_url"],
@@ -55,12 +55,12 @@ export class ViewImageTool extends SdkCallbackTool {
55
55
  const signal = ctx?.signal;
56
56
  const target = input?.path_or_url;
57
57
  if (!target || !target.trim()) {
58
- return "view_image 需要提供 path_or_url 参数(本地图片路径或 http(s) URL)。";
58
+ return "view_image requires the path_or_url parameter (a local image path or an http(s) URL)";
59
59
  }
60
60
  const value = target.trim();
61
61
  // 拒绝服务商无法访问的"本地 URL":file:// 等本地协议,或指向本机回环地址的 http(s) 地址
62
62
  if (isLocalUrl(value)) {
63
- return "不支持本地 URL(API 服务商无法下载访问)。本地图片请使用文件路径,而不是本地链接。";
63
+ return "Local URLs are not supported (the API provider cannot download them). Use a file path for local images, not a local link";
64
64
  }
65
65
  // 按当前模型定位端点:决定走 Files API 上传还是 base64 内联
66
66
  const { model, endpoint } = resolveModelAndEndpoint(this.env.config, ctx?.agent?.model);
@@ -74,11 +74,11 @@ export class ViewImageTool extends SdkCallbackTool {
74
74
  await fs.stat(abs);
75
75
  }
76
76
  catch {
77
- return `本地图片不存在: ${abs}`;
77
+ return `Local image not found: ${abs}`;
78
78
  }
79
79
  const mime = mimeOf(abs);
80
80
  if (!mime || !mime.startsWith("image/")) {
81
- return `不支持的图片格式 "${path.extname(abs) || "(无扩展名)"}"。支持的格式:JPEG、PNG、GIF、WebP。`;
81
+ return `Unsupported image format "${path.extname(abs) || "(no extension)"}". Supported formats: JPEG, PNG, GIF, WebP`;
82
82
  }
83
83
  }
84
84
  const result = await fileToContentSection({
@@ -87,21 +87,21 @@ export class ViewImageTool extends SdkCallbackTool {
87
87
  model,
88
88
  signal,
89
89
  });
90
- const label = isUrl ? `已获取网络图片:${value}` : `已获取本地图片(${path.basename(value)})`;
90
+ const label = isUrl ? `Fetched remote image: ${value}` : `Fetched local image (${path.basename(value)})`;
91
91
  const how = result.transport === "files-api"
92
- ? `,已上传至 Files API(file_id: ${result.section.file_id ?? "?"})`
92
+ ? `, uploaded to the Files API (file_id: ${result.section.file_id ?? "?"})`
93
93
  : result.transport === "inline"
94
- ? `,已按 base64 内联(${(result.bytes / 1024).toFixed(0)} KB)`
94
+ ? `, inlined as base64 (${(result.bytes / 1024).toFixed(0)} KB)`
95
95
  : "";
96
- const extra = result.warning ? `(降级说明:${result.warning})` : "";
96
+ const extra = result.warning ? ` (fallback: ${result.warning})` : "";
97
97
  return [{ type: "text", text: `${label}${how}${extra}` }, result.section];
98
98
  }
99
99
  catch (error) {
100
100
  // 中断(abort)时返回明确的中断结果
101
101
  if (signal?.aborted) {
102
- return "图片查看被中断(aborted)";
102
+ return "Image view aborted";
103
103
  }
104
- return `查看图片失败: ${error instanceof Error ? error.message : String(error)}`;
104
+ return `Failed to view image: ${error instanceof Error ? error.message : String(error)}`;
105
105
  }
106
106
  }
107
107
  }
@@ -4,17 +4,17 @@ import { SdkCallbackTool } from "./SdkCallbackTool.js";
4
4
  export class WriteTool extends SdkCallbackTool {
5
5
  function = {
6
6
  name: "write",
7
- description: "写入文件",
7
+ description: "Write a file",
8
8
  parameters: {
9
9
  type: "object",
10
10
  properties: {
11
11
  path: {
12
12
  type: "string",
13
- description: "文件路径",
13
+ description: "File path",
14
14
  },
15
15
  content: {
16
16
  type: "string",
17
- description: "文件内容",
17
+ description: "File content",
18
18
  },
19
19
  },
20
20
  required: ["path", "content"],
@@ -141,7 +141,7 @@ export class McpConnectionManager {
141
141
  }));
142
142
  }
143
143
  catch (err) {
144
- getLogger().error(`[McpConnectionManager] 获取 "${name}" 工具列表失败: ${err?.message ?? err}`);
144
+ getLogger().error(`[McpConnectionManager] Failed to list tools for "${name}": ${err?.message ?? err}`);
145
145
  }
146
146
  }
147
147
  if (serverCaps?.resources) {
@@ -155,7 +155,7 @@ export class McpConnectionManager {
155
155
  }));
156
156
  }
157
157
  catch (err) {
158
- getLogger().error(`[McpConnectionManager] 获取 "${name}" 资源列表失败: ${err?.message ?? err}`);
158
+ getLogger().error(`[McpConnectionManager] Failed to list resources for "${name}": ${err?.message ?? err}`);
159
159
  }
160
160
  }
161
161
  if (serverCaps?.prompts) {
@@ -167,7 +167,7 @@ export class McpConnectionManager {
167
167
  }));
168
168
  }
169
169
  catch (err) {
170
- getLogger().error(`[McpConnectionManager] 获取 "${name}" 提示列表失败: ${err?.message ?? err}`);
170
+ getLogger().error(`[McpConnectionManager] Failed to list prompts for "${name}": ${err?.message ?? err}`);
171
171
  }
172
172
  }
173
173
  const entry = this.servers.get(name) ?? { state: "connecting" };
@@ -190,7 +190,7 @@ export class McpConnectionManager {
190
190
  }
191
191
  if (config.transport === "stdio") {
192
192
  if (!config.command) {
193
- throw new Error(`MCP stdio server 缺少 command`);
193
+ throw new Error(`MCP stdio server is missing command`);
194
194
  }
195
195
  return new StdioClientTransport({
196
196
  command: config.command,
@@ -201,7 +201,7 @@ export class McpConnectionManager {
201
201
  // http 使用 Streamable HTTP 传输(POST + 可选 SSE 流)
202
202
  if (config.transport === "http") {
203
203
  if (!config.url) {
204
- throw new Error(`MCP http server 缺少 url`);
204
+ throw new Error(`MCP http server is missing url`);
205
205
  }
206
206
  return new StreamableHTTPClientTransport(new URL(config.url), {
207
207
  requestInit: config.headers ? { headers: config.headers } : undefined,
@@ -210,13 +210,13 @@ export class McpConnectionManager {
210
210
  // sse 使用旧版 HTTP+SSE 传输(GET 建立 SSE 流,POST 发送消息)
211
211
  if (config.transport === "sse") {
212
212
  if (!config.url) {
213
- throw new Error(`MCP sse server 缺少 url`);
213
+ throw new Error(`MCP sse server is missing url`);
214
214
  }
215
215
  return new SSEClientTransport(new URL(config.url), {
216
216
  requestInit: config.headers ? { headers: config.headers } : undefined,
217
217
  });
218
218
  }
219
- throw new Error(`不支持的 MCP transport 类型: ${config.transport}`);
219
+ throw new Error(`Unsupported MCP transport type: ${config.transport}`);
220
220
  }
221
221
  // ---- 断开 ----
222
222
  async disconnect(name) {
@@ -82,7 +82,7 @@ export async function discoverMcpServers(paths) {
82
82
  }
83
83
  }
84
84
  catch (err) {
85
- getLogger().warn(`[sdk] 解析 MCP 配置失败: ${path} — ${err?.message ?? err}`);
85
+ getLogger().warn(`[sdk] Failed to parse MCP config: ${path} — ${err?.message ?? err}`);
86
86
  }
87
87
  }
88
88
  return items;