@tachu/extensions 1.0.0-beta.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 +77 -0
- package/LICENSE +201 -0
- package/README.md +825 -0
- package/README_ZH.md +815 -0
- package/dist/backends/file.d.ts +18 -0
- package/dist/backends/file.d.ts.map +1 -0
- package/dist/backends/file.js +69 -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 +57 -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 +53 -0
- package/dist/backends/web.js.map +1 -0
- package/dist/common/net.d.ts +31 -0
- package/dist/common/net.d.ts.map +1 -0
- package/dist/common/net.js +162 -0
- package/dist/common/net.js.map +1 -0
- package/dist/common/path.d.ts +18 -0
- package/dist/common/path.d.ts.map +1 -0
- package/dist/common/path.js +34 -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 +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -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 +70 -0
- package/dist/mcp/sse-adapter.d.ts.map +1 -0
- package/dist/mcp/sse-adapter.js +176 -0
- package/dist/mcp/sse-adapter.js.map +1 -0
- package/dist/mcp/stdio-adapter.d.ts +73 -0
- package/dist/mcp/stdio-adapter.d.ts.map +1 -0
- package/dist/mcp/stdio-adapter.js +178 -0
- package/dist/mcp/stdio-adapter.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 +54 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +298 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +4 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/mock.d.ts +38 -0
- package/dist/providers/mock.d.ts.map +1 -0
- package/dist/providers/mock.js +79 -0
- package/dist/providers/mock.js.map +1 -0
- package/dist/providers/openai.d.ts +61 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +299 -0
- package/dist/providers/openai.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/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 +190 -0
- package/dist/tools/apply-patch/executor.js.map +1 -0
- package/dist/tools/fetch-url/descriptor.md +38 -0
- package/dist/tools/fetch-url/executor.d.ts +20 -0
- package/dist/tools/fetch-url/executor.d.ts.map +1 -0
- package/dist/tools/fetch-url/executor.js +34 -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 +191 -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 +46 -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 +113 -0
- package/dist/tools/search-code/executor.js.map +1 -0
- package/dist/tools/shared.d.ts +21 -0
- package/dist/tools/shared.d.ts.map +1 -0
- package/dist/tools/shared.js +12 -0
- package/dist/tools/shared.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 +81 -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 +65 -0
- package/dist/vector/qdrant.d.ts.map +1 -0
- package/dist/vector/qdrant.js +176 -0
- package/dist/vector/qdrant.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: tool
|
|
3
|
+
name: read-file
|
|
4
|
+
description: 读取工作区内的文件内容
|
|
5
|
+
sideEffect: readonly
|
|
6
|
+
idempotent: true
|
|
7
|
+
requiresApproval: false
|
|
8
|
+
timeout: 5000
|
|
9
|
+
inputSchema:
|
|
10
|
+
type: object
|
|
11
|
+
properties:
|
|
12
|
+
path:
|
|
13
|
+
type: string
|
|
14
|
+
encoding:
|
|
15
|
+
type: string
|
|
16
|
+
enum: [utf-8, base64]
|
|
17
|
+
required: [path]
|
|
18
|
+
outputSchema:
|
|
19
|
+
type: object
|
|
20
|
+
properties:
|
|
21
|
+
content:
|
|
22
|
+
type: string
|
|
23
|
+
bytes:
|
|
24
|
+
type: number
|
|
25
|
+
execute: read-file
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
读取工作区内文件内容。默认返回 UTF-8 文本,可选返回 base64。
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ToolExecutor } from "../shared";
|
|
2
|
+
interface ReadFileInput {
|
|
3
|
+
path: string;
|
|
4
|
+
encoding?: "utf-8" | "base64";
|
|
5
|
+
}
|
|
6
|
+
interface ReadFileOutput {
|
|
7
|
+
content: string;
|
|
8
|
+
bytes: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 读取文件 Tool 执行器。
|
|
12
|
+
*/
|
|
13
|
+
export declare const readFileExecutor: ToolExecutor<ReadFileInput, ReadFileOutput>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/tools/read-file/executor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAK9C,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC/B;AAED,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,YAAY,CAAC,aAAa,EAAE,cAAc,CAoBxE,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { stat, readFile } from "node:fs/promises";
|
|
2
|
+
import { ValidationError } from "@tachu/core";
|
|
3
|
+
import { resolveWorkspacePath } from "../../common/path";
|
|
4
|
+
import { assertNotAborted } from "../shared";
|
|
5
|
+
const MAX_FILE_BYTES = 10 * 1024 * 1024;
|
|
6
|
+
/**
|
|
7
|
+
* 读取文件 Tool 执行器。
|
|
8
|
+
*/
|
|
9
|
+
export const readFileExecutor = async (input, context) => {
|
|
10
|
+
assertNotAborted(context.abortSignal);
|
|
11
|
+
const target = resolveWorkspacePath(context.workspaceRoot, input.path);
|
|
12
|
+
const fileStat = await stat(target);
|
|
13
|
+
if (fileStat.size > MAX_FILE_BYTES) {
|
|
14
|
+
throw new ValidationError("VALIDATION_FILE_TOO_LARGE", `文件超过限制: ${fileStat.size} bytes > ${MAX_FILE_BYTES} bytes`, { context: { path: input.path, size: fileStat.size, max: MAX_FILE_BYTES } });
|
|
15
|
+
}
|
|
16
|
+
const bytes = await readFile(target);
|
|
17
|
+
return {
|
|
18
|
+
content: input.encoding === "base64" ? Buffer.from(bytes).toString("base64") : bytes.toString(),
|
|
19
|
+
bytes: bytes.byteLength,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../src/tools/read-file/executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,cAAc,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAYxC;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAgD,KAAK,EAChF,KAAK,EACL,OAAO,EACP,EAAE;IACF,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,QAAQ,CAAC,IAAI,GAAG,cAAc,EAAE,CAAC;QACnC,MAAM,IAAI,eAAe,CACvB,2BAA2B,EAC3B,WAAW,QAAQ,CAAC,IAAI,YAAY,cAAc,QAAQ,EAC1D,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,cAAc,EAAE,EAAE,CAC5E,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;IACrC,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE;QAC/F,KAAK,EAAE,KAAK,CAAC,UAAU;KACxB,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: tool
|
|
3
|
+
name: run-shell
|
|
4
|
+
description: 在受控环境中执行 shell 命令
|
|
5
|
+
sideEffect: irreversible
|
|
6
|
+
idempotent: false
|
|
7
|
+
requiresApproval: true
|
|
8
|
+
timeout: 30000
|
|
9
|
+
inputSchema:
|
|
10
|
+
type: object
|
|
11
|
+
properties:
|
|
12
|
+
command:
|
|
13
|
+
type: string
|
|
14
|
+
args:
|
|
15
|
+
type: array
|
|
16
|
+
items:
|
|
17
|
+
type: string
|
|
18
|
+
cwd:
|
|
19
|
+
type: string
|
|
20
|
+
env:
|
|
21
|
+
type: object
|
|
22
|
+
timeoutMs:
|
|
23
|
+
type: number
|
|
24
|
+
required: [command]
|
|
25
|
+
outputSchema:
|
|
26
|
+
type: object
|
|
27
|
+
properties:
|
|
28
|
+
stdout:
|
|
29
|
+
type: string
|
|
30
|
+
stderr:
|
|
31
|
+
type: string
|
|
32
|
+
exitCode:
|
|
33
|
+
type: number
|
|
34
|
+
durationMs:
|
|
35
|
+
type: number
|
|
36
|
+
execute: run-shell
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
执行 shell 命令并返回 stdout/stderr,默认只继承 PATH/HOME/LANG 环境变量。
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ToolExecutor } from "../shared";
|
|
2
|
+
interface RunShellInput {
|
|
3
|
+
command: string;
|
|
4
|
+
args?: string[];
|
|
5
|
+
cwd?: string;
|
|
6
|
+
env?: Record<string, string>;
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
}
|
|
9
|
+
interface RunShellOutput {
|
|
10
|
+
stdout: string;
|
|
11
|
+
stderr: string;
|
|
12
|
+
exitCode: number;
|
|
13
|
+
durationMs: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 执行 shell Tool 执行器。
|
|
17
|
+
*/
|
|
18
|
+
export declare const runShellExecutor: ToolExecutor<RunShellInput, RunShellOutput>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/tools/run-shell/executor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C,UAAU,aAAa;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAoBD;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,YAAY,CAAC,aAAa,EAAE,cAAc,CA0DxE,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ValidationError } from "@tachu/core";
|
|
2
|
+
import { resolveWorkspacePath } from "../../common/path";
|
|
3
|
+
import { readStreamWithLimit, terminateProcess } from "../../common/process";
|
|
4
|
+
import { assertNotAborted } from "../shared";
|
|
5
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
6
|
+
const STREAM_LIMIT_BYTES = 1024 * 1024;
|
|
7
|
+
const DEFAULT_ENV_ALLOWLIST = ["PATH", "HOME", "LANG"];
|
|
8
|
+
const buildSandboxedEnv = (extra) => {
|
|
9
|
+
const env = {};
|
|
10
|
+
for (const key of DEFAULT_ENV_ALLOWLIST) {
|
|
11
|
+
const value = process.env[key];
|
|
12
|
+
if (typeof value === "string") {
|
|
13
|
+
env[key] = value;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
for (const [key, value] of Object.entries(extra ?? {})) {
|
|
17
|
+
env[key] = value;
|
|
18
|
+
}
|
|
19
|
+
return env;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* 执行 shell Tool 执行器。
|
|
23
|
+
*/
|
|
24
|
+
export const runShellExecutor = async (input, context) => {
|
|
25
|
+
assertNotAborted(context.abortSignal);
|
|
26
|
+
if (!input.command || input.command.trim().length === 0) {
|
|
27
|
+
throw new ValidationError("VALIDATION_EMPTY_COMMAND", "command 不能为空");
|
|
28
|
+
}
|
|
29
|
+
const cwd = input.cwd
|
|
30
|
+
? resolveWorkspacePath(context.workspaceRoot, input.cwd)
|
|
31
|
+
: context.workspaceRoot;
|
|
32
|
+
const timeoutMs = input.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
33
|
+
const startedAt = Date.now();
|
|
34
|
+
const processRef = Bun.spawn({
|
|
35
|
+
cmd: [input.command, ...(input.args ?? [])],
|
|
36
|
+
cwd,
|
|
37
|
+
env: buildSandboxedEnv(input.env),
|
|
38
|
+
stdout: "pipe",
|
|
39
|
+
stderr: "pipe",
|
|
40
|
+
});
|
|
41
|
+
const onAbort = () => {
|
|
42
|
+
if (processRef.pid) {
|
|
43
|
+
void terminateProcess(processRef.pid);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
context.abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
47
|
+
const timeout = setTimeout(() => {
|
|
48
|
+
if (processRef.pid) {
|
|
49
|
+
void terminateProcess(processRef.pid);
|
|
50
|
+
}
|
|
51
|
+
}, timeoutMs);
|
|
52
|
+
try {
|
|
53
|
+
const [stdoutResult, stderrResult, exitCode] = await Promise.all([
|
|
54
|
+
readStreamWithLimit(processRef.stdout, STREAM_LIMIT_BYTES),
|
|
55
|
+
readStreamWithLimit(processRef.stderr, STREAM_LIMIT_BYTES),
|
|
56
|
+
processRef.exited,
|
|
57
|
+
]);
|
|
58
|
+
const stdout = stdoutResult.truncated
|
|
59
|
+
? `${stdoutResult.text}\n[truncated:${STREAM_LIMIT_BYTES}]`
|
|
60
|
+
: stdoutResult.text;
|
|
61
|
+
const stderr = stderrResult.truncated
|
|
62
|
+
? `${stderrResult.text}\n[truncated:${STREAM_LIMIT_BYTES}]`
|
|
63
|
+
: stderrResult.text;
|
|
64
|
+
return {
|
|
65
|
+
stdout,
|
|
66
|
+
stderr,
|
|
67
|
+
exitCode,
|
|
68
|
+
durationMs: Date.now() - startedAt,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
clearTimeout(timeout);
|
|
73
|
+
context.abortSignal.removeEventListener("abort", onAbort);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../src/tools/run-shell/executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -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,CAyF9E,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { assertNotAborted } from "../shared";
|
|
4
|
+
import { resolveWorkspacePath, 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 = resolveWorkspacePath(context.workspaceRoot, input.path ?? ".");
|
|
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
|
+
const children = await readdir(dir, { withFileTypes: true });
|
|
75
|
+
for (const child of children) {
|
|
76
|
+
if (matches.length >= maxResults) {
|
|
77
|
+
truncated = true;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const target = join(dir, child.name);
|
|
81
|
+
if (child.isDirectory()) {
|
|
82
|
+
await walk(target);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (!child.isFile()) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (input.fileGlob && !target.endsWith(input.fileGlob.replace("*", ""))) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const content = await readFile(target, "utf8").catch(() => "");
|
|
92
|
+
const lines = content.split("\n");
|
|
93
|
+
lines.forEach((line, index) => {
|
|
94
|
+
if (matches.length >= maxResults) {
|
|
95
|
+
truncated = true;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (matcher.test(line)) {
|
|
99
|
+
matches.push({
|
|
100
|
+
file: toWorkspaceRelativePath(context.workspaceRoot, target),
|
|
101
|
+
line: index + 1,
|
|
102
|
+
text: line,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
matcher.lastIndex = 0;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
await walk(root);
|
|
110
|
+
return { matches, truncated };
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
//# 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,21 @@
|
|
|
1
|
+
import type { Session } from "@tachu/core";
|
|
2
|
+
/**
|
|
3
|
+
* Tool 执行时上下文。
|
|
4
|
+
*/
|
|
5
|
+
export interface ToolExecutionContext {
|
|
6
|
+
abortSignal: AbortSignal;
|
|
7
|
+
workspaceRoot: string;
|
|
8
|
+
session: Session;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Tool 执行器签名。
|
|
12
|
+
*/
|
|
13
|
+
export type ToolExecutor<TInput = unknown, TOutput = unknown> = (input: TInput, context: ToolExecutionContext) => Promise<TOutput>;
|
|
14
|
+
/**
|
|
15
|
+
* 检查中断状态。
|
|
16
|
+
*
|
|
17
|
+
* @param signal 取消信号
|
|
18
|
+
* @throws Error 当已中断
|
|
19
|
+
*/
|
|
20
|
+
export declare const assertNotAborted: (signal: AbortSignal) => void;
|
|
21
|
+
//# 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;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/tools/shared.ts"],"names":[],"mappings":"AAmBA;;;;;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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
kind: tool
|
|
3
|
+
name: write-file
|
|
4
|
+
description: 写入工作区内文件内容
|
|
5
|
+
sideEffect: write
|
|
6
|
+
idempotent: false
|
|
7
|
+
requiresApproval: true
|
|
8
|
+
timeout: 5000
|
|
9
|
+
inputSchema:
|
|
10
|
+
type: object
|
|
11
|
+
properties:
|
|
12
|
+
path:
|
|
13
|
+
type: string
|
|
14
|
+
content:
|
|
15
|
+
type: string
|
|
16
|
+
encoding:
|
|
17
|
+
type: string
|
|
18
|
+
enum: [utf-8, base64]
|
|
19
|
+
createDirs:
|
|
20
|
+
type: boolean
|
|
21
|
+
required: [path, content]
|
|
22
|
+
outputSchema:
|
|
23
|
+
type: object
|
|
24
|
+
properties:
|
|
25
|
+
bytesWritten:
|
|
26
|
+
type: number
|
|
27
|
+
execute: write-file
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
向工作区写入文件,支持 UTF-8 与 base64 输入。
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ToolExecutor } from "../shared";
|
|
2
|
+
interface WriteFileInput {
|
|
3
|
+
path: string;
|
|
4
|
+
content: string;
|
|
5
|
+
encoding?: "utf-8" | "base64";
|
|
6
|
+
createDirs?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface WriteFileOutput {
|
|
9
|
+
bytesWritten: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 写入文件 Tool 执行器。
|
|
13
|
+
*/
|
|
14
|
+
export declare const writeFileExecutor: ToolExecutor<WriteFileInput, WriteFileOutput>;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/tools/write-file/executor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,UAAU,eAAe;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,YAAY,CAAC,cAAc,EAAE,eAAe,CAa3E,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { resolveWorkspacePath } from "../../common/path";
|
|
4
|
+
import { assertNotAborted } from "../shared";
|
|
5
|
+
/**
|
|
6
|
+
* 写入文件 Tool 执行器。
|
|
7
|
+
*/
|
|
8
|
+
export const writeFileExecutor = async (input, context) => {
|
|
9
|
+
assertNotAborted(context.abortSignal);
|
|
10
|
+
const target = resolveWorkspacePath(context.workspaceRoot, input.path);
|
|
11
|
+
if (input.createDirs) {
|
|
12
|
+
await mkdir(dirname(target), { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
const payload = input.encoding === "base64" ? Buffer.from(input.content, "base64") : Buffer.from(input.content);
|
|
15
|
+
await writeFile(target, payload);
|
|
16
|
+
return { bytesWritten: payload.byteLength };
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../src/tools/write-file/executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAa7C;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAkD,KAAK,EACnF,KAAK,EACL,OAAO,EACP,EAAE;IACF,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACvE,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACrB,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,OAAO,GACX,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAClG,MAAM,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC;AAC9C,CAAC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { InputEnvelope, InputMetadata, InputTransformer, ModelCapabilities } from "@tachu/core";
|
|
2
|
+
/**
|
|
3
|
+
* 文档转文本转换器(PDF / DOCX)。
|
|
4
|
+
*/
|
|
5
|
+
export declare class DocumentToTextTransformer implements InputTransformer {
|
|
6
|
+
readonly modality = "document";
|
|
7
|
+
/**
|
|
8
|
+
* 判断是否需要文档降级。
|
|
9
|
+
*
|
|
10
|
+
* @param metadata 输入元信息
|
|
11
|
+
* @param modelCapabilities 模型能力
|
|
12
|
+
* @returns true 表示需要转换
|
|
13
|
+
*/
|
|
14
|
+
canHandle(metadata: InputMetadata, modelCapabilities: ModelCapabilities): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* 将文档转换为文本信封。
|
|
17
|
+
*
|
|
18
|
+
* @param envelope 输入信封
|
|
19
|
+
* @returns 文本信封
|
|
20
|
+
*/
|
|
21
|
+
transform(envelope: InputEnvelope): Promise<InputEnvelope>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=document-to-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-to-text.d.ts","sourceRoot":"","sources":["../../src/transformers/document-to-text.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAkBrG;;GAEG;AACH,qBAAa,yBAA0B,YAAW,gBAAgB;IAChE,QAAQ,CAAC,QAAQ,cAAc;IAE/B;;;;;;OAMG;IACH,SAAS,CAAC,QAAQ,EAAE,aAAa,EAAE,iBAAiB,EAAE,iBAAiB,GAAG,OAAO;IAMjF;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;CAkCjE"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { PDFParse } from "pdf-parse";
|
|
3
|
+
import mammoth from "mammoth";
|
|
4
|
+
import { ValidationError } from "@tachu/core";
|
|
5
|
+
const MAX_TEXT_CHARS = 500_000;
|
|
6
|
+
const truncateIfNeeded = (text) => {
|
|
7
|
+
if (text.length <= MAX_TEXT_CHARS) {
|
|
8
|
+
return text;
|
|
9
|
+
}
|
|
10
|
+
const trimmed = text.slice(0, MAX_TEXT_CHARS);
|
|
11
|
+
return `${trimmed}\n\n[TRUNCATED:${text.length - MAX_TEXT_CHARS}]`;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* 文档转文本转换器(PDF / DOCX)。
|
|
15
|
+
*/
|
|
16
|
+
export class DocumentToTextTransformer {
|
|
17
|
+
modality = "document";
|
|
18
|
+
/**
|
|
19
|
+
* 判断是否需要文档降级。
|
|
20
|
+
*
|
|
21
|
+
* @param metadata 输入元信息
|
|
22
|
+
* @param modelCapabilities 模型能力
|
|
23
|
+
* @returns true 表示需要转换
|
|
24
|
+
*/
|
|
25
|
+
canHandle(metadata, modelCapabilities) {
|
|
26
|
+
const modality = metadata.modality ?? "";
|
|
27
|
+
const isDocument = modality === "document" || modality === "file";
|
|
28
|
+
return isDocument && !modelCapabilities.supportedModalities.includes("file");
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 将文档转换为文本信封。
|
|
32
|
+
*
|
|
33
|
+
* @param envelope 输入信封
|
|
34
|
+
* @returns 文本信封
|
|
35
|
+
*/
|
|
36
|
+
async transform(envelope) {
|
|
37
|
+
const content = envelope.content;
|
|
38
|
+
if (!content.path) {
|
|
39
|
+
throw new ValidationError("VALIDATION_DOCUMENT_PATH", "文档输入缺少 path");
|
|
40
|
+
}
|
|
41
|
+
const mimeType = content.mimeType ?? envelope.metadata.mimeType ?? "";
|
|
42
|
+
let text = "";
|
|
43
|
+
if (mimeType.includes("pdf") || content.path.toLowerCase().endsWith(".pdf")) {
|
|
44
|
+
const buffer = await readFile(content.path);
|
|
45
|
+
const parser = new PDFParse({ data: buffer });
|
|
46
|
+
const parsed = await parser.getText();
|
|
47
|
+
text = parsed.text;
|
|
48
|
+
await parser.destroy();
|
|
49
|
+
}
|
|
50
|
+
else if (mimeType.includes("word") ||
|
|
51
|
+
mimeType.includes("officedocument") ||
|
|
52
|
+
content.path.toLowerCase().endsWith(".docx")) {
|
|
53
|
+
const result = await mammoth.extractRawText({ path: content.path });
|
|
54
|
+
text = result.value;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
text = await readFile(content.path, "utf8");
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
content: truncateIfNeeded(text),
|
|
61
|
+
metadata: {
|
|
62
|
+
...envelope.metadata,
|
|
63
|
+
modality: "text",
|
|
64
|
+
mimeType: "text/plain",
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=document-to-text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-to-text.js","sourceRoot":"","sources":["../../src/transformers/document-to-text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAO9C,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAU,EAAE;IAChD,IAAI,IAAI,CAAC,MAAM,IAAI,cAAc,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;IAC9C,OAAO,GAAG,OAAO,kBAAkB,IAAI,CAAC,MAAM,GAAG,cAAc,GAAG,CAAC;AACrE,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,OAAO,yBAAyB;IAC3B,QAAQ,GAAG,UAAU,CAAC;IAE/B;;;;;;OAMG;IACH,SAAS,CAAC,QAAuB,EAAE,iBAAoC;QACrE,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC;QACzC,MAAM,UAAU,GAAG,QAAQ,KAAK,UAAU,IAAI,QAAQ,KAAK,MAAM,CAAC;QAClE,OAAO,UAAU,IAAI,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/E,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,SAAS,CAAC,QAAuB;QACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAA0B,CAAC;QACpD,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,MAAM,IAAI,eAAe,CAAC,0BAA0B,EAAE,aAAa,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC;QAEtE,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5E,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;YAC9C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;YACtC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACnB,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;QACzB,CAAC;aAAM,IACL,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;YACzB,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAC5C,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YACpE,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC9C,CAAC;QAED,OAAO;YACL,OAAO,EAAE,gBAAgB,CAAC,IAAI,CAAC;YAC/B,QAAQ,EAAE;gBACR,GAAG,QAAQ,CAAC,QAAQ;gBACpB,QAAQ,EAAE,MAAM;gBAChB,QAAQ,EAAE,YAAY;aACvB;SACF,CAAC;IACJ,CAAC;CACF"}
|