1import { Type } from "@sinclair/typebox";
2import type { AgentTool } from "@mariozechner/pi-agent-core";
3import Tabstack from "@tabstack/sdk";
4import { FetchError, ToolInputError } from "../../util/errors.js";
5
6export interface WebFetchResult {
7 content: string;
8 url: string;
9}
10
11const FetchSchema = Type.Object({
12 url: Type.String({ description: "URL to fetch" }),
13 nocache: Type.Optional(Type.Boolean({ description: "Bypass cache and fetch fresh content" })),
14});
15
16export function createWebFetchTool(apiKey: string): AgentTool {
17 return {
18 name: "web_fetch",
19 label: "Web Fetch",
20 description: "Fetch a URL and return its content as markdown.",
21 parameters: FetchSchema as any,
22 execute: async (_toolCallId: string, params: any) => {
23 if (!apiKey) {
24 throw new ToolInputError("Web fetch is not configured");
25 }
26
27 const client = new Tabstack({ apiKey });
28
29 try {
30 const result = await client.extract.markdown({
31 url: params.url,
32 nocache: params.nocache ?? false,
33 });
34
35 return {
36 content: [{ type: "text", text: result.content ?? "" }],
37 details: { url: params.url, length: result.content?.length ?? 0 },
38 };
39 } catch (error: any) {
40 throw new FetchError(params.url, error?.message ?? String(error));
41 }
42 },
43 };
44}