diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6f1c68b --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# Build-Ergebnis — wird aus src/ erzeugt +dist/ + +# Abhängigkeiten +node_modules/ + +# Laufzeit-Secrets: das MCP-Bridge-Token gehört nie ins Repo +.token +*.token + +# Python-Nebenprodukte des Schema-Generators +__pycache__/ +*.pyc diff --git a/package.json b/package.json index ff61f4d..6f3df8d 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "private": true, "description": "Nexus Browser Agent – MCP-fähige Chrome/Brave Extension mit Nexus-Gateway-Backend", "scripts": { - "generate": "python ../../tools/generate_tool_defs.py", - "prebuild": "python ../../tools/generate_tool_defs.py", + "generate": "python tools/generate_tool_defs.py", + "prebuild": "python tools/generate_tool_defs.py", "build": "node esbuild.config.mjs", "watch": "node esbuild.config.mjs --watch", "typecheck": "tsc --noEmit", diff --git a/tools/generate_tool_defs.py b/tools/generate_tool_defs.py new file mode 100644 index 0000000..28aa090 --- /dev/null +++ b/tools/generate_tool_defs.py @@ -0,0 +1,128 @@ +"""Generator: tools/schema/*.json → Python ToolSpecs + TypeScript types. + +Liest alle JSON-Dateien aus tools/schema/, erzeugt: +1. agent/browser_tool_defs.py — Liste von Bedrock-toolSpec-Dicts für den Broker +2. extension/src/shared/tool-schemas.generated.ts — TypeScript-Typen + Registry + +Aufruf: + python tools/generate_tool_defs.py + +Im esbuild-Step der Extension als Pre-Build verdrahtet (package.json "prebuild"). +""" +import json +import os +from pathlib import Path + +SCHEMA_DIR = Path(__file__).parent / "schema" + +#: Wurzel dieses Repos (tools/ liegt direkt darunter). +_ROOT = Path(__file__).parent.parent + +#: TypeScript-Ziel — immer vorhanden, dies ist das eigene Repo. +TS_OUTPUT = _ROOT / "src" / "shared" / "tool-schemas.generated.ts" + +#: Python-Ziel im NACHBAR-Repo (agent/). Die Schemata beschreiben Browser-Tools +#: und gehoeren damit zur Extension; der Python-Broker konsumiert nur das +#: Erzeugnis, das dort eingecheckt ist. Liegen die Repos nicht nebeneinander, +#: wird der Python-Teil uebersprungen statt abzubrechen — die Extension muss +#: allein baubar bleiben. +PY_OUTPUT = _ROOT.parent / "browser_tool_defs.py" + + +def load_schemas() -> list[dict]: + schemas = [] + for f in sorted(SCHEMA_DIR.glob("*.json")): + with open(f, encoding="utf-8") as fh: + schemas.append(json.load(fh)) + return schemas + + +def generate_python(schemas: list[dict]) -> str: + lines = [ + '"""Auto-generated browser tool definitions for the Bedrock Converse API.', + '', + 'DO NOT EDIT — generated by tools/generate_tool_defs.py from tools/schema/*.json.', + '"""', + '', + 'BROWSER_TOOL_SPECS: list[dict] = [', + ] + for s in schemas: + spec = { + "toolSpec": { + "name": s["name"], + "description": s["description"], + "inputSchema": {"json": s["inputSchema"]}, + } + } + lines.append(f" {json.dumps(spec, ensure_ascii=False)},") + lines.append("]") + lines.append("") + lines.append("# Mapping: tool name -> requires_confirmation flag") + lines.append("BROWSER_TOOL_CONFIRMATION: dict[str, bool] = {") + for s in schemas: + lines.append(f' "{s["name"]}": {str(s.get("requires_confirmation", False))},') + lines.append("}") + lines.append("") + lines.append(f"BROWSER_TOOL_NAMES: list[str] = {json.dumps([s['name'] for s in schemas])}") + lines.append("") + return "\n".join(lines) + + +def generate_typescript(schemas: list[dict]) -> str: + lines = [ + "/**", + " * Auto-generated browser tool schemas and types.", + " * DO NOT EDIT — generated by tools/generate_tool_defs.py from tools/schema/*.json.", + " */", + "", + "export interface BrowserToolSchema {", + " name: string;", + " description: string;", + " requires_confirmation: boolean;", + " inputSchema: Record;", + "}", + "", + "export const BROWSER_TOOL_SCHEMAS: BrowserToolSchema[] = [", + ] + for s in schemas: + lines.append(f" {json.dumps(s, ensure_ascii=False)},") + lines.append("];") + lines.append("") + lines.append("export const BROWSER_TOOL_NAMES = [") + for s in schemas: + lines.append(f' "{s["name"]}",') + lines.append("] as const;") + lines.append("") + lines.append("export type BrowserToolName = typeof BROWSER_TOOL_NAMES[number];") + lines.append("") + lines.append("export const REQUIRES_CONFIRMATION: Record = {") + for s in schemas: + lines.append(f' "{s["name"]}": {str(s.get("requires_confirmation", False)).lower()},') + lines.append("};") + lines.append("") + return "\n".join(lines) + + +def main(): + schemas = load_schemas() + print(f"Loaded {len(schemas)} tool schemas from {SCHEMA_DIR}") + + py_code = generate_python(schemas) + # NICHT nur auf das Verzeichnis pruefen — das existiert fast immer und der + # Generator schrieb dann in ein beliebiges Nachbarverzeichnis (gemessen). + # Der Marker macht daraus eine echte Aussage: liegt hier das Agenten-Repo? + if (PY_OUTPUT.parent / "tools.py").is_file(): + PY_OUTPUT.write_text(py_code, encoding="utf-8") + print(f"Generated Python: {PY_OUTPUT} ({len(py_code)} bytes)") + else: + print(f"Skipped Python output: {PY_OUTPUT.parent} not found " + f"(agent repo not checked out next to this one)") + + ts_code = generate_typescript(schemas) + TS_OUTPUT.parent.mkdir(parents=True, exist_ok=True) + TS_OUTPUT.write_text(ts_code, encoding="utf-8") + print(f"Generated TypeScript: {TS_OUTPUT} ({len(ts_code)} bytes)") + + +if __name__ == "__main__": + main() diff --git a/tools/schema/browser_batch.json b/tools/schema/browser_batch.json new file mode 100644 index 0000000..a488eb8 --- /dev/null +++ b/tools/schema/browser_batch.json @@ -0,0 +1,37 @@ +{ + "name": "browser_batch", + "description": "Runs several browser tools in one call, in order, returning all results. Saves one model round-trip per step — the dominant cost of form filling and navigation. Use when the whole sequence is known in advance. Do NOT use when a later step depends on what an earlier one returns.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "actions": { + "type": "array", + "description": "Steps in order: [{name, input}, ...].", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the browser tool to run, e.g. 'browser_click', 'browser_type', 'browser_computer'. Must be one of the available browser tools, and not 'browser_batch'." + }, + "input": { + "type": "object", + "description": "Argument object for that tool — exactly what you would pass in a single call. Omit or use {} for tools without arguments." + } + }, + "required": [ + "name" + ] + } + }, + "stopOnError": { + "type": "boolean", + "description": "Stop at the first failing step (default true)." + } + }, + "required": [ + "actions" + ] + } +} diff --git a/tools/schema/browser_click.json b/tools/schema/browser_click.json new file mode 100644 index 0000000..b25e46b --- /dev/null +++ b/tools/schema/browser_click.json @@ -0,0 +1,22 @@ +{ + "name": "browser_click", + "description": "Click an element addressed by ref_id or CSS selector.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "selector": { + "type": "string", + "description": "CSS selector of the element to click, e.g. 'button[type=submit]' or '#login'." + }, + "ref_id": { + "type": "string", + "description": "Stable ref_id from browser_read_page or browser_find." + }, + "trusted": { + "type": "boolean", + "description": "Force real CDP events for this one call even if the extension is configured for synthetic…" + } + } + } +} diff --git a/tools/schema/browser_computer.json b/tools/schema/browser_computer.json new file mode 100644 index 0000000..09536da --- /dev/null +++ b/tools/schema/browser_computer.json @@ -0,0 +1,88 @@ +{ + "name": "browser_computer", + "description": "Operates mouse and keyboard at pixel coordinates via CDP (isTrusted events). Workflow: action='screenshot' first, read coordinates off that image, then act. Use only for canvas, maps, drag&drop and anything that ignores selectors — for normal HTML browser_find + browser_click are cheaper and more reliable.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "action": { + "type": "string", + "enum": [ + "screenshot", + "mouse_move", + "left_click", + "right_click", + "middle_click", + "double_click", + "triple_click", + "left_click_drag", + "left_mouse_down", + "left_mouse_up", + "scroll", + "type", + "key", + "hold_key", + "wait", + "cursor_position" + ], + "description": "What to do. Pixel coordinates come from a screenshot." + }, + "coordinate": { + "type": "array", + "items": { + "type": "integer" + }, + "minItems": 2, + "maxItems": 2, + "description": "[x, y] in screenshot pixels." + }, + "start_coordinate": { + "type": "array", + "items": { + "type": "integer" + }, + "minItems": 2, + "maxItems": 2, + "description": "[x, y] where a drag begins." + }, + "text": { + "type": "string", + "description": "Text to type, or key name for key presses (e.g. 'Return', 'ctrl+a')." + }, + "scroll_direction": { + "type": "string", + "enum": [ + "up", + "down", + "left", + "right" + ], + "description": "up | down | left | right" + }, + "scroll_amount": { + "type": "integer", + "description": "Number of wheel clicks." + }, + "duration": { + "type": "number", + "description": "Seconds to hold or wait." + }, + "modifiers": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "ctrl", + "alt", + "shift", + "meta" + ] + }, + "description": "Held modifier keys, e.g. ['ctrl','shift']." + } + }, + "required": [ + "action" + ] + } +} diff --git a/tools/schema/browser_drag.json b/tools/schema/browser_drag.json new file mode 100644 index 0000000..a5d174a --- /dev/null +++ b/tools/schema/browser_drag.json @@ -0,0 +1,22 @@ +{ + "name": "browser_drag", + "description": "Drag one element onto another with the real mouse: press the left button over the centre of the source, move to the centre of the target in several intermediate steps, and release there.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "sourceSelector": { + "type": "string", + "description": "CSS selector of the element to pick up. The drag starts at its centre." + }, + "targetSelector": { + "type": "string", + "description": "CSS selector of the drop target. The button is released at its centre." + } + }, + "required": [ + "sourceSelector", + "targetSelector" + ] + } +} diff --git a/tools/schema/browser_execute_js.json b/tools/schema/browser_execute_js.json new file mode 100644 index 0000000..8cc6b1d --- /dev/null +++ b/tools/schema/browser_execute_js.json @@ -0,0 +1,17 @@ +{ + "name": "browser_execute_js", + "description": "Run JavaScript in the page's MAIN world and return the result. Same realm as the site's own scripts, so you can reach the application's window globals — frameworks, state stores, config objects, jQuery, data layers — which an isolated content script cannot see.", + "requires_confirmation": true, + "inputSchema": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "JavaScript source to evaluate in the page. The last expression's value is returned, e.g." + } + }, + "required": [ + "code" + ] + } +} diff --git a/tools/schema/browser_file_upload.json b/tools/schema/browser_file_upload.json new file mode 100644 index 0000000..b36868a --- /dev/null +++ b/tools/schema/browser_file_upload.json @@ -0,0 +1,28 @@ +{ + "name": "browser_file_upload", + "description": "Attaches local files to an via CDP, as if picked in the OS dialog, and fires a change event. Paths must be absolute on the machine running the browser. Never try to open the native file dialog by clicking — it cannot be operated.", + "requires_confirmation": true, + "inputSchema": { + "type": "object", + "properties": { + "selector": { + "type": "string", + "description": "CSS selector of the file input." + }, + "ref_id": { + "type": "string", + "description": "ref_id of the file input. Preferred." + }, + "files": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Absolute paths on the browser machine." + } + }, + "required": [ + "files" + ] + } +} diff --git a/tools/schema/browser_find.json b/tools/schema/browser_find.json new file mode 100644 index 0000000..87ea8a6 --- /dev/null +++ b/tools/schema/browser_find.json @@ -0,0 +1,21 @@ +{ + "name": "browser_find", + "description": "Finds elements by plain-language description instead of a CSS selector. Matches label text, accessible name, placeholder, aria-label, title, role and type, ranked by fit. Returns ref_id (for browser_click/type/select), role, text, tag and coordinates. Start here instead of reading the whole page.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "query": { + "type": "string", + "description": "What you are looking for, in plain language." + }, + "limit": { + "type": "integer", + "description": "Maximum number of candidates (default 5)." + } + }, + "required": [ + "query" + ] + } +} diff --git a/tools/schema/browser_form_input.json b/tools/schema/browser_form_input.json new file mode 100644 index 0000000..402d50b --- /dev/null +++ b/tools/schema/browser_form_input.json @@ -0,0 +1,25 @@ +{ + "name": "browser_form_input", + "description": "Fill a form field: handles input, textarea, select, checkbox, radio. For select elements, matches by value or visible text.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "selector": { + "type": "string", + "description": "CSS selector of the form element" + }, + "ref_id": { + "type": "string", + "description": "Stable ref_id from read_page" + }, + "value": { + "type": "string", + "description": "Value to set (for select: option value or text; for checkbox/radio: 'true'/'false')" + } + }, + "required": [ + "value" + ] + } +} diff --git a/tools/schema/browser_get_page_info.json b/tools/schema/browser_get_page_info.json new file mode 100644 index 0000000..d85b8b9 --- /dev/null +++ b/tools/schema/browser_get_page_info.json @@ -0,0 +1,9 @@ +{ + "name": "browser_get_page_info", + "description": "Get current page URL, title, viewport dimensions, scroll position, and document height.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": {} + } +} diff --git a/tools/schema/browser_get_text.json b/tools/schema/browser_get_text.json new file mode 100644 index 0000000..f3bced7 --- /dev/null +++ b/tools/schema/browser_get_text.json @@ -0,0 +1,18 @@ +{ + "name": "browser_get_text", + "description": "Get the text content of the page or a specific element (Readability-style extraction).", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "selector": { + "type": "string", + "description": "CSS selector (default: body)" + }, + "maxLength": { + "type": "number", + "description": "Max characters to return (default 8000)" + } + } + } +} diff --git a/tools/schema/browser_go_back.json b/tools/schema/browser_go_back.json new file mode 100644 index 0000000..61dd72d --- /dev/null +++ b/tools/schema/browser_go_back.json @@ -0,0 +1,9 @@ +{ + "name": "browser_go_back", + "description": "Navigate back in the active tab's history.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": {} + } +} diff --git a/tools/schema/browser_go_forward.json b/tools/schema/browser_go_forward.json new file mode 100644 index 0000000..2955729 --- /dev/null +++ b/tools/schema/browser_go_forward.json @@ -0,0 +1,9 @@ +{ + "name": "browser_go_forward", + "description": "Navigate forward in the active tab's history.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": {} + } +} diff --git a/tools/schema/browser_highlight.json b/tools/schema/browser_highlight.json new file mode 100644 index 0000000..9f1de1a --- /dev/null +++ b/tools/schema/browser_highlight.json @@ -0,0 +1,25 @@ +{ + "name": "browser_highlight", + "description": "Visually highlight an element on the page (for debugging/demonstration).", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "selector": { + "type": "string", + "description": "CSS selector of the element to highlight" + }, + "color": { + "type": "string", + "description": "Outline color (default '#ff6b35')" + }, + "duration": { + "type": "number", + "description": "Highlight duration in ms (default 3000)" + } + }, + "required": [ + "selector" + ] + } +} diff --git a/tools/schema/browser_hover.json b/tools/schema/browser_hover.json new file mode 100644 index 0000000..c81a869 --- /dev/null +++ b/tools/schema/browser_hover.json @@ -0,0 +1,18 @@ +{ + "name": "browser_hover", + "description": "Move the real mouse pointer onto an element and leave it there.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "selector": { + "type": "string", + "description": "CSS selector of the element to hover, e.g. 'nav .menu-item:first-child'." + }, + "ref_id": { + "type": "string", + "description": "Stable ref_id from browser_read_page or browser_find." + } + } + } +} diff --git a/tools/schema/browser_key.json b/tools/schema/browser_key.json new file mode 100644 index 0000000..d265f6c --- /dev/null +++ b/tools/schema/browser_key.json @@ -0,0 +1,30 @@ +{ + "name": "browser_key", + "description": "Press a single key, optionally with modifiers, as a real keystroke through the DevTools Protocol — trusted keydown/keyup with the correct key code, so keyboard shortcuts, form submission via Enter and focus traversal via Tab all behave as they would for a human.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "key": { + "type": "string", + "description": "Key name in DOM KeyboardEvent.key notation, e.g." + }, + "modifiers": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "ctrl", + "alt", + "shift", + "meta" + ] + }, + "description": "Modifier keys held while the key is pressed, e.g." + } + }, + "required": [ + "key" + ] + } +} diff --git a/tools/schema/browser_navigate.json b/tools/schema/browser_navigate.json new file mode 100644 index 0000000..ec90a83 --- /dev/null +++ b/tools/schema/browser_navigate.json @@ -0,0 +1,21 @@ +{ + "name": "browser_navigate", + "description": "Navigate the active tab to a URL, or open a URL in a new tab.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "Target URL to navigate to" + }, + "newTab": { + "type": "boolean", + "description": "If true, open in a new tab instead of the active one" + } + }, + "required": [ + "url" + ] + } +} diff --git a/tools/schema/browser_read_console.json b/tools/schema/browser_read_console.json new file mode 100644 index 0000000..200d7f5 --- /dev/null +++ b/tools/schema/browser_read_console.json @@ -0,0 +1,29 @@ +{ + "name": "browser_read_console", + "description": "Read captured console logs (log, warn, error, info) from the active page.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "clear": { + "type": "boolean", + "description": "Clear the log buffer after reading (default false)" + }, + "level": { + "type": "string", + "enum": [ + "all", + "log", + "warn", + "error", + "info" + ], + "description": "Filter by log level (default 'all')" + }, + "limit": { + "type": "number", + "description": "Max entries to return (default 50)" + } + } + } +} diff --git a/tools/schema/browser_read_network.json b/tools/schema/browser_read_network.json new file mode 100644 index 0000000..02a07db --- /dev/null +++ b/tools/schema/browser_read_network.json @@ -0,0 +1,26 @@ +{ + "name": "browser_read_network", + "description": "Read the network requests the active page has made. Captured live through the DevTools Protocol — the same data the Network tab of DevTools shows: URL, HTTP method, status code, resource type, timing and size.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "filter": { + "type": "string", + "description": "Only return requests whose URL contains this substring, e.g. '/api/' or 'graphql'." + }, + "method": { + "type": "string", + "description": "Only return requests with this HTTP method, e.g. 'GET', 'POST', 'PUT', 'DELETE'." + }, + "limit": { + "type": "integer", + "description": "Maximum number of entries to return, most recent first (default 50)." + }, + "includeBody": { + "type": "boolean", + "description": "Include the response body of matching requests (default false)." + } + } + } +} diff --git a/tools/schema/browser_read_page.json b/tools/schema/browser_read_page.json new file mode 100644 index 0000000..9a781a2 --- /dev/null +++ b/tools/schema/browser_read_page.json @@ -0,0 +1,30 @@ +{ + "name": "browser_read_page", + "description": "Reads the accessibility tree of the page: a compact view of what is on screen and interactive. Cheaper and more precise than a screenshot for normal HTML. Every interactive node carries a ref_id — pass it to browser_click/type/select instead of guessing a selector. Fields report label, role and editable.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "viewportOnly": { + "type": "boolean", + "description": "Only what is currently visible (default true)." + }, + "maxDepth": { + "type": "number", + "description": "Maximum nesting depth." + }, + "maxTokens": { + "type": "number", + "description": "Budget; the tree is cut off when reached." + }, + "includeHidden": { + "type": "boolean", + "description": "Include invisible elements (default false)." + }, + "selector": { + "type": "string", + "description": "Read only this subtree, e.g. a compose form." + } + } + } +} diff --git a/tools/schema/browser_reload.json b/tools/schema/browser_reload.json new file mode 100644 index 0000000..7b0adc2 --- /dev/null +++ b/tools/schema/browser_reload.json @@ -0,0 +1,9 @@ +{ + "name": "browser_reload", + "description": "Reload the current page in the active tab.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": {} + } +} diff --git a/tools/schema/browser_resize_window.json b/tools/schema/browser_resize_window.json new file mode 100644 index 0000000..db4efa1 --- /dev/null +++ b/tools/schema/browser_resize_window.json @@ -0,0 +1,18 @@ +{ + "name": "browser_resize_window", + "description": "Resize the browser window holding the active tab. Changes the viewport, so every pixel coordinate from earlier screenshots becomes invalid — take a fresh screenshot afterwards.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "width": { + "type": "integer", + "description": "Window width in pixels, e.g. 1280 for a desktop layout or 390 to force a mobile layout." + }, + "height": { + "type": "integer", + "description": "Window height in pixels, e.g. 900. Omit to keep the current height." + } + } + } +} diff --git a/tools/schema/browser_screenshot.json b/tools/schema/browser_screenshot.json new file mode 100644 index 0000000..884dee1 --- /dev/null +++ b/tools/schema/browser_screenshot.json @@ -0,0 +1,18 @@ +{ + "name": "browser_screenshot", + "description": "Captures a JPEG of the page as an image you can look at. Read pixel coordinates off it for browser_computer; origin (0,0) is top-left, x grows right, y grows down. Viewport only by default — exactly the area browser_computer can reach. Expensive in tokens: prefer browser_read_page for normal HTML.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "fullPage": { + "type": "boolean", + "description": "Whole page instead of the viewport. Coordinates then no longer match browser_computer." + }, + "maxWidth": { + "type": "integer", + "description": "Scale down to this width in pixels." + } + } + } +} diff --git a/tools/schema/browser_scroll.json b/tools/schema/browser_scroll.json new file mode 100644 index 0000000..b23842f --- /dev/null +++ b/tools/schema/browser_scroll.json @@ -0,0 +1,31 @@ +{ + "name": "browser_scroll", + "description": "Scroll the page, or a specific scrollable element, by a pixel amount.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "direction": { + "type": "string", + "enum": [ + "up", + "down", + "left", + "right" + ], + "description": "Scroll direction." + }, + "amount": { + "type": "number", + "description": "Pixels to scroll (default 500)." + }, + "selector": { + "type": "string", + "description": "CSS selector of the scrollable element (default: the page itself)." + } + }, + "required": [ + "direction" + ] + } +} diff --git a/tools/schema/browser_select.json b/tools/schema/browser_select.json new file mode 100644 index 0000000..7a9fcd8 --- /dev/null +++ b/tools/schema/browser_select.json @@ -0,0 +1,25 @@ +{ + "name": "browser_select", + "description": "Select an option in a element" + }, + "ref_id": { + "type": "string", + "description": "Stable ref_id from read_page" + }, + "value": { + "type": "string", + "description": "Option value or visible text to select" + } + }, + "required": [ + "value" + ] + } +} diff --git a/tools/schema/browser_tabs_close.json b/tools/schema/browser_tabs_close.json new file mode 100644 index 0000000..53c56cb --- /dev/null +++ b/tools/schema/browser_tabs_close.json @@ -0,0 +1,17 @@ +{ + "name": "browser_tabs_close", + "description": "Close a tab by its ID. Get IDs from browser_tabs_list. Use it to tidy up tabs you opened while working; closing a tab does not affect the pages themselves.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "tabId": { + "type": "number", + "description": "The ID of the tab to close, as reported by browser_tabs_list." + } + }, + "required": [ + "tabId" + ] + } +} diff --git a/tools/schema/browser_tabs_create.json b/tools/schema/browser_tabs_create.json new file mode 100644 index 0000000..ee5f9a7 --- /dev/null +++ b/tools/schema/browser_tabs_create.json @@ -0,0 +1,17 @@ +{ + "name": "browser_tabs_create", + "description": "Open a new tab with the given URL.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "URL to open in the new tab" + } + }, + "required": [ + "url" + ] + } +} diff --git a/tools/schema/browser_tabs_list.json b/tools/schema/browser_tabs_list.json new file mode 100644 index 0000000..3bbb99c --- /dev/null +++ b/tools/schema/browser_tabs_list.json @@ -0,0 +1,9 @@ +{ + "name": "browser_tabs_list", + "description": "List all open browser tabs with their IDs, titles, URLs, and active state.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": {} + } +} diff --git a/tools/schema/browser_tabs_select.json b/tools/schema/browser_tabs_select.json new file mode 100644 index 0000000..fe53440 --- /dev/null +++ b/tools/schema/browser_tabs_select.json @@ -0,0 +1,17 @@ +{ + "name": "browser_tabs_select", + "description": "Switch to a tab by its ID (makes it the active tab).", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "tabId": { + "type": "number", + "description": "The tab ID to activate" + } + }, + "required": [ + "tabId" + ] + } +} diff --git a/tools/schema/browser_type.json b/tools/schema/browser_type.json new file mode 100644 index 0000000..be282d6 --- /dev/null +++ b/tools/schema/browser_type.json @@ -0,0 +1,17 @@ +{ + "name": "browser_type", + "description": "Types text into an input, textarea or contenteditable as real CDP keystrokes, so masks, validation and framework state react as for a human. A target is REQUIRED (ref_id or selector) — without one the text would land in whatever happens to be focused, which in forms is usually the wrong field. The result reports typed_into (where the text actually went) and sets target_mismatch=true if that is not the element you asked for.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "selector": { "type": "string", "description": "CSS selector of the field." }, + "ref_id": { "type": "string", "description": "ref_id from browser_find or browser_read_page. Preferred; wins over selector." }, + "text": { "type": "string", "description": "Text to type, character by character." }, + "clear": { "type": "boolean", "description": "Clear the field first (default true)." }, + "submit": { "type": "boolean", "description": "Press Enter afterwards (default false). Submits most forms." }, + "use_focus": { "type": "boolean", "description": "Type into the focused element without a target. Only when you set that focus yourself and mean it." } + }, + "required": ["text"] + } +} diff --git a/tools/schema/browser_wait.json b/tools/schema/browser_wait.json new file mode 100644 index 0000000..88d71a5 --- /dev/null +++ b/tools/schema/browser_wait.json @@ -0,0 +1,22 @@ +{ + "name": "browser_wait", + "description": "Wait for an element to appear or a timeout to elapse.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "selector": { + "type": "string", + "description": "CSS selector to wait for (if omitted, just waits for timeout)" + }, + "timeout": { + "type": "number", + "description": "Max milliseconds to wait (default 5000)" + }, + "visible": { + "type": "boolean", + "description": "Wait until element is visible, not just present (default true)" + } + } + } +} diff --git a/tools/schema/browser_zoom.json b/tools/schema/browser_zoom.json new file mode 100644 index 0000000..2251f49 --- /dev/null +++ b/tools/schema/browser_zoom.json @@ -0,0 +1,17 @@ +{ + "name": "browser_zoom", + "description": "Set the zoom level of the active tab.", + "requires_confirmation": false, + "inputSchema": { + "type": "object", + "properties": { + "level": { + "type": "number", + "description": "Zoom factor (1.0 = 100%, 1.5 = 150%, 0.5 = 50%)" + } + }, + "required": [ + "level" + ] + } +}