@ai-zen/agents-sdk 0.11.0 → 1.0.0-alpha.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 (116) hide show
  1. package/CHANGELOG.md +85 -24
  2. package/README.md +37 -26
  3. package/README.zh.md +37 -26
  4. package/dist/{plugin → agent-plugins}/AutoRefreshToolsPlugin.js +2 -2
  5. package/dist/{plugin → agent-plugins}/UnknownToolHintPlugin.d.ts +7 -5
  6. package/dist/{plugin → agent-plugins}/UnknownToolHintPlugin.js +9 -5
  7. package/dist/config/ConfigManager.d.ts +3 -1
  8. package/dist/config/ConfigManager.js +31 -4
  9. package/dist/config/constants.js +6 -1
  10. package/dist/index.d.ts +37 -29
  11. package/dist/index.js +28 -21
  12. package/dist/runtime/SdkAgent.d.ts +5 -5
  13. package/dist/runtime/SdkAgent.js +4 -4
  14. package/dist/runtime/TaskMigrationService.d.ts +1 -1
  15. package/dist/runtime/TaskMigrationService.js +2 -2
  16. package/dist/runtime/createAgent.d.ts +4 -4
  17. package/dist/runtime/createAgent.js +8 -8
  18. package/dist/runtime/createModel.d.ts +3 -3
  19. package/dist/runtime/createModel.js +3 -3
  20. package/dist/scope/Scope.d.ts +111 -0
  21. package/dist/scope/Scope.js +165 -0
  22. package/dist/scope/ScopePlugin.d.ts +51 -0
  23. package/dist/scope/ScopePlugin.js +1 -0
  24. package/dist/scope/plugins/allInOne.d.ts +18 -0
  25. package/dist/scope/plugins/allInOne.js +23 -0
  26. package/dist/{capabilities/implements → scope/plugins}/builtin/BatchEditTool.d.ts +1 -1
  27. package/dist/{capabilities/implements → scope/plugins}/builtin/BatchEditTool.js +12 -10
  28. package/dist/scope/plugins/builtin/BuiltinToolsScopePlugin.d.ts +20 -0
  29. package/dist/scope/plugins/builtin/BuiltinToolsScopePlugin.js +30 -0
  30. package/dist/{capabilities/implements → scope/plugins}/builtin/CopyTool.d.ts +1 -1
  31. package/dist/{capabilities/implements → scope/plugins}/builtin/CopyTool.js +1 -1
  32. package/dist/{capabilities/implements → scope/plugins}/builtin/CwdTool.d.ts +1 -1
  33. package/dist/{capabilities/implements → scope/plugins}/builtin/CwdTool.js +1 -1
  34. package/dist/{capabilities/implements → scope/plugins}/builtin/DownloadFileTool.d.ts +1 -1
  35. package/dist/{capabilities/implements → scope/plugins}/builtin/DownloadFileTool.js +1 -1
  36. package/dist/{capabilities/implements → scope/plugins}/builtin/EditTool.d.ts +1 -1
  37. package/dist/{capabilities/implements → scope/plugins}/builtin/EditTool.js +1 -1
  38. package/dist/{capabilities/implements → scope/plugins}/builtin/ExecAsyncTool.d.ts +1 -1
  39. package/dist/{capabilities/implements → scope/plugins}/builtin/ExecAsyncTool.js +1 -1
  40. package/dist/{capabilities/implements → scope/plugins}/builtin/ExecTool.d.ts +1 -1
  41. package/dist/{capabilities/implements → scope/plugins}/builtin/ExecTool.js +34 -2
  42. package/dist/{capabilities/implements → scope/plugins}/builtin/ExistTool.d.ts +1 -1
  43. package/dist/{capabilities/implements → scope/plugins}/builtin/ExistTool.js +1 -1
  44. package/dist/{capabilities/implements → scope/plugins}/builtin/FindTextTool.d.ts +6 -1
  45. package/dist/{capabilities/implements → scope/plugins}/builtin/FindTextTool.js +29 -4
  46. package/dist/{capabilities/implements → scope/plugins}/builtin/GenerateImageTool.d.ts +1 -1
  47. package/dist/{capabilities/implements → scope/plugins}/builtin/GenerateImageTool.js +1 -1
  48. package/dist/{capabilities/implements → scope/plugins}/builtin/GlobTool.d.ts +6 -1
  49. package/dist/{capabilities/implements → scope/plugins}/builtin/GlobTool.js +29 -3
  50. package/dist/scope/plugins/builtin/InspectFileTool.d.ts +17 -0
  51. package/dist/scope/plugins/builtin/InspectFileTool.js +150 -0
  52. package/dist/{capabilities/implements → scope/plugins}/builtin/LsTool.d.ts +1 -1
  53. package/dist/scope/plugins/builtin/LsTool.js +52 -0
  54. package/dist/{capabilities/implements → scope/plugins}/builtin/MkdirTool.d.ts +1 -1
  55. package/dist/{capabilities/implements → scope/plugins}/builtin/MkdirTool.js +1 -1
  56. package/dist/{capabilities/implements → scope/plugins}/builtin/ReadFileTool.d.ts +2 -1
  57. package/dist/scope/plugins/builtin/ReadFileTool.js +94 -0
  58. package/dist/{capabilities/implements → scope/plugins}/builtin/RenameTool.d.ts +1 -1
  59. package/dist/{capabilities/implements → scope/plugins}/builtin/RenameTool.js +1 -1
  60. package/dist/{capabilities/implements → scope/plugins}/builtin/RmTool.d.ts +1 -1
  61. package/dist/{capabilities/implements → scope/plugins}/builtin/RmTool.js +1 -1
  62. package/dist/{runtime → scope/plugins/builtin}/SdkCallbackTool.d.ts +1 -1
  63. package/dist/{capabilities/implements → scope/plugins}/builtin/SleepTool.d.ts +1 -1
  64. package/dist/{capabilities/implements → scope/plugins}/builtin/SleepTool.js +1 -1
  65. package/dist/{capabilities/implements → scope/plugins}/builtin/ViewImageTool.d.ts +1 -1
  66. package/dist/{capabilities/implements → scope/plugins}/builtin/ViewImageTool.js +1 -1
  67. package/dist/{capabilities/implements → scope/plugins}/builtin/WriteFileTool.d.ts +1 -1
  68. package/dist/{capabilities/implements → scope/plugins}/builtin/WriteFileTool.js +1 -1
  69. package/dist/{capabilities/discovery/builtin.d.ts → scope/plugins/builtin/discover.d.ts} +1 -1
  70. package/dist/{capabilities/discovery/builtin.js → scope/plugins/builtin/discover.js} +1 -1
  71. package/dist/{capabilities/implements → scope/plugins}/builtin/index.d.ts +5 -4
  72. package/dist/{capabilities/implements → scope/plugins}/builtin/index.js +5 -3
  73. package/dist/scope/plugins/builtin/outputGuard.d.ts +81 -0
  74. package/dist/scope/plugins/builtin/outputGuard.js +73 -0
  75. package/dist/{runtime → scope/plugins/mcp}/McpConnectionManager.d.ts +1 -1
  76. package/dist/{runtime → scope/plugins/mcp}/McpConnectionManager.js +1 -1
  77. package/dist/scope/plugins/mcp/McpScopePlugin.d.ts +29 -0
  78. package/dist/scope/plugins/mcp/McpScopePlugin.js +60 -0
  79. package/dist/{capabilities/discovery/mcp.d.ts → scope/plugins/mcp/discover.d.ts} +1 -1
  80. package/dist/{capabilities/discovery/mcp.js → scope/plugins/mcp/discover.js} +1 -1
  81. package/dist/{capabilities/implements → scope/plugins/mcp}/mcpTools.d.ts +2 -2
  82. package/dist/{capabilities/implements → scope/plugins/mcp}/mcpTools.js +2 -2
  83. package/dist/scope/plugins/skills/SkillsScopePlugin.d.ts +28 -0
  84. package/dist/scope/plugins/skills/SkillsScopePlugin.js +48 -0
  85. package/dist/{capabilities/discovery/skills.js → scope/plugins/skills/discover.js} +1 -1
  86. package/dist/{capabilities/implements → scope/plugins/skills}/skillTools.d.ts +1 -1
  87. package/dist/{capabilities/implements → scope/plugins/skills}/skillTools.js +3 -3
  88. package/dist/scope/plugins/subagents/SubAgentsScopePlugin.d.ts +20 -0
  89. package/dist/scope/plugins/subagents/SubAgentsScopePlugin.js +34 -0
  90. package/dist/{capabilities/discovery/subagents.d.ts → scope/plugins/subagents/discover.d.ts} +1 -1
  91. package/dist/{capabilities/implements → scope/plugins/subagents}/subAgentTools.d.ts +3 -3
  92. package/dist/{capabilities/implements → scope/plugins/subagents}/subAgentTools.js +5 -5
  93. package/dist/scope/plugins/usertools/UserToolsScopePlugin.d.ts +24 -0
  94. package/dist/scope/plugins/usertools/UserToolsScopePlugin.js +28 -0
  95. package/dist/{capabilities/discovery/usertools.js → scope/plugins/usertools/discover.js} +1 -1
  96. package/dist/types/index.d.ts +17 -2
  97. package/package.json +3 -3
  98. package/dist/capabilities/implements/builtin/LsTool.js +0 -31
  99. package/dist/capabilities/implements/builtin/ReadFileTool.js +0 -35
  100. package/dist/runtime/Provider.d.ts +0 -119
  101. package/dist/runtime/Provider.js +0 -218
  102. /package/dist/{plugin → agent-plugins}/AutoMigratePlugin.d.ts +0 -0
  103. /package/dist/{plugin → agent-plugins}/AutoMigratePlugin.js +0 -0
  104. /package/dist/{plugin → agent-plugins}/AutoRefreshToolsPlugin.d.ts +0 -0
  105. /package/dist/{plugin → agent-plugins}/ContextGuardPlugin.d.ts +0 -0
  106. /package/dist/{plugin → agent-plugins}/ContextGuardPlugin.js +0 -0
  107. /package/dist/{capabilities → scope}/PermissionEvaluator.d.ts +0 -0
  108. /package/dist/{capabilities → scope}/PermissionEvaluator.js +0 -0
  109. /package/dist/{capabilities → scope}/disclosure.d.ts +0 -0
  110. /package/dist/{capabilities → scope}/disclosure.js +0 -0
  111. /package/dist/{runtime → scope/plugins/builtin}/SdkCallbackTool.js +0 -0
  112. /package/dist/{capabilities/implements → scope/plugins}/builtin/test-helpers.d.ts +0 -0
  113. /package/dist/{capabilities/implements → scope/plugins}/builtin/test-helpers.js +0 -0
  114. /package/dist/{capabilities/discovery/skills.d.ts → scope/plugins/skills/discover.d.ts} +0 -0
  115. /package/dist/{capabilities/discovery/subagents.js → scope/plugins/subagents/discover.js} +0 -0
  116. /package/dist/{capabilities/discovery/usertools.d.ts → scope/plugins/usertools/discover.d.ts} +0 -0
