@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.
Files changed (67) hide show
  1. package/dist/__tests__/email-tools.test.d.ts +2 -0
  2. package/dist/__tests__/email-tools.test.d.ts.map +1 -0
  3. package/dist/__tests__/email-tools.test.js +705 -0
  4. package/dist/__tests__/email-tools.test.js.map +1 -0
  5. package/dist/__tests__/extended-tools.test.d.ts +2 -0
  6. package/dist/__tests__/extended-tools.test.d.ts.map +1 -0
  7. package/dist/__tests__/extended-tools.test.js +743 -0
  8. package/dist/__tests__/extended-tools.test.js.map +1 -0
  9. package/dist/__tests__/external-api-tools.test.d.ts +2 -0
  10. package/dist/__tests__/external-api-tools.test.d.ts.map +1 -0
  11. package/dist/__tests__/external-api-tools.test.js +1731 -0
  12. package/dist/__tests__/external-api-tools.test.js.map +1 -0
  13. package/dist/__tests__/memory-tools.test.d.ts +2 -0
  14. package/dist/__tests__/memory-tools.test.d.ts.map +1 -0
  15. package/dist/__tests__/memory-tools.test.js +0 -0
  16. package/dist/__tests__/memory-tools.test.js.map +1 -0
  17. package/dist/__tests__/system-tools.test.d.ts +2 -0
  18. package/dist/__tests__/system-tools.test.d.ts.map +1 -0
  19. package/dist/__tests__/system-tools.test.js +417 -0
  20. package/dist/__tests__/system-tools.test.js.map +1 -0
  21. package/dist/adapters/node-shell.d.ts +9 -0
  22. package/dist/adapters/node-shell.d.ts.map +1 -1
  23. package/dist/adapters/node-shell.js +40 -9
  24. package/dist/adapters/node-shell.js.map +1 -1
  25. package/dist/audio-tools.d.ts +25 -27
  26. package/dist/audio-tools.d.ts.map +1 -1
  27. package/dist/audio-tools.js +156 -438
  28. package/dist/audio-tools.js.map +1 -1
  29. package/dist/browser-tools.d.ts.map +1 -1
  30. package/dist/browser-tools.js +5 -1
  31. package/dist/browser-tools.js.map +1 -1
  32. package/dist/email-tools.d.ts.map +1 -1
  33. package/dist/email-tools.js +11 -3
  34. package/dist/email-tools.js.map +1 -1
  35. package/dist/image-tools.d.ts +27 -25
  36. package/dist/image-tools.d.ts.map +1 -1
  37. package/dist/image-tools.js +151 -332
  38. package/dist/image-tools.js.map +1 -1
  39. package/dist/index.d.ts +1 -2
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +3 -2
  42. package/dist/index.js.map +1 -1
  43. package/dist/lib/edge-speech-model.d.ts +61 -0
  44. package/dist/lib/edge-speech-model.d.ts.map +1 -0
  45. package/dist/lib/edge-speech-model.js +144 -0
  46. package/dist/lib/edge-speech-model.js.map +1 -0
  47. package/dist/lib/exa-search-provider.d.ts +27 -0
  48. package/dist/lib/exa-search-provider.d.ts.map +1 -0
  49. package/dist/lib/exa-search-provider.js +109 -0
  50. package/dist/lib/exa-search-provider.js.map +1 -0
  51. package/dist/lib/provider-resolver.d.ts +54 -0
  52. package/dist/lib/provider-resolver.d.ts.map +1 -0
  53. package/dist/lib/provider-resolver.js +115 -0
  54. package/dist/lib/provider-resolver.js.map +1 -0
  55. package/dist/search-tools.d.ts +10 -13
  56. package/dist/search-tools.d.ts.map +1 -1
  57. package/dist/search-tools.js +63 -140
  58. package/dist/search-tools.js.map +1 -1
  59. package/dist/system-tools.d.ts +19 -5
  60. package/dist/system-tools.d.ts.map +1 -1
  61. package/dist/system-tools.js +48 -31
  62. package/dist/system-tools.js.map +1 -1
  63. package/package.json +16 -4
  64. package/dist/phone-tools.d.ts +0 -27
  65. package/dist/phone-tools.d.ts.map +0 -1
  66. package/dist/phone-tools.js +0 -577
  67. 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":"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"}
@@ -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;CAsB7E"}
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 { execaCommand } from "execa";
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 result = await execaCommand(command, {
13
- shell: true,
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
- return {
20
- stdout: result.stdout,
21
- stderr: result.stderr,
22
- exitCode: result.exitCode ?? 0,
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,YAAY,EAAE,MAAM,OAAO,CAAC;AAErC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,OAAO,SAAS;IACpB,KAAK,CAAC,OAAO,CAAC,OAAe,EAAE,OAAsB;QACnD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE;gBACzC,KAAK,EAAE,IAAI;gBACX,GAAG,EAAE,OAAO,EAAE,GAAG;gBACjB,GAAG,EAAE,EAAE,GAAG,WAAW,EAAE,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE;gBAC1C,OAAO,EAAE,OAAO,EAAE,OAAO;gBACzB,MAAM,EAAE,KAAK;aACd,CAAC,CAAC;YACH,OAAO;gBACL,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,CAAC;aAC/B,CAAC;QACJ,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"}
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"}
@@ -1,30 +1,18 @@
1
1
  /**
2
2
  * Audio tools for speech-to-text (STT) and text-to-speech (TTS).
3
3
  *
4
- * Provides agent capabilities to:
5
- * - Transcribe audio files to text (audio_transcribe)
6
- * - Generate speech audio from text (audio_speak)
4
+ * Architecture: thin wrappers over the Vercel AI SDK v6.
5
+ * - audio_transcribe `experimental_transcribe`
6
+ * - audio_speak → `experimental_generateSpeech`
7
7
  *
8
- * Architecture: direct fetch() to provider REST APIs zero vendor SDK dependencies.
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
- * Supported providers:
11
- * STT: openai (Whisper), deepgram (Nova)
12
- * TTS: openai (gpt-4o-mini-tts / tts-1), deepgram (Aura), elevenlabs, edge (free, local)
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
- * @param cwd - Working directory for resolving file paths
39
- * @param allowedPaths - Sandbox paths for file validation
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