@polpo-ai/tools 0.6.31 → 0.7.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.
- package/dist/__tests__/email-tools.test.d.ts +2 -0
- package/dist/__tests__/email-tools.test.d.ts.map +1 -0
- package/dist/__tests__/email-tools.test.js +705 -0
- package/dist/__tests__/email-tools.test.js.map +1 -0
- package/dist/__tests__/extended-tools.test.d.ts +2 -0
- package/dist/__tests__/extended-tools.test.d.ts.map +1 -0
- package/dist/__tests__/extended-tools.test.js +743 -0
- package/dist/__tests__/extended-tools.test.js.map +1 -0
- package/dist/__tests__/external-api-tools.test.d.ts +2 -0
- package/dist/__tests__/external-api-tools.test.d.ts.map +1 -0
- package/dist/__tests__/external-api-tools.test.js +1731 -0
- package/dist/__tests__/external-api-tools.test.js.map +1 -0
- package/dist/__tests__/memory-tools.test.d.ts +2 -0
- package/dist/__tests__/memory-tools.test.d.ts.map +1 -0
- package/dist/__tests__/memory-tools.test.js +0 -0
- package/dist/__tests__/memory-tools.test.js.map +1 -0
- package/dist/__tests__/system-tools.test.d.ts +2 -0
- package/dist/__tests__/system-tools.test.d.ts.map +1 -0
- package/dist/__tests__/system-tools.test.js +417 -0
- package/dist/__tests__/system-tools.test.js.map +1 -0
- package/dist/adapters/node-shell.d.ts +9 -0
- package/dist/adapters/node-shell.d.ts.map +1 -1
- package/dist/adapters/node-shell.js +40 -9
- package/dist/adapters/node-shell.js.map +1 -1
- package/dist/audio-tools.d.ts +25 -27
- package/dist/audio-tools.d.ts.map +1 -1
- package/dist/audio-tools.js +156 -438
- package/dist/audio-tools.js.map +1 -1
- package/dist/browser-tools.d.ts.map +1 -1
- package/dist/browser-tools.js +5 -1
- package/dist/browser-tools.js.map +1 -1
- package/dist/email-tools.d.ts.map +1 -1
- package/dist/email-tools.js +11 -3
- package/dist/email-tools.js.map +1 -1
- package/dist/image-tools.d.ts +27 -25
- package/dist/image-tools.d.ts.map +1 -1
- package/dist/image-tools.js +151 -332
- package/dist/image-tools.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/edge-speech-model.d.ts +61 -0
- package/dist/lib/edge-speech-model.d.ts.map +1 -0
- package/dist/lib/edge-speech-model.js +144 -0
- package/dist/lib/edge-speech-model.js.map +1 -0
- package/dist/lib/exa-search-provider.d.ts +27 -0
- package/dist/lib/exa-search-provider.d.ts.map +1 -0
- package/dist/lib/exa-search-provider.js +109 -0
- package/dist/lib/exa-search-provider.js.map +1 -0
- package/dist/lib/provider-resolver.d.ts +54 -0
- package/dist/lib/provider-resolver.d.ts.map +1 -0
- package/dist/lib/provider-resolver.js +115 -0
- package/dist/lib/provider-resolver.js.map +1 -0
- package/dist/search-tools.d.ts +10 -13
- package/dist/search-tools.d.ts.map +1 -1
- package/dist/search-tools.js +63 -140
- package/dist/search-tools.js.map +1 -1
- package/dist/system-tools.d.ts +19 -5
- package/dist/system-tools.d.ts.map +1 -1
- package/dist/system-tools.js +48 -31
- package/dist/system-tools.js.map +1 -1
- package/package.json +16 -4
- package/dist/phone-tools.d.ts +0 -27
- package/dist/phone-tools.d.ts.map +0 -1
- package/dist/phone-tools.js +0 -577
- package/dist/phone-tools.js.map +0 -1
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Behavioral tests for the 7 core coding tools (read / write / edit /
|
|
3
|
+
* bash / glob / grep / ls). Each tool is exercised via its `execute()`
|
|
4
|
+
* entry point against a fresh temp cwd per test.
|
|
5
|
+
*
|
|
6
|
+
* Focus: production-grade adversarial edge cases. LLMs hallucinate
|
|
7
|
+
* paths, mangle whitespace, retry with mutated args, and produce
|
|
8
|
+
* inputs that look valid but break naive implementations. The test
|
|
9
|
+
* suite covers what we've actually seen go wrong (or what *will* go
|
|
10
|
+
* wrong) in chat-completion runs:
|
|
11
|
+
*
|
|
12
|
+
* - sandbox escapes via `..`, absolute paths, symlink-like traversal
|
|
13
|
+
* - LLM-mangled `edit` old_text (trailing whitespace, regex chars)
|
|
14
|
+
* - bash shell-meta payloads, output explosions, non-zero stderr
|
|
15
|
+
* - read on binary, on directories, with negative/oversize offsets
|
|
16
|
+
* - glob patterns with no match, recursion, hidden files
|
|
17
|
+
* - grep regex metachars vs literal, include/exclude filters
|
|
18
|
+
* - ls on missing paths, on files vs dirs, on hostile paths
|
|
19
|
+
*
|
|
20
|
+
* What's *not* in scope here: AI SDK schema validation (TypeBox is
|
|
21
|
+
* mechanical) and cross-runtime concerns (those are the Layer-2
|
|
22
|
+
* Docker rig).
|
|
23
|
+
*/
|
|
24
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
25
|
+
import { mkdtempSync, rmSync, writeFileSync, mkdirSync, readFileSync, statSync, symlinkSync, } from "node:fs";
|
|
26
|
+
import { tmpdir } from "node:os";
|
|
27
|
+
import { join } from "node:path";
|
|
28
|
+
import { createSystemTools } from "../system-tools.js";
|
|
29
|
+
import { NodeFileSystem } from "../adapters/node-filesystem.js";
|
|
30
|
+
import { NodeShell } from "../adapters/node-shell.js";
|
|
31
|
+
let cwd;
|
|
32
|
+
let tools;
|
|
33
|
+
function tool(name) {
|
|
34
|
+
const t = tools.find((x) => x.name === name);
|
|
35
|
+
if (!t)
|
|
36
|
+
throw new Error(`Tool '${name}' not registered. Got: ${tools.map((x) => x.name).join(", ")}`);
|
|
37
|
+
return t;
|
|
38
|
+
}
|
|
39
|
+
/** Pull the textual payload from the first content block of a tool
|
|
40
|
+
* result. Tool results are a discriminated union of text/image
|
|
41
|
+
* blocks; every tool we test here emits text first. */
|
|
42
|
+
function text(result) {
|
|
43
|
+
const block = result.content[0];
|
|
44
|
+
if (block?.type !== "text")
|
|
45
|
+
throw new Error(`Expected text content block, got ${block?.type}`);
|
|
46
|
+
return block.text;
|
|
47
|
+
}
|
|
48
|
+
beforeEach(() => {
|
|
49
|
+
cwd = mkdtempSync(join(tmpdir(), "polpo-tools-"));
|
|
50
|
+
tools = createSystemTools(cwd, undefined, [cwd], undefined, undefined, new NodeFileSystem(), new NodeShell());
|
|
51
|
+
});
|
|
52
|
+
afterEach(() => {
|
|
53
|
+
rmSync(cwd, { recursive: true, force: true });
|
|
54
|
+
});
|
|
55
|
+
// ────────────────────────────────────────────────────────────
|
|
56
|
+
describe("read — happy path", () => {
|
|
57
|
+
it("returns line-numbered content", async () => {
|
|
58
|
+
writeFileSync(join(cwd, "a.txt"), "alpha\nbeta\ngamma");
|
|
59
|
+
const result = await tool("read").execute("c1", { path: "a.txt" });
|
|
60
|
+
expect(text(result)).toContain("1\talpha");
|
|
61
|
+
expect(text(result)).toContain("3\tgamma");
|
|
62
|
+
expect(result.details).toMatchObject({ lines: 3, total: 3 });
|
|
63
|
+
});
|
|
64
|
+
it("handles a 50k-line file without truncating in details.total", async () => {
|
|
65
|
+
const big = Array.from({ length: 50_000 }, (_, i) => `L${i}`).join("\n");
|
|
66
|
+
writeFileSync(join(cwd, "big.txt"), big);
|
|
67
|
+
const result = await tool("read").execute("c1", { path: "big.txt", limit: 10 });
|
|
68
|
+
expect(result.details).toMatchObject({ total: 50_000, lines: 10 });
|
|
69
|
+
expect(text(result)).toMatch(/more lines/i);
|
|
70
|
+
});
|
|
71
|
+
it("reads files with embedded NUL bytes without crashing", async () => {
|
|
72
|
+
writeFileSync(join(cwd, "nul.txt"), "before\x00after");
|
|
73
|
+
const result = await tool("read").execute("c1", { path: "nul.txt" });
|
|
74
|
+
expect(text(result)).toContain("before");
|
|
75
|
+
});
|
|
76
|
+
it("reads files with multibyte UTF-8 + emoji + RTL", async () => {
|
|
77
|
+
writeFileSync(join(cwd, "u.txt"), "café 中文 🐙 שלום");
|
|
78
|
+
const result = await tool("read").execute("c1", { path: "u.txt" });
|
|
79
|
+
expect(text(result)).toContain("café");
|
|
80
|
+
expect(text(result)).toContain("中文");
|
|
81
|
+
expect(text(result)).toContain("🐙");
|
|
82
|
+
expect(text(result)).toContain("שלום");
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
describe("read — adversarial", () => {
|
|
86
|
+
it("rejects parent traversal `../../../etc/passwd`", async () => {
|
|
87
|
+
await expect(tool("read").execute("c1", { path: "../../../etc/passwd" })).rejects.toThrow(/sandbox|allowed|denied/i);
|
|
88
|
+
});
|
|
89
|
+
it("rejects an absolute path outside the sandbox", async () => {
|
|
90
|
+
await expect(tool("read").execute("c1", { path: "/etc/passwd" })).rejects.toThrow(/sandbox|allowed|denied/i);
|
|
91
|
+
});
|
|
92
|
+
it("rejects a symlink that escapes the sandbox", async () => {
|
|
93
|
+
const escapeLink = join(cwd, "escape");
|
|
94
|
+
symlinkSync("/etc/passwd", escapeLink);
|
|
95
|
+
// The path itself is inside the sandbox, but realpathSync follows
|
|
96
|
+
// the symlink and detects the escape.
|
|
97
|
+
await expect(tool("read").execute("c1", { path: "escape" })).rejects.toThrow(/sandbox|allowed|denied/i);
|
|
98
|
+
});
|
|
99
|
+
it("returns an error on a missing file rather than crashing", async () => {
|
|
100
|
+
await expect(tool("read").execute("c1", { path: "nope.txt" })).rejects.toThrow();
|
|
101
|
+
});
|
|
102
|
+
it("returns an error when path is a directory", async () => {
|
|
103
|
+
mkdirSync(join(cwd, "subdir"));
|
|
104
|
+
await expect(tool("read").execute("c1", { path: "subdir" })).rejects.toThrow();
|
|
105
|
+
});
|
|
106
|
+
it("treats offset beyond the file as empty without crashing", async () => {
|
|
107
|
+
writeFileSync(join(cwd, "small.txt"), "one\ntwo");
|
|
108
|
+
const result = await tool("read").execute("c1", { path: "small.txt", offset: 1000, limit: 10 });
|
|
109
|
+
// Should not throw; lines should be 0, total still 2.
|
|
110
|
+
expect(result.details).toMatchObject({ total: 2, lines: 0 });
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
// ────────────────────────────────────────────────────────────
|
|
114
|
+
describe("write — happy path", () => {
|
|
115
|
+
it("creates the file + parent dirs and reports byte count", async () => {
|
|
116
|
+
const result = await tool("write").execute("c1", { path: "deep/nested/note.md", content: "hello" });
|
|
117
|
+
expect(readFileSync(join(cwd, "deep/nested/note.md"), "utf8")).toBe("hello");
|
|
118
|
+
expect(result.details).toMatchObject({ bytes: 5 });
|
|
119
|
+
});
|
|
120
|
+
it("overwrites an existing file (no append)", async () => {
|
|
121
|
+
writeFileSync(join(cwd, "f.txt"), "old content longer than new");
|
|
122
|
+
await tool("write").execute("c1", { path: "f.txt", content: "new" });
|
|
123
|
+
expect(readFileSync(join(cwd, "f.txt"), "utf8")).toBe("new");
|
|
124
|
+
});
|
|
125
|
+
it("writes empty content without errors", async () => {
|
|
126
|
+
await tool("write").execute("c1", { path: "empty.txt", content: "" });
|
|
127
|
+
expect(readFileSync(join(cwd, "empty.txt"), "utf8")).toBe("");
|
|
128
|
+
expect(statSync(join(cwd, "empty.txt")).size).toBe(0);
|
|
129
|
+
});
|
|
130
|
+
it("preserves multibyte UTF-8 + emoji round-trip", async () => {
|
|
131
|
+
const payload = "café 中文 🐙 \u{1F4A9}";
|
|
132
|
+
await tool("write").execute("c1", { path: "u.txt", content: payload });
|
|
133
|
+
expect(readFileSync(join(cwd, "u.txt"), "utf8")).toBe(payload);
|
|
134
|
+
});
|
|
135
|
+
it("writes a 1MB payload without truncating", async () => {
|
|
136
|
+
const big = "x".repeat(1024 * 1024);
|
|
137
|
+
await tool("write").execute("c1", { path: "big.txt", content: big });
|
|
138
|
+
expect(statSync(join(cwd, "big.txt")).size).toBe(1024 * 1024);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
describe("write — adversarial", () => {
|
|
142
|
+
it("rejects an absolute escape path", async () => {
|
|
143
|
+
await expect(tool("write").execute("c1", { path: "/tmp/escape.txt", content: "x" })).rejects.toThrow(/sandbox|allowed|denied/i);
|
|
144
|
+
});
|
|
145
|
+
it("rejects parent traversal", async () => {
|
|
146
|
+
await expect(tool("write").execute("c1", { path: "../escape.txt", content: "x" })).rejects.toThrow(/sandbox|allowed|denied/i);
|
|
147
|
+
});
|
|
148
|
+
it("rejects writing through a symlink that escapes the sandbox", async () => {
|
|
149
|
+
// Symlink target must exist on disk for realpathSync to resolve
|
|
150
|
+
// it — a dangling symlink throws and the sandbox check falls back
|
|
151
|
+
// to the logical (still-inside-cwd) path, which would then let
|
|
152
|
+
// fs.writeFile follow the link and clobber the host. We point at
|
|
153
|
+
// /etc/hostname (universally present on Linux runners) so the
|
|
154
|
+
// canonical path lands outside cwd and the sandbox refuses
|
|
155
|
+
// before write() is called.
|
|
156
|
+
const link = join(cwd, "out.txt");
|
|
157
|
+
symlinkSync("/etc/hostname", link);
|
|
158
|
+
await expect(tool("write").execute("c1", { path: "out.txt", content: "pwned" })).rejects.toThrow(/sandbox|allowed|denied/i);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
// ────────────────────────────────────────────────────────────
|
|
162
|
+
describe("edit — happy path", () => {
|
|
163
|
+
it("replaces a unique substring", async () => {
|
|
164
|
+
writeFileSync(join(cwd, "f.txt"), "the quick brown fox");
|
|
165
|
+
await tool("edit").execute("c1", { path: "f.txt", old_text: "quick", new_text: "lazy" });
|
|
166
|
+
expect(readFileSync(join(cwd, "f.txt"), "utf8")).toBe("the lazy brown fox");
|
|
167
|
+
});
|
|
168
|
+
it("treats regex metachars literally (.*$+ etc.)", async () => {
|
|
169
|
+
writeFileSync(join(cwd, "f.txt"), "price: $9.99 (sale)");
|
|
170
|
+
await tool("edit").execute("c1", { path: "f.txt", old_text: "$9.99", new_text: "$5.00" });
|
|
171
|
+
expect(readFileSync(join(cwd, "f.txt"), "utf8")).toBe("price: $5.00 (sale)");
|
|
172
|
+
});
|
|
173
|
+
it("preserves trailing newline when present", async () => {
|
|
174
|
+
writeFileSync(join(cwd, "f.txt"), "hello\n");
|
|
175
|
+
await tool("edit").execute("c1", { path: "f.txt", old_text: "hello", new_text: "world" });
|
|
176
|
+
expect(readFileSync(join(cwd, "f.txt"), "utf8")).toBe("world\n");
|
|
177
|
+
});
|
|
178
|
+
it("replaces a multi-line block", async () => {
|
|
179
|
+
writeFileSync(join(cwd, "f.txt"), "line1\nold\nblock\nline4");
|
|
180
|
+
await tool("edit").execute("c1", { path: "f.txt", old_text: "old\nblock", new_text: "fresh\nstuff" });
|
|
181
|
+
expect(readFileSync(join(cwd, "f.txt"), "utf8")).toBe("line1\nfresh\nstuff\nline4");
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
describe("edit — adversarial (LLM hallucinations)", () => {
|
|
185
|
+
it("returns a clear error when old_text is missing (LLM transcription typo)", async () => {
|
|
186
|
+
writeFileSync(join(cwd, "f.txt"), "the actual content");
|
|
187
|
+
const result = await tool("edit").execute("c1", { path: "f.txt", old_text: "the actaul content", new_text: "x" });
|
|
188
|
+
expect(result.details).toMatchObject({ error: "not_found" });
|
|
189
|
+
expect(text(result)).toMatch(/not found/i);
|
|
190
|
+
// File must remain pristine — no half-application.
|
|
191
|
+
expect(readFileSync(join(cwd, "f.txt"), "utf8")).toBe("the actual content");
|
|
192
|
+
});
|
|
193
|
+
it("returns a clear error when old_text is ambiguous (recurring snippet)", async () => {
|
|
194
|
+
writeFileSync(join(cwd, "f.txt"), "import x; import y; import z;");
|
|
195
|
+
const result = await tool("edit").execute("c1", { path: "f.txt", old_text: "import", new_text: "//" });
|
|
196
|
+
expect(result.details).toMatchObject({ error: "not_unique", count: 3 });
|
|
197
|
+
expect(readFileSync(join(cwd, "f.txt"), "utf8")).toBe("import x; import y; import z;");
|
|
198
|
+
});
|
|
199
|
+
it("tolerates an LLM that drops indent (substring match preserves indent)", async () => {
|
|
200
|
+
// Pin actual behavior: the tool does substring replace, so an
|
|
201
|
+
// un-indented old_text still matches its indented occurrence and
|
|
202
|
+
// the indent is preserved automatically. This is forgiving toward
|
|
203
|
+
// the common LLM bug of remembering "the meaningful part" of a
|
|
204
|
+
// line without leading whitespace.
|
|
205
|
+
writeFileSync(join(cwd, "f.ts"), " const x = 1;\n");
|
|
206
|
+
await tool("edit").execute("c1", { path: "f.ts", old_text: "const x = 1;", new_text: "const x = 2;" });
|
|
207
|
+
expect(readFileSync(join(cwd, "f.ts"), "utf8")).toBe(" const x = 2;\n");
|
|
208
|
+
});
|
|
209
|
+
it("treats CRLF vs LF as a real mismatch (cross-OS LLM transcription)", async () => {
|
|
210
|
+
writeFileSync(join(cwd, "f.txt"), "alpha\r\nbeta");
|
|
211
|
+
const result = await tool("edit").execute("c1", { path: "f.txt", old_text: "alpha\nbeta", new_text: "x" });
|
|
212
|
+
expect(result.details).toMatchObject({ error: "not_found" });
|
|
213
|
+
});
|
|
214
|
+
it("permits a no-op replacement (old == new) without corrupting the file", async () => {
|
|
215
|
+
writeFileSync(join(cwd, "f.txt"), "hello");
|
|
216
|
+
const result = await tool("edit").execute("c1", { path: "f.txt", old_text: "hello", new_text: "hello" });
|
|
217
|
+
expect(text(result)).not.toMatch(/error/i);
|
|
218
|
+
expect(readFileSync(join(cwd, "f.txt"), "utf8")).toBe("hello");
|
|
219
|
+
});
|
|
220
|
+
it("rejects edits that target files outside the sandbox", async () => {
|
|
221
|
+
await expect(tool("edit").execute("c1", { path: "/etc/passwd", old_text: "root", new_text: "lol" })).rejects.toThrow(/sandbox|allowed|denied/i);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
// ────────────────────────────────────────────────────────────
|
|
225
|
+
describe("bash — happy path", () => {
|
|
226
|
+
it("runs a command and captures stdout", async () => {
|
|
227
|
+
const result = await tool("bash").execute("c1", { command: "echo hello-from-bash" });
|
|
228
|
+
expect(text(result)).toContain("hello-from-bash");
|
|
229
|
+
});
|
|
230
|
+
it("runs in cwd by default", async () => {
|
|
231
|
+
writeFileSync(join(cwd, "marker-xyz.txt"), "");
|
|
232
|
+
const result = await tool("bash").execute("c1", { command: "ls" });
|
|
233
|
+
expect(text(result)).toContain("marker-xyz.txt");
|
|
234
|
+
});
|
|
235
|
+
it("supports pipes and redirects", async () => {
|
|
236
|
+
const result = await tool("bash").execute("c1", { command: "printf 'a\\nb\\nc\\n' | wc -l" });
|
|
237
|
+
expect(text(result)).toMatch(/3/);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
describe("bash — adversarial", () => {
|
|
241
|
+
it("surfaces a non-zero exit clearly", async () => {
|
|
242
|
+
const result = await tool("bash").execute("c1", { command: "false" });
|
|
243
|
+
expect(text(result).toLowerCase()).toMatch(/exit|fail|error|status/);
|
|
244
|
+
});
|
|
245
|
+
it("captures stderr when stdout is empty", async () => {
|
|
246
|
+
const result = await tool("bash").execute("c1", { command: "echo oops 1>&2" });
|
|
247
|
+
expect(text(result).toLowerCase()).toContain("oops");
|
|
248
|
+
});
|
|
249
|
+
it("kills a hanging process well before the natural runtime", { timeout: 45_000 }, async () => {
|
|
250
|
+
// `sleep 30` would naturally take 30s. We ask for timeout:500.
|
|
251
|
+
// Goal: verify the call returns *well under* 30s — the actual
|
|
252
|
+
// floor on execa's enforcement is loose (observed ~5s) and we
|
|
253
|
+
// intentionally don't pin a tight number, just "not the natural
|
|
254
|
+
// runtime". Surfaces the timeout via the text payload or a
|
|
255
|
+
// non-zero exit.
|
|
256
|
+
const t0 = Date.now();
|
|
257
|
+
const result = await tool("bash").execute("c1", { command: "sleep 30", timeout: 500 });
|
|
258
|
+
const elapsed = Date.now() - t0;
|
|
259
|
+
expect(elapsed).toBeLessThan(20_000);
|
|
260
|
+
expect(text(result).toLowerCase()).toMatch(/timeout|kill|exceed|exit|sigterm|error|terminated/);
|
|
261
|
+
});
|
|
262
|
+
it("truncates massive output instead of OOMing the process", async () => {
|
|
263
|
+
const result = await tool("bash").execute("c1", {
|
|
264
|
+
command: "head -c 10000000 /dev/zero | tr '\\0' 'a'",
|
|
265
|
+
timeout: 10_000,
|
|
266
|
+
});
|
|
267
|
+
// Must not blow up — output bounded, no crash.
|
|
268
|
+
expect(text(result).length).toBeLessThan(2_000_000);
|
|
269
|
+
});
|
|
270
|
+
it("does not let `cd` leak into the next call", async () => {
|
|
271
|
+
await tool("bash").execute("c1", { command: "cd /usr" });
|
|
272
|
+
const result = await tool("bash").execute("c2", { command: "pwd" });
|
|
273
|
+
// Each tool call starts a fresh shell rooted at cwd. Asserting
|
|
274
|
+
// /usr is absent confirms the previous `cd` didn't leak; using
|
|
275
|
+
// /usr (instead of /tmp, which is cwd's parent) avoids a false
|
|
276
|
+
// positive when cwd happens to live under /tmp.
|
|
277
|
+
expect(text(result)).toContain(cwd);
|
|
278
|
+
expect(text(result)).not.toMatch(/^\/usr\b/m);
|
|
279
|
+
});
|
|
280
|
+
it("handles an empty/whitespace command without crashing", async () => {
|
|
281
|
+
const result = await tool("bash").execute("c1", { command: " " });
|
|
282
|
+
// Either runs as no-op or returns a clear error — must not throw.
|
|
283
|
+
expect(result).toBeDefined();
|
|
284
|
+
});
|
|
285
|
+
it("accepts shell-meta in arguments (we are not a sandbox at the bash layer)", async () => {
|
|
286
|
+
// We deliberately do *not* claim bash is safe against injection —
|
|
287
|
+
// it executes a full command line. This test pins the contract so
|
|
288
|
+
// future "sanitization" doesn't silently mangle legitimate uses.
|
|
289
|
+
const result = await tool("bash").execute("c1", { command: "echo 'a; echo b' | head -n1" });
|
|
290
|
+
expect(text(result)).toContain("a; echo b");
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
// ────────────────────────────────────────────────────────────
|
|
294
|
+
describe("glob — happy path", () => {
|
|
295
|
+
it("matches files by simple pattern", async () => {
|
|
296
|
+
writeFileSync(join(cwd, "a.ts"), "");
|
|
297
|
+
writeFileSync(join(cwd, "b.ts"), "");
|
|
298
|
+
writeFileSync(join(cwd, "c.txt"), "");
|
|
299
|
+
const result = await tool("glob").execute("c1", { pattern: "*.ts" });
|
|
300
|
+
expect(text(result)).toContain("a.ts");
|
|
301
|
+
expect(text(result)).toContain("b.ts");
|
|
302
|
+
expect(text(result)).not.toContain("c.txt");
|
|
303
|
+
});
|
|
304
|
+
it("handles `**` recursive patterns", async () => {
|
|
305
|
+
mkdirSync(join(cwd, "src/inner"), { recursive: true });
|
|
306
|
+
writeFileSync(join(cwd, "src/a.ts"), "");
|
|
307
|
+
writeFileSync(join(cwd, "src/inner/b.ts"), "");
|
|
308
|
+
const result = await tool("glob").execute("c1", { pattern: "**/*.ts" });
|
|
309
|
+
expect(text(result)).toContain("a.ts");
|
|
310
|
+
expect(text(result)).toContain("b.ts");
|
|
311
|
+
});
|
|
312
|
+
it("supports brace expansion `{a,b}`", async () => {
|
|
313
|
+
writeFileSync(join(cwd, "a.ts"), "");
|
|
314
|
+
writeFileSync(join(cwd, "b.tsx"), "");
|
|
315
|
+
writeFileSync(join(cwd, "c.md"), "");
|
|
316
|
+
const result = await tool("glob").execute("c1", { pattern: "*.{ts,tsx}" });
|
|
317
|
+
expect(text(result)).toContain("a.ts");
|
|
318
|
+
expect(text(result)).toContain("b.tsx");
|
|
319
|
+
expect(text(result)).not.toContain("c.md");
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
describe("glob — adversarial", () => {
|
|
323
|
+
it("reports no match clearly without throwing", async () => {
|
|
324
|
+
const result = await tool("glob").execute("c1", { pattern: "*.unicorn" });
|
|
325
|
+
expect(text(result).toLowerCase()).toMatch(/no.*(match|found)|0|empty/);
|
|
326
|
+
});
|
|
327
|
+
it("does not crash on an empty pattern", async () => {
|
|
328
|
+
const result = await tool("glob").execute("c1", { pattern: "" });
|
|
329
|
+
expect(result).toBeDefined();
|
|
330
|
+
});
|
|
331
|
+
it("ignores patterns reaching outside cwd (`../*`)", async () => {
|
|
332
|
+
// We can't assert what's outside cwd, but we *can* assert nothing
|
|
333
|
+
// from /etc/ leaks into the result text.
|
|
334
|
+
const result = await tool("glob").execute("c1", { pattern: "../../*" });
|
|
335
|
+
expect(text(result)).not.toMatch(/passwd|hostname|hosts/);
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
// ────────────────────────────────────────────────────────────
|
|
339
|
+
describe("grep — happy path", () => {
|
|
340
|
+
it("finds the pattern across files", async () => {
|
|
341
|
+
writeFileSync(join(cwd, "a.txt"), "needle here\nnothing");
|
|
342
|
+
writeFileSync(join(cwd, "b.txt"), "no match\n");
|
|
343
|
+
writeFileSync(join(cwd, "c.txt"), "needle\nagain");
|
|
344
|
+
const result = await tool("grep").execute("c1", { pattern: "needle" });
|
|
345
|
+
expect(text(result)).toContain("a.txt");
|
|
346
|
+
expect(text(result)).toContain("c.txt");
|
|
347
|
+
expect(text(result)).not.toMatch(/\bb\.txt\b/);
|
|
348
|
+
});
|
|
349
|
+
it("supports include filter", async () => {
|
|
350
|
+
writeFileSync(join(cwd, "a.ts"), "needle\n");
|
|
351
|
+
writeFileSync(join(cwd, "a.md"), "needle\n");
|
|
352
|
+
const result = await tool("grep").execute("c1", { pattern: "needle", include: "*.ts" });
|
|
353
|
+
expect(text(result)).toContain("a.ts");
|
|
354
|
+
expect(text(result)).not.toContain("a.md");
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
describe("grep — adversarial", () => {
|
|
358
|
+
it("supports PCRE escapes (\\d, \\w, \\s)", async () => {
|
|
359
|
+
writeFileSync(join(cwd, "f.txt"), "abc\n123\n");
|
|
360
|
+
const result = await tool("grep").execute("c1", { pattern: "\\d+" });
|
|
361
|
+
expect(text(result)).toContain("f.txt");
|
|
362
|
+
expect(text(result)).toContain("123");
|
|
363
|
+
});
|
|
364
|
+
it("supports lookahead and non-greedy quantifiers (PCRE features)", async () => {
|
|
365
|
+
writeFileSync(join(cwd, "f.txt"), "USD42 EUR99\n");
|
|
366
|
+
// Lookahead: 'EUR' followed by digits.
|
|
367
|
+
const r1 = await tool("grep").execute("c1", { pattern: "(?<=EUR)\\d+" });
|
|
368
|
+
expect(text(r1)).toContain("99");
|
|
369
|
+
});
|
|
370
|
+
it("returns a clean no-match result on a non-matching pattern", async () => {
|
|
371
|
+
writeFileSync(join(cwd, "f.txt"), "alpha\nbeta\n");
|
|
372
|
+
const result = await tool("grep").execute("c1", { pattern: "definitely-not-there-123" });
|
|
373
|
+
expect(text(result).toLowerCase()).toMatch(/no.*(match|found)|0|empty/);
|
|
374
|
+
});
|
|
375
|
+
it("doesn't bleed into binary files when their bytes happen to match", async () => {
|
|
376
|
+
// A binary file with the bytes 'needle' embedded — grep should
|
|
377
|
+
// either skip it or show it without confusing the output.
|
|
378
|
+
writeFileSync(join(cwd, "bin.dat"), Buffer.from([0, 1, 2, 0x6e, 0x65, 0x65, 0x64, 0x6c, 0x65, 0, 0]));
|
|
379
|
+
writeFileSync(join(cwd, "real.txt"), "needle\n");
|
|
380
|
+
const result = await tool("grep").execute("c1", { pattern: "needle" });
|
|
381
|
+
expect(text(result)).toContain("real.txt");
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
// ────────────────────────────────────────────────────────────
|
|
385
|
+
describe("ls — happy path", () => {
|
|
386
|
+
it("lists files and directories", async () => {
|
|
387
|
+
writeFileSync(join(cwd, "file.txt"), "");
|
|
388
|
+
mkdirSync(join(cwd, "subdir"));
|
|
389
|
+
const result = await tool("ls").execute("c1", { path: "." });
|
|
390
|
+
expect(text(result)).toContain("file.txt");
|
|
391
|
+
expect(text(result)).toContain("subdir");
|
|
392
|
+
});
|
|
393
|
+
it("works on a deeply nested subdir", async () => {
|
|
394
|
+
mkdirSync(join(cwd, "a/b/c"), { recursive: true });
|
|
395
|
+
writeFileSync(join(cwd, "a/b/c/leaf.txt"), "");
|
|
396
|
+
const result = await tool("ls").execute("c1", { path: "a/b/c" });
|
|
397
|
+
expect(text(result)).toContain("leaf.txt");
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
describe("ls — adversarial", () => {
|
|
401
|
+
it("rejects paths outside the sandbox", async () => {
|
|
402
|
+
await expect(tool("ls").execute("c1", { path: "/etc" })).rejects.toThrow(/sandbox|allowed|denied/i);
|
|
403
|
+
});
|
|
404
|
+
it("rejects parent traversal", async () => {
|
|
405
|
+
await expect(tool("ls").execute("c1", { path: "../.." })).rejects.toThrow(/sandbox|allowed|denied/i);
|
|
406
|
+
});
|
|
407
|
+
it("returns a clear error on a missing directory", async () => {
|
|
408
|
+
await expect(tool("ls").execute("c1", { path: "no-such-dir" })).rejects.toThrow();
|
|
409
|
+
});
|
|
410
|
+
it("returns a sane result on an empty directory", async () => {
|
|
411
|
+
mkdirSync(join(cwd, "empty"));
|
|
412
|
+
const result = await tool("ls").execute("c1", { path: "empty" });
|
|
413
|
+
// Should not throw; output may be empty or "no entries"-like.
|
|
414
|
+
expect(result).toBeDefined();
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
//# sourceMappingURL=system-tools.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-tools.test.js","sourceRoot":"","sources":["../../src/__tests__/system-tools.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EACL,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,EAC7C,YAAY,EAAE,QAAQ,EAAE,WAAW,GACpC,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAGtD,IAAI,GAAW,CAAC;AAChB,IAAI,KAAuB,CAAC;AAE5B,SAAS,IAAI,CAAC,IAAY;IACxB,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC7C,IAAI,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,SAAS,IAAI,0BAA0B,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtG,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;wDAEwD;AACxD,SAAS,IAAI,CAAC,MAAkE;IAC9E,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAChC,IAAI,KAAK,EAAE,IAAI,KAAK,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/F,OAAO,KAAK,CAAC,IAAI,CAAC;AACpB,CAAC;AAED,UAAU,CAAC,GAAG,EAAE;IACd,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;IAClD,KAAK,GAAG,iBAAiB,CAAC,GAAG,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,cAAc,EAAE,EAAE,IAAI,SAAS,EAAE,CAAC,CAAC;AAChH,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,GAAG,EAAE;IACb,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AAEH,+DAA+D;AAC/D,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,oBAAoB,CAAC,CAAC;QACxD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACnE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzE,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAChF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACnE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,iBAAiB,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QACrE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,iBAAiB,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACnE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,MAAM,CACV,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAC5D,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,MAAM,CACV,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CACpD,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACvC,WAAW,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;QACvC,kEAAkE;QAClE,sCAAsC;QACtC,MAAM,MAAM,CACV,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAC/C,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,MAAM,MAAM,CACV,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CACjD,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC/B,MAAM,MAAM,CACV,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAC/C,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,UAAU,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAChG,sDAAsD;QACtD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,+DAA+D;AAC/D,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACpG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7E,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,6BAA6B,CAAC,CAAC;QACjE,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACrE,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QACtE,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9D,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,OAAO,GAAG,sBAAsB,CAAC;QACvC,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACvE,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QACpC,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;QACrE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,MAAM,CACV,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CACvE,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,MAAM,CACV,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CACrE,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,gEAAgE;QAChE,kEAAkE;QAClE,+DAA+D;QAC/D,iEAAiE;QACjE,8DAA8D;QAC9D,2DAA2D;QAC3D,4BAA4B;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAClC,WAAW,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;QACnC,MAAM,MAAM,CACV,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CACnE,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,+DAA+D;AAC/D,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,qBAAqB,CAAC,CAAC;QACzD,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;QACzF,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,qBAAqB,CAAC,CAAC;QACzD,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC;QAC7C,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,0BAA0B,CAAC,CAAC;QAC9D,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC;QACtG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,yCAAyC,EAAE,GAAG,EAAE;IACvD,EAAE,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;QACvF,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,oBAAoB,CAAC,CAAC;QACxD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;QAClH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QAC7D,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAC3C,mDAAmD;QACnD,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,KAAK,IAAI,EAAE;QACpF,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,+BAA+B,CAAC,CAAC;QACnE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACvG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACxE,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;QACrF,8DAA8D;QAC9D,iEAAiE;QACjE,kEAAkE;QAClE,+DAA+D;QAC/D,mCAAmC;QACnC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC;QACrD,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC;QACvG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3G,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,KAAK,IAAI,EAAE;QACpF,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QACzG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,MAAM,CACV,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CACvF,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,+DAA+D;AAC/D,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC,CAAC;QACrF,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;QACtC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACnE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;QAC5C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC,CAAC;QAC9F,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACtE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAC;QAC/E,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,IAAI,EAAE;QAC5F,+DAA+D;QAC/D,8DAA8D;QAC9D,8DAA8D;QAC9D,gEAAgE;QAChE,2DAA2D;QAC3D,iBAAiB;QACjB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;QACvF,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;QAChC,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC;IAClG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE;YAC9C,OAAO,EAAE,2CAA2C;YACpD,OAAO,EAAE,MAAM;SAChB,CAAC,CAAC;QACH,+CAA+C;QAC/C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACpE,+DAA+D;QAC/D,+DAA+D;QAC/D,+DAA+D;QAC/D,gDAAgD;QAChD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACpE,kEAAkE;QAClE,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,kEAAkE;QAClE,kEAAkE;QAClE,iEAAiE;QACjE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAAC,CAAC;QAC5F,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,+DAA+D;AAC/D,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QACrE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;QACzC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;QACxE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACtC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;QAC3E,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QAC1E,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QACjE,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,kEAAkE;QAClE,yCAAyC;QACzC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;QACxE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,+DAA+D;AAC/D,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,sBAAsB,CAAC,CAAC;QAC1D,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC;QAChD,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;QACvC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;QAC7C,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QACxF,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QACrE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC;QACnD,uCAAuC;QACvC,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;QACzE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QACzE,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC,CAAC;QACzF,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;QAChF,+DAA+D;QAC/D,0DAA0D;QAC1D,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACtG,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,UAAU,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,+DAA+D;AAC/D,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;QACzC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QAC7D,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACjE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACtG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACvG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACjE,8DAA8D;QAC9D,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { Shell, ShellOptions, ShellResult } from "@polpo-ai/core/shell";
|
|
2
|
+
/**
|
|
3
|
+
* Fork the command into a fresh process group so we can kill the
|
|
4
|
+
* whole tree on timeout. execa's built-in `timeout` only sends
|
|
5
|
+
* SIGTERM to the spawned shell process; with `shell: true` the
|
|
6
|
+
* shell becomes a parent of the user's command (e.g. `sleep 30`),
|
|
7
|
+
* which survives the SIGTERM and keeps running until natural exit.
|
|
8
|
+
* We bypass that by spawning detached and killing -PID with
|
|
9
|
+
* SIGKILL when our timer fires.
|
|
10
|
+
*/
|
|
2
11
|
export declare class NodeShell implements Shell {
|
|
3
12
|
execute(command: string, options?: ShellOptions): Promise<ShellResult>;
|
|
4
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-shell.d.ts","sourceRoot":"","sources":["../../src/adapters/node-shell.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAG7E,qBAAa,SAAU,YAAW,KAAK;IAC/B,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"node-shell.d.ts","sourceRoot":"","sources":["../../src/adapters/node-shell.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAG7E;;;;;;;;GAQG;AACH,qBAAa,SAAU,YAAW,KAAK;IAC/B,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;CA0C7E"}
|
|
@@ -4,23 +4,54 @@
|
|
|
4
4
|
* Default implementation for self-hosted mode. Executes real shell commands.
|
|
5
5
|
* Drop-in replacement pattern: swap with JustBashShell, SandboxProxyShell, etc.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { execa } from "execa";
|
|
8
8
|
import { bashSafeEnv } from "../safe-env.js";
|
|
9
|
+
/**
|
|
10
|
+
* Fork the command into a fresh process group so we can kill the
|
|
11
|
+
* whole tree on timeout. execa's built-in `timeout` only sends
|
|
12
|
+
* SIGTERM to the spawned shell process; with `shell: true` the
|
|
13
|
+
* shell becomes a parent of the user's command (e.g. `sleep 30`),
|
|
14
|
+
* which survives the SIGTERM and keeps running until natural exit.
|
|
15
|
+
* We bypass that by spawning detached and killing -PID with
|
|
16
|
+
* SIGKILL when our timer fires.
|
|
17
|
+
*/
|
|
9
18
|
export class NodeShell {
|
|
10
19
|
async execute(command, options) {
|
|
20
|
+
const timeout = options?.timeout;
|
|
11
21
|
try {
|
|
12
|
-
const
|
|
13
|
-
|
|
22
|
+
const child = execa("bash", ["-c", command], {
|
|
23
|
+
detached: true,
|
|
14
24
|
cwd: options?.cwd,
|
|
15
25
|
env: { ...bashSafeEnv(), ...options?.env },
|
|
16
|
-
timeout: options?.timeout,
|
|
17
26
|
reject: false,
|
|
18
27
|
});
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
let killedByTimeout = false;
|
|
29
|
+
const timer = timeout
|
|
30
|
+
? setTimeout(() => {
|
|
31
|
+
killedByTimeout = true;
|
|
32
|
+
try {
|
|
33
|
+
if (child.pid)
|
|
34
|
+
process.kill(-child.pid, "SIGKILL");
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// process already gone
|
|
38
|
+
}
|
|
39
|
+
}, timeout)
|
|
40
|
+
: null;
|
|
41
|
+
try {
|
|
42
|
+
const result = await child;
|
|
43
|
+
return {
|
|
44
|
+
stdout: result.stdout?.toString() ?? "",
|
|
45
|
+
stderr: killedByTimeout
|
|
46
|
+
? `${result.stderr ?? ""}\nCommand timed out after ${timeout}ms (SIGKILL).`
|
|
47
|
+
: result.stderr?.toString() ?? "",
|
|
48
|
+
exitCode: result.exitCode ?? (killedByTimeout ? 124 : (result.signal ? 130 : 0)),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
if (timer)
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
}
|
|
24
55
|
}
|
|
25
56
|
catch (err) {
|
|
26
57
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-shell.js","sourceRoot":"","sources":["../../src/adapters/node-shell.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"node-shell.js","sourceRoot":"","sources":["../../src/adapters/node-shell.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAE9B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C;;;;;;;;GAQG;AACH,MAAM,OAAO,SAAS;IACpB,KAAK,CAAC,OAAO,CAAC,OAAe,EAAE,OAAsB;QACnD,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE;gBAC3C,QAAQ,EAAE,IAAI;gBACd,GAAG,EAAE,OAAO,EAAE,GAAG;gBACjB,GAAG,EAAE,EAAE,GAAG,WAAW,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE;gBAC1C,MAAM,EAAE,KAAK;aACd,CAAC,CAAC;YAEH,IAAI,eAAe,GAAG,KAAK,CAAC;YAC5B,MAAM,KAAK,GAAG,OAAO;gBACnB,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE;oBACd,eAAe,GAAG,IAAI,CAAC;oBACvB,IAAI,CAAC;wBACH,IAAI,KAAK,CAAC,GAAG;4BAAE,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;oBACrD,CAAC;oBAAC,MAAM,CAAC;wBACP,uBAAuB;oBACzB,CAAC;gBACH,CAAC,EAAE,OAAO,CAAC;gBACb,CAAC,CAAC,IAAI,CAAC;YAET,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC;gBAC3B,OAAO;oBACL,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACvC,MAAM,EAAE,eAAe;wBACrB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,6BAA6B,OAAO,eAAe;wBAC3E,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACnC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;iBACjF,CAAC;YACJ,CAAC;oBAAS,CAAC;gBACT,IAAI,KAAK;oBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO;gBACL,MAAM,EAAE,EAAE;gBACV,MAAM,EAAE,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC;gBAClC,QAAQ,EAAE,CAAC;aACZ,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
|
package/dist/audio-tools.d.ts
CHANGED
|
@@ -1,30 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Audio tools for speech-to-text (STT) and text-to-speech (TTS).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Architecture: thin wrappers over the Vercel AI SDK v6.
|
|
5
|
+
* - audio_transcribe → `experimental_transcribe`
|
|
6
|
+
* - audio_speak → `experimental_generateSpeech`
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* Model selection: each tool picks its model in this order:
|
|
9
|
+
* 1. per-call `model` input (`<provider>/<model>` string),
|
|
10
|
+
* 2. agent-config default (transcribe_model / tts_model),
|
|
11
|
+
* 3. DEFAULT_TRANSCRIBE_MODEL / DEFAULT_TTS_MODEL from @polpo-ai/core.
|
|
9
12
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* Edge TTS: Uses Microsoft Edge's neural TTS engine via the `edge-tts` CLI.
|
|
15
|
-
* Free, no API key, ~400 voices in 60+ languages. Auto-selects voice from
|
|
16
|
-
* language + gender params. Also used as automatic fallback when cloud providers fail.
|
|
17
|
-
* Install: `pip install edge-tts`
|
|
18
|
-
*
|
|
19
|
-
* Credential resolution order (same as email/image tools):
|
|
20
|
-
* 1. Agent vault (per-agent credentials — e.g. service "openai" key "key")
|
|
21
|
-
* 2. Environment variables (global fallback)
|
|
22
|
-
* 3. Edge TTS (automatic fallback — no credentials needed)
|
|
23
|
-
*
|
|
24
|
-
* Environment variables (fallback):
|
|
25
|
-
* OPENAI_API_KEY — openai provider (STT + TTS)
|
|
26
|
-
* DEEPGRAM_API_KEY — deepgram provider (STT + TTS)
|
|
27
|
-
* ELEVENLABS_API_KEY — elevenlabs provider (TTS)
|
|
13
|
+
* audio_speak's `edge` provider is wrapped as a custom SpeechModelV3 in
|
|
14
|
+
* `lib/edge-speech-model.ts` so it slots into the same SDK call as
|
|
15
|
+
* cloud providers (no special-casing in the tool layer).
|
|
28
16
|
*/
|
|
29
17
|
import type { PolpoTool as AgentTool } from "@polpo-ai/core";
|
|
30
18
|
import type { FileSystem } from "@polpo-ai/core/filesystem";
|
|
@@ -32,13 +20,23 @@ import type { Shell } from "@polpo-ai/core";
|
|
|
32
20
|
import type { ResolvedVault } from "./types.js";
|
|
33
21
|
export type AudioToolName = "audio_transcribe" | "audio_speak";
|
|
34
22
|
export declare const ALL_AUDIO_TOOL_NAMES: AudioToolName[];
|
|
23
|
+
export interface CreateAudioToolsOptions {
|
|
24
|
+
cwd: string;
|
|
25
|
+
allowedPaths?: string[];
|
|
26
|
+
allowedTools?: string[];
|
|
27
|
+
vault?: ResolvedVault;
|
|
28
|
+
fs?: FileSystem;
|
|
29
|
+
shell?: Shell;
|
|
30
|
+
/** Resolved agent.transcribe_model. Format: "provider/model". */
|
|
31
|
+
transcribeModel?: string;
|
|
32
|
+
/** Resolved agent.tts_model. Format: "provider/model". */
|
|
33
|
+
ttsModel?: string;
|
|
34
|
+
}
|
|
35
35
|
/**
|
|
36
36
|
* Create audio tools for speech-to-text and text-to-speech.
|
|
37
37
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* @param allowedTools - Optional filter
|
|
41
|
-
* @param vault - Resolved vault credentials for credential resolution
|
|
38
|
+
* The 6-arg positional signature is preserved for back-compat. Prefer
|
|
39
|
+
* the options-object form for new callers.
|
|
42
40
|
*/
|
|
43
|
-
export declare function createAudioTools(cwd: string, allowedPaths?: string[], allowedTools?: string[], vault?: ResolvedVault, fs?: FileSystem, shell?: Shell): AgentTool<any>[];
|
|
41
|
+
export declare function createAudioTools(cwd: string | CreateAudioToolsOptions, allowedPaths?: string[], allowedTools?: string[], vault?: ResolvedVault, fs?: FileSystem, shell?: Shell): AgentTool<any>[];
|
|
44
42
|
//# sourceMappingURL=audio-tools.d.ts.map
|