@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.
- package/CHANGELOG.md +223 -171
- package/README.md +15 -0
- package/README.zh.md +15 -0
- package/dist/agent-plugins/AutoMigratePlugin.js +1 -1
- package/dist/agent-plugins/UnknownToolHintPlugin.js +4 -4
- package/dist/config/constants.js +29 -24
- package/dist/config/factory-skills.js +56 -56
- package/dist/config/migrate.d.ts +10 -2
- package/dist/config/migrate.js +23 -2
- package/dist/runtime/HandoffGuardPlugin.js +2 -2
- package/dist/runtime/HandoffService.js +22 -22
- package/dist/runtime/createAgent.d.ts +7 -3
- package/dist/runtime/createAgent.js +7 -5
- package/dist/runtime/createModel.js +3 -3
- package/dist/scope/PermissionEvaluator.js +1 -1
- package/dist/scope/Scope.js +1 -1
- package/dist/scope/plugins/builtin/BatchEditTool.js +8 -8
- package/dist/scope/plugins/builtin/CopyTool.js +4 -4
- package/dist/scope/plugins/builtin/CwdTool.js +1 -1
- package/dist/scope/plugins/builtin/DownloadFileTool.js +8 -8
- package/dist/scope/plugins/builtin/EditTool.js +9 -9
- package/dist/scope/plugins/builtin/ExecTool.js +8 -8
- package/dist/scope/plugins/builtin/ExistTool.js +2 -2
- package/dist/scope/plugins/builtin/FindTextTool.js +10 -10
- package/dist/scope/plugins/builtin/GenerateImageTool.js +13 -13
- package/dist/scope/plugins/builtin/GlobTool.js +4 -4
- package/dist/scope/plugins/builtin/InspectFileTool.js +7 -7
- package/dist/scope/plugins/builtin/LsTool.js +5 -5
- package/dist/scope/plugins/builtin/MkdirTool.js +3 -3
- package/dist/scope/plugins/builtin/ReadTool.js +8 -8
- package/dist/scope/plugins/builtin/RenameTool.js +3 -3
- package/dist/scope/plugins/builtin/RmTool.js +3 -3
- package/dist/scope/plugins/builtin/SleepTool.js +6 -6
- package/dist/scope/plugins/builtin/SpawnTool.js +9 -9
- package/dist/scope/plugins/builtin/ViewImageTool.js +12 -12
- package/dist/scope/plugins/builtin/WriteTool.js +3 -3
- package/dist/scope/plugins/mcp/McpConnectionManager.js +7 -7
- package/dist/scope/plugins/mcp/discover.js +1 -1
- package/dist/scope/plugins/mcp/mcpTools.js +29 -29
- package/dist/scope/plugins/skills/discover.js +7 -7
- package/dist/scope/plugins/skills/skillTools.js +17 -17
- package/dist/scope/plugins/subagents/subAgentTools.js +2 -2
- package/dist/scope/plugins/usertools/discover.js +2 -2
- package/dist/shared/content-blocks.js +9 -9
- package/dist/shared/errors.js +3 -3
- package/dist/types/index.d.ts +22 -1
- 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: "
|
|
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: "
|
|
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: '
|
|
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: "
|
|
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: "
|
|
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:
|
|
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:
|
|
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:
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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:
|
|
72
|
-
|
|
73
|
-
|
|
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: "
|
|
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: "
|
|
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:
|
|
65
|
-
|
|
66
|
-
|
|
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:
|
|
39
|
-
|
|
40
|
-
|
|
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: "
|
|
18
|
-
"
|
|
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(
|
|
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: () =>
|
|
48
|
-
|
|
49
|
-
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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:
|
|
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: "
|
|
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:
|
|
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: "
|
|
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: "
|
|
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:
|
|
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:
|
|
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
|
-
?
|
|
74
|
-
:
|
|
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:
|
|
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: "
|
|
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: "
|
|
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
|
|
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 "
|
|
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
|
|
77
|
+
return `Local image not found: ${abs}`;
|
|
78
78
|
}
|
|
79
79
|
const mime = mimeOf(abs);
|
|
80
80
|
if (!mime || !mime.startsWith("image/")) {
|
|
81
|
-
return
|
|
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 ?
|
|
90
|
+
const label = isUrl ? `Fetched remote image: ${value}` : `Fetched local image (${path.basename(value)})`;
|
|
91
91
|
const how = result.transport === "files-api"
|
|
92
|
-
?
|
|
92
|
+
? `, uploaded to the Files API (file_id: ${result.section.file_id ?? "?"})`
|
|
93
93
|
: result.transport === "inline"
|
|
94
|
-
?
|
|
94
|
+
? `, inlined as base64 (${(result.bytes / 1024).toFixed(0)} KB)`
|
|
95
95
|
: "";
|
|
96
|
-
const extra = 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 "
|
|
102
|
+
return "Image view aborted";
|
|
103
103
|
}
|
|
104
|
-
return
|
|
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]
|
|
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]
|
|
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]
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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]
|
|
85
|
+
getLogger().warn(`[sdk] Failed to parse MCP config: ${path} — ${err?.message ?? err}`);
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
return items;
|