@@ -0,0 +1,150 @@
1
+ import * as fsp from "fs/promises";
2
+ import { createReadStream } from "fs";
3
+ import { StringDecoder } from "string_decoder";
4
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
5
+ import { DEFAULT_MAX_TOOL_OUTPUT } from "./outputGuard.js";
6
+ /**
7
+ * 勘察文件结构概况(行数、每行列数等),不做内容读取。
8
+ *
9
+ * 定位与 readFile 的 range 配套:大文件先看结构(有多少行、每行多长),
10
+ * 再决定 readFile 的读取范围。流式扫描,故不受 readFile 的 300KB 读取阈值限制。
11
+ */
12
+ export class InspectFileTool extends SdkCallbackTool {
13
+ function = {
14
+ name: "inspectFile",
15
+ description: "勘察文件的结构概况:总行数、总字符数、最长行的列数及其行索引、平均列数、行尾类型(LF/CRLF)。可选返回每行的列数映射。适用于在 readFile 之前先了解文件规模,再决定用 range 读取哪一段。仅做流式扫描,不受 readFile 的 300KB 读取阈值限制。",
16
+ parameters: {
17
+ type: "object",
18
+ properties: {
19
+ path: {
20
+ type: "string",
21
+ description: "文件路径",
22
+ },
23
+ withColCountMap: {
24
+ type: "boolean",
25
+ description: "是否返回每行列数映射(对象:行索引 → 列数,行索引从 0 开始)。默认 false。行数很多时该映射可能过大,此时将只返回概况字段。",
26
+ default: false,
27
+ },
28
+ },
29
+ required: ["path"],
30
+ additionalProperties: false,
31
+ },
32
+ };
33
+ constructor(env) {
34
+ super({ env });
35
+ }
36
+ async call(input) {
37
+ try {
38
+ const filePath = this.resolve(input.path);
39
+ const stats = await fsp.stat(filePath);
40
+ if (!stats.isFile()) {
41
+ return `"${filePath}" 不是文件`;
42
+ }
43
+ const withColCountMap = input.withColCountMap ?? false;
44
+ const result = await scan(filePath, withColCountMap);
45
+ const summary = {
46
+ path: filePath,
47
+ bytes: stats.size,
48
+ lines: result.lines,
49
+ chars: result.chars,
50
+ maxCol: result.maxCol,
51
+ lineIndexOfMaxCol: result.lineIndexOfMaxCol,
52
+ avgCol: result.lines === 0 ? 0 : Math.round(result.chars / result.lines),
53
+ lineEnding: result.lineEnding,
54
+ };
55
+ if (!withColCountMap)
56
+ return JSON.stringify(summary);
57
+ // 明细超限时只返回概况 + 提示(不落盘):文件规模已超出可处理范围
58
+ const limit = this.env.config.maxToolOutput ?? DEFAULT_MAX_TOOL_OUTPUT;
59
+ const payload = JSON.stringify({ ...summary, colCountMap: result.colCountMap });
60
+ if (payload.length > limit) {
61
+ return JSON.stringify({
62
+ ...summary,
63
+ colCountMapOmitted: true,
64
+ warning: `行长度明细过大:概况与 colCountMap 合计 ${payload.length} 字符,` +
65
+ `超过上限 ${limit} 字符,未落盘返回。文件规模超出可处理范围,` +
66
+ `建议改用 findText 定位后再按 range 分段读取。`,
67
+ });
68
+ }
69
+ return payload;
70
+ }
71
+ catch (error) {
72
+ return error?.message;
73
+ }
74
+ }
75
+ }
76
+ /**
77
+ * 流式扫描文件,统计行数、字符数与每行列数。
78
+ *
79
+ * 口径:行索引 0-based;列数按字符数(UTF-16 长度)计、不含行尾换行符(CRLF 的 \r 不计)。
80
+ */
81
+ async function scan(filePath, withColCountMap) {
82
+ const decoder = new StringDecoder("utf8");
83
+ const colCountMap = {};
84
+ let lines = 0;
85
+ let chars = 0;
86
+ let col = 0;
87
+ let maxCol = 0;
88
+ let lineIndexOfMaxCol = 0;
89
+ let sawLf = false;
90
+ let sawCrlf = false;
91
+ let lastWasNewline = false;
92
+ let sawAnyChar = false;
93
+ /** 上一个字符是 \r,等待判定它是否属于 CRLF */
94
+ let pendingCr = false;
95
+ const endLine = () => {
96
+ if (withColCountMap)
97
+ colCountMap[String(lines)] = col;
98
+ if (col > maxCol) {
99
+ maxCol = col;
100
+ lineIndexOfMaxCol = lines;
101
+ }
102
+ chars += col;
103
+ lines++;
104
+ col = 0;
105
+ lastWasNewline = true;
106
+ };
107
+ const processText = (text) => {
108
+ // 按 code unit 遍历,与 String.length 口径一致
109
+ for (let index = 0; index < text.length; index++) {
110
+ const char = text[index];
111
+ sawAnyChar = true;
112
+ if (char === "\n") {
113
+ if (pendingCr) {
114
+ sawCrlf = true;
115
+ pendingCr = false;
116
+ }
117
+ else {
118
+ sawLf = true;
119
+ }
120
+ endLine();
121
+ continue;
122
+ }
123
+ // 前一个字符是 \r 且其后不是 \n:属孤立的 \r,作为行内字符计入
124
+ if (pendingCr) {
125
+ col++;
126
+ pendingCr = false;
127
+ }
128
+ if (char === "\r") {
129
+ pendingCr = true;
130
+ lastWasNewline = false;
131
+ continue;
132
+ }
133
+ col++;
134
+ lastWasNewline = false;
135
+ }
136
+ };
137
+ const stream = createReadStream(filePath);
138
+ for await (const chunk of stream) {
139
+ processText(decoder.write(chunk));
140
+ }
141
+ processText(decoder.end());
142
+ // 文件末尾残留的孤立 \r
143
+ if (pendingCr)
144
+ col++;
145
+ // 末行未以换行结束(空文件不计行)
146
+ if (sawAnyChar && !lastWasNewline)
147
+ endLine();
148
+ const lineEnding = sawCrlf && sawLf ? "mixed" : sawCrlf ? "CRLF" : "LF";
149
+ return { lines, chars, maxCol, lineIndexOfMaxCol, lineEnding, colCountMap };
150
+ }
@@ -1,4 +1,4 @@
1
- import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
1
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
2
2
  import type { ToolEnv } from "../../../types/index.js";
