@tachu/extensions 1.0.0-alpha.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 +119 -0
- package/LICENSE +201 -0
- package/README.md +1104 -0
- package/README_ZH.md +1082 -0
- package/dist/backends/file.d.ts +18 -0
- package/dist/backends/file.d.ts.map +1 -0
- package/dist/backends/file.js +85 -0
- package/dist/backends/file.js.map +1 -0
- package/dist/backends/index.d.ts +4 -0
- package/dist/backends/index.d.ts.map +1 -0
- package/dist/backends/index.js +4 -0
- package/dist/backends/index.js.map +1 -0
- package/dist/backends/terminal.d.ts +18 -0
- package/dist/backends/terminal.d.ts.map +1 -0
- package/dist/backends/terminal.js +81 -0
- package/dist/backends/terminal.js.map +1 -0
- package/dist/backends/web.d.ts +18 -0
- package/dist/backends/web.d.ts.map +1 -0
- package/dist/backends/web.js +55 -0
- package/dist/backends/web.js.map +1 -0
- package/dist/common/net.d.ts +39 -0
- package/dist/common/net.d.ts.map +1 -0
- package/dist/common/net.js +177 -0
- package/dist/common/net.js.map +1 -0
- package/dist/common/path.d.ts +51 -0
- package/dist/common/path.d.ts.map +1 -0
- package/dist/common/path.js +76 -0
- package/dist/common/path.js.map +1 -0
- package/dist/common/process.d.ts +19 -0
- package/dist/common/process.d.ts.map +1 -0
- package/dist/common/process.js +67 -0
- package/dist/common/process.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +3 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/sse-adapter.d.ts +82 -0
- package/dist/mcp/sse-adapter.d.ts.map +1 -0
- package/dist/mcp/sse-adapter.js +201 -0
- package/dist/mcp/sse-adapter.js.map +1 -0
- package/dist/mcp/stdio-adapter.d.ts +85 -0
- package/dist/mcp/stdio-adapter.d.ts.map +1 -0
- package/dist/mcp/stdio-adapter.js +203 -0
- package/dist/mcp/stdio-adapter.js.map +1 -0
- package/dist/memory/fs-memory-system.d.ts +147 -0
- package/dist/memory/fs-memory-system.d.ts.map +1 -0
- package/dist/memory/fs-memory-system.js +266 -0
- package/dist/memory/fs-memory-system.js.map +1 -0
- package/dist/memory/index.d.ts +2 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +2 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/observability/index.d.ts +3 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +3 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/jsonl-emitter.d.ts +58 -0
- package/dist/observability/jsonl-emitter.d.ts.map +1 -0
- package/dist/observability/jsonl-emitter.js +96 -0
- package/dist/observability/jsonl-emitter.js.map +1 -0
- package/dist/observability/otel-emitter.d.ts +52 -0
- package/dist/observability/otel-emitter.d.ts.map +1 -0
- package/dist/observability/otel-emitter.js +143 -0
- package/dist/observability/otel-emitter.js.map +1 -0
- package/dist/providers/anthropic.d.ts +73 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +521 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +5 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/mock.d.ts +81 -0
- package/dist/providers/mock.d.ts.map +1 -0
- package/dist/providers/mock.js +160 -0
- package/dist/providers/mock.js.map +1 -0
- package/dist/providers/openai.d.ts +95 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +529 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/qwen.d.ts +145 -0
- package/dist/providers/qwen.d.ts.map +1 -0
- package/dist/providers/qwen.js +669 -0
- package/dist/providers/qwen.js.map +1 -0
- package/dist/rules/index.d.ts +9 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +15 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/no-hallucination.md +11 -0
- package/dist/rules/no-sensitive-output.md +11 -0
- package/dist/rules/prefer-concise-response.md +11 -0
- package/dist/rules/require-tool-verification.md +11 -0
- package/dist/safety/default-gate.d.ts +112 -0
- package/dist/safety/default-gate.d.ts.map +1 -0
- package/dist/safety/default-gate.js +188 -0
- package/dist/safety/default-gate.js.map +1 -0
- package/dist/safety/index.d.ts +2 -0
- package/dist/safety/index.d.ts.map +1 -0
- package/dist/safety/index.js +2 -0
- package/dist/safety/index.js.map +1 -0
- package/dist/tools/_shared/web-client.d.ts +18 -0
- package/dist/tools/_shared/web-client.d.ts.map +1 -0
- package/dist/tools/_shared/web-client.js +46 -0
- package/dist/tools/_shared/web-client.js.map +1 -0
- package/dist/tools/apply-patch/descriptor.md +27 -0
- package/dist/tools/apply-patch/executor.d.ts +19 -0
- package/dist/tools/apply-patch/executor.d.ts.map +1 -0
- package/dist/tools/apply-patch/executor.js +193 -0
- package/dist/tools/apply-patch/executor.js.map +1 -0
- package/dist/tools/fetch-url/descriptor.md +44 -0
- package/dist/tools/fetch-url/executor.d.ts +28 -0
- package/dist/tools/fetch-url/executor.d.ts.map +1 -0
- package/dist/tools/fetch-url/executor.js +115 -0
- package/dist/tools/fetch-url/executor.js.map +1 -0
- package/dist/tools/index.d.ts +12 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +286 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/list-dir/descriptor.md +29 -0
- package/dist/tools/list-dir/executor.d.ts +22 -0
- package/dist/tools/list-dir/executor.d.ts.map +1 -0
- package/dist/tools/list-dir/executor.js +48 -0
- package/dist/tools/list-dir/executor.js.map +1 -0
- package/dist/tools/read-file/descriptor.md +28 -0
- package/dist/tools/read-file/executor.d.ts +15 -0
- package/dist/tools/read-file/executor.d.ts.map +1 -0
- package/dist/tools/read-file/executor.js +22 -0
- package/dist/tools/read-file/executor.js.map +1 -0
- package/dist/tools/run-shell/descriptor.md +39 -0
- package/dist/tools/run-shell/executor.d.ts +20 -0
- package/dist/tools/run-shell/executor.d.ts.map +1 -0
- package/dist/tools/run-shell/executor.js +76 -0
- package/dist/tools/run-shell/executor.js.map +1 -0
- package/dist/tools/search-code/descriptor.md +31 -0
- package/dist/tools/search-code/executor.d.ts +23 -0
- package/dist/tools/search-code/executor.d.ts.map +1 -0
- package/dist/tools/search-code/executor.js +122 -0
- package/dist/tools/search-code/executor.js.map +1 -0
- package/dist/tools/shared.d.ts +47 -0
- package/dist/tools/shared.d.ts.map +1 -0
- package/dist/tools/shared.js +27 -0
- package/dist/tools/shared.js.map +1 -0
- package/dist/tools/web-fetch/descriptor.md +198 -0
- package/dist/tools/web-fetch/errors.d.ts +32 -0
- package/dist/tools/web-fetch/errors.d.ts.map +1 -0
- package/dist/tools/web-fetch/errors.js +91 -0
- package/dist/tools/web-fetch/errors.js.map +1 -0
- package/dist/tools/web-fetch/executor.d.ts +10 -0
- package/dist/tools/web-fetch/executor.d.ts.map +1 -0
- package/dist/tools/web-fetch/executor.js +191 -0
- package/dist/tools/web-fetch/executor.js.map +1 -0
- package/dist/tools/web-fetch/index.d.ts +4 -0
- package/dist/tools/web-fetch/index.d.ts.map +1 -0
- package/dist/tools/web-fetch/index.js +3 -0
- package/dist/tools/web-fetch/index.js.map +1 -0
- package/dist/tools/web-fetch/types.d.ts +157 -0
- package/dist/tools/web-fetch/types.d.ts.map +1 -0
- package/dist/tools/web-fetch/types.js +7 -0
- package/dist/tools/web-fetch/types.js.map +1 -0
- package/dist/tools/web-search/descriptor.md +89 -0
- package/dist/tools/web-search/errors.d.ts +33 -0
- package/dist/tools/web-search/errors.d.ts.map +1 -0
- package/dist/tools/web-search/errors.js +45 -0
- package/dist/tools/web-search/errors.js.map +1 -0
- package/dist/tools/web-search/executor.d.ts +10 -0
- package/dist/tools/web-search/executor.d.ts.map +1 -0
- package/dist/tools/web-search/executor.js +185 -0
- package/dist/tools/web-search/executor.js.map +1 -0
- package/dist/tools/web-search/index.d.ts +4 -0
- package/dist/tools/web-search/index.d.ts.map +1 -0
- package/dist/tools/web-search/index.js +3 -0
- package/dist/tools/web-search/index.js.map +1 -0
- package/dist/tools/web-search/types.d.ts +86 -0
- package/dist/tools/web-search/types.d.ts.map +1 -0
- package/dist/tools/web-search/types.js +7 -0
- package/dist/tools/web-search/types.js.map +1 -0
- package/dist/tools/write-file/descriptor.md +30 -0
- package/dist/tools/write-file/executor.d.ts +16 -0
- package/dist/tools/write-file/executor.d.ts.map +1 -0
- package/dist/tools/write-file/executor.js +18 -0
- package/dist/tools/write-file/executor.js.map +1 -0
- package/dist/transformers/document-to-text.d.ts +23 -0
- package/dist/transformers/document-to-text.d.ts.map +1 -0
- package/dist/transformers/document-to-text.js +69 -0
- package/dist/transformers/document-to-text.js.map +1 -0
- package/dist/transformers/image-to-text.d.ts +38 -0
- package/dist/transformers/image-to-text.d.ts.map +1 -0
- package/dist/transformers/image-to-text.js +82 -0
- package/dist/transformers/image-to-text.js.map +1 -0
- package/dist/transformers/index.d.ts +3 -0
- package/dist/transformers/index.d.ts.map +1 -0
- package/dist/transformers/index.js +3 -0
- package/dist/transformers/index.js.map +1 -0
- package/dist/vector/index.d.ts +3 -0
- package/dist/vector/index.d.ts.map +1 -0
- package/dist/vector/index.js +3 -0
- package/dist/vector/index.js.map +1 -0
- package/dist/vector/local-fs.d.ts +76 -0
- package/dist/vector/local-fs.d.ts.map +1 -0
- package/dist/vector/local-fs.js +153 -0
- package/dist/vector/local-fs.js.map +1 -0
- package/dist/vector/qdrant.d.ts +85 -0
- package/dist/vector/qdrant.d.ts.map +1 -0
- package/dist/vector/qdrant.js +208 -0
- package/dist/vector/qdrant.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: tool
|
|
3
|
+
name: search-code
|
|
4
|
+
description: 在工作区内按模式搜索代码
|
|
5
|
+
sideEffect: readonly
|
|
6
|
+
idempotent: true
|
|
7
|
+
requiresApproval: false
|
|
8
|
+
timeout: 10000
|
|
9
|
+
inputSchema:
|
|
10
|
+
type: object
|
|
11
|
+
properties:
|
|
12
|
+
pattern:
|
|
13
|
+
type: string
|
|
14
|
+
path:
|
|
15
|
+
type: string
|
|
16
|
+
fileGlob:
|
|
17
|
+
type: string
|
|
18
|
+
maxResults:
|
|
19
|
+
type: number
|
|
20
|
+
caseSensitive:
|
|
21
|
+
type: boolean
|
|
22
|
+
required: [pattern]
|
|
23
|
+
outputSchema:
|
|
24
|
+
type: object
|
|
25
|
+
properties:
|
|
26
|
+
matches:
|
|
27
|
+
type: array
|
|
28
|
+
execute: search-code
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
优先使用 ripgrep 搜索;若系统不存在 rg,则回退到 JS 递归搜索。
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ToolExecutor } from "../shared";
|
|
2
|
+
interface SearchCodeInput {
|
|
3
|
+
pattern: string;
|
|
4
|
+
path?: string;
|
|
5
|
+
fileGlob?: string;
|
|
6
|
+
maxResults?: number;
|
|
7
|
+
caseSensitive?: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface SearchCodeMatch {
|
|
10
|
+
file: string;
|
|
11
|
+
line: number;
|
|
12
|
+
text: string;
|
|
13
|
+
}
|
|
14
|
+
interface SearchCodeOutput {
|
|
15
|
+
matches: SearchCodeMatch[];
|
|
16
|
+
truncated: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 搜索代码 Tool 执行器。
|
|
20
|
+
*/
|
|
21
|
+
export declare const searchCodeExecutor: ToolExecutor<SearchCodeInput, SearchCodeOutput>;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/tools/search-code/executor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAI9C,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;CACpB;AA0BD;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,YAAY,CAAC,eAAe,EAAE,gBAAgB,CAkG9E,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { assertNotAborted, resolveSandboxPolicy } from "../shared";
|
|
4
|
+
import { resolveAllowedPath, toWorkspaceRelativePath } from "../../common/path";
|
|
5
|
+
const parseRgOutput = (output, maxResults) => {
|
|
6
|
+
const matches = [];
|
|
7
|
+
const lines = output.split("\n").filter((line) => line.length > 0);
|
|
8
|
+
for (const line of lines) {
|
|
9
|
+
const first = line.indexOf(":");
|
|
10
|
+
const second = first >= 0 ? line.indexOf(":", first + 1) : -1;
|
|
11
|
+
if (first <= 0 || second <= first + 1) {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
matches.push({
|
|
15
|
+
file: line.slice(0, first),
|
|
16
|
+
line: Number(line.slice(first + 1, second)),
|
|
17
|
+
text: line.slice(second + 1),
|
|
18
|
+
});
|
|
19
|
+
if (matches.length >= maxResults) {
|
|
20
|
+
return { matches, truncated: true };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return { matches, truncated: false };
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* 搜索代码 Tool 执行器。
|
|
27
|
+
*/
|
|
28
|
+
export const searchCodeExecutor = async (input, context) => {
|
|
29
|
+
assertNotAborted(context.abortSignal);
|
|
30
|
+
const root = resolveAllowedPath(input.path ?? ".", resolveSandboxPolicy(context));
|
|
31
|
+
const maxResults = input.maxResults ?? 100;
|
|
32
|
+
try {
|
|
33
|
+
const args = [
|
|
34
|
+
"--line-number",
|
|
35
|
+
"--no-heading",
|
|
36
|
+
"--color",
|
|
37
|
+
"never",
|
|
38
|
+
input.caseSensitive ? "--case-sensitive" : "--ignore-case",
|
|
39
|
+
"--max-count",
|
|
40
|
+
String(maxResults),
|
|
41
|
+
];
|
|
42
|
+
if (input.fileGlob) {
|
|
43
|
+
args.push("--glob", input.fileGlob);
|
|
44
|
+
}
|
|
45
|
+
args.push(input.pattern, root);
|
|
46
|
+
const process = Bun.spawn({
|
|
47
|
+
cmd: ["rg", ...args],
|
|
48
|
+
stdout: "pipe",
|
|
49
|
+
stderr: "pipe",
|
|
50
|
+
cwd: root,
|
|
51
|
+
});
|
|
52
|
+
const [stdout, stderr] = await Promise.all([
|
|
53
|
+
new Response(process.stdout).text(),
|
|
54
|
+
new Response(process.stderr).text(),
|
|
55
|
+
]);
|
|
56
|
+
const code = await process.exited;
|
|
57
|
+
if (code !== 0 && code !== 1) {
|
|
58
|
+
throw new Error(stderr || `rg exited with code ${code}`);
|
|
59
|
+
}
|
|
60
|
+
const parsed = parseRgOutput(stdout, maxResults);
|
|
61
|
+
return {
|
|
62
|
+
matches: parsed.matches.map((item) => ({
|
|
63
|
+
...item,
|
|
64
|
+
file: toWorkspaceRelativePath(context.workspaceRoot, join(root, item.file)),
|
|
65
|
+
})),
|
|
66
|
+
truncated: parsed.truncated,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
const matcher = new RegExp(input.pattern, input.caseSensitive ? "g" : "gi");
|
|
71
|
+
const matches = [];
|
|
72
|
+
let truncated = false;
|
|
73
|
+
const walk = async (dir) => {
|
|
74
|
+
// D1-LOW-10:进入新目录前先检查取消,避免在大型仓库里无休止递归。
|
|
75
|
+
assertNotAborted(context.abortSignal);
|
|
76
|
+
const children = await readdir(dir, { withFileTypes: true });
|
|
77
|
+
for (const child of children) {
|
|
78
|
+
// 每个子条目都做一次取消检查,粒度足够细而开销极低。
|
|
79
|
+
assertNotAborted(context.abortSignal);
|
|
80
|
+
if (matches.length >= maxResults) {
|
|
81
|
+
truncated = true;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const target = join(dir, child.name);
|
|
85
|
+
if (child.isDirectory()) {
|
|
86
|
+
await walk(target);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (!child.isFile()) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (input.fileGlob && !target.endsWith(input.fileGlob.replace("*", ""))) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const content = await readFile(target, "utf8").catch(() => "");
|
|
96
|
+
const lines = content.split("\n");
|
|
97
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
98
|
+
// 大文件按行遍历时同样做细粒度取消检查。
|
|
99
|
+
if (index % 256 === 0) {
|
|
100
|
+
assertNotAborted(context.abortSignal);
|
|
101
|
+
}
|
|
102
|
+
if (matches.length >= maxResults) {
|
|
103
|
+
truncated = true;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
const line = lines[index] ?? "";
|
|
107
|
+
if (matcher.test(line)) {
|
|
108
|
+
matches.push({
|
|
109
|
+
file: toWorkspaceRelativePath(context.workspaceRoot, target),
|
|
110
|
+
line: index + 1,
|
|
111
|
+
text: line,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
matcher.lastIndex = 0;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
await walk(root);
|
|
119
|
+
return { matches, truncated };
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../src/tools/search-code/executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Session } from "@tachu/core";
|
|
2
|
+
/**
|
|
3
|
+
* Tool 执行时上下文。
|
|
4
|
+
*
|
|
5
|
+
* 字段语义:
|
|
6
|
+
* - `workspaceRoot`:工作区根目录(绝对路径)。向后兼容保留,路径校验不再
|
|
7
|
+
* 直接依赖它,而是以 {@link allowedRoots} 为准。
|
|
8
|
+
* - `allowedRoots`:允许读写的根目录列表;由宿主在 engine-factory 层组装,
|
|
9
|
+
* 通常包含 `workspaceRoot`、平台临时目录(`os.tmpdir()`),以及用户通过
|
|
10
|
+
* `safety.allowedWriteRoots` 配置扩展的路径。长度 ≥ 1。
|
|
11
|
+
* - `sandboxWaived`:本次调用是否豁免沙箱(审批已通过)。见
|
|
12
|
+
* `@tachu/core` 的 `TaskNode.metadata.approvalGranted`:宿主在审批通过后
|
|
13
|
+
* 把它翻译成这里的布尔值。
|
|
14
|
+
* - `session`:当前会话引用。
|
|
15
|
+
*
|
|
16
|
+
* 兼容性:历史代码读 `workspaceRoot` 仍然可用;新代码请走 {@link resolveAllowedPath}
|
|
17
|
+
* + `allowedRoots` + `sandboxWaived` 三件套。
|
|
18
|
+
*/
|
|
19
|
+
export interface ToolExecutionContext {
|
|
20
|
+
abortSignal: AbortSignal;
|
|
21
|
+
workspaceRoot: string;
|
|
22
|
+
allowedRoots?: readonly string[];
|
|
23
|
+
sandboxWaived?: boolean;
|
|
24
|
+
session: Session;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Tool 执行器签名。
|
|
28
|
+
*/
|
|
29
|
+
export type ToolExecutor<TInput = unknown, TOutput = unknown> = (input: TInput, context: ToolExecutionContext) => Promise<TOutput>;
|
|
30
|
+
/**
|
|
31
|
+
* 检查中断状态。
|
|
32
|
+
*
|
|
33
|
+
* @param signal 取消信号
|
|
34
|
+
* @throws Error 当已中断
|
|
35
|
+
*/
|
|
36
|
+
export declare const assertNotAborted: (signal: AbortSignal) => void;
|
|
37
|
+
/**
|
|
38
|
+
* 从 `ToolExecutionContext` 推导出本次工具调用的沙箱策略。
|
|
39
|
+
*
|
|
40
|
+
* 老版本 context 只有 `workspaceRoot`;本函数做一次规范化,让工具执行器
|
|
41
|
+
* 不必关心调用方是否已经迁移到新字段。
|
|
42
|
+
*/
|
|
43
|
+
export declare const resolveSandboxPolicy: (context: ToolExecutionContext) => {
|
|
44
|
+
allowedRoots: readonly string[];
|
|
45
|
+
sandboxWaived: boolean;
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/tools/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,CAC9D,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,oBAAoB,KAC1B,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,QAAQ,WAAW,KAAG,IAItD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,SAAS,oBAAoB,KAC5B;IAAE,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,aAAa,EAAE,OAAO,CAAA;CAQ3D,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 检查中断状态。
|
|
3
|
+
*
|
|
4
|
+
* @param signal 取消信号
|
|
5
|
+
* @throws Error 当已中断
|
|
6
|
+
*/
|
|
7
|
+
export const assertNotAborted = (signal) => {
|
|
8
|
+
if (signal.aborted) {
|
|
9
|
+
throw signal.reason ?? new Error("aborted");
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* 从 `ToolExecutionContext` 推导出本次工具调用的沙箱策略。
|
|
14
|
+
*
|
|
15
|
+
* 老版本 context 只有 `workspaceRoot`;本函数做一次规范化,让工具执行器
|
|
16
|
+
* 不必关心调用方是否已经迁移到新字段。
|
|
17
|
+
*/
|
|
18
|
+
export const resolveSandboxPolicy = (context) => {
|
|
19
|
+
const roots = context.allowedRoots && context.allowedRoots.length > 0
|
|
20
|
+
? context.allowedRoots
|
|
21
|
+
: [context.workspaceRoot];
|
|
22
|
+
return {
|
|
23
|
+
allowedRoots: roots,
|
|
24
|
+
sandboxWaived: context.sandboxWaived === true,
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/tools/shared.ts"],"names":[],"mappings":"AAmCA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAmB,EAAQ,EAAE;IAC5D,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,OAA6B,EACgC,EAAE;IAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;QACnE,CAAC,CAAC,OAAO,CAAC,YAAY;QACtB,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC5B,OAAO;QACL,YAAY,EAAE,KAAK;QACnB,aAAa,EAAE,OAAO,CAAC,aAAa,KAAK,IAAI;KAC9C,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: tool
|
|
3
|
+
id: web-fetch
|
|
4
|
+
name: web-fetch
|
|
5
|
+
version: "0.1.0"
|
|
6
|
+
category: "web"
|
|
7
|
+
dangerous: true
|
|
8
|
+
description: |
|
|
9
|
+
通过 @tachu/web-fetch-server 远程渲染并结构化抓取 URL:服务端以 Bun.fetch(静态)或 Playwright(浏览器)拉取页面,经 Readability/Turndown 等管线输出标题、正文与可选链接/图片/JSON-LD;`renderMode` 为 auto 时可在静态不足时自动升级到浏览器重试一次。
|
|
10
|
+
sideEffect: readonly
|
|
11
|
+
idempotent: false
|
|
12
|
+
requiresApproval: true
|
|
13
|
+
timeout: 120000
|
|
14
|
+
inputSchema:
|
|
15
|
+
type: object
|
|
16
|
+
properties:
|
|
17
|
+
url:
|
|
18
|
+
type: string
|
|
19
|
+
description: 目标 http(s) URL(协议层唯一必填;将发往服务端并由 SSRF 规则校验)
|
|
20
|
+
renderMode:
|
|
21
|
+
type: string
|
|
22
|
+
enum: [static, browser, auto]
|
|
23
|
+
description: 渲染模式;默认 auto(先 static,不满足条件时浏览器重试一次)
|
|
24
|
+
waitFor:
|
|
25
|
+
description: |
|
|
26
|
+
仅 browser 模式:等待策略。可为 load / domcontentloaded / networkidle,
|
|
27
|
+
或 { "selector": "<css>" } 等待元素可见,或 { "timeMs": <number> } 固定等待。
|
|
28
|
+
oneOf:
|
|
29
|
+
- type: string
|
|
30
|
+
enum: [load, domcontentloaded, networkidle]
|
|
31
|
+
- type: object
|
|
32
|
+
required: [selector]
|
|
33
|
+
properties:
|
|
34
|
+
selector:
|
|
35
|
+
type: string
|
|
36
|
+
- type: object
|
|
37
|
+
required: [timeMs]
|
|
38
|
+
properties:
|
|
39
|
+
timeMs:
|
|
40
|
+
type: number
|
|
41
|
+
waitTimeoutMs:
|
|
42
|
+
type: number
|
|
43
|
+
description: 渲染等待超时(毫秒);默认 15000,硬上限 60000
|
|
44
|
+
scroll:
|
|
45
|
+
description: |
|
|
46
|
+
仅 browser:是否滚动以触发懒加载。false | true |
|
|
47
|
+
{ "steps": number, "delayMs": number }
|
|
48
|
+
oneOf:
|
|
49
|
+
- type: boolean
|
|
50
|
+
- type: object
|
|
51
|
+
required: [steps, delayMs]
|
|
52
|
+
properties:
|
|
53
|
+
steps:
|
|
54
|
+
type: number
|
|
55
|
+
delayMs:
|
|
56
|
+
type: number
|
|
57
|
+
userAgent:
|
|
58
|
+
type: string
|
|
59
|
+
description: 覆盖 User-Agent;请求中可省略或显式传 null 以使用服务端 UA 池
|
|
60
|
+
extraHeaders:
|
|
61
|
+
type: object
|
|
62
|
+
additionalProperties:
|
|
63
|
+
type: string
|
|
64
|
+
description: 额外 HTTP 头;静态模式直传;浏览器模式作为 route 注入
|
|
65
|
+
cookies:
|
|
66
|
+
type: array
|
|
67
|
+
description: 注入 Cookie 列表(仅 browser 模式生效;元素形状由服务端解析)
|
|
68
|
+
items:
|
|
69
|
+
type: object
|
|
70
|
+
additionalProperties: true
|
|
71
|
+
blockResources:
|
|
72
|
+
type: array
|
|
73
|
+
description: |
|
|
74
|
+
仅 browser:资源拦截类型。未传时服务端默认 ["image","font","media"];传 [] 表示不拦截。
|
|
75
|
+
items:
|
|
76
|
+
type: string
|
|
77
|
+
enum: [image, font, media, stylesheet, other]
|
|
78
|
+
stealth:
|
|
79
|
+
type: boolean
|
|
80
|
+
description: 可省略或传 null 继承服务级;传 true/false 为请求级覆盖
|
|
81
|
+
outputFormat:
|
|
82
|
+
type: string
|
|
83
|
+
enum: [markdown, text, html, structured]
|
|
84
|
+
description: 正文形态;markdown 为默认 GFM
|
|
85
|
+
includeLinks:
|
|
86
|
+
type: boolean
|
|
87
|
+
description: 是否在输出中包含 links[]
|
|
88
|
+
includeImages:
|
|
89
|
+
type: boolean
|
|
90
|
+
description: 是否在输出中包含 images[]
|
|
91
|
+
includeStructured:
|
|
92
|
+
type: boolean
|
|
93
|
+
description: 是否包含 JSON-LD structured 字段
|
|
94
|
+
maxBodyChars:
|
|
95
|
+
type: number
|
|
96
|
+
description: body 字符上限;默认 32768,硬上限 524288
|
|
97
|
+
traceId:
|
|
98
|
+
type: string
|
|
99
|
+
description: 可选追踪 ID;省略或 null 时由服务端生成
|
|
100
|
+
required: [url]
|
|
101
|
+
outputSchema:
|
|
102
|
+
type: object
|
|
103
|
+
description: 对应 POST /v1/extract 200 响应(字段随选项省略)
|
|
104
|
+
properties:
|
|
105
|
+
url:
|
|
106
|
+
type: string
|
|
107
|
+
finalUrl:
|
|
108
|
+
type: string
|
|
109
|
+
status:
|
|
110
|
+
type: number
|
|
111
|
+
renderedWith:
|
|
112
|
+
type: string
|
|
113
|
+
enum: [static, browser]
|
|
114
|
+
renderedAtMs:
|
|
115
|
+
type: number
|
|
116
|
+
title:
|
|
117
|
+
type: string
|
|
118
|
+
description:
|
|
119
|
+
type: string
|
|
120
|
+
siteName:
|
|
121
|
+
type: string
|
|
122
|
+
lang:
|
|
123
|
+
type: string
|
|
124
|
+
byline:
|
|
125
|
+
type: string
|
|
126
|
+
publishedTime:
|
|
127
|
+
type: string
|
|
128
|
+
body:
|
|
129
|
+
type: string
|
|
130
|
+
wordCount:
|
|
131
|
+
type: number
|
|
132
|
+
truncated:
|
|
133
|
+
type: boolean
|
|
134
|
+
links:
|
|
135
|
+
type: array
|
|
136
|
+
images:
|
|
137
|
+
type: array
|
|
138
|
+
structured:
|
|
139
|
+
type: object
|
|
140
|
+
additionalProperties: true
|
|
141
|
+
warnings:
|
|
142
|
+
type: array
|
|
143
|
+
items:
|
|
144
|
+
type: string
|
|
145
|
+
traceId:
|
|
146
|
+
type: string
|
|
147
|
+
execute: web-fetch
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 常用字段说明
|
|
151
|
+
|
|
152
|
+
协议上仅 **`url`** 必填。实际调用中常与其他字段组合使用,例如:
|
|
153
|
+
|
|
154
|
+
- **`renderMode`**:静态站用 `static` 省资源,强 JS 页用 `browser` 或默认 `auto`
|
|
155
|
+
- **`outputFormat`**:需要 Markdown 摘要时用 `markdown`(默认),只要纯文本用 `text`
|
|
156
|
+
- **`waitTimeoutMs` / `waitFor`**:浏览器渲染时的超时与就绪条件
|
|
157
|
+
- **`maxBodyChars`**:控制返回给模型的正文长度,避免上下文爆炸
|
|
158
|
+
- **`includeLinks` / `includeImages` / `includeStructured`**:按需打开结构化附属字段
|
|
159
|
+
|
|
160
|
+
## 输出结构示例(200 成功,节选)
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"url": "https://example.com/article",
|
|
165
|
+
"finalUrl": "https://example.com/article",
|
|
166
|
+
"status": 200,
|
|
167
|
+
"renderedWith": "browser",
|
|
168
|
+
"renderedAtMs": 234,
|
|
169
|
+
"title": "示例文章",
|
|
170
|
+
"description": "页面 meta 描述",
|
|
171
|
+
"siteName": "Example",
|
|
172
|
+
"lang": "zh",
|
|
173
|
+
"byline": null,
|
|
174
|
+
"publishedTime": "2026-04-20T00:00:00.000Z",
|
|
175
|
+
"body": "# 示例文章\n\n正文 Markdown …",
|
|
176
|
+
"wordCount": 1234,
|
|
177
|
+
"truncated": false,
|
|
178
|
+
"links": [{ "text": "下一页", "href": "https://example.com/next" }],
|
|
179
|
+
"images": [],
|
|
180
|
+
"structured": null,
|
|
181
|
+
"warnings": [],
|
|
182
|
+
"traceId": "req_01HY..."
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## 安全提示
|
|
187
|
+
|
|
188
|
+
1. **客户端须配置 Web Fetch Server 的 endpoint 与鉴权**:工具通过 HTTP 调用服务端;需正确设置服务地址与 `Authorization: Bearer <token>` 所用 token(与部署环境一致)。未配置 token 时服务端仅允许绑定本机回环,运维需按环境变量与网络策略部署。
|
|
189
|
+
2. **URL 会经服务端 SSRF 校验**:私网、元数据地址、黑名单域名等会被拒绝(如 `SSRF_BLOCKED` / `DOMAIN_NOT_ALLOWED`);请勿将本工具用于探测内网。
|
|
190
|
+
3. **robots.txt 与爬取礼仪**:是否遵守 robots 及额外策略由 **服务端实现与配置** 决定,本工具不在客户端重复裁决。
|
|
191
|
+
|
|
192
|
+
## 与 `fetch-url` 的区别
|
|
193
|
+
|
|
194
|
+
| 维度 | `web-fetch` | `fetch-url` |
|
|
195
|
+
| --- | --- | --- |
|
|
196
|
+
| 数据形态 | 结构化正文(标题、Markdown/文本/HTML、可选链接与 JSON-LD) | 原始响应体 + 简单 HTML 清洗 |
|
|
197
|
+
| 依赖 | 需要可用的 `@tachu/web-fetch-server` | 仅需受控直连,无需独立 fetch 服务 |
|
|
198
|
+
| 渲染 | 支持静态与浏览器渲染管线 | 单次 HTTP,无浏览器渲染 |
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ErrorResponseBody, WebFetchErrorCode } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* 客户端在解析失败或网络层错误时使用的扩展码(契约 §3 行为要求;不在纯 HTTP 错误体中出现)。
|
|
4
|
+
*/
|
|
5
|
+
export type WebFetchClientOnlyErrorCode = "MALFORMED_RESPONSE" | "NETWORK_ERROR";
|
|
6
|
+
export type WebFetchClientErrorCode = WebFetchErrorCode | WebFetchClientOnlyErrorCode;
|
|
7
|
+
/**
|
|
8
|
+
* `web-fetch` / `web-search` 工具在客户端抛出的统一错误类型。
|
|
9
|
+
*
|
|
10
|
+
* @see docs/adr/decisions/0003d-web-fetch-errors.md §4
|
|
11
|
+
*/
|
|
12
|
+
export declare class WebFetchClientError extends Error {
|
|
13
|
+
readonly code: WebFetchClientErrorCode;
|
|
14
|
+
readonly userMessage: string;
|
|
15
|
+
readonly detail?: unknown | undefined;
|
|
16
|
+
readonly name = "WebFetchClientError";
|
|
17
|
+
constructor(code: WebFetchClientErrorCode, userMessage: string, detail?: unknown | undefined, options?: {
|
|
18
|
+
cause?: unknown;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 将服务端错误响应映射为 {@link WebFetchClientError}。
|
|
23
|
+
*
|
|
24
|
+
* @see docs/adr/decisions/0003d-web-fetch-errors.md §4.2
|
|
25
|
+
*/
|
|
26
|
+
export declare function mapServerErrorToClient(httpStatus: number, body: ErrorResponseBody | null, ctx: {
|
|
27
|
+
endpoint: string;
|
|
28
|
+
}): WebFetchClientError;
|
|
29
|
+
export declare function getMalformedResponseError(): WebFetchClientError;
|
|
30
|
+
export declare function getNetworkError(endpoint: string, originalError: unknown): WebFetchClientError;
|
|
31
|
+
export declare function getTimeoutError(timeoutMs: number): WebFetchClientError;
|
|
32
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/tools/web-fetch/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEpE;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG,oBAAoB,GAAG,eAAe,CAAC;AAEjF,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,GAAG,2BAA2B,CAAC;AAEtF;;;;GAIG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;aAI1B,IAAI,EAAE,uBAAuB;aAC7B,WAAW,EAAE,MAAM;aACnB,MAAM,CAAC,EAAE,OAAO;IALlC,QAAQ,CAAC,IAAI,yBAAyB;gBAGpB,IAAI,EAAE,uBAAuB,EAC7B,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,OAAO,YAAA,EAChC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAIhC;AAkDD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,iBAAiB,GAAG,IAAI,EAC9B,GAAG,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GACxB,mBAAmB,CAUrB;AAED,wBAAgB,yBAAyB,IAAI,mBAAmB,CAM/D;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,GAAG,mBAAmB,CAO7F;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,CAMtE"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `web-fetch` / `web-search` 工具在客户端抛出的统一错误类型。
|
|
3
|
+
*
|
|
4
|
+
* @see docs/adr/decisions/0003d-web-fetch-errors.md §4
|
|
5
|
+
*/
|
|
6
|
+
export class WebFetchClientError extends Error {
|
|
7
|
+
code;
|
|
8
|
+
userMessage;
|
|
9
|
+
detail;
|
|
10
|
+
name = "WebFetchClientError";
|
|
11
|
+
constructor(code, userMessage, detail, options) {
|
|
12
|
+
super(userMessage, options);
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.userMessage = userMessage;
|
|
15
|
+
this.detail = detail;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** @see docs/adr/decisions/0003d-web-fetch-errors.md §5 */
|
|
19
|
+
const HTTP_STATUS_TO_CODE = {
|
|
20
|
+
400: "INVALID_REQUEST",
|
|
21
|
+
401: "UNAUTHORIZED",
|
|
22
|
+
403: "FORBIDDEN",
|
|
23
|
+
404: "INVALID_REQUEST",
|
|
24
|
+
408: "REQUEST_TIMEOUT",
|
|
25
|
+
413: "REQUEST_TOO_LARGE",
|
|
26
|
+
422: "RENDER_FAILED",
|
|
27
|
+
429: "RATE_LIMITED",
|
|
28
|
+
500: "INTERNAL_ERROR",
|
|
29
|
+
502: "UPSTREAM_ERROR",
|
|
30
|
+
503: "BROWSER_POOL_EXHAUSTED",
|
|
31
|
+
504: "PROVIDER_TIMEOUT",
|
|
32
|
+
};
|
|
33
|
+
function inferCodeFromStatus(httpStatus) {
|
|
34
|
+
return HTTP_STATUS_TO_CODE[httpStatus] ?? "INTERNAL_ERROR";
|
|
35
|
+
}
|
|
36
|
+
const USER_MESSAGE_ZH = {
|
|
37
|
+
INVALID_REQUEST: "请求格式无效。请检查参数后重试。",
|
|
38
|
+
INVALID_URL: "URL 无效。请使用合法的 http/https 地址。",
|
|
39
|
+
UNAUTHORIZED: "鉴权失败。请检查 Web Fetch 服务的访问令牌配置。",
|
|
40
|
+
FORBIDDEN: "访问被拒绝。请确认令牌与权限配置是否正确。",
|
|
41
|
+
SSRF_BLOCKED: "出于安全策略,无法访问该地址。请仅使用允许的公网 URL。",
|
|
42
|
+
DOMAIN_NOT_ALLOWED: "域名不在允许列表中。请调整白名单或更换 URL。",
|
|
43
|
+
REQUEST_TIMEOUT: "请求处理超时。请稍后重试,或尝试缩短等待时间。",
|
|
44
|
+
REQUEST_TOO_LARGE: "请求体过大。请减小提交内容后重试。",
|
|
45
|
+
RESPONSE_TOO_LARGE: "目标页面响应过大。请尝试降低正文长度上限或更换页面。",
|
|
46
|
+
RENDER_FAILED: "页面渲染失败。可尝试更换渲染模式或稍后重试。",
|
|
47
|
+
RATE_LIMITED: "触发限流。请稍后再试或降低请求频率。",
|
|
48
|
+
INTERNAL_ERROR: "服务端出现内部错误。请稍后重试或联系管理员。",
|
|
49
|
+
UPSTREAM_ERROR: "上游站点返回异常。请稍后重试。",
|
|
50
|
+
BROWSER_POOL_EXHAUSTED: "浏览器资源繁忙。请降低并发或稍后重试。",
|
|
51
|
+
BROWSER_CRASHED: "浏览器进程异常。请立即重试,通常可以恢复。",
|
|
52
|
+
PROVIDER_NOT_CONFIGURED: "搜索提供方未配置。请检查搜索相关环境变量。",
|
|
53
|
+
PROVIDER_UPSTREAM_ERROR: "搜索提供方返回异常。请稍后重试。",
|
|
54
|
+
PROVIDER_TIMEOUT: "搜索提供方调用超时。请稍后重试。",
|
|
55
|
+
TIMEOUT_WEB_FETCH: "网页抓取超时。请缩短正文长度上限或更换 URL 后重试。",
|
|
56
|
+
TIMEOUT_WEB_SEARCH: "搜索超时。请缩短查询或减少抓取条数后重试。",
|
|
57
|
+
WEB_FETCH_SERVER_UNREACHABLE: "渲染服务不可达。请检查网络或服务端状态。",
|
|
58
|
+
WEB_FETCH_ENDPOINT_NOT_CONFIGURED: "未能连接到 Web Fetch 服务。请先启动渲染服务,或通过 TACHU_WEB_FETCH_ENDPOINT 配置远端地址。",
|
|
59
|
+
MALFORMED_RESPONSE: "服务返回了无法解析的响应。请检查服务端版本或稍后重试。",
|
|
60
|
+
NETWORK_ERROR: "网络请求失败。请检查网络连接与服务是否可用。",
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* 将服务端错误响应映射为 {@link WebFetchClientError}。
|
|
64
|
+
*
|
|
65
|
+
* @see docs/adr/decisions/0003d-web-fetch-errors.md §4.2
|
|
66
|
+
*/
|
|
67
|
+
export function mapServerErrorToClient(httpStatus, body, ctx) {
|
|
68
|
+
const code = body?.error.code ?? inferCodeFromStatus(httpStatus);
|
|
69
|
+
const userMessage = USER_MESSAGE_ZH[code] ?? body?.error.message ?? USER_MESSAGE_ZH.INTERNAL_ERROR;
|
|
70
|
+
const detail = {
|
|
71
|
+
...(body?.error.detail ?? {}),
|
|
72
|
+
httpStatus,
|
|
73
|
+
endpoint: ctx.endpoint,
|
|
74
|
+
requestId: body?.error.requestId,
|
|
75
|
+
};
|
|
76
|
+
return new WebFetchClientError(code, userMessage, detail);
|
|
77
|
+
}
|
|
78
|
+
export function getMalformedResponseError() {
|
|
79
|
+
return new WebFetchClientError("MALFORMED_RESPONSE", USER_MESSAGE_ZH.MALFORMED_RESPONSE, undefined);
|
|
80
|
+
}
|
|
81
|
+
export function getNetworkError(endpoint, originalError) {
|
|
82
|
+
const original = originalError instanceof Error ? originalError.message : String(originalError);
|
|
83
|
+
return new WebFetchClientError("NETWORK_ERROR", USER_MESSAGE_ZH.NETWORK_ERROR, {
|
|
84
|
+
endpoint,
|
|
85
|
+
originalError: original,
|
|
86
|
+
}, { cause: originalError instanceof Error ? originalError : undefined });
|
|
87
|
+
}
|
|
88
|
+
export function getTimeoutError(timeoutMs) {
|
|
89
|
+
return new WebFetchClientError("REQUEST_TIMEOUT", USER_MESSAGE_ZH.REQUEST_TIMEOUT, { timeoutMs, phase: "fetch" });
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/tools/web-fetch/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WebFetchToolInput, WebFetchToolOutput } from "./types";
|
|
2
|
+
import type { ToolExecutionContext } from "../shared";
|
|
3
|
+
/**
|
|
4
|
+
* 调用 Web Fetch Server `/v1/extract`,返回正文与元数据。
|
|
5
|
+
*
|
|
6
|
+
* @see docs/adr/decisions/0003c-web-fetch-config.md §5.1
|
|
7
|
+
* @see docs/adr/decisions/0003d-web-fetch-errors.md §4
|
|
8
|
+
*/
|
|
9
|
+
export declare function executeWebFetch(input: WebFetchToolInput, ctx: ToolExecutionContext): Promise<WebFetchToolOutput>;
|
|
10
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/tools/web-fetch/executor.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAsD,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AACzH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAuHtD;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,iBAAiB,EACxB,GAAG,EAAE,oBAAoB,GACxB,OAAO,CAAC,kBAAkB,CAAC,CAmD7B"}
|