@ai-zen/agents-sdk 0.7.0 → 0.7.1

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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.7.1] - 2026-08-25
4
+
5
+ ### 🚀 New Features
6
+
7
+ - **`FindTextTool` (findText) gains three-layer output protection** — prevents search results from blowing up the context window:
8
+ - **`maxMatches`** (default 200) — caps the total number of matches; once reached, scanning stops and the result is marked `truncated`
9
+ - **`maxFileSize`** (default 300KB, aligned with `ReadFileTool`) — files larger than this are **skipped** rather than rejected, so an oversized file doesn't block the whole search
10
+ - **`maxLineLength`** (default 200) — each matched line's `content` and the regex `match` substring are truncated (with a trailing `…`)
11
+ - All three are optional parameters that can be overridden by the caller; when truncated the result returns `{ truncated: true, totalMatches, results }`, while non-truncated results keep the original JSON array shape (backward compatible)
12
+
3
13
  ## [0.7.0] - 2026-08-14
4
14
 
5
15
  ### ⚠️ Breaking
@@ -10,5 +10,8 @@ export declare class FindTextTool extends SdkCallbackTool {
10
10
  text?: string;
11
11
  regex?: string;
12
12
  exclude?: string[];
13
+ maxMatches?: number;
14
+ maxFileSize?: number;
15
+ maxLineLength?: number;
13
16
  }, ctx?: ToolCallContext): Promise<string>;
14
17
  }
@@ -1,10 +1,16 @@
1
1
  import * as fsp from "fs/promises";
2
2
  import * as path from "path";
3
3
  import { SdkCallbackTool } from "../../../runtime/SdkCallbackTool.js";
4
+ /** 默认总匹配数上限 */
5
+ const DEFAULT_MAX_MATCHES = 200;
6
+ /** 默认文件大小上限(字节,与 ReadFileTool 的 300KB 口径一致) */
7
+ const DEFAULT_MAX_FILE_SIZE = 300 * 1024;
8
+ /** 默认行内容/匹配子串截断长度 */
9
+ const DEFAULT_MAX_LINE_LENGTH = 200;
4
10
  export class FindTextTool extends SdkCallbackTool {
5
11
  function = {
6
12
  name: "findText",
7
- description: "查找文本出现的位置,支持普通文本或正则匹配,返回文件名及具体行号、行内容",
13
+ description: "查找文本出现的位置,支持普通文本或正则匹配,返回文件名及具体行号、行内容。为避免结果撑爆上下文,默认限制总匹配数、单文件大小与行内容长度,超限会截断并标记 truncated。",
8
14
  parameters: {
9
15
  type: "object",
10
16
  properties: {
@@ -31,6 +37,18 @@ export class FindTextTool extends SdkCallbackTool {
31
37
  type: "string",
32
38
  },
33
39
  },
40
+ maxMatches: {
41
+ type: "number",
42
+ description: "总匹配数上限,默认 200",
43
+ },
44
+ maxFileSize: {
45
+ type: "number",
46
+ description: "单文件大小上限(字节),超过则跳过该文件,默认 307200(300KB)",
47
+ },
48
+ maxLineLength: {
49
+ type: "number",
50
+ description: "行内容与匹配子串的截断长度,默认 200",
51
+ },
34
52
  },
35
53
  required: ["path", "pattern"],
36
54
  },
@@ -49,48 +67,70 @@ export class FindTextTool extends SdkCallbackTool {
49
67
  return "请提供 text 或 regex 参数";
50
68
  }
51
69
  const regex = regexStr ? new RegExp(regexStr) : null;
70
+ const maxMatches = input.maxMatches ?? DEFAULT_MAX_MATCHES;
71
+ const maxFileSize = input.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;
72
+ const maxLineLength = input.maxLineLength ?? DEFAULT_MAX_LINE_LENGTH;
73
+ let totalMatches = 0;
74
+ let truncated = false;
52
75
  for await (const file of fsp.glob(input.pattern, {
53
76
  cwd,
54
77
  exclude: input.exclude || ["**/node_modules/**"],
55
78
  })) {
56
79
  if (signal?.aborted)
57
80
  break; // 中断:停止继续遍历/消费
81
+ if (totalMatches >= maxMatches) {
82
+ truncated = true;
83
+ break;
84
+ }
58
85
  const fullPath = path.join(cwd, file);
59
86
  const stats = await fsp.stat(fullPath);
60
87
  if (signal?.aborted)
61
88
  break; // 中断:stat 后再次检查
62
- if (stats.isFile()) {
63
- const content = await fsp.readFile(fullPath, "utf-8");
64
- if (signal?.aborted)
65
- break; // 中断:readFile 后再次检查
66
- const lines = content.split("\n");
67
- const matches = [];
68
- lines.forEach((lineContent, index) => {
69
- if (regex) {
70
- const matchResult = lineContent.match(regex);
71
- if (matchResult) {
72
- matches.push({
73
- line: index + 1,
74
- content: lineContent,
75
- match: matchResult[0],
76
- });
77
- }
78
- }
79
- else if (lineContent.includes(text)) {
89
+ if (!stats.isFile())
90
+ continue;
91
+ // 文件过大则跳过(避免撑爆上下文;与 ReadFileTool 300KB 口径一致,但此处为跳过而非报错)
92
+ if (stats.size > maxFileSize)
93
+ continue;
94
+ const content = await fsp.readFile(fullPath, "utf-8");
95
+ if (signal?.aborted)
96
+ break; // 中断:readFile 后再次检查
97
+ const lines = content.split("\n");
98
+ const matches = [];
99
+ for (let index = 0; index < lines.length; index++) {
100
+ if (totalMatches >= maxMatches) {
101
+ truncated = true;
102
+ break;
103
+ }
104
+ const lineContent = lines[index];
105
+ if (regex) {
106
+ const matchResult = lineContent.match(regex);
107
+ if (matchResult) {
80
108
  matches.push({
81
109
  line: index + 1,
82
- content: lineContent,
110
+ content: truncate(lineContent, maxLineLength),
111
+ match: truncate(matchResult[0], maxLineLength),
83
112
  });
113
+ totalMatches++;
84
114
  }
85
- });
86
- if (matches.length > 0) {
87
- result.push({ file, matches });
88
115
  }
116
+ else if (lineContent.includes(text)) {
117
+ matches.push({
118
+ line: index + 1,
119
+ content: truncate(lineContent, maxLineLength),
120
+ });
121
+ totalMatches++;
122
+ }
123
+ }
124
+ if (matches.length > 0) {
125
+ result.push({ file, matches });
89
126
  }
90
127
  }
91
128
  if (signal?.aborted) {
92
129
  return JSON.stringify({ aborted: true, results: result });
93
130
  }
131
+ if (truncated) {
132
+ return JSON.stringify({ truncated: true, totalMatches, results: result });
133
+ }
94
134
  return JSON.stringify(result);
95
135
  }
96
136
  catch (error) {
@@ -98,3 +138,9 @@ export class FindTextTool extends SdkCallbackTool {
98
138
  }
99
139
  }
100
140
  }
141
+ /** 截断字符串到指定长度,超出部分以 "…" 结尾标记 */
142
+ function truncate(s, max) {
143
+ if (s.length <= max)
144
+ return s;
145
+ return s.slice(0, max) + "…";
146
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-zen/agents-sdk",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "AI-Zen Agents SDK — shared business logic for CLI and Desktop",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",