3
3
  import type { AgentNS } from "@ai-zen/agents-core";
4
4
  export declare class LsTool extends SdkCallbackTool {
@@ -0,0 +1,52 @@
1
+ import * as fsp from "fs/promises";
2
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
3
+ import { DEFAULT_MAX_TOOL_OUTPUT, guardOutput, headPreview } from "./outputGuard.js";
4
+ export class LsTool extends SdkCallbackTool {
5
+ function = {
6
+ name: "ls",
7
+ description: "列出目录",
8
+ parameters: {
9
+ type: "object",
10
+ properties: {
11
+ path: {
12
+ type: "string",
13
+ description: "目录路径",
14
+ },
15
+ },
16
+ required: ["path"],
17
+ additionalProperties: false,
18
+ },
19
+ };
20
+ constructor(env) {
21
+ super({ env });
22
+ }
23
+ async call(input) {
24
+ try {
25
+ const entries = await fsp.readdir(this.resolve(input.path));
26
+ const json = JSON.stringify(entries);
27
+ // 输出保护:结果超过 maxToolOutput 时落盘为 result.json,返回警告 + 头部预览
28
+ const limit = this.env.config.maxToolOutput ?? DEFAULT_MAX_TOOL_OUTPUT;
29
+ return await guardOutput({
30
+ tool: "ls",
31
+ content: json,
32
+ isOverLimit: (text) => text.length > limit,
33
+ dump: (_dir, text) => [{ name: "result.json", content: text }],
34
+ buildWarning: (ctx) => {
35
+ const preview = headPreview(json);
36
+ return JSON.stringify({
37
+ outputTooLarge: true,
38
+ warning: `输出过大:目录条目共 ${entries.length} 项、${json.length} 字符,超过上限 ${limit} 字符。` +
39
+ `完整列表已落盘(result.json),可用 readFile 分批读取;` +
40
+ `也可改用 glob 按模式筛选。`,
41
+ files: ctx.files,
42
+ chars: json.length,
43
+ ...preview,
44
+ });
45
+ },
46
+ });
47
+ }
48
+ catch (error) {
49
+ return error?.message;
50
+ }
51
+ }
52
+ }
@@ -1,4 +1,4 @@
1
- import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
1
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
2
2
  import type { ToolEnv } from "../../../types/index.js";
3
3
  import type { AgentNS } from "@ai-zen/agents-core";
4
4
  export declare class MkdirTool extends SdkCallbackTool {
@@ -1,5 +1,5 @@
1
1
  import * as fsp from "fs/promises";
2
- import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
2
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
3
3
  export class MkdirTool extends SdkCallbackTool {
4
4
  function = {
5
5
  name: "mkdir",
@@ -1,4 +1,4 @@
1
- import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
1
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
2
2
  import type { ToolEnv } from "../../../types/index.js";
3
3
  import type { AgentNS } from "@ai-zen/agents-core";
4
4
  export declare class ReadFileTool extends SdkCallbackTool {
@@ -6,5 +6,6 @@ export declare class ReadFileTool extends SdkCallbackTool {
6
6
  constructor(env: ToolEnv);
7
7
  call(input: {
8
8
  path: string;
9
+ range?: number[];
9
10
  }): Promise<string>;
10
11
  }
@@ -0,0 +1,94 @@
1
+ import * as fsp from "fs/promises";
2
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
3
+ import { DEFAULT_MAX_TOOL_OUTPUT, guardOutput } from "./outputGuard.js";
4
+ export class ReadFileTool extends SdkCallbackTool {
5
+ function = {
6
+ name: "readFile",
7
+ description: "读取文件",
8
+ parameters: {
9
+ type: "object",
10
+ properties: {
11
+ path: {
12
+ type: "string",
13
+ description: "文件路径",
14
+ },
15
+ range: {
16
+ type: "array",
17
+ description: "读取范围 [起始行, 起始列, 结束行, 结束列],行列均从 0 开始,-1 表示末位;" +
18
+ "例如 [0, 0, 100, -1] 表示从第 0 行第 0 列读到第 100 行最后一列。省略则读取整个文件。",
19
+ items: {
20
+ type: "number",
21
+ },
22
+ },
23
+ },
24
+ required: ["path"],
25
+ additionalProperties: false,
26
+ },
27
+ };
28
+ constructor(env) {
29
+ super({ env });
30
+ }
31
+ async call(input) {
32
+ try {
33
+ const filePath = this.resolve(input.path);
34
+ const stats = await fsp.stat(filePath);
35
+ // 读取阈值:文件过大时拒绝读取(与输出阈值 maxToolOutput 无关)
36
+ if (stats.size > 300 * 1024) {
37
+ throw new Error(`文件过大,无法读取,当前文件大小 ${stats.size} 字节`);
38
+ }
39
+ const content = await fsp.readFile(filePath, "utf-8");
40
+ const output = input.range ? sliceByRange(content, input.range) : content;
41
+ // 输出保护:本次返回内容超过上限时只警告、不落盘,并提示用 range 分批读取
42
+ const limit = this.env.config.maxToolOutput ?? DEFAULT_MAX_TOOL_OUTPUT;
43
+ return await guardOutput({
44
+ tool: "readFile",
45
+ content: output,
46
+ isOverLimit: (text) => text.length > limit,
47
+ buildWarning: () => `读取内容过大:本次输出 ${output.length} 字符,超过上限 ${limit} 字符,未落盘。` +
48
+ `文件共 ${countLines(content)} 行、${content.length} 字符,` +
49
+ `请用 range 参数分范围读取(形如 [起始行, 起始列, 结束行, 结束列],行列从 0 开始,-1 表示末位)。`,
50
+ });
51
+ }
52
+ catch (error) {
53
+ return error?.message;
54
+ }
55
+ }
56
+ }
57
+ /**
58
+ * 按 [起始行, 起始列, 结束行, 结束列] 切片(0-based,-1 表末位)。
59
+ *
60
+ * - 起始行至结束行逐行取出;起始行从起始列起截取,结束行截取到结束列(含);
61
+ * - 结束列为 -1 时取到行末,故 [0, 0, 100, -1] 即"第 0 行第 0 列到第 100 行末";
62
+ * - 越界索引自动夹取到有效范围。
63
+ */
64
+ function sliceByRange(content, range) {
65
+ const lines = content.split("\n");
66
+ const [rawStartLine = 0, rawStartCol = 0, rawEndLine = -1, rawEndCol = -1] = range;
67
+ const startLine = resolveIndex(rawStartLine, lines.length);
68
+ const endLine = resolveIndex(rawEndLine, lines.length);
69
+ if (endLine < startLine)
70
+ return "";
71
+ const selected = [];
72
+ for (let index = startLine; index <= endLine; index++) {
73
+ const line = lines[index] ?? "";
74
+ const from = index === startLine ? resolveIndex(rawStartCol, line.length) : 0;
75
+ const to = index === endLine ? resolveIndex(rawEndCol, line.length) : line.length - 1;
76
+ selected.push(line.slice(from, to + 1));
77
+ }
78
+ return selected.join("\n");
79
+ }
80
+ /** 解析行列索引:-1 表末位,其余负值自末尾倒数,越界夹取到有效范围 */
81
+ function resolveIndex(index, length) {
82
+ if (!Number.isFinite(index) || length === 0)
83
+ return 0;
84
+ const normalized = index < 0 ? length + index : index;
85
+ if (normalized < 0)
86
+ return 0;
87
+ if (normalized > length - 1)
88
+ return length - 1;
89
+ return normalized;
90
+ }
91
+ /** 统计文本行数(空文本记 0 行) */
92
+ function countLines(text) {
93
+ return text.length === 0 ? 0 : text.split("\n").length;
94
+ }
@@ -1,4 +1,4 @@
1
- import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
1
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
2
2
  import type { ToolEnv } from "../../../types/index.js";
3
3
  import type { AgentNS } from "@ai-zen/agents-core";
4
4
  export declare class RenameTool extends SdkCallbackTool {
@@ -1,5 +1,5 @@
1
1
  import * as fsp from "fs/promises";
2
- import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
2
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
3
3
  export class RenameTool extends SdkCallbackTool {
4
4
  function = {
5
5
  name: "rename",
@@ -1,4 +1,4 @@
1
- import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
1
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
2
2
  import type { ToolEnv } from "../../../types/index.js";
3
3
  import type { AgentNS } from "@ai-zen/agents-core";
4
4
  export declare class RmTool extends SdkCallbackTool {
@@ -1,5 +1,5 @@
1
1
  import * as fsp from "fs/promises";
2
- import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
2
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
3
3
  export class RmTool extends SdkCallbackTool {
4
4
  function = {
5
5
  name: "rm",
@@ -1,6 +1,6 @@
1
1
  import { Tool, ToolCallContext } from "@ai-zen/agents-core";
2
2
  import type { AgentNS } from "@ai-zen/agents-core";
3
- import type { AgentDefinition, AppConfig, ToolEnv } from "../types/index.js";
3
+ import type { AgentDefinition, AppConfig, ToolEnv } from "../../../types/index.js";
4
4
  /** SdkCallbackTool 构造选项。env 为核心字段,未来可在此扩展可选项。 */
5
5
  export interface SdkCallbackToolOptions {
6
6
  /** 注入的工具环境 */
@@ -1,4 +1,4 @@
1
- import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
1
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
2
2
  import type { ToolEnv } from "../../../types/index.js";
3
3
  import type { AgentNS, ToolCallContext } from "@ai-zen/agents-core";
4
4
  export declare class SleepTool extends SdkCallbackTool {
@@ -1,4 +1,4 @@
1
- import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
1
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
2
2
  export class SleepTool extends SdkCallbackTool {
3
3
  function = {
4
4
  name: "sleep",
@@ -1,5 +1,5 @@
1
1
  import type { AgentNS, ToolCallContext } from "@ai-zen/agents-core";
2
- import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
2
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
3
3
  import type { AgentDefinition, AppConfig, ToolEnv } from "../../../types/index.js";
4
4
  /**
5
5
  * 查看图片工具 — 让 Agent 主动查看/分析一张图片。**仅对视觉模型可用**:
@@ -1,7 +1,7 @@
1
1
  import OpenAI, { toFile } from "openai";
2
2
  import { promises as fs } from "node:fs";
3
3
  import path from "node:path";
4
- import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
4
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
5
5
  const SUPPORTED_EXT = [".jpg", ".jpeg", ".png", ".gif", ".webp"];
6
6
  /**
7
7
  * 是否为"本地 URL"——指向本地/回环地址,API 服务商无法下载访问。
@@ -1,4 +1,4 @@
1
- import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
1
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
2
2
  import type { ToolEnv } from "../../../types/index.js";
3
3
  import type { AgentNS } from "@ai-zen/agents-core";
4
4
  export declare class WriteFileTool extends SdkCallbackTool {
@@ -1,6 +1,6 @@
1
1
  import * as fsp from "fs/promises";
2
2
  import * as path from "path";
3
- import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
3
+ import { SdkCallbackTool } from "./SdkCallbackTool.js";
4
4
  export class WriteFileTool extends SdkCallbackTool {
5
5
  function = {
6
6
  name: "writeFile",
@@ -1,5 +1,5 @@
1
1
  import type { Tool } from "@ai-zen/agents-core";
2
- import type { ToolEnv } from "../../types/index.js";
2
+ import type { ToolEnv } from "../../../types/index.js";
3
3
  /**
4
4
  * 发现内置工具:按静态注册表实例化全部内置工具(无任何过滤)。
5
5
  *
@@ -1,4 +1,4 @@
1
- import { BUILTIN_TOOL_CLASSES } from "../implements/builtin/index.js";
1
+ import { BUILTIN_TOOL_CLASSES } from "./index.js";
2
2
  /**
3
3
  * 发现内置工具:按静态注册表实例化全部内置工具(无任何过滤)。
4
4
  *
@@ -1,7 +1,8 @@
1
- import type { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
1
+ import type { SdkCallbackTool } from "./SdkCallbackTool.js";
2
2
  import type { ToolEnv } from "../../../types/index.js";
3
3
  import { CwdTool } from "./CwdTool.js";
4
4
  import { ReadFileTool } from "./ReadFileTool.js";
5
+ import { InspectFileTool } from "./InspectFileTool.js";
5
6
  import { WriteFileTool } from "./WriteFileTool.js";
6
7
  import { ExecTool } from "./ExecTool.js";
7
8
  import { MkdirTool } from "./MkdirTool.js";
@@ -20,12 +21,12 @@ import { SleepTool } from "./SleepTool.js";
20
21
  import { ViewImageTool } from "./ViewImageTool.js";
21
22
  import { GenerateImageTool } from "./GenerateImageTool.js";
22
23
  /**
23
- * 全部内置工具类(19 个)。
24
- * 工具类由 Provider 用 ToolEnv 实例化(每个 Provider 一套实例,注入其 cwd)。
24
+ * 全部内置工具类(20 个)。
25
+ * 工具类由 Scope 的内置工具插件(BuiltinToolsScopePlugin)用 ToolEnv 实例化(每个 Scope 一套实例,注入其 cwd)。
25
26
  *
26
27
  * 发现层不做任何过滤——工具的可用性由各工具自行声明(SdkCallbackTool.isAvailable,
27
28
  * 入参含完整 config + 模型信息),在 buildTools/filter 阶段按声明过滤。
28
29
  * 如 GenerateImageTool 依赖 defaultImageModel、ViewImageTool 仅视觉模型可用。
29
30
  */
30
31
  export declare const BUILTIN_TOOL_CLASSES: Array<new (env: ToolEnv) => SdkCallbackTool>;
31
- export { CwdTool, ReadFileTool, WriteFileTool, ExecTool, MkdirTool, RmTool, GlobTool, LsTool, ExistTool, FindTextTool, DownloadFileTool, RenameTool, CopyTool, BatchEditTool, EditTool, ExecAsyncTool, SleepTool, ViewImageTool, GenerateImageTool, };
32
+ export { CwdTool, ReadFileTool, InspectFileTool, WriteFileTool, ExecTool, MkdirTool, RmTool, GlobTool, LsTool, ExistTool, FindTextTool, DownloadFileTool, RenameTool, CopyTool, BatchEditTool, EditTool, ExecAsyncTool, SleepTool, ViewImageTool, GenerateImageTool, };
@@ -1,5 +1,6 @@
1
1
  import { CwdTool } from "./CwdTool.js";
2
2
  import { ReadFileTool } from "./ReadFileTool.js";
3
+ import { InspectFileTool } from "./InspectFileTool.js";
3
4
  import { WriteFileTool } from "./WriteFileTool.js";
4
5
  import { ExecTool } from "./ExecTool.js";
5
6
  import { MkdirTool } from "./MkdirTool.js";
@@ -18,8 +19,8 @@ import { SleepTool } from "./SleepTool.js";
18
19
  import { ViewImageTool } from "./ViewImageTool.js";
19
20
  import { GenerateImageTool } from "./GenerateImageTool.js";
20
21
  /**
21
- * 全部内置工具类(19 个)。
22
- * 工具类由 Provider 用 ToolEnv 实例化(每个 Provider 一套实例,注入其 cwd)。
22
+ * 全部内置工具类(20 个)。
23
+ * 工具类由 Scope 的内置工具插件(BuiltinToolsScopePlugin)用 ToolEnv 实例化(每个 Scope 一套实例,注入其 cwd)。
23
24
  *
24
25
  * 发现层不做任何过滤——工具的可用性由各工具自行声明(SdkCallbackTool.isAvailable,
25
26
  * 入参含完整 config + 模型信息),在 buildTools/filter 阶段按声明过滤。
@@ -28,6 +29,7 @@ import { GenerateImageTool } from "./GenerateImageTool.js";
28
29
  export const BUILTIN_TOOL_CLASSES = [
29
30
  CwdTool,
30
31
  ReadFileTool,
32
+ InspectFileTool,
31
33
  WriteFileTool,
32
34
  ExecTool,
33
35
  MkdirTool,
@@ -46,4 +48,4 @@ export const BUILTIN_TOOL_CLASSES = [
46
48
  ViewImageTool,
47
49
  GenerateImageTool,
48
50
  ];
49
- export { CwdTool, ReadFileTool, WriteFileTool, ExecTool, MkdirTool, RmTool, GlobTool, LsTool, ExistTool, FindTextTool, DownloadFileTool, RenameTool, CopyTool, BatchEditTool, EditTool, ExecAsyncTool, SleepTool, ViewImageTool, GenerateImageTool, };
51
+ export { CwdTool, ReadFileTool, InspectFileTool, WriteFileTool, ExecTool, MkdirTool, RmTool, GlobTool, LsTool, ExistTool, FindTextTool, DownloadFileTool, RenameTool, CopyTool, BatchEditTool, EditTool, ExecAsyncTool, SleepTool, ViewImageTool, GenerateImageTool, };
@@ -0,0 +1,81 @@
1
+ /**
2
+ * 工具输出上限的缺省值(字符数)。
3
+ *
4
+ * 可由 AppConfig.maxToolOutput 覆盖;上限由各工具自行读取并判定,
5
+ * 骨架不感知配置,以便不同工具按自身口径(如 stdout/stderr 合计)判断。
6
+ */
7
+ export declare const DEFAULT_MAX_TOOL_OUTPUT = 32768;
8
+ /** 待落盘的文件:文件名(不含目录)+ 内容 */
9
+ export interface GuardDumpFile {
10
+ /** 文件名,如 "stdout.log" */
11
+ name: string;
12
+ /** 文件内容 */
13
+ content: string;
14
+ }
15
+ /** buildWarning 回调收到的落盘结果 */
16
+ export interface GuardWarningContext {
17
+ /** 本次落盘目录;未落盘(工具未提供 dump)时为 null */
18
+ dir: string | null;
19
+ /** 已落盘文件:文件名 → 绝对路径;未落盘时为空对象 */
20
+ files: Record<string, string>;
21
+ }
22
+ /** guardOutput 入参:骨架所需的一切(判定、落盘、警告)均由工具以回调提供 */
23
+ export interface OutputGuardOptions<T> {
24
+ /** 工具名,用于落盘目录命名(如 "exec") */
25
+ tool: string;
26
+ /** 工具本应返回的完整内容 */
27
+ content: T;
28
+ /** 超限判定:上限由工具自行从 config 读取,骨架不传参 */
29
+ isOverLimit: (content: T) => boolean;
30
+ /**
31
+ * 落盘内容组织(可选)。缺省表示"只警告、不落盘"(如 readFile)。
32
+ * 返回的文件按顺序写入本次调用专属的目录。
33
+ */
34
+ dump?: (dir: string, content: T) => GuardDumpFile[] | Promise<GuardDumpFile[]>;
35
+ /** 生成超限时的返回体(各工具自定义,可含头尾预览、统计、原有字段等) */
36
+ buildWarning: (ctx: GuardWarningContext) => string;
37
+ }
38
+ /**
39
+ * 标准输出保护骨架。
40
+ *
41
+ * 各工具在 call() 出口调用,只需提供三个回调:
42
+ * 1) isOverLimit —— 是否超过上限(工具自读 config 判定,未被超限即原样返回 content);
43
+ * 2) dump —— 超限时落盘哪些文件(可省略 = 只警告不落盘);
44
+ * 3) buildWarning —— 超限时返回给模型的内容。
45
+ *
46
+ * 骨架职责:判定 → 未超限原样返回 / 超限时创建独立目录并写文件 → 交给 buildWarning。
47
+ *
48
+ * 落盘目录:<os.tmpdir()>/ai-zen/tool-output/<tool>-<时间戳>-<随机串>/,
49
+ * 每次调用独立目录,互不覆盖;不做自清理,依赖系统对临时目录的清理策略。
50
+ *
51
+ * 落盘失败(磁盘满、权限不足等)不吞异常,直接向上抛出。
52
+ */
53
+ export declare function guardOutput<T>(options: OutputGuardOptions<T>): Promise<T | string>;
54
+ /** 头部预览 */
55
+ export interface HeadPreview {
56
+ /** 头部内容(最多 size 字符) */
57
+ head: string;
58
+ /** 被省略的字符数;为 0 表示无省略(此时 head 为全文) */
59
+ omitted: number;
60
+ }
61
+ /**
62
+ * 生成头部预览:最多 size 字符。
63
+ *
64
+ * 适用于结果按出现顺序排列、尾部参考价值低的工具(如 findText)。
65
+ */
66
+ export declare function headPreview(text: string, size?: number): HeadPreview;
67
+ /** 头尾预览 */
68
+ export interface HeadTailPreview {
69
+ /** 头部内容(最多 size 字符) */
70
+ head: string;
71
+ /** 尾部内容(最多 size 字符);无省略时为空串 */
72
+ tail: string;
73
+ /** 被省略的字符数;为 0 表示无省略(此时 head 为全文) */
74
+ omitted: number;
75
+ }
76
+ /**
77
+ * 生成头尾预览:头部最多 size 字符 + 尾部最多 size 字符。
78
+ *
79
+ * 供各工具的 buildWarning 按需取用(也可自行组织预览,骨架不做限制)。
80
+ */
81
+ export declare function headTailPreview(text: string, size?: number): HeadTailPreview;
@@ -0,0 +1,73 @@
1
+ import * as fsp from "fs/promises";
2
+ import * as os from "os";
3
+ import * as path from "path";
4
+ /**
5
+ * 工具输出上限的缺省值(字符数)。
6
+ *
7
+ * 可由 AppConfig.maxToolOutput 覆盖;上限由各工具自行读取并判定,
8
+ * 骨架不感知配置,以便不同工具按自身口径(如 stdout/stderr 合计)判断。
9
+ */
10
+ export const DEFAULT_MAX_TOOL_OUTPUT = 32_768;
11
+ /**
12
+ * 标准输出保护骨架。
13
+ *
14
+ * 各工具在 call() 出口调用,只需提供三个回调:
15
+ * 1) isOverLimit —— 是否超过上限(工具自读 config 判定,未被超限即原样返回 content);
16
+ * 2) dump —— 超限时落盘哪些文件(可省略 = 只警告不落盘);
17
+ * 3) buildWarning —— 超限时返回给模型的内容。
18
+ *
19
+ * 骨架职责:判定 → 未超限原样返回 / 超限时创建独立目录并写文件 → 交给 buildWarning。
20
+ *
21
+ * 落盘目录:<os.tmpdir()>/ai-zen/tool-output/<tool>-<时间戳>-<随机串>/,
22
+ * 每次调用独立目录,互不覆盖;不做自清理,依赖系统对临时目录的清理策略。
23
+ *
24
+ * 落盘失败(磁盘满、权限不足等)不吞异常,直接向上抛出。
25
+ */
26
+ export async function guardOutput(options) {
27
+ const { tool, content, isOverLimit, dump, buildWarning } = options;
28
+ if (!isOverLimit(content))
29
+ return content;
30
+ if (!dump)
31
+ return buildWarning({ dir: null, files: {} });
32
+ const dir = await createDumpDir(tool);
33
+ const files = await dump(dir, content);
34
+ const paths = {};
35
+ for (const file of files) {
36
+ const target = path.join(dir, file.name);
37
+ await fsp.writeFile(target, file.content, "utf-8");
38
+ paths[file.name] = target;
39
+ }
40
+ return buildWarning({ dir, files: paths });
41
+ }
42
+ /**
43
+ * 生成头部预览:最多 size 字符。
44
+ *
45
+ * 适用于结果按出现顺序排列、尾部参考价值低的工具(如 findText)。
46
+ */
47
+ export function headPreview(text, size = 1000) {
48
+ if (text.length <= size)
49
+ return { head: text, omitted: 0 };
50
+ return { head: text.slice(0, size), omitted: text.length - size };
51
+ }
52
+ /**
53
+ * 生成头尾预览:头部最多 size 字符 + 尾部最多 size 字符。
54
+ *
55
+ * 供各工具的 buildWarning 按需取用(也可自行组织预览,骨架不做限制)。
56
+ */
57
+ export function headTailPreview(text, size = 1000) {
58
+ if (text.length <= size * 2)
59
+ return { head: text, tail: "", omitted: 0 };
60
+ return {
61
+ head: text.slice(0, size),
62
+ tail: text.slice(-size),
63
+ omitted: text.length - size * 2,
64
+ };
65
+ }
66
+ /** 创建本次调用专属的落盘目录 */
67
+ async function createDumpDir(tool) {
68
+ const stamp = new Date().toISOString().replace(/[:.]/g, "-");
69
+ const rand = Math.random().toString(36).slice(2, 8);
70
+ const dir = path.join(os.tmpdir(), "ai-zen", "tool-output", `${tool}-${stamp}-${rand}`);
71
+ await fsp.mkdir(dir, { recursive: true });
72
+ return dir;
73
+ }