This commit is contained in:
2026-02-19 22:18:38 +00:00
parent 841d257757
commit c242a0ca53
7 changed files with 239 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import {
DEFAULT_MAX_BYTES,
DEFAULT_MAX_LINES,
formatSize,
truncateHead,
} from "@mariozechner/pi-coding-agent";
import { Type } from "@sinclair/typebox";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
async function writeTempFile(content: string): Promise<string> {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "pi-fetch-"));
const filePath = path.join(dir, "response.txt");
await fs.writeFile(filePath, content, "utf8");
return filePath;
}
export default function (pi: ExtensionAPI) {
pi.registerTool({
name: "fetch_url",
label: "Fetch URL",
description:
"Fetch a URL over HTTP(S) and return the response body as text (truncated to 50KB/2000 lines).",
parameters: Type.Object({
url: Type.String({ description: "URL to fetch" }),
timeoutMs: Type.Optional(
Type.Number({ description: "Timeout in milliseconds (default: 10000)" })
),
headers: Type.Optional(
Type.Record(Type.String(), Type.String(), {
description: "Optional request headers",
})
),
}),
async execute(_toolCallId, params, signal) {
const controller = new AbortController();
const timeout = setTimeout(
() => controller.abort(),
params.timeoutMs ?? 10000
);
const combinedSignal = signal
? AbortSignal.any([signal, controller.signal])
: controller.signal;
try {
const response = await fetch(params.url, {
headers: params.headers,
signal: combinedSignal,
});
const body = await response.text();
const truncation = truncateHead(body, {
maxLines: DEFAULT_MAX_LINES,
maxBytes: DEFAULT_MAX_BYTES,
});
let content = truncation.content;
if (truncation.truncated) {
const tempFile = await writeTempFile(body);
content += `\n\n[Output truncated: ${truncation.outputLines} of ${truncation.totalLines} lines (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)}). Full output saved to: ${tempFile}]`;
}
return {
content: [{ type: "text", text: content }],
details: {
status: response.status,
statusText: response.statusText,
contentType: response.headers.get("content-type"),
url: response.url,
},
};
} finally {
clearTimeout(timeout);
}
},
});
}

Submodule pi/files/agent/extensions/pi-web-access added at 4461c2bcb2

View File

@@ -0,0 +1,18 @@
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
export default function (pi: ExtensionAPI) {
pi.registerCommand("tools", {
description: "List available and active tools",
handler: async (_args, ctx) => {
const allTools = pi.getAllTools();
const activeTools = new Set(pi.getActiveTools());
const lines = allTools
.map((tool) => {
const status = activeTools.has(tool.name) ? "active" : "inactive";
return `- ${tool.name} (${status})${tool.description ? `: ${tool.description}` : ""}`;
})
.join("\n");
ctx.ui.notify(lines || "No tools registered.", "info");
},
});
}

4
pi/files/web-search.json Normal file
View File

@@ -0,0 +1,4 @@
{
"provider": "duckduckgo",
"searchProvider": "duckduckgo"
}