|
| 1 | +/** |
| 2 | + * Schema-only tool definitions — shared between the chat.handover |
| 3 | + * route handler and the trigger.dev agent task. |
| 4 | + * |
| 5 | + * ⚠️ HARD CONSTRAINT — bundle isolation |
| 6 | + * |
| 7 | + * This file is imported by `app/api/chat/route.ts` (the chat.handover |
| 8 | + * POST handler) and runs in the Next.js process. Anything imported |
| 9 | + * here lands in the route-handler bundle. |
| 10 | + * |
| 11 | + * Allowed imports: `ai` (for `tool()`), `zod`, type-only AI SDK |
| 12 | + * imports. Nothing else. |
| 13 | + * |
| 14 | + * DO NOT import from this file: |
| 15 | + * - `@e2b/code-interpreter`, `puppeteer`, `playwright`, native bindings |
| 16 | + * - `node:child_process`, heavy filesystem ops |
| 17 | + * - `@trigger.dev/sdk` runtime (`task`, `schemaTask`, |
| 18 | + * `chat.stream.writer`, etc. — pulls in the whole task runtime) |
| 19 | + * - `turndown`, image processing libs, anything that pulls weight |
| 20 | + * |
| 21 | + * Heavy `execute` fns live in `src/trigger/chat-tools.ts` — that file |
| 22 | + * imports these schemas and adds executes on top. The agent task |
| 23 | + * picks up the executes when it runs; the route handler never sees |
| 24 | + * them and never imports their deps. |
| 25 | + * |
| 26 | + * If you need to add a new tool to the chat.agent's schema-only set, |
| 27 | + * declare its description + inputSchema here, then wire its execute |
| 28 | + * fn in `src/trigger/chat-tools.ts`. |
| 29 | + */ |
| 30 | +import { tool } from "ai"; |
| 31 | +import type { InferUITools, UIDataTypes, UIMessage } from "ai"; |
| 32 | +import { z } from "zod"; |
| 33 | + |
| 34 | +export const inspectEnvironment = tool({ |
| 35 | + description: |
| 36 | + "Inspect the current execution environment. Returns runtime info (Node.js/Bun/Deno version), " + |
| 37 | + "OS details, CPU architecture, memory usage, environment variables, and platform metadata.", |
| 38 | + inputSchema: z.object({}), |
| 39 | + // execute → src/trigger/chat-tools.ts |
| 40 | +}); |
| 41 | + |
| 42 | +export const webFetch = tool({ |
| 43 | + description: |
| 44 | + "Fetch a URL and return the response as text. " + |
| 45 | + "Use this to retrieve web pages, APIs, or any HTTP resource.", |
| 46 | + inputSchema: z.object({ |
| 47 | + url: z.string().url().describe("The URL to fetch"), |
| 48 | + }), |
| 49 | + // execute → src/trigger/chat-tools.ts (uses turndown) |
| 50 | +}); |
| 51 | + |
| 52 | +export const deepResearch = tool({ |
| 53 | + description: |
| 54 | + "Research a topic by fetching multiple URLs and synthesizing the results. " + |
| 55 | + "Streams progress updates to the chat as it works.", |
| 56 | + inputSchema: z.object({ |
| 57 | + query: z.string().describe("The research query or topic"), |
| 58 | + urls: z.array(z.string().url()).describe("URLs to fetch and analyze"), |
| 59 | + }), |
| 60 | + // execute → src/trigger/chat-tools.ts (subtask via ai.toolExecute) |
| 61 | +}); |
| 62 | + |
| 63 | +export const posthogQuery = tool({ |
| 64 | + description: |
| 65 | + "Query PostHog analytics using HogQL. Use this to answer questions about events, " + |
| 66 | + "pageviews, user activity, feature flag usage, or any product analytics question. " + |
| 67 | + "Write a HogQL query (SQL-like syntax over PostHog events).", |
| 68 | + inputSchema: z.object({ |
| 69 | + query: z |
| 70 | + .string() |
| 71 | + .describe( |
| 72 | + "HogQL query, e.g. SELECT event, count() FROM events WHERE timestamp > now() - interval 1 day GROUP BY event ORDER BY count() DESC LIMIT 10" |
| 73 | + ), |
| 74 | + }), |
| 75 | + // execute → src/trigger/chat-tools.ts (HTTP to PostHog) |
| 76 | +}); |
| 77 | + |
| 78 | +export const executeCode = tool({ |
| 79 | + description: |
| 80 | + "Run code in an isolated E2B sandbox (Python by default; other languages supported by E2B). " + |
| 81 | + "Use for calculations, data analysis, or transforming tool outputs (e.g. PostHog query results). " + |
| 82 | + "The sandbox persists across turns in the same run until the chat idles and suspends.", |
| 83 | + inputSchema: z.object({ |
| 84 | + code: z.string().describe("Source code to execute in the sandbox"), |
| 85 | + language: z |
| 86 | + .string() |
| 87 | + .optional() |
| 88 | + .describe("Language id (e.g. python, javascript). Defaults to python."), |
| 89 | + }), |
| 90 | + // execute → src/trigger/chat-tools.ts (E2B sandbox — heavy native dep) |
| 91 | +}); |
| 92 | + |
| 93 | +export const sendEmail = tool({ |
| 94 | + description: |
| 95 | + "Send an email to a recipient. Requires human approval before sending. " + |
| 96 | + "Use when the user asks you to send, draft, or compose an email.", |
| 97 | + inputSchema: z.object({ |
| 98 | + to: z.string().describe("Recipient email address"), |
| 99 | + subject: z.string().describe("Email subject line"), |
| 100 | + body: z.string().describe("Email body text"), |
| 101 | + }), |
| 102 | + needsApproval: true, |
| 103 | + // execute → src/trigger/chat-tools.ts |
| 104 | +}); |
| 105 | + |
| 106 | +export const askUser = tool({ |
| 107 | + description: |
| 108 | + "Ask the user a question when you need clarification or input before proceeding. " + |
| 109 | + "Present 2-4 options for the user to choose from. Use when uncertain about the user's intent.", |
| 110 | + inputSchema: z.object({ |
| 111 | + question: z.string().describe("The question to ask the user"), |
| 112 | + options: z |
| 113 | + .array( |
| 114 | + z.object({ |
| 115 | + id: z.string().describe("Unique option identifier"), |
| 116 | + label: z.string().describe("Short option title"), |
| 117 | + description: z.string().optional().describe("Longer explanation"), |
| 118 | + }) |
| 119 | + ) |
| 120 | + .min(2) |
| 121 | + .max(4), |
| 122 | + }), |
| 123 | + // No execute by design — round-tripped through the frontend's addToolOutput. |
| 124 | +}); |
| 125 | + |
| 126 | +/** |
| 127 | + * The schema-only tool set passed to `chat.headStart`'s `streamText` |
| 128 | + * call. The agent task imports each schema individually and adds the |
| 129 | + * matching `execute` fn — see `src/trigger/chat-tools.ts`. |
| 130 | + */ |
| 131 | +export const headStartTools = { |
| 132 | + inspectEnvironment, |
| 133 | + webFetch, |
| 134 | + deepResearch, |
| 135 | + posthogQuery, |
| 136 | + executeCode, |
| 137 | + sendEmail, |
| 138 | + askUser, |
| 139 | +}; |
| 140 | + |
| 141 | +type ChatToolSet = typeof headStartTools; |
| 142 | +export type ChatUiTools = InferUITools<ChatToolSet>; |
| 143 | +export type ChatUiMessage = UIMessage<unknown, UIDataTypes, ChatUiTools>; |
0 commit comments