import { z } from 'zod'; import { tool, DynamicStructuredTool } from '@langchain/core/tools'; import type * as _t from '@/types'; /** * Browser tool names - keep in sync with the browser extension * These tools execute locally in the browser extension, NOT on the server */ export const EBrowserTools = { CLICK: 'browser_click', TYPE: 'browser_type', NAVIGATE: 'browser_navigate', SCROLL: 'browser_scroll', EXTRACT: 'browser_extract', HOVER: 'browser_hover', WAIT: 'browser_wait', BACK: 'browser_back', SCREENSHOT: 'browser_screenshot', GET_PAGE_STATE: 'browser_get_page_state', KEYPRESS: 'browser_keypress', SWITCH_TAB: 'browser_switch_tab', } as const; export type BrowserToolName = (typeof EBrowserTools)[keyof typeof EBrowserTools]; /** * Callback function type for waiting on browser action results * This allows the host server to provide a callback that waits for the extension * to POST results back to the server before returning to the LLM. * * @param action - The browser action (click, type, navigate, etc.) * @param args - Arguments for the action * @param toolCallId - Unique ID for this tool call (from config.toolCall.id) * @returns Promise that resolves with the actual browser result (page state, etc.) */ export type BrowserToolCallback = ( action: string, args: Record, toolCallId: string ) => Promise; /** * Result returned from browser action execution */ export interface BrowserActionResult { success: boolean; url?: string; title?: string; elementList?: string; // Text-based element list error?: string; screenshot?: string; // Base64 screenshot (if requested) } /** * Check if browser capability is available based on request headers or context * The browser extension sets these headers when connected: * - X-Illuma-Browser-Extension: true * - X-Illuma-Browser-Capable: true */ export function hasBrowserCapability(req?: { headers?: Record; }): boolean { if (!req?.headers) { return false; } const browserExtension = req.headers['x-illuma-browser-extension']; const browserCapable = req.headers['x-illuma-browser-capable']; return browserExtension === 'true' || browserCapable === 'true'; } // Tool schemas const BrowserClickSchema = z.object({ index: z .number() .describe( 'The [index] of the element to click. Use fieldLabel to identify the correct element. For form fields, target or