@ai-zen/agents-sdk 1.0.0-alpha.22 → 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 +216 -184
- package/README.md +13 -0
- package/README.zh.md +13 -0
- package/dist/agent-plugins/AutoMigratePlugin.js +1 -1
- package/dist/agent-plugins/UnknownToolHintPlugin.js +4 -4
- package/dist/config/constants.js +24 -24
- package/dist/config/factory-skills.js +56 -56
- package/dist/runtime/HandoffGuardPlugin.js +2 -2
- package/dist/runtime/HandoffService.js +22 -22
- package/dist/runtime/createAgent.js +2 -2
- 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/package.json +10 -1
|
@@ -4,33 +4,33 @@ export class BatchEditTool extends SdkCallbackTool {
|
|
|
4
4
|
function = {
|
|
5
5
|
name: "batch_edit",
|
|
6
6
|
description: [
|
|
7
|
-
"
|
|
8
|
-
"
|
|
7
|
+
"Edit text in a file in batches. Prefer this tool when making edits to a file.",
|
|
8
|
+
"Submit all changes to the same file in a single call (the replacements array) instead of calling edit in parallel multiple times — parallel edits to the same file overwrite each other.",
|
|
9
9
|
].join("\n"),
|
|
10
10
|
parameters: {
|
|
11
11
|
type: "object",
|
|
12
12
|
properties: {
|
|
13
13
|
path: {
|
|
14
14
|
type: "string",
|
|
15
|
-
description: "
|
|
15
|
+
description: "File path",
|
|
16
16
|
},
|
|
17
17
|
replacements: {
|
|
18
18
|
type: "array",
|
|
19
|
-
description: "
|
|
19
|
+
description: "Array of replacements",
|
|
20
20
|
items: {
|
|
21
21
|
type: "object",
|
|
22
22
|
properties: {
|
|
23
23
|
oldText: {
|
|
24
24
|
type: "string",
|
|
25
|
-
description: "
|
|
25
|
+
description: "Text to replace",
|
|
26
26
|
},
|
|
27
27
|
newText: {
|
|
28
28
|
type: "string",
|
|
29
|
-
description: "
|
|
29
|
+
description: "Replacement text",
|
|
30
30
|
},
|
|
31
31
|
isReplaceAll: {
|
|
32
32
|
type: "boolean",
|
|
33
|
-
description: "
|
|
33
|
+
description: "Whether to replace all matches (by default only the first match is replaced). Make sure the oldText you provide is precise enough to avoid unintended replacements",
|
|
34
34
|
default: false,
|
|
35
35
|
},
|
|
36
36
|
},
|
|
@@ -60,7 +60,7 @@ export class BatchEditTool extends SdkCallbackTool {
|
|
|
60
60
|
failed.push({
|
|
61
61
|
oldText: replacement.oldText,
|
|
62
62
|
newText: replacement.newText,
|
|
63
|
-
reason: "
|
|
63
|
+
reason: "No exact match found for the text to replace",
|
|
64
64
|
});
|
|
65
65
|
continue;
|
|
66
66
|
}
|
|
@@ -3,21 +3,21 @@ import { SdkCallbackTool } from "./SdkCallbackTool.js";
|
|
|
3
3
|
export class CopyTool extends SdkCallbackTool {
|
|
4
4
|
function = {
|
|
5
5
|
name: "copy",
|
|
6
|
-
description: "
|
|
6
|
+
description: "Copy a file or directory (equivalent to the cp command)",
|
|
7
7
|
parameters: {
|
|
8
8
|
type: "object",
|
|
9
9
|
properties: {
|
|
10
10
|
src: {
|
|
11
11
|
type: "string",
|
|
12
|
-
description: "
|
|
12
|
+
description: "Source path",
|
|
13
13
|
},
|
|
14
14
|
dest: {
|
|
15
15
|
type: "string",
|
|
16
|
-
description: "
|
|
16
|
+
description: "Destination path",
|
|
17
17
|
},
|
|
18
18
|
recursive: {
|
|
19
19
|
type: "boolean",
|
|
20
|
-
description: "
|
|
20
|
+
description: "Whether to copy directories recursively; must be true when copying a directory",
|
|
21
21
|
},
|
|
22
22
|
},
|
|
23
23
|
required: ["src", "dest"],
|
|
@@ -2,7 +2,7 @@ import { SdkCallbackTool } from "./SdkCallbackTool.js";
|
|
|
2
2
|
export class CwdTool extends SdkCallbackTool {
|
|
3
3
|
function = {
|
|
4
4
|
name: "cwd",
|
|
5
|
-
description: "
|
|
5
|
+
description: "Get the current working directory (cwd)",
|
|
6
6
|
parameters: {
|
|
7
7
|
type: "object",
|
|
8
8
|
properties: {},
|
|
@@ -4,17 +4,17 @@ import { SdkCallbackTool } from "./SdkCallbackTool.js";
|
|
|
4
4
|
export class DownloadFileTool extends SdkCallbackTool {
|
|
5
5
|
function = {
|
|
6
6
|
name: "download_file",
|
|
7
|
-
description: "
|
|
7
|
+
description: "Download a file from a URL (images, PDFs and other binary files) and save it to the local disk. The file name is inferred from the URL, or you can specify the save path.",
|
|
8
8
|
parameters: {
|
|
9
9
|
type: "object",
|
|
10
10
|
properties: {
|
|
11
11
|
url: {
|
|
12
12
|
type: "string",
|
|
13
|
-
description: "
|
|
13
|
+
description: "URL to download the file from",
|
|
14
14
|
},
|
|
15
15
|
outputPath: {
|
|
16
16
|
type: "string",
|
|
17
|
-
description: "
|
|
17
|
+
description: "Save path (optional). May be a directory or a full file path. If omitted, the file is saved to the current working directory with the file name inferred from the URL.",
|
|
18
18
|
},
|
|
19
19
|
},
|
|
20
20
|
required: ["url"],
|
|
@@ -30,7 +30,7 @@ export class DownloadFileTool extends SdkCallbackTool {
|
|
|
30
30
|
try {
|
|
31
31
|
const url = input.url;
|
|
32
32
|
if (!url)
|
|
33
|
-
throw new Error("url
|
|
33
|
+
throw new Error("url must not be empty");
|
|
34
34
|
if (input.outputPath) {
|
|
35
35
|
savePath = this.resolve(input.outputPath);
|
|
36
36
|
const stat = await fsp.stat(savePath).catch(() => null);
|
|
@@ -48,7 +48,7 @@ export class DownloadFileTool extends SdkCallbackTool {
|
|
|
48
48
|
await fsp.mkdir(path.dirname(savePath), { recursive: true });
|
|
49
49
|
const response = await fetch(url, { signal });
|
|
50
50
|
if (!response.ok) {
|
|
51
|
-
throw new Error(
|
|
51
|
+
throw new Error(`Download failed: HTTP ${response.status} ${response.statusText}`);
|
|
52
52
|
}
|
|
53
53
|
const contentType = response.headers.get("content-type") || "";
|
|
54
54
|
const arrayBuffer = await response.arrayBuffer();
|
|
@@ -61,7 +61,7 @@ export class DownloadFileTool extends SdkCallbackTool {
|
|
|
61
61
|
filePath: path.resolve(savePath),
|
|
62
62
|
fileSize: `${fileSizeKB} KB`,
|
|
63
63
|
contentType,
|
|
64
|
-
note: "
|
|
64
|
+
note: "File saved to local disk",
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
67
|
catch (error) {
|
|
@@ -71,12 +71,12 @@ export class DownloadFileTool extends SdkCallbackTool {
|
|
|
71
71
|
return JSON.stringify({
|
|
72
72
|
success: false,
|
|
73
73
|
aborted: true,
|
|
74
|
-
error: "
|
|
74
|
+
error: "Download aborted",
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
return JSON.stringify({
|
|
78
78
|
success: false,
|
|
79
|
-
error: error?.message || "
|
|
79
|
+
error: error?.message || "Download failed",
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
}
|
|
@@ -16,29 +16,29 @@ export class EditTool extends SdkCallbackTool {
|
|
|
16
16
|
function = {
|
|
17
17
|
name: "edit",
|
|
18
18
|
description: [
|
|
19
|
-
"
|
|
19
|
+
"Edit text in a file, supporting exact replacement or replacing all matches.",
|
|
20
20
|
"",
|
|
21
|
-
"
|
|
22
|
-
"
|
|
21
|
+
"Concurrency limit (important): never edit the same file in parallel. Do not issue multiple edit calls for the same path within one reply — each call reads the old content and writes it back, so the later write overwrites the earlier one, losing changes or corrupting the file.",
|
|
22
|
+
"To apply multiple changes to one file, use batch_edit instead and submit all replacements in a single call. Only edit different files in parallel.",
|
|
23
23
|
].join("\n"),
|
|
24
24
|
parameters: {
|
|
25
25
|
type: "object",
|
|
26
26
|
properties: {
|
|
27
27
|
path: {
|
|
28
28
|
type: "string",
|
|
29
|
-
description: "
|
|
29
|
+
description: "File path",
|
|
30
30
|
},
|
|
31
31
|
oldText: {
|
|
32
32
|
type: "string",
|
|
33
|
-
description: "
|
|
33
|
+
description: "Text to replace",
|
|
34
34
|
},
|
|
35
35
|
newText: {
|
|
36
36
|
type: "string",
|
|
37
|
-
description: "
|
|
37
|
+
description: "Replacement text",
|
|
38
38
|
},
|
|
39
39
|
isReplaceAll: {
|
|
40
40
|
type: "boolean",
|
|
41
|
-
description: "
|
|
41
|
+
description: "Whether to replace all matches (default false, only the first match is replaced). Make sure the oldText you provide is precise enough to avoid unintended replacements",
|
|
42
42
|
default: false,
|
|
43
43
|
},
|
|
44
44
|
},
|
|
@@ -59,7 +59,7 @@ export class EditTool extends SdkCallbackTool {
|
|
|
59
59
|
const count = countOccurrences(content, oldText);
|
|
60
60
|
if (count === 0) {
|
|
61
61
|
return JSON.stringify({
|
|
62
|
-
result: "
|
|
62
|
+
result: "No exact match found for the text to replace",
|
|
63
63
|
matchCount: 0,
|
|
64
64
|
});
|
|
65
65
|
}
|
|
@@ -69,7 +69,7 @@ export class EditTool extends SdkCallbackTool {
|
|
|
69
69
|
await fsp.writeFile(filePath, newContent);
|
|
70
70
|
if (!isReplaceAll && count > 1) {
|
|
71
71
|
return JSON.stringify({
|
|
72
|
-
result:
|
|
72
|
+
result: `Warning: replace-all is off (isReplaceAll=false), but the text "${oldText}" occurs ${count} times in the file; only the first match was replaced. Set isReplaceAll to true to replace all matches`,
|
|
73
73
|
matchCount: count,
|
|
74
74
|
replacedCount: 1,
|
|
75
75
|
});
|
|
@@ -4,17 +4,17 @@ import { DEFAULT_MAX_TOOL_OUTPUT, guardOutput, headTailPreview } from "./outputG
|
|
|
4
4
|
export class ExecTool extends SdkCallbackTool {
|
|
5
5
|
function = {
|
|
6
6
|
name: "exec",
|
|
7
|
-
description: "
|
|
7
|
+
description: "Execute a shell command",
|
|
8
8
|
parameters: {
|
|
9
9
|
type: "object",
|
|
10
10
|
properties: {
|
|
11
11
|
command: {
|
|
12
12
|
type: "string",
|
|
13
|
-
description: "
|
|
13
|
+
description: "Command to execute",
|
|
14
14
|
},
|
|
15
15
|
timeout: {
|
|
16
16
|
type: "number",
|
|
17
|
-
description: "
|
|
17
|
+
description: "Timeout in milliseconds (required). The process is killed on timeout. For long-running commands, prefer spawn to run them asynchronously.",
|
|
18
18
|
},
|
|
19
19
|
},
|
|
20
20
|
required: ["command", "timeout"],
|
|
@@ -29,7 +29,7 @@ export class ExecTool extends SdkCallbackTool {
|
|
|
29
29
|
const { timeout } = input;
|
|
30
30
|
// 运行时双校验:timeout 必填且必须为正数
|
|
31
31
|
if (typeof timeout !== "number" || !Number.isFinite(timeout) || timeout <= 0) {
|
|
32
|
-
throw new Error(`exec:
|
|
32
|
+
throw new Error(`exec: timeout is required and must be a positive number (milliseconds), got: ${JSON.stringify(timeout)}`);
|
|
33
33
|
}
|
|
34
34
|
const signal = ctx?.signal;
|
|
35
35
|
const result = await new Promise((resolve) => {
|
|
@@ -37,7 +37,7 @@ export class ExecTool extends SdkCallbackTool {
|
|
|
37
37
|
if (signal?.aborted) {
|
|
38
38
|
resolve({
|
|
39
39
|
stdout: "",
|
|
40
|
-
stderr: "
|
|
40
|
+
stderr: "Process aborted",
|
|
41
41
|
exitCode: null,
|
|
42
42
|
killed: true,
|
|
43
43
|
terminated: "aborted",
|
|
@@ -72,7 +72,7 @@ export class ExecTool extends SdkCallbackTool {
|
|
|
72
72
|
// 即便 exec 回调因信号处理而未能及时触发,也立即返回中断结果,避免挂起
|
|
73
73
|
settle({
|
|
74
74
|
stdout: "",
|
|
75
|
-
stderr: "
|
|
75
|
+
stderr: "Process aborted",
|
|
76
76
|
exitCode: null,
|
|
77
77
|
killed: true,
|
|
78
78
|
terminated: "aborted",
|
|
@@ -97,8 +97,8 @@ export class ExecTool extends SdkCallbackTool {
|
|
|
97
97
|
const stderr = headTailPreview(result.stderr);
|
|
98
98
|
return JSON.stringify({
|
|
99
99
|
outputTooLarge: true,
|
|
100
|
-
warning:
|
|
101
|
-
|
|
100
|
+
warning: `Output too large: stdout + stderr total ${result.stdout.length + result.stderr.length} characters, ` +
|
|
101
|
+
`exceeds the limit of ${limit} characters. Full content was written to separate files (stdout.log / stderr.log); use read to fetch it in chunks`,
|
|
102
102
|
files: ctx.files,
|
|
103
103
|
stdout: { chars: result.stdout.length, lines: countLines(result.stdout), ...stdout },
|
|
104
104
|
stderr: { chars: result.stderr.length, lines: countLines(result.stderr), ...stderr },
|
|
@@ -3,13 +3,13 @@ import { SdkCallbackTool } from "./SdkCallbackTool.js";
|
|
|
3
3
|
export class ExistTool extends SdkCallbackTool {
|
|
4
4
|
function = {
|
|
5
5
|
name: "exist",
|
|
6
|
-
description: "
|
|
6
|
+
description: "Check whether a file or directory exists",
|
|
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
|
},
|
|
15
15
|
required: ["path"],
|
|
@@ -11,7 +11,7 @@ const DEFAULT_MAX_LINE_LENGTH = 200;
|
|
|
11
11
|
export class FindTextTool extends SdkCallbackTool {
|
|
12
12
|
function = {
|
|
13
13
|
name: "find_text",
|
|
14
|
-
description: "
|
|
14
|
+
description: "Find where text occurs, supporting plain text or regex matching; returns file names with line numbers and line content. To avoid blowing up the context, the total match count, per-file size and line content length are limited by default, and results beyond the limits are truncated and marked truncated.",
|
|
15
15
|
parameters: {
|
|
16
16
|
type: "object",
|
|
17
17
|
properties: {
|
|
@@ -25,30 +25,30 @@ export class FindTextTool extends SdkCallbackTool {
|
|
|
25
25
|
},
|
|
26
26
|
text: {
|
|
27
27
|
type: "string",
|
|
28
|
-
description: "
|
|
28
|
+
description: "Text to search for (mutually exclusive with regex)",
|
|
29
29
|
},
|
|
30
30
|
regex: {
|
|
31
31
|
type: "string",
|
|
32
|
-
description: "
|
|
32
|
+
description: "Regular expression (mutually exclusive with text, e.g. \\bconst\\s+\\w+)",
|
|
33
33
|
},
|
|
34
34
|
exclude: {
|
|
35
35
|
type: "array",
|
|
36
|
-
description: "
|
|
36
|
+
description: "Array of glob patterns to exclude",
|
|
37
37
|
items: {
|
|
38
38
|
type: "string",
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
41
|
maxMatches: {
|
|
42
42
|
type: "number",
|
|
43
|
-
description: "
|
|
43
|
+
description: "Maximum total matches (default 200)",
|
|
44
44
|
},
|
|
45
45
|
maxFileSize: {
|
|
46
46
|
type: "number",
|
|
47
|
-
description: "
|
|
47
|
+
description: "Maximum file size in bytes; larger files are skipped (default 307200, i.e. 300KB)",
|
|
48
48
|
},
|
|
49
49
|
maxLineLength: {
|
|
50
50
|
type: "number",
|
|
51
|
-
description: "
|
|
51
|
+
description: "Truncation length for line content and matched substrings (default 200)",
|
|
52
52
|
},
|
|
53
53
|
},
|
|
54
54
|
required: ["path", "pattern"],
|
|
@@ -65,7 +65,7 @@ export class FindTextTool extends SdkCallbackTool {
|
|
|
65
65
|
const text = input.text;
|
|
66
66
|
const regexStr = input.regex;
|
|
67
67
|
if (!text && !regexStr) {
|
|
68
|
-
return "
|
|
68
|
+
return "Provide either the text or the regex parameter";
|
|
69
69
|
}
|
|
70
70
|
const regex = regexStr ? new RegExp(regexStr) : null;
|
|
71
71
|
const maxMatches = input.maxMatches ?? DEFAULT_MAX_MATCHES;
|
|
@@ -153,8 +153,8 @@ export class FindTextTool extends SdkCallbackTool {
|
|
|
153
153
|
const preview = headPreview(json);
|
|
154
154
|
return JSON.stringify({
|
|
155
155
|
outputTooLarge: true,
|
|
156
|
-
warning:
|
|
157
|
-
|
|
156
|
+
warning: `Output too large: the results total ${json.length} characters, exceeding the limit of ${limit} characters. ` +
|
|
157
|
+
`The full result has been written to disk (result.json) and can be read in chunks with read.`,
|
|
158
158
|
files: ctx.files,
|
|
159
159
|
chars: json.length,
|
|
160
160
|
...preview,
|
|
@@ -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) {
|