@polpo-ai/tools 0.2.4
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/adapters/node-filesystem.d.ts +12 -0
- package/dist/adapters/node-filesystem.d.ts.map +1 -0
- package/dist/adapters/node-filesystem.js +46 -0
- package/dist/adapters/node-filesystem.js.map +1 -0
- package/dist/adapters/node-shell.d.ts +5 -0
- package/dist/adapters/node-shell.d.ts.map +1 -0
- package/dist/adapters/node-shell.js +34 -0
- package/dist/adapters/node-shell.js.map +1 -0
- package/dist/audio-tools.d.ts +42 -0
- package/dist/audio-tools.d.ts.map +1 -0
- package/dist/audio-tools.js +552 -0
- package/dist/audio-tools.js.map +1 -0
- package/dist/browser-tools.d.ts +36 -0
- package/dist/browser-tools.d.ts.map +1 -0
- package/dist/browser-tools.js +525 -0
- package/dist/browser-tools.js.map +1 -0
- package/dist/coding-tools.d.ts +99 -0
- package/dist/coding-tools.d.ts.map +1 -0
- package/dist/coding-tools.js +434 -0
- package/dist/coding-tools.js.map +1 -0
- package/dist/docx-tools.d.ts +22 -0
- package/dist/docx-tools.d.ts.map +1 -0
- package/dist/docx-tools.js +236 -0
- package/dist/docx-tools.js.map +1 -0
- package/dist/email-tools.d.ts +34 -0
- package/dist/email-tools.d.ts.map +1 -0
- package/dist/email-tools.js +787 -0
- package/dist/email-tools.js.map +1 -0
- package/dist/excel-tools.d.ts +25 -0
- package/dist/excel-tools.d.ts.map +1 -0
- package/dist/excel-tools.js +409 -0
- package/dist/excel-tools.js.map +1 -0
- package/dist/http-tools.d.ts +23 -0
- package/dist/http-tools.d.ts.map +1 -0
- package/dist/http-tools.js +214 -0
- package/dist/http-tools.js.map +1 -0
- package/dist/image-tools.d.ts +40 -0
- package/dist/image-tools.d.ts.map +1 -0
- package/dist/image-tools.js +522 -0
- package/dist/image-tools.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/memory-tools.d.ts +19 -0
- package/dist/memory-tools.d.ts.map +1 -0
- package/dist/memory-tools.js +104 -0
- package/dist/memory-tools.js.map +1 -0
- package/dist/outcome-tools.d.ts +25 -0
- package/dist/outcome-tools.d.ts.map +1 -0
- package/dist/outcome-tools.js +191 -0
- package/dist/outcome-tools.js.map +1 -0
- package/dist/path-sandbox.d.ts +28 -0
- package/dist/path-sandbox.d.ts.map +1 -0
- package/dist/path-sandbox.js +58 -0
- package/dist/path-sandbox.js.map +1 -0
- package/dist/pdf-tools.d.ts +25 -0
- package/dist/pdf-tools.d.ts.map +1 -0
- package/dist/pdf-tools.js +363 -0
- package/dist/pdf-tools.js.map +1 -0
- package/dist/phone-tools.d.ts +27 -0
- package/dist/phone-tools.d.ts.map +1 -0
- package/dist/phone-tools.js +577 -0
- package/dist/phone-tools.js.map +1 -0
- package/dist/safe-env.d.ts +26 -0
- package/dist/safe-env.d.ts.map +1 -0
- package/dist/safe-env.js +76 -0
- package/dist/safe-env.js.map +1 -0
- package/dist/search-tools.d.ts +22 -0
- package/dist/search-tools.d.ts.map +1 -0
- package/dist/search-tools.js +205 -0
- package/dist/search-tools.js.map +1 -0
- package/dist/ssrf-guard.d.ts +17 -0
- package/dist/ssrf-guard.d.ts.map +1 -0
- package/dist/ssrf-guard.js +95 -0
- package/dist/ssrf-guard.js.map +1 -0
- package/dist/types.d.ts +21 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/vault-tools.d.ts +26 -0
- package/dist/vault-tools.d.ts.map +1 -0
- package/dist/vault-tools.js +86 -0
- package/dist/vault-tools.js.map +1 -0
- package/dist/whatsapp-tools.d.ts +18 -0
- package/dist/whatsapp-tools.d.ts.map +1 -0
- package/dist/whatsapp-tools.js +206 -0
- package/dist/whatsapp-tools.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory tools for agents — scoped to a single agent's private memory.
|
|
3
|
+
*
|
|
4
|
+
* These tools let an agent read and write its own persistent memory
|
|
5
|
+
* during direct-chat sessions. The agent scope is baked in at creation
|
|
6
|
+
* time so the agent cannot access other agents' or shared memory.
|
|
7
|
+
*/
|
|
8
|
+
import { Type } from "@sinclair/typebox";
|
|
9
|
+
import { agentMemoryScope } from "@polpo-ai/core";
|
|
10
|
+
// ── Tool names ──
|
|
11
|
+
export const ALL_MEMORY_TOOL_NAMES = [
|
|
12
|
+
"memory_get",
|
|
13
|
+
"memory_save",
|
|
14
|
+
"memory_append",
|
|
15
|
+
"memory_update",
|
|
16
|
+
];
|
|
17
|
+
// ── Schemas ──
|
|
18
|
+
const MemoryGetSchema = Type.Object({});
|
|
19
|
+
const MemorySaveSchema = Type.Object({
|
|
20
|
+
content: Type.String({ description: "The full memory content to save (overwrites existing)" }),
|
|
21
|
+
});
|
|
22
|
+
const MemoryAppendSchema = Type.Object({
|
|
23
|
+
text: Type.String({ description: "Text to append to your memory" }),
|
|
24
|
+
});
|
|
25
|
+
const MemoryUpdateSchema = Type.Object({
|
|
26
|
+
old_text: Type.String({ description: "Exact substring in your memory to find" }),
|
|
27
|
+
new_text: Type.String({ description: "Replacement text" }),
|
|
28
|
+
});
|
|
29
|
+
// ── Factory ──
|
|
30
|
+
/**
|
|
31
|
+
* Create memory tools for an agent, scoped to that agent's private memory.
|
|
32
|
+
*
|
|
33
|
+
* @param store The MemoryStore instance
|
|
34
|
+
* @param agent The agent name — tools will only access `agent:<name>` scope
|
|
35
|
+
*/
|
|
36
|
+
export function createMemoryTools(store, agent) {
|
|
37
|
+
const scope = agentMemoryScope(agent);
|
|
38
|
+
const memoryGet = {
|
|
39
|
+
name: "memory_get",
|
|
40
|
+
label: "Read Memory",
|
|
41
|
+
description: "Read your persistent memory. This memory survives across sessions " +
|
|
42
|
+
"and contains your personal notes, learnings, and context. " +
|
|
43
|
+
"Returns empty string if you have no saved memory yet.",
|
|
44
|
+
parameters: MemoryGetSchema,
|
|
45
|
+
async execute() {
|
|
46
|
+
const content = await store.get(scope);
|
|
47
|
+
return {
|
|
48
|
+
content: [{ type: "text", text: content || "(no memory saved yet)" }],
|
|
49
|
+
details: { scope },
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
const memorySave = {
|
|
54
|
+
name: "memory_save",
|
|
55
|
+
label: "Save Memory",
|
|
56
|
+
description: "Overwrite your entire persistent memory with new content. " +
|
|
57
|
+
"Use this when you want to restructure or rewrite your memory completely. " +
|
|
58
|
+
"For adding a single note, prefer memory_append instead.",
|
|
59
|
+
parameters: MemorySaveSchema,
|
|
60
|
+
async execute(_toolCallId, params) {
|
|
61
|
+
await store.save(params.content, scope);
|
|
62
|
+
return {
|
|
63
|
+
content: [{ type: "text", text: `Memory saved (${params.content.length} chars).` }],
|
|
64
|
+
details: { scope, chars: params.content.length },
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
const memoryAppend = {
|
|
69
|
+
name: "memory_append",
|
|
70
|
+
label: "Append to Memory",
|
|
71
|
+
description: "Append a timestamped line to your persistent memory. " +
|
|
72
|
+
"Good for quick notes, learnings, or observations you want to remember.",
|
|
73
|
+
parameters: MemoryAppendSchema,
|
|
74
|
+
async execute(_toolCallId, params) {
|
|
75
|
+
await store.append(params.text, scope);
|
|
76
|
+
return {
|
|
77
|
+
content: [{ type: "text", text: `Appended to memory: "${params.text}"` }],
|
|
78
|
+
details: { scope },
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
const memoryUpdate = {
|
|
83
|
+
name: "memory_update",
|
|
84
|
+
label: "Update Memory",
|
|
85
|
+
description: "Find and replace a specific section in your memory. " +
|
|
86
|
+
"The old_text must be an exact unique substring of your current memory.",
|
|
87
|
+
parameters: MemoryUpdateSchema,
|
|
88
|
+
async execute(_toolCallId, params) {
|
|
89
|
+
const result = await store.update(params.old_text, params.new_text, scope);
|
|
90
|
+
if (result === true) {
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: "text", text: "Memory updated successfully." }],
|
|
93
|
+
details: { scope, success: true },
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
content: [{ type: "text", text: `Failed to update memory: ${result}` }],
|
|
98
|
+
details: { scope, success: false },
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
return [memoryGet, memorySave, memoryAppend, memoryUpdate];
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=memory-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-tools.js","sourceRoot":"","sources":["../src/memory-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outcome registration tool.
|
|
3
|
+
*
|
|
4
|
+
* The ONLY mechanism for agents to declare task outcomes. Producing a file
|
|
5
|
+
* (via write, pdf_create, bash, etc.) does NOT auto-register it as an
|
|
6
|
+
* outcome — the agent must explicitly call register_outcome for every
|
|
7
|
+
* deliverable artifact.
|
|
8
|
+
*
|
|
9
|
+
* Supports files, media, text, URLs, and structured JSON data.
|
|
10
|
+
* The tool validates that file outcomes actually exist on disk before
|
|
11
|
+
* registering them.
|
|
12
|
+
*/
|
|
13
|
+
import type { AgentTool } from "@mariozechner/pi-agent-core";
|
|
14
|
+
export type OutcomeToolName = "register_outcome";
|
|
15
|
+
export declare const ALL_OUTCOME_TOOL_NAMES: OutcomeToolName[];
|
|
16
|
+
/**
|
|
17
|
+
* Create outcome registration tools.
|
|
18
|
+
*
|
|
19
|
+
* @param cwd - Working directory
|
|
20
|
+
* @param allowedPaths - Sandbox paths
|
|
21
|
+
* @param allowedTools - Optional filter
|
|
22
|
+
* @param outputDir - Per-task output directory for deliverables
|
|
23
|
+
*/
|
|
24
|
+
export declare function createOutcomeTools(cwd: string, allowedPaths?: string[], allowedTools?: string[], outputDir?: string): AgentTool<any>[];
|
|
25
|
+
//# sourceMappingURL=outcome-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outcome-tools.d.ts","sourceRoot":"","sources":["../src/outcome-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAiK7D,MAAM,MAAM,eAAe,GAAG,kBAAkB,CAAC;AAEjD,eAAO,MAAM,sBAAsB,EAAE,eAAe,EAAyB,CAAC;AAE9E;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAYtI"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outcome registration tool.
|
|
3
|
+
*
|
|
4
|
+
* The ONLY mechanism for agents to declare task outcomes. Producing a file
|
|
5
|
+
* (via write, pdf_create, bash, etc.) does NOT auto-register it as an
|
|
6
|
+
* outcome — the agent must explicitly call register_outcome for every
|
|
7
|
+
* deliverable artifact.
|
|
8
|
+
*
|
|
9
|
+
* Supports files, media, text, URLs, and structured JSON data.
|
|
10
|
+
* The tool validates that file outcomes actually exist on disk before
|
|
11
|
+
* registering them.
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync, statSync } from "node:fs";
|
|
14
|
+
import { resolve } from "node:path";
|
|
15
|
+
import { Type } from "@sinclair/typebox";
|
|
16
|
+
import { resolveAllowedPaths, assertPathAllowed } from "./path-sandbox.js";
|
|
17
|
+
// ─── Tool: register_outcome ───
|
|
18
|
+
const RegisterOutcomeSchema = Type.Object({
|
|
19
|
+
type: Type.Union([
|
|
20
|
+
Type.Literal("file"),
|
|
21
|
+
Type.Literal("media"),
|
|
22
|
+
Type.Literal("text"),
|
|
23
|
+
Type.Literal("url"),
|
|
24
|
+
Type.Literal("json"),
|
|
25
|
+
], { description: "Outcome type. 'file' for documents (PDF, Excel, DOCX, HTML, archives). 'media' for images/audio/video. 'text' for inline text content. 'url' for links. 'json' for structured data." }),
|
|
26
|
+
label: Type.String({ description: "Human-readable label for this outcome (e.g. 'Q4 Sales Report', 'Architecture Diagram', 'API Response')" }),
|
|
27
|
+
path: Type.Optional(Type.String({ description: "File path (required for type 'file' or 'media'). Relative paths resolved from cwd." })),
|
|
28
|
+
text: Type.Optional(Type.String({ description: "Text content (for type 'text'). The actual content to include in the outcome." })),
|
|
29
|
+
url: Type.Optional(Type.String({ description: "URL (for type 'url'). Link to external resource." })),
|
|
30
|
+
data: Type.Optional(Type.Unknown({ description: "Structured data (for type 'json'). Any JSON-serializable value." })),
|
|
31
|
+
tags: Type.Optional(Type.Array(Type.String(), { description: "Optional tags for categorization (e.g. ['report', 'quarterly'])" })),
|
|
32
|
+
});
|
|
33
|
+
/** MIME type inference from file extension. */
|
|
34
|
+
const EXT_MIME = {
|
|
35
|
+
".mp3": "audio/mpeg", ".wav": "audio/wav", ".ogg": "audio/ogg", ".flac": "audio/flac", ".m4a": "audio/mp4",
|
|
36
|
+
".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".webp": "image/webp", ".gif": "image/gif", ".svg": "image/svg+xml",
|
|
37
|
+
".mp4": "video/mp4", ".webm": "video/webm", ".mov": "video/quicktime",
|
|
38
|
+
".pdf": "application/pdf",
|
|
39
|
+
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
40
|
+
".xls": "application/vnd.ms-excel",
|
|
41
|
+
".csv": "text/csv",
|
|
42
|
+
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
43
|
+
".doc": "application/msword",
|
|
44
|
+
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
45
|
+
".json": "application/json",
|
|
46
|
+
".txt": "text/plain",
|
|
47
|
+
".html": "text/html", ".htm": "text/html",
|
|
48
|
+
".zip": "application/zip",
|
|
49
|
+
".tar": "application/x-tar",
|
|
50
|
+
".gz": "application/gzip",
|
|
51
|
+
};
|
|
52
|
+
function guessMime(filePath) {
|
|
53
|
+
const dot = filePath.lastIndexOf(".");
|
|
54
|
+
if (dot === -1)
|
|
55
|
+
return undefined;
|
|
56
|
+
return EXT_MIME[filePath.slice(dot).toLowerCase()];
|
|
57
|
+
}
|
|
58
|
+
function createRegisterOutcomeTool(cwd, sandbox, outputDir) {
|
|
59
|
+
// Use outputDir in examples when available so the agent naturally writes there
|
|
60
|
+
const exampleDir = outputDir ? outputDir.replace(/\/$/, "") : "output";
|
|
61
|
+
return {
|
|
62
|
+
name: "register_outcome",
|
|
63
|
+
label: "Register Outcome",
|
|
64
|
+
description: "Register a file, text, URL, or data as a task outcome. This is the ONLY way to declare " +
|
|
65
|
+
"deliverables — producing files does NOT auto-register them. You MUST call this tool for " +
|
|
66
|
+
"every artifact that should appear in notifications and the task record.\n\n" +
|
|
67
|
+
(outputDir ? `Your task output directory is: ${outputDir}\nWrite deliverable files there before registering them.\n\n` : "") +
|
|
68
|
+
"Examples:\n" +
|
|
69
|
+
`- After creating a PDF: register_outcome({type: 'file', label: 'Sales Report', path: '${exampleDir}/report.pdf'})\n` +
|
|
70
|
+
`- After generating an image: register_outcome({type: 'media', label: 'Revenue Chart', path: '${exampleDir}/revenue.png'})\n` +
|
|
71
|
+
"- To share a deploy URL: register_outcome({type: 'url', label: 'Staging Deploy', url: 'https://staging.example.com'})\n" +
|
|
72
|
+
"- To include analysis results: register_outcome({type: 'text', label: 'Summary', text: 'Revenue increased 23%...'})\n" +
|
|
73
|
+
"- To return structured data: register_outcome({type: 'json', label: 'Metrics', data: {revenue: 1234}})",
|
|
74
|
+
parameters: RegisterOutcomeSchema,
|
|
75
|
+
async execute(_id, params) {
|
|
76
|
+
const { type, label } = params;
|
|
77
|
+
// Validate type-specific fields
|
|
78
|
+
if ((type === "file" || type === "media") && !params.path) {
|
|
79
|
+
return {
|
|
80
|
+
content: [{ type: "text", text: `Error: 'path' is required for outcome type '${type}'` }],
|
|
81
|
+
details: { error: "missing_path" },
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
if (type === "text" && !params.text) {
|
|
85
|
+
return {
|
|
86
|
+
content: [{ type: "text", text: `Error: 'text' is required for outcome type 'text'` }],
|
|
87
|
+
details: { error: "missing_text" },
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (type === "url" && !params.url) {
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: "text", text: `Error: 'url' is required for outcome type 'url'` }],
|
|
93
|
+
details: { error: "missing_url" },
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (type === "json" && params.data === undefined) {
|
|
97
|
+
return {
|
|
98
|
+
content: [{ type: "text", text: `Error: 'data' is required for outcome type 'json'` }],
|
|
99
|
+
details: { error: "missing_data" },
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
// For file/media outcomes, validate the file exists
|
|
103
|
+
let filePath;
|
|
104
|
+
let fileSize;
|
|
105
|
+
let mimeType;
|
|
106
|
+
if (params.path) {
|
|
107
|
+
filePath = resolve(cwd, params.path);
|
|
108
|
+
assertPathAllowed(filePath, sandbox, "register_outcome");
|
|
109
|
+
if (!existsSync(filePath)) {
|
|
110
|
+
return {
|
|
111
|
+
content: [{ type: "text", text: `Error: file not found: ${filePath}` }],
|
|
112
|
+
details: { error: "file_not_found", path: filePath },
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
const stats = statSync(filePath);
|
|
117
|
+
fileSize = stats.size;
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// stat failed — file may have been deleted between exists check and stat
|
|
121
|
+
}
|
|
122
|
+
mimeType = guessMime(filePath);
|
|
123
|
+
}
|
|
124
|
+
// Build the details object that engine.ts collectOutcome() will consume.
|
|
125
|
+
// The key fields are: path, outcomeType, outcomeLabel, outcomeTags,
|
|
126
|
+
// outcomeMimeType, outcomeSize, outcomeText, outcomeUrl, outcomeData.
|
|
127
|
+
const details = {
|
|
128
|
+
path: filePath,
|
|
129
|
+
outcomeType: type,
|
|
130
|
+
outcomeLabel: label,
|
|
131
|
+
};
|
|
132
|
+
if (mimeType)
|
|
133
|
+
details.outcomeMimeType = mimeType;
|
|
134
|
+
if (fileSize !== undefined)
|
|
135
|
+
details.outcomeSize = fileSize;
|
|
136
|
+
if (params.text)
|
|
137
|
+
details.outcomeText = params.text;
|
|
138
|
+
if (params.url)
|
|
139
|
+
details.outcomeUrl = params.url;
|
|
140
|
+
if (params.data !== undefined)
|
|
141
|
+
details.outcomeData = params.data;
|
|
142
|
+
if (params.tags)
|
|
143
|
+
details.outcomeTags = params.tags;
|
|
144
|
+
// Build human-readable confirmation
|
|
145
|
+
const parts = [`Outcome registered: "${label}" (${type})`];
|
|
146
|
+
if (filePath)
|
|
147
|
+
parts.push(` Path: ${filePath}`);
|
|
148
|
+
if (mimeType)
|
|
149
|
+
parts.push(` MIME: ${mimeType}`);
|
|
150
|
+
if (fileSize !== undefined)
|
|
151
|
+
parts.push(` Size: ${formatBytes(fileSize)}`);
|
|
152
|
+
if (params.url)
|
|
153
|
+
parts.push(` URL: ${params.url}`);
|
|
154
|
+
if (params.text)
|
|
155
|
+
parts.push(` Text: ${params.text.slice(0, 100)}${params.text.length > 100 ? "..." : ""}`);
|
|
156
|
+
if (params.tags?.length)
|
|
157
|
+
parts.push(` Tags: ${params.tags.join(", ")}`);
|
|
158
|
+
return {
|
|
159
|
+
content: [{ type: "text", text: parts.join("\n") }],
|
|
160
|
+
details,
|
|
161
|
+
};
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function formatBytes(bytes) {
|
|
166
|
+
if (bytes < 1024)
|
|
167
|
+
return `${bytes} B`;
|
|
168
|
+
if (bytes < 1024 * 1024)
|
|
169
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
170
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
171
|
+
}
|
|
172
|
+
export const ALL_OUTCOME_TOOL_NAMES = ["register_outcome"];
|
|
173
|
+
/**
|
|
174
|
+
* Create outcome registration tools.
|
|
175
|
+
*
|
|
176
|
+
* @param cwd - Working directory
|
|
177
|
+
* @param allowedPaths - Sandbox paths
|
|
178
|
+
* @param allowedTools - Optional filter
|
|
179
|
+
* @param outputDir - Per-task output directory for deliverables
|
|
180
|
+
*/
|
|
181
|
+
export function createOutcomeTools(cwd, allowedPaths, allowedTools, outputDir) {
|
|
182
|
+
const sandbox = resolveAllowedPaths(cwd, allowedPaths);
|
|
183
|
+
const factories = {
|
|
184
|
+
register_outcome: () => createRegisterOutcomeTool(cwd, sandbox, outputDir),
|
|
185
|
+
};
|
|
186
|
+
const names = allowedTools
|
|
187
|
+
? ALL_OUTCOME_TOOL_NAMES.filter(n => allowedTools.some(a => a.toLowerCase() === n))
|
|
188
|
+
: ALL_OUTCOME_TOOL_NAMES;
|
|
189
|
+
return names.map(n => factories[n]());
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=outcome-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outcome-tools.js","sourceRoot":"","sources":["../src/outcome-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path sandboxing for agent filesystem access.
|
|
3
|
+
*
|
|
4
|
+
* When an agent has `allowedPaths` configured, all file tool operations
|
|
5
|
+
* (read/write/edit/glob/grep/ls) validate that resolved paths fall within
|
|
6
|
+
* the allowed directories. This prevents agents from escaping their workspace
|
|
7
|
+
* via absolute paths or `../` traversal.
|
|
8
|
+
*
|
|
9
|
+
* The bash tool cannot be fully sandboxed at this level (arbitrary shell commands),
|
|
10
|
+
* but its cwd is set to the agent's primary allowed path.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Resolve allowedPaths to absolute paths, normalizing relative paths against cwd.
|
|
14
|
+
* If no allowedPaths are configured, defaults to [cwd] (the project workDir).
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveAllowedPaths(cwd: string, allowedPaths?: string[]): string[];
|
|
17
|
+
/**
|
|
18
|
+
* Check whether a resolved absolute path falls within any of the allowed directories.
|
|
19
|
+
* Uses path prefix matching with separator awareness to prevent partial matches
|
|
20
|
+
* (e.g. `/home/user/project-evil` should NOT match `/home/user/project`).
|
|
21
|
+
*/
|
|
22
|
+
export declare function isPathAllowed(filePath: string, allowedPaths: string[]): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Validate a path and throw a descriptive error if it's outside the sandbox.
|
|
25
|
+
* Call this in every file tool's execute() before performing the operation.
|
|
26
|
+
*/
|
|
27
|
+
export declare function assertPathAllowed(filePath: string, allowedPaths: string[], toolName: string): void;
|
|
28
|
+
//# sourceMappingURL=path-sandbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-sandbox.d.ts","sourceRoot":"","sources":["../src/path-sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAKlF;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAa/E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAOlG"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path sandboxing for agent filesystem access.
|
|
3
|
+
*
|
|
4
|
+
* When an agent has `allowedPaths` configured, all file tool operations
|
|
5
|
+
* (read/write/edit/glob/grep/ls) validate that resolved paths fall within
|
|
6
|
+
* the allowed directories. This prevents agents from escaping their workspace
|
|
7
|
+
* via absolute paths or `../` traversal.
|
|
8
|
+
*
|
|
9
|
+
* The bash tool cannot be fully sandboxed at this level (arbitrary shell commands),
|
|
10
|
+
* but its cwd is set to the agent's primary allowed path.
|
|
11
|
+
*/
|
|
12
|
+
import { resolve, sep } from "node:path";
|
|
13
|
+
import { realpathSync } from "node:fs";
|
|
14
|
+
/**
|
|
15
|
+
* Resolve allowedPaths to absolute paths, normalizing relative paths against cwd.
|
|
16
|
+
* If no allowedPaths are configured, defaults to [cwd] (the project workDir).
|
|
17
|
+
*/
|
|
18
|
+
export function resolveAllowedPaths(cwd, allowedPaths) {
|
|
19
|
+
if (!allowedPaths || allowedPaths.length === 0) {
|
|
20
|
+
return [resolve(cwd)];
|
|
21
|
+
}
|
|
22
|
+
return allowedPaths.map((p) => resolve(cwd, p));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Check whether a resolved absolute path falls within any of the allowed directories.
|
|
26
|
+
* Uses path prefix matching with separator awareness to prevent partial matches
|
|
27
|
+
* (e.g. `/home/user/project-evil` should NOT match `/home/user/project`).
|
|
28
|
+
*/
|
|
29
|
+
export function isPathAllowed(filePath, allowedPaths) {
|
|
30
|
+
let resolved = resolve(filePath);
|
|
31
|
+
// Resolve symlinks to prevent symlink-based sandbox escape
|
|
32
|
+
try {
|
|
33
|
+
resolved = realpathSync(resolved);
|
|
34
|
+
}
|
|
35
|
+
catch { /* file may not exist yet — use logical path */ }
|
|
36
|
+
for (const allowed of allowedPaths) {
|
|
37
|
+
const normalizedAllowed = resolve(allowed);
|
|
38
|
+
// Exact match
|
|
39
|
+
if (resolved === normalizedAllowed)
|
|
40
|
+
return true;
|
|
41
|
+
// Prefix match with separator (e.g. /foo/bar/ is prefix of /foo/bar/baz)
|
|
42
|
+
const prefix = normalizedAllowed.endsWith(sep) ? normalizedAllowed : normalizedAllowed + sep;
|
|
43
|
+
if (resolved.startsWith(prefix))
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Validate a path and throw a descriptive error if it's outside the sandbox.
|
|
50
|
+
* Call this in every file tool's execute() before performing the operation.
|
|
51
|
+
*/
|
|
52
|
+
export function assertPathAllowed(filePath, allowedPaths, toolName) {
|
|
53
|
+
if (!isPathAllowed(filePath, allowedPaths)) {
|
|
54
|
+
const dirs = allowedPaths.join(", ");
|
|
55
|
+
throw new Error(`[sandbox] ${toolName}: access denied — "${filePath}" is outside allowed directories [${dirs}]`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=path-sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-sandbox.js","sourceRoot":"","sources":["../src/path-sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW,EAAE,YAAuB;IACtE,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;AAClD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,YAAsB;IACpE,IAAI,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjC,2DAA2D;IAC3D,IAAI,CAAC;QAAC,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,+CAA+C,CAAC,CAAC;IACpG,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACnC,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAC3C,cAAc;QACd,IAAI,QAAQ,KAAK,iBAAiB;YAAE,OAAO,IAAI,CAAC;QAChD,yEAAyE;QACzE,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,iBAAiB,GAAG,GAAG,CAAC;QAC7F,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;IAC/C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,YAAsB,EAAE,QAAgB;IAC1F,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,IAAI,KAAK,CACb,aAAa,QAAQ,sBAAsB,QAAQ,qCAAqC,IAAI,GAAG,CAChG,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PDF tools for document operations.
|
|
3
|
+
*
|
|
4
|
+
* Provides tools for agents to:
|
|
5
|
+
* - Read text from PDF files
|
|
6
|
+
* - Create new PDF documents with text, images, and pages
|
|
7
|
+
* - Merge multiple PDFs into one
|
|
8
|
+
* - Extract pages from a PDF
|
|
9
|
+
* - Get PDF metadata (pages, title, author, etc.)
|
|
10
|
+
*
|
|
11
|
+
* Uses `pdf-lib` for creation/manipulation and a built-in text extractor.
|
|
12
|
+
* All file operations enforce path sandboxing.
|
|
13
|
+
*/
|
|
14
|
+
import type { AgentTool } from "@mariozechner/pi-agent-core";
|
|
15
|
+
export type PdfToolName = "pdf_read" | "pdf_create" | "pdf_merge" | "pdf_info";
|
|
16
|
+
export declare const ALL_PDF_TOOL_NAMES: PdfToolName[];
|
|
17
|
+
/**
|
|
18
|
+
* Create PDF tools.
|
|
19
|
+
*
|
|
20
|
+
* @param cwd - Working directory
|
|
21
|
+
* @param allowedPaths - Sandbox paths
|
|
22
|
+
* @param allowedTools - Optional filter
|
|
23
|
+
*/
|
|
24
|
+
export declare function createPdfTools(cwd: string, allowedPaths?: string[], allowedTools?: string[]): AgentTool<any>[];
|
|
25
|
+
//# sourceMappingURL=pdf-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf-tools.d.ts","sourceRoot":"","sources":["../src/pdf-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,6BAA6B,CAAC;AA4W9E,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,UAAU,CAAC;AAE/E,eAAO,MAAM,kBAAkB,EAAE,WAAW,EAAwD,CAAC;AAErG;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAe9G"}
|