// Computer use loop skeleton (Node SDK, beta namespace for computer_20251124). // STATUS: UNVERIFIED as a script (identical raw requests LIVE_VERIFIED 2026-09-18: tmp-live/tools/h1_*, h2_*, h4_*). Nothing is executed: // executeAction is a stub returning a 1x1 PNG for screenshot/zoom. Run: node --env-file=.env --experimental-strip-types examples/anthropic/computer-use/computer_use_loop.ts import Anthropic from "@anthropic-ai/sdk"; import { logRequest } from "../../shared/tool-loop/log.ts"; const client = new Anthropic(); const PNG = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="; const NOT_EXECUTED = "Not executed: an earlier computer action in this turn failed."; const useToolset = process.argv.includes("--toolset"); const model = useToolset ? "claude-sonnet-5" : "claude-sonnet-4-6"; const tools: any[] = useToolset ? [{ type: "computer_toolset_20260801", configs: { zoom: { enabled: false } } }] : [{ type: "computer_20251124", name: "computer", display_width_px: 1024, display_height_px: 768, display_number: 1 }]; function executeAction(action: string, params: any): any { if (action === "screenshot" || action === "zoom") return [{ type: "image", source: { type: "base64", media_type: "image/png", data: PNG } }]; if (action === "cursor_position") return "X=512, Y=384"; if (["left_click", "right_click", "middle_click", "double_click", "triple_click", "mouse_move", "left_click_drag", "scroll", "type", "key", "hold_key", "wait", "left_mouse_down", "left_mouse_up"].includes(action)) return "OK"; // stub throw new Error(`Unknown action ${action}`); } function processToolCalls(content: any[]): any[] { const results: any[] = []; let failed = false; for (const b of content) { if (b.type !== "tool_use") continue; const member = b.toolset_name === "computer"; if (!member && b.name !== "computer") continue; const action = member ? b.name : b.input.action; const r: any = { type: "tool_result", tool_use_id: b.id, ...(member ? { toolset_name: "computer" } : {}) }; if (failed) Object.assign(r, { content: NOT_EXECUTED, is_error: true }); else try { r.content = executeAction(action, b.input); } catch (e) { Object.assign(r, { content: `Error: ${(e as Error).message}`, is_error: true }); failed = true; } results.push(r); } return results; } const messages: any[] = [{ role: "user", content: "Take a screenshot." }]; let maxTokens = 100; for (let i = 0; i < 2; i++) { const params: any = { model, max_tokens: maxTokens, tools, messages }; const resp: any = useToolset ? await client.messages.create(params) : await client.beta.messages.create({ ...params, betas: ["computer-use-2025-11-24"] }); logRequest("anthropic", "POST", "/v1/messages", 200, 0.007, `computer_use_loop.ts iter ${i}`); messages.push({ role: "assistant", content: resp.content }); console.log(i, resp.stop_reason, resp.content.filter((b: any) => b.type === "tool_use").map((b: any) => [b.name, b.toolset_name, b.input])); const results = processToolCalls(resp.content); if (!results.length || resp.stop_reason !== "tool_use") break; messages.push({ role: "user", content: results }); maxTokens = 50; }