diff --git a/pkg/templates/typescript/anthropic-computer-use/README.md b/pkg/templates/typescript/anthropic-computer-use/README.md index d4cd552c..839659fb 100644 --- a/pkg/templates/typescript/anthropic-computer-use/README.md +++ b/pkg/templates/typescript/anthropic-computer-use/README.md @@ -1,8 +1,8 @@ # Kernel TypeScript Sample App - Anthropic Computer Use -This is a Kernel application that implements a prompt loop using Anthropic Computer Use with Kernel's Computer Controls API. +This is a Kernel application that runs Anthropic Computer Use against a Kernel cloud browser. -It generally follows the [Anthropic Reference Implementation](https://github.com/anthropics/anthropic-quickstarts/tree/main/computer-use-demo) but uses Kernel's Computer Controls API instead of `xdotool` and `gnome-screenshot`. +It uses [`@onkernel/cua-agent`](https://www.npmjs.com/package/@onkernel/cua-agent) to run the computer-use loop: the `CuaAgent` class translates Claude's computer-use tool calls into Kernel browser controls and feeds a fresh screenshot back on every turn. The app entry point just provisions a browser, hands it to `CuaAgent`, and returns the final answer. ## Setup @@ -35,13 +35,26 @@ kernel invoke ts-anthropic-cua cua-task --payload '{"query": "Navigate to https: When enabled, the response will include a `replay_url` field with a link to view the recorded session. -## Known Limitations +## Playwright escape hatch -### Cursor Position +Some steps are awkward as raw clicks and keystrokes — precise DOM reads, form fills, data extraction, or waiting on a selector. Pass `playwright: true` when constructing the agent in `index.ts` to add a `playwright_execute` tool that runs Playwright/TypeScript directly against the live browser session: -The `cursor_position` action is not supported with Kernel's Computer Controls API. If the model attempts to use this action, an error will be returned. This is a known limitation that does not significantly impact most computer use workflows, as the model typically tracks cursor position through screenshots. +```ts +const agent = new CuaAgent({ + browser: session.browser, + client: kernel, + playwright: true, + initialState: { + model: 'anthropic:claude-sonnet-4-6', + systemPrompt: SYSTEM_PROMPT, + }, +}); +``` + +Inside `playwright_execute`, `page`, `context`, and `browser` are in scope and the code may `return` a JSON-serializable value. Each call runs in a fresh context (locals don't persist across calls), and no screenshot is returned automatically — the model can request one on a follow-up turn. See [`@onkernel/cua-agent`](https://www.npmjs.com/package/@onkernel/cua-agent) for details and per-model support status. ## Resources +- [@onkernel/cua-agent](https://www.npmjs.com/package/@onkernel/cua-agent) - [Anthropic Computer Use Documentation](https://docs.anthropic.com/en/docs/build-with-claude/computer-use) - [Kernel Documentation](https://www.kernel.sh/docs/quickstart) diff --git a/pkg/templates/typescript/anthropic-computer-use/index.ts b/pkg/templates/typescript/anthropic-computer-use/index.ts index 9508fa2b..f3c7e4d3 100644 --- a/pkg/templates/typescript/anthropic-computer-use/index.ts +++ b/pkg/templates/typescript/anthropic-computer-use/index.ts @@ -1,5 +1,6 @@ import { Kernel, type KernelContext } from '@onkernel/sdk'; -import { samplingLoop } from './loop'; +import { CuaAgent } from '@onkernel/cua-agent'; +import type { AssistantMessage } from '@onkernel/cua-ai'; import { KernelBrowserSession } from './session'; const kernel = new Kernel(); @@ -16,11 +17,40 @@ interface QueryOutput { replay_url?: string; } -// LLM API Keys are set in the environment during `kernel deploy -e ANTHROPIC_API_KEY=XXX` -// See https://www.kernel.sh/docs/launch/deploy#environment-variables -const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY; +const CURRENT_DATE = new Intl.DateTimeFormat('en-US', { + weekday: 'long', + month: 'long', + day: 'numeric', + year: 'numeric', +}).format(new Date()); + +// System prompt optimized for the Kernel cloud browser environment. +const SYSTEM_PROMPT = ` +* You are utilising an Ubuntu virtual machine using ${process.arch} architecture with internet access. +* When you connect to the display, CHROMIUM IS ALREADY OPEN. The url bar is not visible but it is there. +* If you need to navigate to a new page, use ctrl+l to focus the url bar and then enter the url. +* You won't be able to see the url bar from the screenshot but ctrl-l still works. +* As the initial step click on the search bar. +* When viewing a page it can be helpful to zoom out so that you can see everything on the page. +* Either that, or make sure you scroll down to see everything before deciding something isn't available. +* Scroll action: scroll_amount and the tool result are in wheel units (not pixels). +* When using your computer function calls, they take a while to run and send back to you. +* Where possible/feasible, try to chain multiple of these calls all into one function calls request. +* The current date is ${CURRENT_DATE}. +* After each step, take a screenshot and carefully evaluate if you have achieved the right outcome. +* Explicitly show your thinking: "I have evaluated step X..." If not correct, try again. +* Only when you confirm a step was executed correctly should you move on to the next one. + + + +* When using Chromium, if a startup wizard appears, IGNORE IT. Do not even click "skip this step". +* Instead, click on the search bar on the center of the screen where it says "Search or enter address", and enter the appropriate search term or URL there. +`; -if (!ANTHROPIC_API_KEY) { +// LLM API keys are set in the environment during `kernel deploy -e ANTHROPIC_API_KEY=XXX`. +// See https://www.kernel.sh/docs/launch/deploy#environment-variables +// CuaAgent reads ANTHROPIC_API_KEY (or ANTHROPIC_OAUTH_TOKEN) from the environment by default. +if (!process.env.ANTHROPIC_API_KEY) { throw new Error('ANTHROPIC_API_KEY is not set'); } @@ -42,36 +72,26 @@ app.action( console.log('Kernel browser live view url:', session.liveViewUrl); try { - // Run the sampling loop - const finalMessages = await samplingLoop({ - model: 'claude-sonnet-4-6', - messages: [{ - role: 'user', - content: payload.query, - }], - apiKey: ANTHROPIC_API_KEY, - thinkingBudget: 1024, - kernel, - sessionId: session.sessionId, + const agent = new CuaAgent({ + browser: session.browser, + client: kernel, + // Set to true to expose a playwright_execute tool for DOM reads, form fills, and selector waits. + playwright: false, + initialState: { + model: 'anthropic:claude-sonnet-4-6', + systemPrompt: SYSTEM_PROMPT, + }, }); - // Extract the final result from the messages - if (finalMessages.length === 0) { - throw new Error('No messages were generated during the sampling loop'); - } - - const lastMessage = finalMessages[finalMessages.length - 1]; - if (!lastMessage) { - throw new Error('Failed to get the last message from the sampling loop'); - } + await agent.prompt(payload.query); - const result = typeof lastMessage.content === 'string' - ? lastMessage.content - : lastMessage.content.map(block => - block.type === 'text' ? block.text : '' - ).join(''); + const lastAssistant = [...agent.state.messages] + .reverse() + .find((message): message is AssistantMessage => message.role === 'assistant'); + const result = lastAssistant?.content + .flatMap((block) => (block.type === 'text' ? [block.text] : [])) + .join('') ?? ''; - // Stop session and get replay URL if recording was enabled const sessionInfo = await session.stop(); return { @@ -79,7 +99,7 @@ app.action( replay_url: sessionInfo.replayViewUrl, }; } catch (error) { - console.error('Error in sampling loop:', error); + console.error('Error running CUA task:', error); await session.stop(); throw error; } diff --git a/pkg/templates/typescript/anthropic-computer-use/loop.ts b/pkg/templates/typescript/anthropic-computer-use/loop.ts deleted file mode 100644 index 24d60251..00000000 --- a/pkg/templates/typescript/anthropic-computer-use/loop.ts +++ /dev/null @@ -1,218 +0,0 @@ -import { Anthropic } from '@anthropic-ai/sdk'; -import type { Kernel } from '@onkernel/sdk'; -import { DEFAULT_TOOL_VERSION, TOOL_GROUPS_BY_VERSION, ToolCollection, type ToolVersion } from './tools/collection'; -import { ComputerTool20241022, ComputerTool20250124, ComputerTool20251124 } from './tools/computer'; -import type { ActionParams } from './tools/types/computer'; -import { Action } from './tools/types/computer'; -import type { BetaMessageParam, BetaTextBlock } from './types/beta'; -import { injectPromptCaching, maybeFilterToNMostRecentImages, PROMPT_CACHING_BETA_FLAG, responseToParams } from './utils/message-processing'; -import { makeApiToolResult } from './utils/tool-results'; - -const CURRENT_DATE = new Intl.DateTimeFormat('en-US', { - weekday: 'long', - month: 'long', - day: 'numeric', - year: 'numeric', -}).format(new Date()); - -// System prompt optimized for the environment -const SYSTEM_PROMPT = ` -* You are utilising an Ubuntu virtual machine using ${process.arch} architecture with internet access. -* When you connect to the display, CHROMIUM IS ALREADY OPEN. The url bar is not visible but it is there. -* If you need to navigate to a new page, use ctrl+l to focus the url bar and then enter the url. -* You won't be able to see the url bar from the screenshot but ctrl-l still works. -* As the initial step click on the search bar. -* When viewing a page it can be helpful to zoom out so that you can see everything on the page. -* Either that, or make sure you scroll down to see everything before deciding something isn't available. -* Scroll action: scroll_amount and the tool result are in wheel units (not pixels). -* When using your computer function calls, they take a while to run and send back to you. -* Where possible/feasible, try to chain multiple of these calls all into one function calls request. -* The current date is ${CURRENT_DATE}. -* After each step, take a screenshot and carefully evaluate if you have achieved the right outcome. -* Explicitly show your thinking: "I have evaluated step X..." If not correct, try again. -* Only when you confirm a step was executed correctly should you move on to the next one. - - - -* When using Chromium, if a startup wizard appears, IGNORE IT. Do not even click "skip this step". -* Instead, click on the search bar on the center of the screen where it says "Search or enter address", and enter the appropriate search term or URL there. -`; - -// Add new type definitions -interface ThinkingConfig { - type: 'enabled'; - budget_tokens: number; -} - -interface ExtraBodyConfig { - thinking?: ThinkingConfig; -} - -interface ToolUseInput extends Record { - action: Action; -} - -function getToolVersionForModel(model: string): ToolVersion { - if ( - model.includes('claude-sonnet-4-6') - || model.includes('claude-opus-4-6') - || model.includes('claude-opus-4-5') - ) { - return 'computer_use_20251124'; - } - return 'computer_use_20250124'; -} - -export async function samplingLoop({ - model, - systemPromptSuffix, - messages, - apiKey, - onlyNMostRecentImages, - maxTokens = 4096, - toolVersion, - thinkingBudget, - tokenEfficientToolsBeta = false, - kernel, - sessionId, - viewportWidth = 1280, - viewportHeight = 800, -}: { - model: string; - systemPromptSuffix?: string; - messages: BetaMessageParam[]; - apiKey: string; - onlyNMostRecentImages?: number; - maxTokens?: number; - toolVersion?: ToolVersion; - thinkingBudget?: number; - tokenEfficientToolsBeta?: boolean; - kernel: Kernel; - sessionId: string; - viewportWidth?: number; - viewportHeight?: number; -}): Promise { - const selectedVersion = toolVersion || getToolVersionForModel(model) || DEFAULT_TOOL_VERSION; - const toolGroup = TOOL_GROUPS_BY_VERSION[selectedVersion]; - const toolCollection = new ToolCollection(...toolGroup.tools.map((Tool: typeof ComputerTool20241022 | typeof ComputerTool20250124 | typeof ComputerTool20251124) => new Tool(kernel, sessionId, viewportWidth, viewportHeight))); - - const system: BetaTextBlock = { - type: 'text', - text: `${SYSTEM_PROMPT}${systemPromptSuffix ? ' ' + systemPromptSuffix : ''}`, - }; - - while (true) { - const betas: string[] = toolGroup.beta_flag ? [toolGroup.beta_flag] : []; - - if (tokenEfficientToolsBeta) { - betas.push('token-efficient-tools-2025-02-19'); - } - - let imageTruncationThreshold = onlyNMostRecentImages || 0; - - const client = new Anthropic({ apiKey, maxRetries: 4 }); - const enablePromptCaching = true; - - if (enablePromptCaching) { - betas.push(PROMPT_CACHING_BETA_FLAG); - injectPromptCaching(messages); - onlyNMostRecentImages = 0; - (system as BetaTextBlock).cache_control = { type: 'ephemeral' }; - } - - if (onlyNMostRecentImages) { - maybeFilterToNMostRecentImages( - messages, - onlyNMostRecentImages, - imageTruncationThreshold - ); - } - - const extraBody: ExtraBodyConfig = {}; - if (thinkingBudget) { - extraBody.thinking = { type: 'enabled', budget_tokens: thinkingBudget }; - } - - const toolParams = toolCollection.toParams(); - - const response = await client.beta.messages.create({ - max_tokens: maxTokens, - messages, - model, - system: [system], - tools: toolParams, - betas, - ...extraBody, - }); - - const responseParams = responseToParams(response); - - const loggableContent = responseParams.map(block => { - if (block.type === 'tool_use') { - return { - type: 'tool_use', - name: block.name, - input: block.input - }; - } - return block; - }); - console.log('=== LLM RESPONSE ==='); - console.log('Stop reason:', response.stop_reason); - console.log(loggableContent); - console.log("===") - - messages.push({ - role: 'assistant', - content: responseParams, - }); - - if (response.stop_reason === 'end_turn') { - console.log('LLM has completed its task, ending loop'); - return messages; - } - - const toolResultContent = []; - let hasToolUse = false; - - for (const contentBlock of responseParams) { - if (contentBlock.type === 'tool_use' && contentBlock.name && contentBlock.input && typeof contentBlock.input === 'object') { - const input = contentBlock.input as ToolUseInput; - if ('action' in input && typeof input.action === 'string') { - hasToolUse = true; - const toolInput: ActionParams = { - action: input.action as Action, - ...Object.fromEntries( - Object.entries(input).filter(([key]) => key !== 'action') - ) - }; - - try { - const result = await toolCollection.run( - contentBlock.name, - toolInput - ); - - const toolResult = makeApiToolResult(result, contentBlock.id!); - toolResultContent.push(toolResult); - } catch (error) { - console.error(error); - throw error; - } - } - } - } - - if (toolResultContent.length === 0 && !hasToolUse && response.stop_reason !== 'tool_use') { - console.log('No tool use or results, and not waiting for tool use, ending loop'); - return messages; - } - - if (toolResultContent.length > 0) { - messages.push({ - role: 'user', - content: toolResultContent, - }); - } - } -} diff --git a/pkg/templates/typescript/anthropic-computer-use/package.json b/pkg/templates/typescript/anthropic-computer-use/package.json index a3e9d631..206033ea 100644 --- a/pkg/templates/typescript/anthropic-computer-use/package.json +++ b/pkg/templates/typescript/anthropic-computer-use/package.json @@ -4,8 +4,9 @@ "type": "module", "private": true, "dependencies": { - "@anthropic-ai/sdk": "^0.71.2", - "@onkernel/sdk": "^0.35.0" + "@onkernel/cua-agent": "^0.3.4", + "@onkernel/cua-ai": "^0.3.1", + "@onkernel/sdk": "0.49.0" }, "devDependencies": { "@types/node": "^22.15.17", diff --git a/pkg/templates/typescript/anthropic-computer-use/pnpm-lock.yaml b/pkg/templates/typescript/anthropic-computer-use/pnpm-lock.yaml index 4b96f83f..05786132 100644 --- a/pkg/templates/typescript/anthropic-computer-use/pnpm-lock.yaml +++ b/pkg/templates/typescript/anthropic-computer-use/pnpm-lock.yaml @@ -8,12 +8,15 @@ importers: .: dependencies: - '@anthropic-ai/sdk': - specifier: ^0.71.2 - version: 0.71.2 + '@onkernel/cua-agent': + specifier: ^0.3.4 + version: 0.3.4(ws@8.21.0)(zod@4.4.3) + '@onkernel/cua-ai': + specifier: ^0.3.1 + version: 0.3.1(ws@8.21.0)(zod@4.4.3) '@onkernel/sdk': - specifier: ^0.35.0 - version: 0.35.0 + specifier: 0.49.0 + version: 0.49.0 devDependencies: '@types/node': specifier: ^22.15.17 @@ -24,8 +27,8 @@ importers: packages: - '@anthropic-ai/sdk@0.71.2': - resolution: {integrity: sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ==} + '@anthropic-ai/sdk@0.91.1': + resolution: {integrity: sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==} hasBin: true peerDependencies: zod: ^3.25.0 || ^4.0.0 @@ -33,23 +36,519 @@ packages: zod: optional: true + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-bedrock-runtime@3.1048.0': + resolution: {integrity: sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.974.23': + resolution: {integrity: sha512-MiWR/uWjxjFXGzrE0Ghc5lWxUxzHsUWFhV+OX7M4cR9SrmrnZs6TXavnCWnzzdwJeFri34xQo81rvGNzK3c4BQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.49': + resolution: {integrity: sha512-liB3yQNHCM9k/gu/w36XHMKPluT7HTlnGUhRbBGSISDQkcr/Sy1zsZabiuvQj8WG5yW573u9RehrBvvnIQ9OEQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.51': + resolution: {integrity: sha512-XET0H2oofciJ5lMRWNIvRjAP7Q3wv2XT+JtJJEdhPWUMwe3TvQ9qcxonpu7vXmNngncvFpi4E2It+Tamas/naA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.972.56': + resolution: {integrity: sha512-IAmc61hbgQiHht9U3x0tnRwz0lzdwOwD/i9voRgdJrKamF+JtmrBOsW9GwB7mfFonNWOWL4qARWYrF8veEMe3w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.55': + resolution: {integrity: sha512-hBBkANo3cDn+h2qxxzER4a+J8JCO9o9Z/YYmU7iky6AcaarX5RRdRcHNC6SLdwY0vAXQygn6soUbDqPn3GghaA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.58': + resolution: {integrity: sha512-OyCLVmSI7pZO8hxwNVX6pXhTVlJqRBTp+ijdEfJSUj0RyjHnF602OfAarOzGq6wkGodeFkYBt8MmJ6A6ycRgWw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.49': + resolution: {integrity: sha512-C8h36lBuC/RnBSsjlO+dn6xZm3KbAl5vpJaVPAfQnMmz2/OISmKOc8XZcqMQgO2ADwBYNRMM6Kf3vz9G/TulMQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.972.55': + resolution: {integrity: sha512-1FkOz74Ea5QGS9jtIoXp55T/IkSS3spv+nLTT07fRY/+T5xmEOqaYBVIaEmX4zTNvbV6g2lrtlaVKWEoNyJt3w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.55': + resolution: {integrity: sha512-g2BoECD1q01kTPByi56+VLVvdWDzMkKIcr77qixpqH0okw2t0U5CoPv+6S8v/D1Y2Wa6QKKtn6XAtDzP+Kfpvg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/eventstream-handler-node@3.972.22': + resolution: {integrity: sha512-tqPJv0dz4+O0hWGm1a6YekcMZyPhDFs/zH73Von7icaVT5n0Jqvm86typ3jRrG+qoUdPhALOnboRLTmnWQTlYQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-eventstream@3.972.18': + resolution: {integrity: sha512-OHpk8YoZi3yexPq8aFt1vN1IxA2zLKvsIR5GpWYylX/ve6kQmY7wxHNSFy/D3t2apMZ16rs76Co4dJWcDyIk3A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-websocket@3.972.31': + resolution: {integrity: sha512-ps1rumU1LybSFHaW9dTDgkhCMJLVaedEY78kKSzUDDY+b9974/g6aiaYYA0U9WV0oL4CJCJrVWG+EZ/qr4or7g==} + engines: {node: '>= 14.0.0'} + + '@aws-sdk/nested-clients@3.997.23': + resolution: {integrity: sha512-gO93ZPsI2bxeFZD42f1/qjDw6FAZkNZcKRO94LIiT03fzOmcJ9e/tunxjVjA1Rl69ClmVJzz8H3G9CdKef10PA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.996.35': + resolution: {integrity: sha512-6L/VWs+Wch2stHemCGTmUNqKLMzURxQDK5boNG3Jn3kAOp71meDUuS5sbObpEvFxHDq0uWeSLFDNSYsjNt+Dlg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1048.0': + resolution: {integrity: sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1074.0': + resolution: {integrity: sha512-pv80IzgGW4RnXWtft692chZOM9i6PhebVsLCcnaM4dBEPZva2fE6FXAHs76G7Rc7s3yGyX/68G0nZMrUy+Vmpg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.973.13': + resolution: {integrity: sha512-pEHZqRkAlHfnfAU9tK+WpKv/gBNjGJrHMgA3A0iYRGyswBS2t0pfez+lWlwktb3Bqa0ovh7w/QJTFwp3fDxLNg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-locate-window@3.965.8': + resolution: {integrity: sha512-uUbMs1cBZPafD0ohUj6EwNf0fPZ534NvBxHox4hjX+0Rxq5paSYUem7+hi833pYrzrcnBATKIYpR02MDXT5M9g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/xml-builder@3.972.31': + resolution: {integrity: sha512-SzE4Pgyl+hDF+BuyuzxUSpwnuUu9lJuO1YGgteG89/4Qv0+2IQiVQqdbPV32IozLvXWQChPQcdkk/sKvb1QHiQ==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.2.4': + resolution: {integrity: sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==} + engines: {node: '>=18.0.0'} + '@babel/runtime@7.28.4': resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} - '@onkernel/sdk@0.35.0': - resolution: {integrity: sha512-EnTEyTm85WwOOXZziDTySNHl46ZO+DSJjVDJDJNarwkD+kv623TzXDLpgH7vwy4LfQjQ4DzOQe0hHKgCYrAv5A==} + '@earendil-works/pi-agent-core@0.79.1': + resolution: {integrity: sha512-PBPjBa2YBm9jauiLtHAKaSfVJ4Dvm3/nK/bR/oHebLjwBCS2tGx3aQDX7MSGAOXi6BejlhzbB/z82BkyAyNjjQ==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-ai@0.79.1': + resolution: {integrity: sha512-UnORwrcsTNLm4StEvoM8iEom0u87Te7BXEWxhec3iNXygWD6eEBosUoq9ddcveqtj/QpUZBMPWUu81cCtZxzkQ==} + engines: {node: '>=22.19.0'} + hasBin: true + + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + + '@google/genai@1.52.0': + resolution: {integrity: sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@modelcontextprotocol/sdk': ^1.25.2 + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@mistralai/mistralai@2.2.1': + resolution: {integrity: sha512-uKU8CZmL2RzYKmplsU01hii4p3pe4HqJefpWNRWXm1Tcm0Sm4xXfwSLIy4k7ZCPlbETCGcp69E7hZs+WOJ5itQ==} + + '@onkernel/cua-agent@0.3.4': + resolution: {integrity: sha512-MlSbxmd/HrYTM7ZEHs0fXgisLOKhM7JGG2hrDDNS8ZjDzu/BjcZ4Vq7h6BE+RRaXGO32wskqif/SH+6Wf3bePg==} + + '@onkernel/cua-ai@0.3.1': + resolution: {integrity: sha512-85w4GRzskuGho+prPKAFFCYpDyWjIUEkUiJqPU/CTW2+/Co7B4qmeqm1A2T+No+y7C+4vDnbW3Bvvy7Q1nFWYg==} + + '@onkernel/sdk@0.49.0': + resolution: {integrity: sha512-nsq5OfkaNKxRTCdXQF8BSTj/Wl0iBIqyWoI/ATgQt15pV+59E22MsZ+IHPiVwwb33tXLtnOqUe5ffOxm7l3GHg==} + + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.1': + resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} + + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.1': + resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==} + + '@smithy/core@3.26.0': + resolution: {integrity: sha512-mLUktFAn+Pa2agl1J7VgtYNFWCX8/b4GMJSK1hCu4YCvtBfM6F8Os3EP4ry+DFFlXOf3wyvlgXhuUdFoy52D3g==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.4.2': + resolution: {integrity: sha512-18UMDMyrAbDcpmL1gLUA7ww0fRTcdCrSjSJOi2Sbld+tVjwD/pW+OAwjlScFLR7vvBnhZrIPQ7kVuTf1mnJLug==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.5.2': + resolution: {integrity: sha512-Ei/UK/QMhq0rKaMqGPlOAkE2yS9DZeYmZdk1RAKc3vp3zxgleZHZyBLlZv8yLsxljX4svCRuMTD6u3LLIcU4Bg==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/node-http-handler@4.7.3': + resolution: {integrity: sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.8.2': + resolution: {integrity: sha512-wfl1uwrAqMH9/pi4kqBo5LBcFwrJLxuDLqL7p7qNcJIFcyZDUc6pzhYk4CYv+DP7fIUpQCZumwNnkhPKS52osQ==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.5.2': + resolution: {integrity: sha512-7xHpmPY4rt0IOmeAA8EfjgEH8isT+587TCdy9H6a7d4OMi5CQ0oEHhWllunvPu4j4Cq0vTFwdxXN/kABWPjdyA==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.15.0': + resolution: {integrity: sha512-Z5TAOxygoFvybJV3igo5SloFflSokHx2hu1eFA+DxDTcn+FtKxUSui+rbTRG1pAafMA888Z3MVvCWUuvCrTXjg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} '@types/node@22.19.3': resolution: {integrity: sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==} + '@types/retry@0.12.0': + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + + '@tzafon/lightcone@0.7.2': + resolution: {integrity: sha512-jzXTAOeE77FuuzP8J2dtxXxlBnN3Jb1o/iF7taVLGsT4ch8EemztVKjHH6KOJtu+3KvQzSioYoJCIX6pJ35jTA==} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + gaxios@7.1.5: + resolution: {integrity: sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg==} + engines: {node: '>=18'} + + gcp-metadata@8.1.2: + resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} + engines: {node: '>=18'} + + google-auth-library@10.7.0: + resolution: {integrity: sha512-QpTAbNJ36TliZLx3TTtahR8HG0hN9RllL1e3FymOvQSIKK8JmgV58H924ub2wa2DsS3ANjjP1Aw1N+Ramc8hqQ==} + engines: {node: '>=18'} + + google-logging-utils@1.1.3: + resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} + engines: {node: '>=14'} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + json-schema-to-ts@3.1.1: resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} engines: {node: '>=16'} + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + openai@6.26.0: + resolution: {integrity: sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + openai@6.44.0: + resolution: {integrity: sha512-09/gH+8jH0RgUwsgWHAaxsKGRT5zVZ95IaJUnqAWj6XejIBmnFRwq2WUIF37VtDEsmGrtPmvCs5+yBSeZGWvkA==} + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + + partial-json@0.1.7: + resolution: {integrity: sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==} + + protobufjs@7.6.4: + resolution: {integrity: sha512-RJJPTTpvFfHcWLkIa2JFWK4XvtSzS0yEWDmunqHXli1h3JlkbcQZXDZdcWxv+JK3Xsl5/UFDPZ0iGm7DAengYw==} + engines: {node: '>=12.0.0'} + + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + ts-algebra@2.0.0: resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typebox@1.1.38: + resolution: {integrity: sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -58,27 +557,730 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + snapshots: - '@anthropic-ai/sdk@0.71.2': + '@anthropic-ai/sdk@0.91.1(zod@4.4.3)': dependencies: json-schema-to-ts: 3.1.1 + optionalDependencies: + zod: 4.4.3 + + '@aws-crypto/crc32@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.13 + tslib: 2.8.1 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.13 + '@aws-sdk/util-locate-window': 3.965.8 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.13 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.973.13 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-bedrock-runtime@3.1048.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.974.23 + '@aws-sdk/credential-provider-node': 3.972.58 + '@aws-sdk/eventstream-handler-node': 3.972.22 + '@aws-sdk/middleware-eventstream': 3.972.18 + '@aws-sdk/middleware-websocket': 3.972.31 + '@aws-sdk/token-providers': 3.1048.0 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/fetch-http-handler': 5.5.2 + '@smithy/node-http-handler': 4.7.3 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/core@3.974.23': + dependencies: + '@aws-sdk/types': 3.973.13 + '@aws-sdk/xml-builder': 3.972.31 + '@aws/lambda-invoke-store': 0.2.4 + '@smithy/core': 3.26.0 + '@smithy/signature-v4': 5.5.2 + '@smithy/types': 4.15.0 + bowser: 2.14.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.972.49': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.972.51': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/fetch-http-handler': 5.5.2 + '@smithy/node-http-handler': 4.8.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.972.56': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/credential-provider-env': 3.972.49 + '@aws-sdk/credential-provider-http': 3.972.51 + '@aws-sdk/credential-provider-login': 3.972.55 + '@aws-sdk/credential-provider-process': 3.972.49 + '@aws-sdk/credential-provider-sso': 3.972.55 + '@aws-sdk/credential-provider-web-identity': 3.972.55 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/credential-provider-imds': 4.4.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-login@3.972.55': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-node@3.972.58': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.49 + '@aws-sdk/credential-provider-http': 3.972.51 + '@aws-sdk/credential-provider-ini': 3.972.56 + '@aws-sdk/credential-provider-process': 3.972.49 + '@aws-sdk/credential-provider-sso': 3.972.55 + '@aws-sdk/credential-provider-web-identity': 3.972.55 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/credential-provider-imds': 4.4.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-process@3.972.49': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.972.55': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/token-providers': 3.1074.0 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-web-identity@3.972.55': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/eventstream-handler-node@3.972.22': + dependencies: + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-eventstream@3.972.18': + dependencies: + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-websocket@3.972.31': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/fetch-http-handler': 5.5.2 + '@smithy/signature-v4': 5.5.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.997.23': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.974.23 + '@aws-sdk/signature-v4-multi-region': 3.996.35 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/fetch-http-handler': 5.5.2 + '@smithy/node-http-handler': 4.8.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.996.35': + dependencies: + '@aws-sdk/types': 3.973.13 + '@smithy/signature-v4': 5.5.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1048.0': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1074.0': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/types@3.973.13': + dependencies: + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.965.8': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.31': + dependencies: + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.2.4': {} '@babel/runtime@7.28.4': {} - '@onkernel/sdk@0.35.0': {} + '@earendil-works/pi-agent-core@0.79.1(ws@8.21.0)(zod@4.4.3)': + dependencies: + '@earendil-works/pi-ai': 0.79.1(ws@8.21.0)(zod@4.4.3) + ignore: 7.0.5 + typebox: 1.1.38 + yaml: 2.9.0 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-ai@0.79.1(ws@8.21.0)(zod@4.4.3)': + dependencies: + '@anthropic-ai/sdk': 0.91.1(zod@4.4.3) + '@aws-sdk/client-bedrock-runtime': 3.1048.0 + '@google/genai': 1.52.0 + '@mistralai/mistralai': 2.2.1 + '@smithy/node-http-handler': 4.7.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + openai: 6.26.0(ws@8.21.0)(zod@4.4.3) + partial-json: 0.1.7 + typebox: 1.1.38 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@google/genai@1.52.0': + dependencies: + google-auth-library: 10.7.0 + p-retry: 4.6.2 + protobufjs: 7.6.4 + ws: 8.21.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.11.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@mistralai/mistralai@2.2.1': + dependencies: + ws: 8.21.0 + zod: 4.4.3 + zod-to-json-schema: 3.25.2(zod@4.4.3) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@onkernel/cua-agent@0.3.4(ws@8.21.0)(zod@4.4.3)': + dependencies: + '@earendil-works/pi-agent-core': 0.79.1(ws@8.21.0)(zod@4.4.3) + '@earendil-works/pi-ai': 0.79.1(ws@8.21.0)(zod@4.4.3) + '@onkernel/cua-ai': 0.3.1(ws@8.21.0)(zod@4.4.3) + '@onkernel/sdk': 0.49.0 + sharp: 0.34.5 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@onkernel/cua-ai@0.3.1(ws@8.21.0)(zod@4.4.3)': + dependencies: + '@earendil-works/pi-ai': 0.79.1(ws@8.21.0)(zod@4.4.3) + '@tzafon/lightcone': 0.7.2 + openai: 6.44.0(ws@8.21.0)(zod@4.4.3) + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@onkernel/sdk@0.49.0': {} + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.1': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.1': {} + + '@smithy/core@3.26.0': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.4.2': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.5.2': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/node-http-handler@4.7.3': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.8.2': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.5.2': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/types@4.15.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 '@types/node@22.19.3': dependencies: undici-types: 6.21.0 + '@types/retry@0.12.0': {} + + '@tzafon/lightcone@0.7.2': {} + + agent-base@7.1.4: {} + + base64-js@1.5.1: {} + + bignumber.js@9.3.1: {} + + bowser@2.14.1: {} + + buffer-equal-constant-time@1.0.1: {} + + data-uri-to-buffer@4.0.1: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + detect-libc@2.1.2: {} + + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + + extend@3.0.2: {} + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + + gaxios@7.1.5: + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + transitivePeerDependencies: + - supports-color + + gcp-metadata@8.1.2: + dependencies: + gaxios: 7.1.5 + google-logging-utils: 1.1.3 + json-bigint: 1.0.0 + transitivePeerDependencies: + - supports-color + + google-auth-library@10.7.0: + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.1.5 + gcp-metadata: 8.1.2 + google-logging-utils: 1.1.3 + jws: 4.0.1 + transitivePeerDependencies: + - supports-color + + google-logging-utils@1.1.3: {} + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ignore@7.0.5: {} + + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 + json-schema-to-ts@3.1.1: dependencies: '@babel/runtime': 7.28.4 ts-algebra: 2.0.0 + jwa@2.0.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@4.0.1: + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + + long@5.3.2: {} + + ms@2.1.3: {} + + node-domexception@1.0.0: {} + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + + openai@6.26.0(ws@8.21.0)(zod@4.4.3): + optionalDependencies: + ws: 8.21.0 + zod: 4.4.3 + + openai@6.44.0(ws@8.21.0)(zod@4.4.3): + optionalDependencies: + ws: 8.21.0 + zod: 4.4.3 + + p-retry@4.6.2: + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + + partial-json@0.1.7: {} + + protobufjs@7.6.4: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.1 + '@types/node': 22.19.3 + long: 5.3.2 + + retry@0.13.1: {} + + safe-buffer@5.2.1: {} + + semver@7.8.5: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + ts-algebra@2.0.0: {} + tslib@2.8.1: {} + + typebox@1.1.38: {} + typescript@5.9.3: {} undici-types@6.21.0: {} + + web-streams-polyfill@3.3.3: {} + + ws@8.21.0: {} + + yaml@2.9.0: {} + + zod-to-json-schema@3.25.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@4.4.3: {} diff --git a/pkg/templates/typescript/anthropic-computer-use/session.ts b/pkg/templates/typescript/anthropic-computer-use/session.ts index e533742b..1a42b527 100644 --- a/pkg/templates/typescript/anthropic-computer-use/session.ts +++ b/pkg/templates/typescript/anthropic-computer-use/session.ts @@ -6,6 +6,7 @@ */ import type { Kernel } from '@onkernel/sdk'; +import type { BrowserCreateResponse } from '@onkernel/sdk/resources/browsers'; export interface SessionOptions { /** Invocation ID to link browser session to the action invocation */ @@ -63,6 +64,7 @@ export class KernelBrowserSession { private options: SessionOptionsWithDefaults; // Session state + private _browser: BrowserCreateResponse | null = null; private _sessionId: string | null = null; private _liveViewUrl: string | null = null; private _replayId: string | null = null; @@ -80,6 +82,13 @@ export class KernelBrowserSession { return this._sessionId; } + get browser(): BrowserCreateResponse { + if (!this._browser) { + throw new Error('Session not started. Call start() first.'); + } + return this._browser; + } + get liveViewUrl(): string | null { return this._liveViewUrl; } @@ -122,6 +131,7 @@ export class KernelBrowserSession { }, }); + this._browser = browser; this._sessionId = browser.session_id; this._liveViewUrl = browser.browser_live_view_url ?? null; @@ -230,6 +240,7 @@ export class KernelBrowserSession { } // Reset state + this._browser = null; this._sessionId = null; this._liveViewUrl = null; this._replayId = null; diff --git a/pkg/templates/typescript/anthropic-computer-use/tools/collection.ts b/pkg/templates/typescript/anthropic-computer-use/tools/collection.ts deleted file mode 100644 index db914ca0..00000000 --- a/pkg/templates/typescript/anthropic-computer-use/tools/collection.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { ComputerTool20241022, ComputerTool20250124, ComputerTool20251124 } from './computer'; -import { Action } from './types/computer'; -import type { ActionParams, ComputerToolParams, ToolResult } from './types/computer'; - -export type ToolVersion = 'computer_use_20250124' | 'computer_use_20241022' | 'computer_use_20250429' | 'computer_use_20251124'; - -export const DEFAULT_TOOL_VERSION: ToolVersion = 'computer_use_20251124'; - -interface ToolGroup { - readonly version: ToolVersion; - readonly tools: (typeof ComputerTool20241022 | typeof ComputerTool20250124 | typeof ComputerTool20251124)[]; - readonly beta_flag: string; -} - -export const TOOL_GROUPS: ToolGroup[] = [ - { - version: 'computer_use_20241022', - tools: [ComputerTool20241022], - beta_flag: 'computer-use-2024-10-22', - }, - { - version: 'computer_use_20250124', - tools: [ComputerTool20250124], - beta_flag: 'computer-use-2025-01-24', - }, - { - version: 'computer_use_20251124', - tools: [ComputerTool20251124], - beta_flag: 'computer-use-2025-11-24', - }, - // 20250429 version inherits from 20250124 - { - version: 'computer_use_20250429', - tools: [ComputerTool20250124], - beta_flag: 'computer-use-2025-01-24', - }, -]; - -export const TOOL_GROUPS_BY_VERSION: Record = Object.fromEntries( - TOOL_GROUPS.map(group => [group.version, group]) -) as Record; - -export class ToolCollection { - private tools: Map; - - constructor(...tools: (ComputerTool20241022 | ComputerTool20250124 | ComputerTool20251124)[]) { - this.tools = new Map(tools.map(tool => [tool.name, tool])); - } - - toParams(): ComputerToolParams[] { - return Array.from(this.tools.values()).map(tool => tool.toParams()); - } - - async run(name: string, toolInput: ActionParams): Promise { - const tool = this.tools.get(name); - if (!tool) { - throw new Error(`Tool ${name} not found`); - } - - if (!Object.values(Action).includes(toolInput.action)) { - throw new Error(`Invalid action ${toolInput.action} for tool ${name}`); - } - - return await tool.call(toolInput); - } -} \ No newline at end of file diff --git a/pkg/templates/typescript/anthropic-computer-use/tools/computer.ts b/pkg/templates/typescript/anthropic-computer-use/tools/computer.ts deleted file mode 100644 index 1d30b36a..00000000 --- a/pkg/templates/typescript/anthropic-computer-use/tools/computer.ts +++ /dev/null @@ -1,402 +0,0 @@ -import { Buffer } from 'buffer'; -import type { Kernel } from '@onkernel/sdk'; -import type { ActionParams, BaseAnthropicTool, ComputerToolParams, ToolResult } from './types/computer'; -import { Action, ToolError } from './types/computer'; -import { ActionValidator } from './utils/validator'; - -const TYPING_DELAY_MS = 12; - -export class ComputerTool implements BaseAnthropicTool { - name: 'computer' = 'computer'; - protected kernel: Kernel; - protected sessionId: string; - protected _screenshotDelay = 2.0; - protected version: '20241022' | '20250124' | '20251124'; - protected width: number; - protected height: number; - - private lastMousePosition: [number, number] = [0, 0]; - - private readonly mouseActions = new Set([ - Action.LEFT_CLICK, - Action.RIGHT_CLICK, - Action.MIDDLE_CLICK, - Action.DOUBLE_CLICK, - Action.TRIPLE_CLICK, - Action.MOUSE_MOVE, - Action.LEFT_MOUSE_DOWN, - Action.LEFT_MOUSE_UP, - ]); - - private readonly keyboardActions = new Set([ - Action.KEY, - Action.TYPE, - Action.HOLD_KEY, - ]); - - private readonly systemActions = new Set([ - Action.SCREENSHOT, - Action.CURSOR_POSITION, - Action.SCROLL, - Action.WAIT, - ]); - - constructor(kernel: Kernel, sessionId: string, version: '20241022' | '20250124' | '20251124' = '20250124', width = 1280, height = 800) { - this.kernel = kernel; - this.sessionId = sessionId; - this.version = version; - this.width = width; - this.height = height; - } - - get apiType(): 'computer_20241022' | 'computer_20250124' | 'computer_20251124' { - if (this.version === '20241022') { - return 'computer_20241022'; - } - if (this.version === '20250124') { - return 'computer_20250124'; - } - return 'computer_20251124'; - } - - toParams(): ComputerToolParams { - const params = { - name: this.name, - type: this.apiType, - display_width_px: this.width, - display_height_px: this.height, - display_number: null, - }; - return params; - } - - private getMouseButton(action: Action): 'left' | 'right' | 'middle' { - switch (action) { - case Action.LEFT_CLICK: - case Action.DOUBLE_CLICK: - case Action.TRIPLE_CLICK: - case Action.LEFT_CLICK_DRAG: - case Action.LEFT_MOUSE_DOWN: - case Action.LEFT_MOUSE_UP: - return 'left'; - case Action.RIGHT_CLICK: - return 'right'; - case Action.MIDDLE_CLICK: - return 'middle'; - default: - throw new ToolError(`Invalid mouse action: ${action}`); - } - } - - private async handleMouseAction(action: Action, coordinate: [number, number]): Promise { - const [x, y] = ActionValidator.validateAndGetCoordinates(coordinate); - - if (action === Action.MOUSE_MOVE) { - await this.kernel.browsers.computer.moveMouse(this.sessionId, { - x, - y, - }); - this.lastMousePosition = [x, y]; - } else if (action === Action.LEFT_MOUSE_DOWN) { - await this.kernel.browsers.computer.clickMouse(this.sessionId, { - x, - y, - button: 'left', - click_type: 'down', - }); - this.lastMousePosition = [x, y]; - } else if (action === Action.LEFT_MOUSE_UP) { - await this.kernel.browsers.computer.clickMouse(this.sessionId, { - x, - y, - button: 'left', - click_type: 'up', - }); - this.lastMousePosition = [x, y]; - } else { - const button = this.getMouseButton(action); - let numClicks = 1; - if (action === Action.DOUBLE_CLICK) { - numClicks = 2; - } else if (action === Action.TRIPLE_CLICK) { - numClicks = 3; - } - - await this.kernel.browsers.computer.clickMouse(this.sessionId, { - x, - y, - button, - click_type: 'click', - num_clicks: numClicks, - }); - this.lastMousePosition = [x, y]; - } - - await new Promise(resolve => setTimeout(resolve, 500)); - return await this.screenshot(); - } - - private async handleKeyboardAction(action: Action, text: string, duration?: number): Promise { - if (action === Action.HOLD_KEY) { - const key = this.convertToKernelKey(text); - await this.kernel.browsers.computer.pressKey(this.sessionId, { - keys: [key], - duration: duration ? duration * 1000 : undefined, - }); - } else if (action === Action.KEY) { - const key = this.convertKeyCombinationToKernel(text); - await this.kernel.browsers.computer.pressKey(this.sessionId, { - keys: [key], - }); - } else { - await this.kernel.browsers.computer.typeText(this.sessionId, { - text, - delay: TYPING_DELAY_MS, - }); - } - - await new Promise(resolve => setTimeout(resolve, 500)); - return await this.screenshot(); - } - - // Key mappings for Kernel Computer Controls API (xdotool format) - private static readonly KEY_MAP: Record = { - // Enter/Return - 'return': 'Return', - 'enter': 'Return', - 'Enter': 'Return', - // Arrow keys - 'left': 'Left', - 'right': 'Right', - 'up': 'Up', - 'down': 'Down', - 'ArrowLeft': 'Left', - 'ArrowRight': 'Right', - 'ArrowUp': 'Up', - 'ArrowDown': 'Down', - // Navigation - 'home': 'Home', - 'end': 'End', - 'pageup': 'Page_Up', - 'page_up': 'Page_Up', - 'PageUp': 'Page_Up', - 'pagedown': 'Page_Down', - 'page_down': 'Page_Down', - 'PageDown': 'Page_Down', - // Editing - 'delete': 'Delete', - 'backspace': 'BackSpace', - 'Backspace': 'BackSpace', - 'tab': 'Tab', - 'insert': 'Insert', - // Escape - 'esc': 'Escape', - 'escape': 'Escape', - // Function keys - 'f1': 'F1', - 'f2': 'F2', - 'f3': 'F3', - 'f4': 'F4', - 'f5': 'F5', - 'f6': 'F6', - 'f7': 'F7', - 'f8': 'F8', - 'f9': 'F9', - 'f10': 'F10', - 'f11': 'F11', - 'f12': 'F12', - // Misc - 'space': 'space', - 'minus': 'minus', - 'equal': 'equal', - 'plus': 'plus', - }; - - // Modifier key mappings (xdotool format) - private static readonly MODIFIER_MAP: Record = { - 'ctrl': 'ctrl', - 'control': 'ctrl', - 'Control': 'ctrl', - 'alt': 'alt', - 'Alt': 'alt', - 'shift': 'shift', - 'Shift': 'shift', - 'meta': 'super', - 'Meta': 'super', - 'cmd': 'super', - 'command': 'super', - 'win': 'super', - 'super': 'super', - }; - - private convertToKernelKey(key: string): string { - // Check modifier keys first - if (ComputerTool.MODIFIER_MAP[key]) { - return ComputerTool.MODIFIER_MAP[key]; - } - // Check special keys - if (ComputerTool.KEY_MAP[key]) { - return ComputerTool.KEY_MAP[key]; - } - // Return as-is if no mapping exists - return key; - } - - private convertKeyCombinationToKernel(combo: string): string { - // Handle key combinations (e.g., "ctrl+a", "Control+t") - if (combo.includes('+')) { - const parts = combo.split('+'); - const mappedParts = parts.map(part => this.convertToKernelKey(part.trim())); - return mappedParts.join('+'); - } - // Single key - just convert it - return this.convertToKernelKey(combo); - } - - async screenshot(): Promise { - try { - console.log('Starting screenshot...'); - await new Promise(resolve => setTimeout(resolve, this._screenshotDelay * 1000)); - const response = await this.kernel.browsers.computer.captureScreenshot(this.sessionId); - const blob = await response.blob(); - const arrayBuffer = await blob.arrayBuffer(); - const buffer = Buffer.from(arrayBuffer); - console.log('Screenshot taken, size:', buffer.length, 'bytes'); - - return { - base64Image: buffer.toString('base64'), - }; - } catch (error) { - throw new ToolError(`Failed to take screenshot: ${error}`); - } - } - - async call(params: ActionParams): Promise { - const { - action, - text, - coordinate, - scrollDirection: scrollDirectionParam, - scroll_amount, - scrollAmount, - duration, - ...kwargs - } = params; - - ActionValidator.validateActionParams(params, this.mouseActions, this.keyboardActions); - - if (action === Action.SCREENSHOT) { - return await this.screenshot(); - } - - if (action === Action.CURSOR_POSITION) { - throw new ToolError('Cursor position is not available with Kernel Computer Controls API'); - } - - if (action === Action.SCROLL) { - if (this.version === '20241022') { - throw new ToolError(`${action} is only available in versions 20250124 and 20251124`); - } - - const scrollDirection = scrollDirectionParam || kwargs.scroll_direction; - const scrollAmountValue = scrollAmount || scroll_amount; - - const dir = scrollDirection && typeof scrollDirection === 'string' && ['up', 'down', 'left', 'right'].includes(scrollDirection) ? scrollDirection : null; - if (!dir) { - throw new ToolError(`Scroll direction "${String(scrollDirection)}" must be 'up', 'down', 'left', or 'right'`); - } - if (typeof scrollAmountValue !== 'number' || scrollAmountValue < 0) { - throw new ToolError(`Scroll amount "${scrollAmountValue}" must be a non-negative number`); - } - - const [x, y] = coordinate - ? ActionValidator.validateAndGetCoordinates(coordinate) - : this.lastMousePosition; - - // Backend (kernel-images) uses delta_x/delta_y as wheel-event repeat count (notches), not pixels. - const notches = Math.max(scrollAmountValue ?? 1, 1); - let delta_x = 0; - let delta_y = 0; - if (dir === 'down') delta_y = notches; - if (dir === 'up') delta_y = -notches; - if (dir === 'right') delta_x = notches; - if (dir === 'left') delta_x = -notches; - - await this.kernel.browsers.computer.scroll(this.sessionId, { x, y, delta_x, delta_y }); - - await new Promise(resolve => setTimeout(resolve, 200)); - const screenshotResult = await this.screenshot(); - return { - ...screenshotResult, - output: `Scrolled ${notches} wheel unit(s) ${dir}.`, - }; - } - - if (action === Action.WAIT) { - if (this.version === '20241022') { - throw new ToolError(`${action} is only available in versions 20250124 and 20251124`); - } - await new Promise(resolve => setTimeout(resolve, duration! * 1000)); - return await this.screenshot(); - } - - if (action === Action.LEFT_CLICK_DRAG) { - if (!coordinate) { - throw new ToolError(`coordinate is required for ${action}`); - } - - const [endX, endY] = ActionValidator.validateAndGetCoordinates(coordinate); - const startCoordinate = kwargs.start_coordinate as [number, number] | undefined; - const [startX, startY] = startCoordinate - ? ActionValidator.validateAndGetCoordinates(startCoordinate) - : this.lastMousePosition; - - console.log(`Dragging from (${startX}, ${startY}) to (${endX}, ${endY})`); - - await this.kernel.browsers.computer.dragMouse(this.sessionId, { - path: [[startX, startY], [endX, endY]], - button: 'left', - }); - - this.lastMousePosition = [endX, endY]; - - await new Promise(resolve => setTimeout(resolve, 500)); - return await this.screenshot(); - } - - if (this.mouseActions.has(action)) { - if (!coordinate) { - throw new ToolError(`coordinate is required for ${action}`); - } - return await this.handleMouseAction(action, coordinate); - } - - if (this.keyboardActions.has(action)) { - if (!text) { - throw new ToolError(`text is required for ${action}`); - } - return await this.handleKeyboardAction(action, text, duration); - } - - throw new ToolError(`Invalid action: ${action}`); - } -} - -// For backward compatibility -export class ComputerTool20241022 extends ComputerTool { - constructor(kernel: Kernel, sessionId: string, width = 1280, height = 800) { - super(kernel, sessionId, '20241022', width, height); - } -} - -export class ComputerTool20250124 extends ComputerTool { - constructor(kernel: Kernel, sessionId: string, width = 1280, height = 800) { - super(kernel, sessionId, '20250124', width, height); - } -} - -export class ComputerTool20251124 extends ComputerTool { - constructor(kernel: Kernel, sessionId: string, width = 1280, height = 800) { - super(kernel, sessionId, '20251124', width, height); - } -} diff --git a/pkg/templates/typescript/anthropic-computer-use/tools/types/computer.ts b/pkg/templates/typescript/anthropic-computer-use/tools/types/computer.ts deleted file mode 100644 index 6377d5f3..00000000 --- a/pkg/templates/typescript/anthropic-computer-use/tools/types/computer.ts +++ /dev/null @@ -1,75 +0,0 @@ -import type { - BetaToolComputerUse20241022, - BetaToolComputerUse20250124, - BetaToolComputerUse20251124, -} from '@anthropic-ai/sdk/resources/beta/messages/messages'; - -export enum Action { - // Mouse actions - MOUSE_MOVE = 'mouse_move', - LEFT_CLICK = 'left_click', - RIGHT_CLICK = 'right_click', - MIDDLE_CLICK = 'middle_click', - DOUBLE_CLICK = 'double_click', - TRIPLE_CLICK = 'triple_click', - LEFT_CLICK_DRAG = 'left_click_drag', - LEFT_MOUSE_DOWN = 'left_mouse_down', - LEFT_MOUSE_UP = 'left_mouse_up', - - // Keyboard actions - KEY = 'key', - TYPE = 'type', - HOLD_KEY = 'hold_key', - - // System actions - SCREENSHOT = 'screenshot', - CURSOR_POSITION = 'cursor_position', - SCROLL = 'scroll', - WAIT = 'wait', -} - -// For backward compatibility -export type Action_20241022 = Action; -export type Action_20250124 = Action; - -export type MouseButton = 'left' | 'right' | 'middle'; -export type ScrollDirection = 'up' | 'down' | 'left' | 'right'; -export type Coordinate = [number, number]; -export type Duration = number; - -export interface ActionParams { - action: Action; - text?: string; - coordinate?: Coordinate; - scrollDirection?: ScrollDirection; - scroll_amount?: number; - scrollAmount?: number; - duration?: Duration; - key?: string; - [key: string]: Action | string | Coordinate | ScrollDirection | number | Duration | undefined; -} - -export type ComputerToolParams = - | BetaToolComputerUse20241022 - | BetaToolComputerUse20250124 - | BetaToolComputerUse20251124; - -export interface ToolResult { - output?: string; - error?: string; - base64Image?: string; - system?: string; -} - -export interface BaseAnthropicTool { - name: string; - apiType: string; - toParams(): ComputerToolParams; -} - -export class ToolError extends Error { - constructor(message: string) { - super(message); - this.name = 'ToolError'; - } -} \ No newline at end of file diff --git a/pkg/templates/typescript/anthropic-computer-use/tools/utils/keyboard.ts b/pkg/templates/typescript/anthropic-computer-use/tools/utils/keyboard.ts deleted file mode 100644 index 244cddf8..00000000 --- a/pkg/templates/typescript/anthropic-computer-use/tools/utils/keyboard.ts +++ /dev/null @@ -1,88 +0,0 @@ -export class KeyboardUtils { - // Only map alternative names to standard Playwright modifier keys - private static readonly modifierKeyMap: Record = { - 'ctrl': 'Control', - 'alt': 'Alt', - 'cmd': 'Meta', - 'command': 'Meta', - 'win': 'Meta', - }; - - // Essential key mappings for Playwright compatibility - private static readonly keyMap: Record = { - 'return': 'Enter', - 'space': ' ', - 'left': 'ArrowLeft', - 'right': 'ArrowRight', - 'up': 'ArrowUp', - 'down': 'ArrowDown', - 'home': 'Home', - 'end': 'End', - 'pageup': 'PageUp', - 'page_up': 'PageUp', - 'pagedown': 'PageDown', - 'page_down': 'PageDown', - 'delete': 'Delete', - 'backspace': 'Backspace', - 'tab': 'Tab', - 'esc': 'Escape', - 'escape': 'Escape', - 'insert': 'Insert', - 'super_l': 'Meta', - 'f1': 'F1', - 'f2': 'F2', - 'f3': 'F3', - 'f4': 'F4', - 'f5': 'F5', - 'f6': 'F6', - 'f7': 'F7', - 'f8': 'F8', - 'f9': 'F9', - 'f10': 'F10', - 'f11': 'F11', - 'f12': 'F12', - 'minus': '-', - 'equal': '=', - 'plus': '+', - }; - - static isModifierKey(key: string | undefined): boolean { - if (!key) return false; - const normalizedKey = this.modifierKeyMap[key.toLowerCase()] || key; - return ['Control', 'Alt', 'Shift', 'Meta'].includes(normalizedKey); - } - - static getPlaywrightKey(key: string | undefined): string { - if (!key) { - throw new Error('Key cannot be undefined'); - } - - const normalizedKey = key.toLowerCase(); - - // Handle special cases - if (normalizedKey in this.keyMap) { - return this.keyMap[normalizedKey] as string; - } - - // Normalize modifier keys - if (normalizedKey in this.modifierKeyMap) { - return this.modifierKeyMap[normalizedKey] as string; - } - - // Return the key as is - Playwright handles standard key names - return key; - } - - static parseKeyCombination(combo: string): string[] { - if (!combo) { - throw new Error('Key combination cannot be empty'); - } - return combo.toLowerCase().split('+').map(key => { - const trimmedKey = key.trim(); - if (!trimmedKey) { - throw new Error('Invalid key combination: empty key'); - } - return this.getPlaywrightKey(trimmedKey); - }); - } -} \ No newline at end of file diff --git a/pkg/templates/typescript/anthropic-computer-use/tools/utils/validator.ts b/pkg/templates/typescript/anthropic-computer-use/tools/utils/validator.ts deleted file mode 100644 index b8522c8b..00000000 --- a/pkg/templates/typescript/anthropic-computer-use/tools/utils/validator.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Action, ToolError } from '../types/computer'; -import type { ActionParams, Coordinate, Duration } from '../types/computer'; - -export class ActionValidator { - static validateText(text: string | undefined, required: boolean, action: string): void { - if (required && text === undefined) { - throw new ToolError(`text is required for ${action}`); - } - if (text !== undefined && typeof text !== 'string') { - throw new ToolError(`${text} must be a string`); - } - } - - static validateCoordinate(coordinate: Coordinate | undefined, required: boolean, action: string): void { - if (required && !coordinate) { - throw new ToolError(`coordinate is required for ${action}`); - } - if (coordinate) { - this.validateAndGetCoordinates(coordinate); - } - } - - static validateDuration(duration: Duration | undefined): void { - if (duration === undefined || typeof duration !== 'number') { - throw new ToolError(`${duration} must be a number`); - } - if (duration < 0) { - throw new ToolError(`${duration} must be non-negative`); - } - if (duration > 100) { - throw new ToolError(`${duration} is too long`); - } - } - - static validateAndGetCoordinates(coordinate: Coordinate): Coordinate { - if (!Array.isArray(coordinate) || coordinate.length !== 2) { - throw new ToolError(`${coordinate} must be a tuple of length 2`); - } - if (!coordinate.every(i => typeof i === 'number' && i >= 0)) { - throw new ToolError(`${coordinate} must be a tuple of non-negative numbers`); - } - return coordinate; - } - - static validateActionParams(params: ActionParams, mouseActions: Set, keyboardActions: Set): void { - const { action, text, coordinate, duration } = params; - - // Validate text parameter - if (keyboardActions.has(action)) { - this.validateText(text, true, action); - } else { - this.validateText(text, false, action); - } - - // Validate coordinate parameter - if (mouseActions.has(action)) { - this.validateCoordinate(coordinate, true, action); - } else { - this.validateCoordinate(coordinate, false, action); - } - - // Validate duration parameter - if (action === Action.HOLD_KEY || action === Action.WAIT) { - this.validateDuration(duration); - } - } -} \ No newline at end of file diff --git a/pkg/templates/typescript/anthropic-computer-use/types/beta.ts b/pkg/templates/typescript/anthropic-computer-use/types/beta.ts deleted file mode 100644 index c83219e1..00000000 --- a/pkg/templates/typescript/anthropic-computer-use/types/beta.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { - BetaContentBlockParam as AnthropicContentBlockParam, - BetaImageBlockParam as AnthropicImageBlockParam, - BetaMessage as AnthropicMessage, - BetaMessageParam as AnthropicMessageParam, - BetaTextBlockParam as AnthropicTextBlockParam, - BetaToolResultBlockParam as AnthropicToolResultBlockParam, -} from '@anthropic-ai/sdk/resources/beta/messages/messages'; - -export type BetaMessageParam = AnthropicMessageParam; -export type BetaMessage = AnthropicMessage; -export type BetaContentBlock = AnthropicContentBlockParam; -export type BetaTextBlock = AnthropicTextBlockParam; -export type BetaImageBlock = AnthropicImageBlockParam; -export type BetaToolResultBlock = AnthropicToolResultBlockParam; -export type BetaLocalContentBlock = AnthropicContentBlockParam; \ No newline at end of file diff --git a/pkg/templates/typescript/anthropic-computer-use/utils/message-processing.ts b/pkg/templates/typescript/anthropic-computer-use/utils/message-processing.ts deleted file mode 100644 index f8043733..00000000 --- a/pkg/templates/typescript/anthropic-computer-use/utils/message-processing.ts +++ /dev/null @@ -1,80 +0,0 @@ -import type { BetaMessage, BetaMessageParam, BetaToolResultBlock, BetaContentBlock, BetaLocalContentBlock } from '../types/beta'; - -export function responseToParams(response: BetaMessage): BetaContentBlock[] { - return response.content.map(block => { - if (block.type === 'text' && block.text) { - return { type: 'text', text: block.text }; - } - if (block.type === 'thinking') { - return { type: 'thinking', thinking: block.thinking, signature: block.signature }; - } - return block as BetaContentBlock; - }); -} - -export function maybeFilterToNMostRecentImages( - messages: BetaMessageParam[], - imagesToKeep: number, - minRemovalThreshold: number -): void { - if (!imagesToKeep) return; - - const toolResultBlocks = messages - .flatMap(message => Array.isArray(message?.content) ? message.content : []) - .filter((item): item is BetaToolResultBlock => - typeof item === 'object' && item.type === 'tool_result' - ); - - const totalImages = toolResultBlocks.reduce((count, toolResult) => { - if (!Array.isArray(toolResult.content)) return count; - return count + toolResult.content.filter( - content => typeof content === 'object' && content.type === 'image' - ).length; - }, 0); - - let imagesToRemove = Math.floor((totalImages - imagesToKeep) / minRemovalThreshold) * minRemovalThreshold; - - for (const toolResult of toolResultBlocks) { - if (Array.isArray(toolResult.content)) { - toolResult.content = toolResult.content.filter(content => { - if (typeof content === 'object' && content.type === 'image') { - if (imagesToRemove > 0) { - imagesToRemove--; - return false; - } - } - return true; - }); - } - } -} - -const PROMPT_CACHING_BETA_FLAG = 'prompt-caching-2024-07-31'; - -export function injectPromptCaching(messages: BetaMessageParam[]): void { - let breakpointsRemaining = 3; - - for (let i = messages.length - 1; i >= 0; i--) { - const message = messages[i]; - if (!message) continue; - if (message.role === 'user' && Array.isArray(message.content)) { - if (breakpointsRemaining > 0) { - breakpointsRemaining--; - const lastContent = message.content[message.content.length - 1]; - if (lastContent) { - const cacheable = lastContent as BetaLocalContentBlock & { cache_control?: { type: 'ephemeral' } | null }; - cacheable.cache_control = { type: 'ephemeral' }; - } - } else { - const lastContent = message.content[message.content.length - 1]; - if (lastContent) { - const cacheable = lastContent as BetaLocalContentBlock & { cache_control?: { type: 'ephemeral' } | null }; - delete cacheable.cache_control; - } - break; - } - } - } -} - -export { PROMPT_CACHING_BETA_FLAG }; \ No newline at end of file diff --git a/pkg/templates/typescript/anthropic-computer-use/utils/tool-results.ts b/pkg/templates/typescript/anthropic-computer-use/utils/tool-results.ts deleted file mode 100644 index c18eab22..00000000 --- a/pkg/templates/typescript/anthropic-computer-use/utils/tool-results.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { ToolResult } from '../tools/types/computer'; -import type { BetaToolResultBlock, BetaTextBlock, BetaImageBlock } from '../types/beta'; - -export function makeApiToolResult( - result: ToolResult, - toolUseId: string -): BetaToolResultBlock { - const toolResultContent: (BetaTextBlock | BetaImageBlock)[] = []; - let isError = false; - - if (result.error) { - isError = true; - toolResultContent.push({ - type: 'text', - text: maybePrependSystemToolResult(result, result.error), - }); - } else { - if (result.output) { - toolResultContent.push({ - type: 'text', - text: maybePrependSystemToolResult(result, result.output), - }); - } - if (result.base64Image) { - toolResultContent.push({ - type: 'image', - source: { - type: 'base64', - media_type: 'image/png', - data: result.base64Image, - }, - }); - } - } - - return { - type: 'tool_result', - content: toolResultContent, - tool_use_id: toolUseId, - is_error: isError, - }; -} - -export function maybePrependSystemToolResult(result: ToolResult, resultText: string): string { - if (result.system) { - return `${result.system}\n${resultText}`; - } - return resultText; -} \ No newline at end of file diff --git a/pkg/templates/typescript/gemini-computer-use/README.md b/pkg/templates/typescript/gemini-computer-use/README.md index 0a62590e..1e884a0d 100644 --- a/pkg/templates/typescript/gemini-computer-use/README.md +++ b/pkg/templates/typescript/gemini-computer-use/README.md @@ -1,6 +1,8 @@ # Kernel TypeScript Sample App - Gemini Computer Use -This is a Kernel application that implements a prompt loop using Google's Gemini Computer Use model with Kernel's Computer Controls API. +This is a Kernel application that runs Google's Gemini computer-use model against a Kernel cloud browser. + +It uses [`@onkernel/cua-agent`](https://www.npmjs.com/package/@onkernel/cua-agent) to run the computer-use loop: the `CuaAgent` class translates Gemini's computer-use function calls into Kernel browser controls and feeds a fresh screenshot back on every turn. The app runs the `gemini-3-flash-preview` model. ## Setup @@ -33,35 +35,26 @@ kernel invoke ts-gemini-cua cua-task --payload '{"query": "Navigate to https://e When enabled, the response will include a `replay_url` field with a link to view the recorded session. -## Gemini Computer Use Actions - -The Gemini model can execute the following browser actions: - -| Action | Description | -|--------|-------------| -| `open_web_browser` | Returns a screenshot (browser is already running) | -| `click_at` | Click at coordinates (x, y) | -| `hover_at` | Move mouse to coordinates (x, y) | -| `type_text_at` | Click and type text at coordinates | -| `scroll_document` | Scroll the page (up/down/left/right) | -| `scroll_at` | Scroll at specific coordinates | -| `search` | Focus the browser URL bar | -| `navigate` | Navigate to a URL | -| `go_back` | Go back in browser history | -| `go_forward` | Go forward in browser history | -| `key_combination` | Press key combination (e.g., "ctrl+c") | -| `drag_and_drop` | Drag from one point to another | -| `wait_5_seconds` | Wait for 5 seconds | +## Playwright escape hatch -## Known Limitations +Some steps are awkward as raw clicks and keystrokes — precise DOM reads, form fills, data extraction, or waiting on a selector. Pass `playwright: true` when constructing the agent in `index.ts` to add a `playwright_execute` tool that runs Playwright/TypeScript directly against the live browser session: -### URL Reporting - -The Gemini Computer Use API requires a URL in all function responses. However, the Kernel Computer Controls API doesn't provide a method to retrieve the current page URL. +```ts +const agent = new CuaAgent({ + browser: session.browser, + client: kernel, + playwright: true, + initialState: { + model: 'google:gemini-3-flash-preview', + systemPrompt, + }, +}); +``` -As a workaround, this template reports `about:blank` as the URL in all responses. This works because Gemini primarily uses the screenshot to understand page state - the URL is a required field but not critical for functionality. +Inside `playwright_execute`, `page`, `context`, and `browser` are in scope and the code may `return` a JSON-serializable value. Each call runs in a fresh context (locals don't persist across calls), and no screenshot is returned automatically — the model can request one on a follow-up turn. See [`@onkernel/cua-agent`](https://www.npmjs.com/package/@onkernel/cua-agent) for details and per-model support status. ## Resources +- [@onkernel/cua-agent](https://www.npmjs.com/package/@onkernel/cua-agent) - [Google Gemini Computer Use Documentation](https://ai.google.dev/gemini-api/docs/computer-use) -- [Kernel Computer Controls](https://www.kernel.sh/docs/browsers/computer-controls) +- [Kernel Documentation](https://www.kernel.sh/docs/quickstart) diff --git a/pkg/templates/typescript/gemini-computer-use/index.ts b/pkg/templates/typescript/gemini-computer-use/index.ts index dd55ff10..9433d66c 100644 --- a/pkg/templates/typescript/gemini-computer-use/index.ts +++ b/pkg/templates/typescript/gemini-computer-use/index.ts @@ -1,5 +1,6 @@ import { Kernel, type KernelContext } from '@onkernel/sdk'; -import { samplingLoop } from './loop'; +import { CuaAgent } from '@onkernel/cua-agent'; +import type { AssistantMessage } from '@onkernel/cua-ai'; import { KernelBrowserSession } from './session'; const kernel = new Kernel(); @@ -14,16 +15,12 @@ interface QueryInput { interface QueryOutput { result: string; replay_url?: string; - error?: string; } -// API Key for Gemini -// - GOOGLE_API_KEY: Required for Gemini Computer Use model -// Set via environment variables or `kernel deploy --env-file .env` +// CuaAgent reads GOOGLE_API_KEY (or GEMINI_API_KEY) from the environment by default. +// Set it via environment variable or `kernel deploy index.ts --env-file .env`. // See https://www.kernel.sh/docs/launch/deploy#environment-variables -const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY; - -if (!GOOGLE_API_KEY) { +if (!process.env.GOOGLE_API_KEY && !process.env.GEMINI_API_KEY) { throw new Error( 'GOOGLE_API_KEY is not set. ' + 'Set it via environment variable or deploy with: kernel deploy index.ts --env-file .env' @@ -47,62 +44,49 @@ app.action( await session.start(); console.log('Kernel browser live view url:', session.liveViewUrl); + const currentDate = new Date().toLocaleDateString('en-US', { + weekday: 'long', + year: 'numeric', + month: 'long', + day: 'numeric', + }); + const systemPrompt = `You are a helpful assistant operating a Chrome browser on a Kernel cloud VM through computer-use tools. +The browser is already open and ready for use. +When you need to navigate to a page, use the navigate action with a full URL. +After each action, carefully evaluate the screenshot to determine your next step. +The current date is ${currentDate}.`; + try { - // Run the Gemini sampling loop - const result = await samplingLoop({ - model: 'gemini-2.5-computer-use-preview-10-2025', - query: payload.query, - apiKey: GOOGLE_API_KEY, - kernel, - sessionId: session.sessionId, + const agent = new CuaAgent({ + browser: session.browser, + client: kernel, + // Set to true to expose a playwright_execute tool for DOM reads, form fills, and selector waits. + playwright: false, + initialState: { + model: 'google:gemini-3-flash-preview', + systemPrompt, + }, }); - // Stop session and get replay URL if recording was enabled + await agent.prompt(payload.query); + + const lastAssistant = [...agent.state.messages] + .reverse() + .find((message): message is AssistantMessage => message.role === 'assistant'); + const result = lastAssistant?.content + .flatMap((block) => (block.type === 'text' ? [block.text] : [])) + .join('') ?? ''; + const sessionInfo = await session.stop(); return { - result: result.finalResponse, + result, replay_url: sessionInfo.replayViewUrl, - error: result.error, }; } catch (error) { - console.error('Error in sampling loop:', error); + console.error('Error running CUA task:', error); await session.stop(); throw error; } }, ); - -// Run locally when not in Kernel invocation. Execute via: npx tsx index.ts -if (!process.env.KERNEL_INVOCATION && import.meta.url === `file://${process.argv[1]}`) { - const testQuery = "Navigate to https://www.google.com and describe what you see"; - - console.log('Running local test with query:', testQuery); - - const session = new KernelBrowserSession(kernel, { - stealth: true, - recordReplay: false, - }); - - session.start().then(async () => { - try { - const result = await samplingLoop({ - model: 'gemini-2.5-computer-use-preview-10-2025', - query: testQuery, - apiKey: GOOGLE_API_KEY, - kernel, - sessionId: session.sessionId, - }); - console.log('Result:', result.finalResponse); - if (result.error) { - console.error('Error:', result.error); - } - } finally { - await session.stop(); - } - process.exit(0); - }).catch(error => { - console.error('Local execution failed:', error); - process.exit(1); - }); -} diff --git a/pkg/templates/typescript/gemini-computer-use/loop.ts b/pkg/templates/typescript/gemini-computer-use/loop.ts deleted file mode 100644 index bc917966..00000000 --- a/pkg/templates/typescript/gemini-computer-use/loop.ts +++ /dev/null @@ -1,301 +0,0 @@ -/** - * Gemini Computer Use sampling loop. - * Based on Google's computer-use-preview reference implementation. - */ - -import { - GoogleGenAI, - Environment, - type Content, - type FunctionCall, - type Part, -} from '@google/genai'; -import type { Kernel } from '@onkernel/sdk'; -import { ComputerTool } from './tools/computer'; -import { PREDEFINED_COMPUTER_USE_FUNCTIONS, type GeminiFunctionArgs } from './tools/types/gemini'; - -// System prompt for browser-based computer use -function getSystemPrompt(): string { - const currentDate = new Date().toLocaleDateString('en-US', { - weekday: 'long', - year: 'numeric', - month: 'long', - day: 'numeric', - }); - - return `You are a helpful assistant that can use a web browser. -You are operating a Chrome browser through computer use tools. -The browser is already open and ready for use. - -When you need to navigate to a page, use the navigate action with a full URL. -When you need to interact with elements, use click_at, type_text_at, etc. -After each action, carefully evaluate the screenshot to determine your next step. - -Current date: ${currentDate}.`; -} - -// Maximum number of recent turns to keep screenshots for (to manage context) -const MAX_RECENT_TURN_WITH_SCREENSHOTS = 3; - -interface SamplingLoopOptions { - model: string; - query: string; - apiKey: string; - kernel: Kernel; - sessionId: string; - maxIterations?: number; - systemPromptSuffix?: string; -} - -interface SamplingLoopResult { - finalResponse: string; - iterations: number; - error?: string; -} - -/** - * Run the Gemini computer use sampling loop. - */ -export async function samplingLoop({ - model, - query, - apiKey, - kernel, - sessionId, - maxIterations = 50, - systemPromptSuffix = '', -}: SamplingLoopOptions): Promise { - const ai = new GoogleGenAI({ apiKey }); - - const computerTool = new ComputerTool(kernel, sessionId); - - // Initialize conversation with user query - const contents: Content[] = [ - { - role: 'user', - parts: [{ text: query }], - }, - ]; - - const basePrompt = getSystemPrompt(); - const systemPrompt = systemPromptSuffix - ? `${basePrompt}\n\n${systemPromptSuffix}` - : basePrompt; - - let iteration = 0; - let finalResponse = ''; - let error: string | undefined; - - while (iteration < maxIterations) { - iteration++; - console.log(`\n=== Iteration ${iteration} ===`); - - try { - // Generate response from Gemini - const response = await ai.models.generateContent({ - model, - contents, - config: { - temperature: 1, - topP: 0.95, - topK: 40, - maxOutputTokens: 8192, - systemInstruction: systemPrompt, - tools: [ - { - computerUse: { - environment: Environment.ENVIRONMENT_BROWSER, - }, - }, - ], - thinkingConfig: { - includeThoughts: true, - }, - }, - }); - - if (!response.candidates || response.candidates.length === 0) { - console.log('No candidates in response'); - break; - } - - const candidate = response.candidates[0]; - if (!candidate?.content) { - console.log('No content in candidate'); - break; - } - - // Add assistant response to conversation - contents.push(candidate.content); - - // Extract text and function calls - const reasoning = extractText(candidate.content); - const functionCalls = extractFunctionCalls(candidate.content); - - // Log the response - console.log('Reasoning:', reasoning || '(none)'); - console.log('Function calls:', functionCalls.length); - for (const fc of functionCalls) { - console.log(` - ${fc.name}:`, fc.args); - } - - // Check finish reason - const finishReason = candidate.finishReason; - if (finishReason === 'MALFORMED_FUNCTION_CALL' && !functionCalls.length) { - console.log('Malformed function call, retrying...'); - continue; - } - - // If no function calls, the model is done - if (functionCalls.length === 0) { - console.log('Agent loop complete'); - finalResponse = reasoning || ''; - break; - } - - // Execute function calls and collect results - const functionResponses: Part[] = []; - for (const fc of functionCalls) { - if (!fc.name) continue; - const args = fc.args as GeminiFunctionArgs || {}; - - // Handle safety decisions if present - if (args.safety_decision?.decision === 'require_confirmation') { - console.log('Safety confirmation required:', args.safety_decision.explanation); - // Auto-acknowledge for automated execution - console.log('Auto-acknowledging safety check'); - } - - // Execute the action - console.log(`Executing action: ${fc.name}`); - const result = await computerTool.executeAction(fc.name, args); - - if (result.error) { - console.log(`Action error: ${result.error}`); - functionResponses.push({ - functionResponse: { - name: fc.name, - // Always include URL (required by Gemini Computer Use API) - response: { error: result.error, url: result.url || 'about:blank' }, - }, - }); - } else { - // Build response with screenshot - always include URL (required by Computer Use API) - const responseData: Record = { - url: result.url || 'about:blank', - }; - - functionResponses.push({ - functionResponse: { - name: fc.name, - response: responseData, - // Include screenshot as inline data - ...(result.base64Image && isPredefinedFunction(fc.name) ? { - parts: [{ - inlineData: { - mimeType: 'image/png', - data: result.base64Image, - }, - }], - } : {}), - }, - }); - } - } - - // Add function responses to conversation - contents.push({ - role: 'user', - parts: functionResponses, - }); - - // Manage screenshot history to avoid context overflow - pruneOldScreenshots(contents); - - } catch (err) { - error = err instanceof Error ? err.message : String(err); - console.error('Error in sampling loop:', error); - break; - } - } - - if (iteration >= maxIterations) { - console.log('Max iterations reached'); - } - - return { - finalResponse, - iterations: iteration, - error, - }; -} - -function extractText(content: Content): string { - if (!content.parts) return ''; - - const texts: string[] = []; - for (const part of content.parts) { - if ('text' in part && part.text) { - texts.push(part.text); - } - } - return texts.join(' '); -} - -function extractFunctionCalls(content: Content): FunctionCall[] { - if (!content.parts) return []; - - const calls: FunctionCall[] = []; - for (const part of content.parts) { - if ('functionCall' in part && part.functionCall) { - calls.push(part.functionCall); - } - } - return calls; -} - -function isPredefinedFunction(name: string): boolean { - return PREDEFINED_COMPUTER_USE_FUNCTIONS.includes(name as typeof PREDEFINED_COMPUTER_USE_FUNCTIONS[number]); -} - -function pruneOldScreenshots(contents: Content[]): void { - let turnsWithScreenshots = 0; - - // Iterate in reverse to find recent turns with screenshots - for (let i = contents.length - 1; i >= 0; i--) { - const content = contents[i]; - if (!content || content.role !== 'user' || !content.parts) continue; - - // Check if this turn has screenshots from predefined functions - let hasScreenshot = false; - for (const part of content.parts) { - if ('functionResponse' in part && - part.functionResponse && - isPredefinedFunction(part.functionResponse.name || '')) { - // Check if it has inline data (screenshot) - const fr = part.functionResponse as { parts?: Array<{ inlineData?: unknown }> }; - if (fr.parts?.some(p => p.inlineData)) { - hasScreenshot = true; - break; - } - } - } - - if (hasScreenshot) { - turnsWithScreenshots++; - - // Remove screenshots from old turns - if (turnsWithScreenshots > MAX_RECENT_TURN_WITH_SCREENSHOTS) { - for (const part of content.parts) { - if ('functionResponse' in part && - part.functionResponse && - isPredefinedFunction(part.functionResponse.name || '')) { - // Remove the parts array (which contains the screenshot) - const fr = part.functionResponse as { parts?: unknown }; - delete fr.parts; - } - } - } - } - } -} diff --git a/pkg/templates/typescript/gemini-computer-use/package.json b/pkg/templates/typescript/gemini-computer-use/package.json index eee99372..61415010 100644 --- a/pkg/templates/typescript/gemini-computer-use/package.json +++ b/pkg/templates/typescript/gemini-computer-use/package.json @@ -4,8 +4,9 @@ "type": "module", "private": true, "dependencies": { - "@google/genai": "^1.0.0", - "@onkernel/sdk": "^0.35.0" + "@onkernel/cua-agent": "^0.3.4", + "@onkernel/cua-ai": "^0.3.1", + "@onkernel/sdk": "0.49.0" }, "devDependencies": { "@types/node": "^22.15.17", diff --git a/pkg/templates/typescript/gemini-computer-use/pnpm-lock.yaml b/pkg/templates/typescript/gemini-computer-use/pnpm-lock.yaml new file mode 100644 index 00000000..7b4d14a4 --- /dev/null +++ b/pkg/templates/typescript/gemini-computer-use/pnpm-lock.yaml @@ -0,0 +1,1286 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@onkernel/cua-agent': + specifier: ^0.3.4 + version: 0.3.4(ws@8.21.0)(zod@4.4.3) + '@onkernel/cua-ai': + specifier: ^0.3.1 + version: 0.3.1(ws@8.21.0)(zod@4.4.3) + '@onkernel/sdk': + specifier: 0.49.0 + version: 0.49.0 + devDependencies: + '@types/node': + specifier: ^22.15.17 + version: 22.20.0 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + +packages: + + '@anthropic-ai/sdk@0.91.1': + resolution: {integrity: sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==} + hasBin: true + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-bedrock-runtime@3.1048.0': + resolution: {integrity: sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.974.23': + resolution: {integrity: sha512-MiWR/uWjxjFXGzrE0Ghc5lWxUxzHsUWFhV+OX7M4cR9SrmrnZs6TXavnCWnzzdwJeFri34xQo81rvGNzK3c4BQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.49': + resolution: {integrity: sha512-liB3yQNHCM9k/gu/w36XHMKPluT7HTlnGUhRbBGSISDQkcr/Sy1zsZabiuvQj8WG5yW573u9RehrBvvnIQ9OEQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.51': + resolution: {integrity: sha512-XET0H2oofciJ5lMRWNIvRjAP7Q3wv2XT+JtJJEdhPWUMwe3TvQ9qcxonpu7vXmNngncvFpi4E2It+Tamas/naA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.972.56': + resolution: {integrity: sha512-IAmc61hbgQiHht9U3x0tnRwz0lzdwOwD/i9voRgdJrKamF+JtmrBOsW9GwB7mfFonNWOWL4qARWYrF8veEMe3w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.55': + resolution: {integrity: sha512-hBBkANo3cDn+h2qxxzER4a+J8JCO9o9Z/YYmU7iky6AcaarX5RRdRcHNC6SLdwY0vAXQygn6soUbDqPn3GghaA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.58': + resolution: {integrity: sha512-OyCLVmSI7pZO8hxwNVX6pXhTVlJqRBTp+ijdEfJSUj0RyjHnF602OfAarOzGq6wkGodeFkYBt8MmJ6A6ycRgWw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.49': + resolution: {integrity: sha512-C8h36lBuC/RnBSsjlO+dn6xZm3KbAl5vpJaVPAfQnMmz2/OISmKOc8XZcqMQgO2ADwBYNRMM6Kf3vz9G/TulMQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.972.55': + resolution: {integrity: sha512-1FkOz74Ea5QGS9jtIoXp55T/IkSS3spv+nLTT07fRY/+T5xmEOqaYBVIaEmX4zTNvbV6g2lrtlaVKWEoNyJt3w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.55': + resolution: {integrity: sha512-g2BoECD1q01kTPByi56+VLVvdWDzMkKIcr77qixpqH0okw2t0U5CoPv+6S8v/D1Y2Wa6QKKtn6XAtDzP+Kfpvg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/eventstream-handler-node@3.972.22': + resolution: {integrity: sha512-tqPJv0dz4+O0hWGm1a6YekcMZyPhDFs/zH73Von7icaVT5n0Jqvm86typ3jRrG+qoUdPhALOnboRLTmnWQTlYQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-eventstream@3.972.18': + resolution: {integrity: sha512-OHpk8YoZi3yexPq8aFt1vN1IxA2zLKvsIR5GpWYylX/ve6kQmY7wxHNSFy/D3t2apMZ16rs76Co4dJWcDyIk3A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-websocket@3.972.31': + resolution: {integrity: sha512-ps1rumU1LybSFHaW9dTDgkhCMJLVaedEY78kKSzUDDY+b9974/g6aiaYYA0U9WV0oL4CJCJrVWG+EZ/qr4or7g==} + engines: {node: '>= 14.0.0'} + + '@aws-sdk/nested-clients@3.997.23': + resolution: {integrity: sha512-gO93ZPsI2bxeFZD42f1/qjDw6FAZkNZcKRO94LIiT03fzOmcJ9e/tunxjVjA1Rl69ClmVJzz8H3G9CdKef10PA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.996.35': + resolution: {integrity: sha512-6L/VWs+Wch2stHemCGTmUNqKLMzURxQDK5boNG3Jn3kAOp71meDUuS5sbObpEvFxHDq0uWeSLFDNSYsjNt+Dlg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1048.0': + resolution: {integrity: sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1074.0': + resolution: {integrity: sha512-pv80IzgGW4RnXWtft692chZOM9i6PhebVsLCcnaM4dBEPZva2fE6FXAHs76G7Rc7s3yGyX/68G0nZMrUy+Vmpg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.973.13': + resolution: {integrity: sha512-pEHZqRkAlHfnfAU9tK+WpKv/gBNjGJrHMgA3A0iYRGyswBS2t0pfez+lWlwktb3Bqa0ovh7w/QJTFwp3fDxLNg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-locate-window@3.965.8': + resolution: {integrity: sha512-uUbMs1cBZPafD0ohUj6EwNf0fPZ534NvBxHox4hjX+0Rxq5paSYUem7+hi833pYrzrcnBATKIYpR02MDXT5M9g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/xml-builder@3.972.31': + resolution: {integrity: sha512-SzE4Pgyl+hDF+BuyuzxUSpwnuUu9lJuO1YGgteG89/4Qv0+2IQiVQqdbPV32IozLvXWQChPQcdkk/sKvb1QHiQ==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.2.4': + resolution: {integrity: sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==} + engines: {node: '>=18.0.0'} + + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + + '@earendil-works/pi-agent-core@0.79.1': + resolution: {integrity: sha512-PBPjBa2YBm9jauiLtHAKaSfVJ4Dvm3/nK/bR/oHebLjwBCS2tGx3aQDX7MSGAOXi6BejlhzbB/z82BkyAyNjjQ==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-ai@0.79.1': + resolution: {integrity: sha512-UnORwrcsTNLm4StEvoM8iEom0u87Te7BXEWxhec3iNXygWD6eEBosUoq9ddcveqtj/QpUZBMPWUu81cCtZxzkQ==} + engines: {node: '>=22.19.0'} + hasBin: true + + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + + '@google/genai@1.52.0': + resolution: {integrity: sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@modelcontextprotocol/sdk': ^1.25.2 + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@mistralai/mistralai@2.2.1': + resolution: {integrity: sha512-uKU8CZmL2RzYKmplsU01hii4p3pe4HqJefpWNRWXm1Tcm0Sm4xXfwSLIy4k7ZCPlbETCGcp69E7hZs+WOJ5itQ==} + + '@onkernel/cua-agent@0.3.4': + resolution: {integrity: sha512-MlSbxmd/HrYTM7ZEHs0fXgisLOKhM7JGG2hrDDNS8ZjDzu/BjcZ4Vq7h6BE+RRaXGO32wskqif/SH+6Wf3bePg==} + + '@onkernel/cua-ai@0.3.1': + resolution: {integrity: sha512-85w4GRzskuGho+prPKAFFCYpDyWjIUEkUiJqPU/CTW2+/Co7B4qmeqm1A2T+No+y7C+4vDnbW3Bvvy7Q1nFWYg==} + + '@onkernel/sdk@0.49.0': + resolution: {integrity: sha512-nsq5OfkaNKxRTCdXQF8BSTj/Wl0iBIqyWoI/ATgQt15pV+59E22MsZ+IHPiVwwb33tXLtnOqUe5ffOxm7l3GHg==} + + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.1': + resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} + + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.1': + resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==} + + '@smithy/core@3.26.0': + resolution: {integrity: sha512-mLUktFAn+Pa2agl1J7VgtYNFWCX8/b4GMJSK1hCu4YCvtBfM6F8Os3EP4ry+DFFlXOf3wyvlgXhuUdFoy52D3g==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.4.2': + resolution: {integrity: sha512-18UMDMyrAbDcpmL1gLUA7ww0fRTcdCrSjSJOi2Sbld+tVjwD/pW+OAwjlScFLR7vvBnhZrIPQ7kVuTf1mnJLug==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.5.2': + resolution: {integrity: sha512-Ei/UK/QMhq0rKaMqGPlOAkE2yS9DZeYmZdk1RAKc3vp3zxgleZHZyBLlZv8yLsxljX4svCRuMTD6u3LLIcU4Bg==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/node-http-handler@4.7.3': + resolution: {integrity: sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.8.2': + resolution: {integrity: sha512-wfl1uwrAqMH9/pi4kqBo5LBcFwrJLxuDLqL7p7qNcJIFcyZDUc6pzhYk4CYv+DP7fIUpQCZumwNnkhPKS52osQ==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.5.2': + resolution: {integrity: sha512-7xHpmPY4rt0IOmeAA8EfjgEH8isT+587TCdy9H6a7d4OMi5CQ0oEHhWllunvPu4j4Cq0vTFwdxXN/kABWPjdyA==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.15.0': + resolution: {integrity: sha512-Z5TAOxygoFvybJV3igo5SloFflSokHx2hu1eFA+DxDTcn+FtKxUSui+rbTRG1pAafMA888Z3MVvCWUuvCrTXjg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@types/node@22.20.0': + resolution: {integrity: sha512-QWlFW2wf3nTjC13/DqRnBpR4ZO36VJH/JVBkA/vcnmbTBNQIlnObqyqZE1tUR7+Ni23Lda8R1BxMfbXRpCUx5g==} + + '@types/retry@0.12.0': + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + + '@tzafon/lightcone@0.7.2': + resolution: {integrity: sha512-jzXTAOeE77FuuzP8J2dtxXxlBnN3Jb1o/iF7taVLGsT4ch8EemztVKjHH6KOJtu+3KvQzSioYoJCIX6pJ35jTA==} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + gaxios@7.1.5: + resolution: {integrity: sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg==} + engines: {node: '>=18'} + + gcp-metadata@8.1.2: + resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} + engines: {node: '>=18'} + + google-auth-library@10.7.0: + resolution: {integrity: sha512-QpTAbNJ36TliZLx3TTtahR8HG0hN9RllL1e3FymOvQSIKK8JmgV58H924ub2wa2DsS3ANjjP1Aw1N+Ramc8hqQ==} + engines: {node: '>=18'} + + google-logging-utils@1.1.3: + resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} + engines: {node: '>=14'} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + + json-schema-to-ts@3.1.1: + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} + + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + openai@6.26.0: + resolution: {integrity: sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + openai@6.44.0: + resolution: {integrity: sha512-09/gH+8jH0RgUwsgWHAaxsKGRT5zVZ95IaJUnqAWj6XejIBmnFRwq2WUIF37VtDEsmGrtPmvCs5+yBSeZGWvkA==} + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + + partial-json@0.1.7: + resolution: {integrity: sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==} + + protobufjs@7.6.4: + resolution: {integrity: sha512-RJJPTTpvFfHcWLkIa2JFWK4XvtSzS0yEWDmunqHXli1h3JlkbcQZXDZdcWxv+JK3Xsl5/UFDPZ0iGm7DAengYw==} + engines: {node: '>=12.0.0'} + + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + ts-algebra@2.0.0: + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typebox@1.1.38: + resolution: {integrity: sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + +snapshots: + + '@anthropic-ai/sdk@0.91.1(zod@4.4.3)': + dependencies: + json-schema-to-ts: 3.1.1 + optionalDependencies: + zod: 4.4.3 + + '@aws-crypto/crc32@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.13 + tslib: 2.8.1 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.13 + '@aws-sdk/util-locate-window': 3.965.8 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.13 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.973.13 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-bedrock-runtime@3.1048.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.974.23 + '@aws-sdk/credential-provider-node': 3.972.58 + '@aws-sdk/eventstream-handler-node': 3.972.22 + '@aws-sdk/middleware-eventstream': 3.972.18 + '@aws-sdk/middleware-websocket': 3.972.31 + '@aws-sdk/token-providers': 3.1048.0 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/fetch-http-handler': 5.5.2 + '@smithy/node-http-handler': 4.7.3 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/core@3.974.23': + dependencies: + '@aws-sdk/types': 3.973.13 + '@aws-sdk/xml-builder': 3.972.31 + '@aws/lambda-invoke-store': 0.2.4 + '@smithy/core': 3.26.0 + '@smithy/signature-v4': 5.5.2 + '@smithy/types': 4.15.0 + bowser: 2.14.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.972.49': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.972.51': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/fetch-http-handler': 5.5.2 + '@smithy/node-http-handler': 4.8.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.972.56': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/credential-provider-env': 3.972.49 + '@aws-sdk/credential-provider-http': 3.972.51 + '@aws-sdk/credential-provider-login': 3.972.55 + '@aws-sdk/credential-provider-process': 3.972.49 + '@aws-sdk/credential-provider-sso': 3.972.55 + '@aws-sdk/credential-provider-web-identity': 3.972.55 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/credential-provider-imds': 4.4.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-login@3.972.55': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-node@3.972.58': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.49 + '@aws-sdk/credential-provider-http': 3.972.51 + '@aws-sdk/credential-provider-ini': 3.972.56 + '@aws-sdk/credential-provider-process': 3.972.49 + '@aws-sdk/credential-provider-sso': 3.972.55 + '@aws-sdk/credential-provider-web-identity': 3.972.55 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/credential-provider-imds': 4.4.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-process@3.972.49': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.972.55': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/token-providers': 3.1074.0 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-web-identity@3.972.55': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/eventstream-handler-node@3.972.22': + dependencies: + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-eventstream@3.972.18': + dependencies: + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-websocket@3.972.31': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/fetch-http-handler': 5.5.2 + '@smithy/signature-v4': 5.5.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.997.23': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.974.23 + '@aws-sdk/signature-v4-multi-region': 3.996.35 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/fetch-http-handler': 5.5.2 + '@smithy/node-http-handler': 4.8.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.996.35': + dependencies: + '@aws-sdk/types': 3.973.13 + '@smithy/signature-v4': 5.5.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1048.0': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1074.0': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/types@3.973.13': + dependencies: + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.965.8': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.31': + dependencies: + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.2.4': {} + + '@babel/runtime@7.29.7': {} + + '@earendil-works/pi-agent-core@0.79.1(ws@8.21.0)(zod@4.4.3)': + dependencies: + '@earendil-works/pi-ai': 0.79.1(ws@8.21.0)(zod@4.4.3) + ignore: 7.0.5 + typebox: 1.1.38 + yaml: 2.9.0 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-ai@0.79.1(ws@8.21.0)(zod@4.4.3)': + dependencies: + '@anthropic-ai/sdk': 0.91.1(zod@4.4.3) + '@aws-sdk/client-bedrock-runtime': 3.1048.0 + '@google/genai': 1.52.0 + '@mistralai/mistralai': 2.2.1 + '@smithy/node-http-handler': 4.7.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + openai: 6.26.0(ws@8.21.0)(zod@4.4.3) + partial-json: 0.1.7 + typebox: 1.1.38 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@google/genai@1.52.0': + dependencies: + google-auth-library: 10.7.0 + p-retry: 4.6.2 + protobufjs: 7.6.4 + ws: 8.21.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.11.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@mistralai/mistralai@2.2.1': + dependencies: + ws: 8.21.0 + zod: 4.4.3 + zod-to-json-schema: 3.25.2(zod@4.4.3) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@onkernel/cua-agent@0.3.4(ws@8.21.0)(zod@4.4.3)': + dependencies: + '@earendil-works/pi-agent-core': 0.79.1(ws@8.21.0)(zod@4.4.3) + '@earendil-works/pi-ai': 0.79.1(ws@8.21.0)(zod@4.4.3) + '@onkernel/cua-ai': 0.3.1(ws@8.21.0)(zod@4.4.3) + '@onkernel/sdk': 0.49.0 + sharp: 0.34.5 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@onkernel/cua-ai@0.3.1(ws@8.21.0)(zod@4.4.3)': + dependencies: + '@earendil-works/pi-ai': 0.79.1(ws@8.21.0)(zod@4.4.3) + '@tzafon/lightcone': 0.7.2 + openai: 6.44.0(ws@8.21.0)(zod@4.4.3) + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@onkernel/sdk@0.49.0': {} + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.1': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.1': {} + + '@smithy/core@3.26.0': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.4.2': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.5.2': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/node-http-handler@4.7.3': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.8.2': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.5.2': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/types@4.15.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + + '@types/node@22.20.0': + dependencies: + undici-types: 6.21.0 + + '@types/retry@0.12.0': {} + + '@tzafon/lightcone@0.7.2': {} + + agent-base@7.1.4: {} + + base64-js@1.5.1: {} + + bignumber.js@9.3.1: {} + + bowser@2.14.1: {} + + buffer-equal-constant-time@1.0.1: {} + + data-uri-to-buffer@4.0.1: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + detect-libc@2.1.2: {} + + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + + extend@3.0.2: {} + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + + gaxios@7.1.5: + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + transitivePeerDependencies: + - supports-color + + gcp-metadata@8.1.2: + dependencies: + gaxios: 7.1.5 + google-logging-utils: 1.1.3 + json-bigint: 1.0.0 + transitivePeerDependencies: + - supports-color + + google-auth-library@10.7.0: + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.1.5 + gcp-metadata: 8.1.2 + google-logging-utils: 1.1.3 + jws: 4.0.1 + transitivePeerDependencies: + - supports-color + + google-logging-utils@1.1.3: {} + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ignore@7.0.5: {} + + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 + + json-schema-to-ts@3.1.1: + dependencies: + '@babel/runtime': 7.29.7 + ts-algebra: 2.0.0 + + jwa@2.0.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@4.0.1: + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + + long@5.3.2: {} + + ms@2.1.3: {} + + node-domexception@1.0.0: {} + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + + openai@6.26.0(ws@8.21.0)(zod@4.4.3): + optionalDependencies: + ws: 8.21.0 + zod: 4.4.3 + + openai@6.44.0(ws@8.21.0)(zod@4.4.3): + optionalDependencies: + ws: 8.21.0 + zod: 4.4.3 + + p-retry@4.6.2: + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + + partial-json@0.1.7: {} + + protobufjs@7.6.4: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.1 + '@types/node': 22.20.0 + long: 5.3.2 + + retry@0.13.1: {} + + safe-buffer@5.2.1: {} + + semver@7.8.5: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + + ts-algebra@2.0.0: {} + + tslib@2.8.1: {} + + typebox@1.1.38: {} + + typescript@5.9.3: {} + + undici-types@6.21.0: {} + + web-streams-polyfill@3.3.3: {} + + ws@8.21.0: {} + + yaml@2.9.0: {} + + zod-to-json-schema@3.25.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@4.4.3: {} diff --git a/pkg/templates/typescript/gemini-computer-use/session.ts b/pkg/templates/typescript/gemini-computer-use/session.ts index 89e7a8bf..d402aa92 100644 --- a/pkg/templates/typescript/gemini-computer-use/session.ts +++ b/pkg/templates/typescript/gemini-computer-use/session.ts @@ -6,7 +6,9 @@ */ import type { Kernel } from '@onkernel/sdk'; -import { DEFAULT_SCREEN_SIZE } from './tools/types/gemini'; +import type { BrowserCreateResponse } from '@onkernel/sdk/resources/browsers'; + +const DEFAULT_SCREEN_SIZE = { width: 1200, height: 800 }; export interface SessionOptions { /** Invocation ID to link browser session to the action invocation */ @@ -38,6 +40,7 @@ export class KernelBrowserSession { private options: SessionOptionsWithDefaults; // Session state + private _browser: BrowserCreateResponse | null = null; private _sessionId: string | null = null; private _liveViewUrl: string | null = null; private _replayId: string | null = null; @@ -55,6 +58,13 @@ export class KernelBrowserSession { return this._sessionId; } + get browser(): BrowserCreateResponse { + if (!this._browser) { + throw new Error('Session not started. Call start() first.'); + } + return this._browser; + } + get liveViewUrl(): string | null { return this._liveViewUrl; } @@ -84,6 +94,7 @@ export class KernelBrowserSession { }, }); + this._browser = browser; this._sessionId = browser.session_id ?? null; this._liveViewUrl = browser.browser_live_view_url ?? null; @@ -190,6 +201,7 @@ export class KernelBrowserSession { } // Reset state + this._browser = null; this._sessionId = null; this._liveViewUrl = null; this._replayId = null; diff --git a/pkg/templates/typescript/gemini-computer-use/tools/computer.ts b/pkg/templates/typescript/gemini-computer-use/tools/computer.ts deleted file mode 100644 index 9c459513..00000000 --- a/pkg/templates/typescript/gemini-computer-use/tools/computer.ts +++ /dev/null @@ -1,292 +0,0 @@ -/** - * Gemini Computer Tool - Maps Gemini actions to Kernel Computer Controls API. - * Based on Google's computer-use-preview reference implementation. - */ - -import { Buffer } from 'buffer'; -import type { Kernel } from '@onkernel/sdk'; -import { - GeminiAction, - PREDEFINED_COMPUTER_USE_FUNCTIONS, - DEFAULT_SCREEN_SIZE, - COORDINATE_SCALE, - type GeminiFunctionArgs, - type ToolResult, - type ScreenSize, -} from './types/gemini'; - -const TYPING_DELAY_MS = 12; -const SCREENSHOT_DELAY_MS = 500; -const PX_PER_NOTCH = 60; -const MAX_NOTCHES_PER_ACTION = 17; - -/** - * Computer tool that maps Gemini actions to Kernel's Computer Controls API. - */ -export class ComputerTool { - private kernel: Kernel; - private sessionId: string; - private screenSize: ScreenSize; - - constructor(kernel: Kernel, sessionId: string, screenSize: ScreenSize = DEFAULT_SCREEN_SIZE) { - this.kernel = kernel; - this.sessionId = sessionId; - this.screenSize = screenSize; - } - - private denormalizeX(x: number): number { - return Math.round((x / COORDINATE_SCALE) * this.screenSize.width); - } - - private denormalizeY(y: number): number { - return Math.round((y / COORDINATE_SCALE) * this.screenSize.height); - } - - async screenshot(): Promise { - try { - await this.sleep(SCREENSHOT_DELAY_MS); - const response = await this.kernel.browsers.computer.captureScreenshot(this.sessionId); - const blob = await response.blob(); - const arrayBuffer = await blob.arrayBuffer(); - const buffer = Buffer.from(arrayBuffer); - - return { - base64Image: buffer.toString('base64'), - url: 'about:blank', - }; - } catch (error) { - return { - error: `Failed to take screenshot: ${error}`, - url: 'about:blank', - }; - } - } - - async executeAction(actionName: string, args: GeminiFunctionArgs): Promise { - // Check if this is a known computer use function - if (!PREDEFINED_COMPUTER_USE_FUNCTIONS.includes(actionName as GeminiAction)) { - return { error: `Unknown action: ${actionName}` }; - } - - try { - switch (actionName) { - case GeminiAction.OPEN_WEB_BROWSER: - // Browser is already open in Kernel, just return screenshot - break; - - case GeminiAction.CLICK_AT: { - if (args.x === undefined || args.y === undefined) { - return { error: 'click_at requires x and y coordinates' }; - } - const x = this.denormalizeX(args.x); - const y = this.denormalizeY(args.y); - await this.kernel.browsers.computer.clickMouse(this.sessionId, { - x, - y, - button: 'left', - click_type: 'click', - num_clicks: 1, - }); - break; - } - - case GeminiAction.HOVER_AT: { - if (args.x === undefined || args.y === undefined) { - return { error: 'hover_at requires x and y coordinates' }; - } - const x = this.denormalizeX(args.x); - const y = this.denormalizeY(args.y); - await this.kernel.browsers.computer.moveMouse(this.sessionId, { x, y }); - break; - } - - case GeminiAction.TYPE_TEXT_AT: { - if (args.x === undefined || args.y === undefined) { - return { error: 'type_text_at requires x and y coordinates' }; - } - if (!args.text) { - return { error: 'type_text_at requires text' }; - } - - const x = this.denormalizeX(args.x); - const y = this.denormalizeY(args.y); - - // Click at the location first - await this.kernel.browsers.computer.clickMouse(this.sessionId, { - x, - y, - button: 'left', - click_type: 'click', - num_clicks: 1, - }); - - // Clear existing text if requested (default: true) - if (args.clear_before_typing !== false) { - await this.kernel.browsers.computer.pressKey(this.sessionId, { - keys: ['ctrl+a'], - }); - await this.sleep(50); - } - - // Type the text - await this.kernel.browsers.computer.typeText(this.sessionId, { - text: args.text, - delay: TYPING_DELAY_MS, - }); - - // Press enter if requested - if (args.press_enter) { - await this.sleep(100); - await this.kernel.browsers.computer.pressKey(this.sessionId, { - keys: ['Return'], - }); - } - break; - } - - case GeminiAction.SCROLL_DOCUMENT: { - if (!args.direction) { - return { error: 'scroll_document requires direction' }; - } - const centerX = Math.round(this.screenSize.width / 2); - const centerY = Math.round(this.screenSize.height / 2); - - const magnitudePx = args.magnitude ?? 400; - const docNotches = Math.min(MAX_NOTCHES_PER_ACTION, Math.max(1, Math.round(magnitudePx / PX_PER_NOTCH))); - let docDx = 0; - let docDy = 0; - if (args.direction === 'down') docDy = docNotches; - else if (args.direction === 'up') docDy = -docNotches; - else if (args.direction === 'right') docDx = docNotches; - else if (args.direction === 'left') docDx = -docNotches; - await this.kernel.browsers.computer.scroll(this.sessionId, { - x: centerX, - y: centerY, - delta_x: docDx, - delta_y: docDy, - }); - break; - } - - case GeminiAction.SCROLL_AT: { - if (args.x === undefined || args.y === undefined) { - return { error: 'scroll_at requires x and y coordinates' }; - } - if (!args.direction) { - return { error: 'scroll_at requires direction' }; - } - - const x = this.denormalizeX(args.x); - const y = this.denormalizeY(args.y); - - const magnitudePx = args.magnitude ?? 400; - const notches = Math.min(MAX_NOTCHES_PER_ACTION, Math.max(1, Math.round(magnitudePx / PX_PER_NOTCH))); - let atDx = 0; - let atDy = 0; - if (args.direction === 'down') atDy = notches; - else if (args.direction === 'up') atDy = -notches; - else if (args.direction === 'right') atDx = notches; - else if (args.direction === 'left') atDx = -notches; - await this.kernel.browsers.computer.scroll(this.sessionId, { - x, - y, - delta_x: atDx, - delta_y: atDy, - }); - break; - } - - case GeminiAction.WAIT_5_SECONDS: - await this.sleep(5000); - break; - - case GeminiAction.GO_BACK: - await this.kernel.browsers.computer.pressKey(this.sessionId, { - keys: ['alt+Left'], - }); - await this.sleep(1000); - break; - - case GeminiAction.GO_FORWARD: - await this.kernel.browsers.computer.pressKey(this.sessionId, { - keys: ['alt+Right'], - }); - await this.sleep(1000); - break; - - case GeminiAction.SEARCH: - // Focus URL bar (Ctrl+L) - equivalent to clicking search - await this.kernel.browsers.computer.pressKey(this.sessionId, { - keys: ['ctrl+l'], - }); - break; - - case GeminiAction.NAVIGATE: { - if (!args.url) { - return { error: 'navigate requires url' }; - } - // Focus URL bar and type the URL - await this.kernel.browsers.computer.pressKey(this.sessionId, { - keys: ['ctrl+l'], - }); - await this.sleep(100); - await this.kernel.browsers.computer.typeText(this.sessionId, { - text: args.url, - delay: TYPING_DELAY_MS, - }); - await this.sleep(100); - await this.kernel.browsers.computer.pressKey(this.sessionId, { - keys: ['Return'], - }); - await this.sleep(1500); // Wait for navigation - break; - } - - case GeminiAction.KEY_COMBINATION: { - if (!args.keys) { - return { error: 'key_combination requires keys' }; - } - // Gemini sends keys as "key1+key2+key3" - await this.kernel.browsers.computer.pressKey(this.sessionId, { - keys: [args.keys], - }); - break; - } - - case GeminiAction.DRAG_AND_DROP: { - if (args.x === undefined || args.y === undefined || - args.destination_x === undefined || args.destination_y === undefined) { - return { error: 'drag_and_drop requires x, y, destination_x, and destination_y' }; - } - - const startX = this.denormalizeX(args.x); - const startY = this.denormalizeY(args.y); - const endX = this.denormalizeX(args.destination_x); - const endY = this.denormalizeY(args.destination_y); - - await this.kernel.browsers.computer.dragMouse(this.sessionId, { - path: [[startX, startY], [endX, endY]], - button: 'left', - }); - break; - } - - default: - return { error: `Unhandled action: ${actionName}` }; - } - - // Wait a moment for the action to complete, then take a screenshot - await this.sleep(SCREENSHOT_DELAY_MS); - return await this.screenshot(); - - } catch (error) { - // Return about:blank as URL fallback (required by Gemini Computer Use API) - // Note: Computer Controls API doesn't provide a way to get current page URL - return { error: `Action failed: ${error}`, url: 'about:blank' }; - } - } - - private sleep(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); - } -} diff --git a/pkg/templates/typescript/gemini-computer-use/tools/types/gemini.ts b/pkg/templates/typescript/gemini-computer-use/tools/types/gemini.ts deleted file mode 100644 index 56764b5f..00000000 --- a/pkg/templates/typescript/gemini-computer-use/tools/types/gemini.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Type definitions for Gemini Computer Use actions. - * Based on Google's computer-use-preview reference implementation. - */ - -export enum GeminiAction { - OPEN_WEB_BROWSER = 'open_web_browser', - CLICK_AT = 'click_at', - HOVER_AT = 'hover_at', - TYPE_TEXT_AT = 'type_text_at', - SCROLL_DOCUMENT = 'scroll_document', - SCROLL_AT = 'scroll_at', - WAIT_5_SECONDS = 'wait_5_seconds', - GO_BACK = 'go_back', - GO_FORWARD = 'go_forward', - SEARCH = 'search', - NAVIGATE = 'navigate', - KEY_COMBINATION = 'key_combination', - DRAG_AND_DROP = 'drag_and_drop', -} - -// Derive from enum to prevent drift when adding new actions -export const PREDEFINED_COMPUTER_USE_FUNCTIONS = Object.values(GeminiAction); - -export type ScrollDirection = 'up' | 'down' | 'left' | 'right'; - -export interface GeminiFunctionArgs { - // click_at, hover_at, scroll_at - x?: number; - y?: number; - - // type_text_at - text?: string; - press_enter?: boolean; - clear_before_typing?: boolean; - - // scroll_document, scroll_at - direction?: ScrollDirection; - magnitude?: number; - - // navigate - url?: string; - - // key_combination - keys?: string; - - // drag_and_drop - destination_x?: number; - destination_y?: number; - - // Safety decision (may be included in any function call) - safety_decision?: { - decision: string; - explanation: string; - }; -} - -export interface ToolResult { - /** Base64-encoded screenshot image */ - base64Image?: string; - /** Current URL of the browser */ - url?: string; - /** Error message if the action failed */ - error?: string; -} - -export interface ScreenSize { - width: number; - height: number; -} - -export const DEFAULT_SCREEN_SIZE: ScreenSize = { - width: 1200, - height: 800, -}; - -// Gemini uses normalized coordinates (0-1000) -export const COORDINATE_SCALE = 1000; diff --git a/pkg/templates/typescript/openai-computer-use/README.md b/pkg/templates/typescript/openai-computer-use/README.md index b8bab4aa..e6000a78 100644 --- a/pkg/templates/typescript/openai-computer-use/README.md +++ b/pkg/templates/typescript/openai-computer-use/README.md @@ -1,28 +1,49 @@ # Kernel TypeScript Sample App - OpenAI Computer Use -This is a Kernel application that demonstrates using the Computer Use Agent (CUA) from OpenAI with Kernel's native browser control API. +This is a Kernel application that runs an OpenAI computer-use agent against a Kernel cloud browser. -It uses Kernel's computer control endpoints (screenshot, click, type, scroll, batch, etc.) and includes a `batch_computer_actions` tool that executes multiple actions in a single API call for lower latency. +It uses [`@onkernel/cua-agent`](https://www.npmjs.com/package/@onkernel/cua-agent) to run the computer-use loop: the `CuaAgent` class translates OpenAI's computer-use tool calls into Kernel browser controls and feeds a fresh screenshot back on every turn. OpenAI's computer tool has no native URL navigation, so the template enables `computerUseExtra` to give the model a `goto`/`back`/`forward`/`url` helper. -## Local testing - -You can test against a remote Kernel browser without deploying: +## Deploy to Kernel ```bash -cp .env.example .env -# Fill in OPENAI_API_KEY and KERNEL_API_KEY in .env -pnpm install -pnpm exec tsx run_local.ts -pnpm exec tsx run_local.ts --task "go to https://news.ycombinator.com and get the top 5 articles" +kernel login +cp .env.example .env # Add your OPENAI_API_KEY +kernel deploy index.ts --env-file .env +kernel invoke ts-openai-cua cua-task -p '{"task":"Go to https://news.ycombinator.com and get the top 5 articles"}' ``` -The local runner defaults to a built-in sample task. Pass `--task "..."` to run a custom prompt locally, and add `--debug` to include verbose in-flight events. +## Recording Replays -## Deploy to Kernel +> **Note:** Replay recording is only available to Kernel users on paid plans. + +Add `"replay": true` to your payload to capture a video of the browser session. When enabled, the response includes a `replay_url` field with a link to view the recording. ```bash -kernel deploy index.ts --env-file .env -kernel invoke ts-openai-cua cua-task -p '{"task":"Go to https://news.ycombinator.com and get the top 5 articles"}' +kernel invoke ts-openai-cua cua-task -p '{"task":"Go to https://news.ycombinator.com", "replay": true}' +``` + +## Playwright escape hatch + +Some steps are awkward as raw clicks and keystrokes — precise DOM reads, form fills, data extraction, or waiting on a selector. Pass `playwright: true` when constructing the agent in `index.ts` to add a `playwright_execute` tool that runs Playwright/TypeScript directly against the live browser session: + +```ts +const agent = new CuaAgent({ + browser, + client: kernel, + computerUseExtra: true, + playwright: true, + initialState: { + model: 'openai:gpt-5.5', + systemPrompt: `...`, + }, +}); ``` -See the [docs](https://www.kernel.sh/docs/quickstart) for more information. +Inside `playwright_execute`, `page`, `context`, and `browser` are in scope and the code may `return` a JSON-serializable value. Each call runs in a fresh context (locals don't persist across calls), and no screenshot is returned automatically — the model can request one on a follow-up turn. See [`@onkernel/cua-agent`](https://www.npmjs.com/package/@onkernel/cua-agent) for details and per-model support status. + +## Resources + +- [@onkernel/cua-agent](https://www.npmjs.com/package/@onkernel/cua-agent) +- [OpenAI Computer Use Documentation](https://platform.openai.com/docs/guides/tools-computer-use) +- [Kernel Documentation](https://www.kernel.sh/docs/quickstart) diff --git a/pkg/templates/typescript/openai-computer-use/index.ts b/pkg/templates/typescript/openai-computer-use/index.ts index e6a9a343..d18e9537 100644 --- a/pkg/templates/typescript/openai-computer-use/index.ts +++ b/pkg/templates/typescript/openai-computer-use/index.ts @@ -1,19 +1,10 @@ import { Kernel, type KernelContext } from '@onkernel/sdk'; -import * as dotenv from 'dotenv'; -import type { ResponseItem, ResponseOutputMessage } from 'openai/resources/responses/responses'; -import { Agent } from './lib/agent'; -import { KernelComputer } from './lib/kernel-computer'; +import { CuaAgent } from '@onkernel/cua-agent'; +import type { AssistantMessage } from '@onkernel/cua-ai'; import { maybeStartReplay, maybeStopReplay } from './lib/replay'; -import { - createEventLogger, - emitBrowserDeleteDone, - emitBrowserDeleteStarted, - emitBrowserNewDone, - emitBrowserNewStarted, - emitSessionState, -} from './lib/logging'; -dotenv.config({ override: true, quiet: true }); +const kernel = new Kernel(); +const app = kernel.app('ts-openai-cua'); interface CuaInput { task: string; @@ -23,108 +14,59 @@ interface CuaOutput { elapsed: number; answer: string | null; replay_url?: string; - logs?: ResponseItem[]; } -const kernel = new Kernel(); -const app = kernel.app('ts-openai-cua'); - if (!process.env.OPENAI_API_KEY) { throw new Error('OPENAI_API_KEY is not set'); } -/** - * Example app that run an agent using openai CUA - * Args: - * ctx: Kernel context containing invocation information - * payload: An object with a `task` property - * Returns: - * An answer to the task, elapsed time and optionally the messages stack - * Invoke this via CLI: - * kernel login # or: export KERNEL_API_KEY= - * kernel deploy index.ts -e OPENAI_API_KEY=XXXXX --force - * kernel invoke ts-openai-cua cua-task -p "{\"task\":\"current market price range for a used dreamcast\"}" - */ - app.action( 'cua-task', async (ctx: KernelContext, payload?: CuaInput): Promise => { const start = Date.now(); if (!payload?.task) throw new Error('task is required'); - const onEvent = createEventLogger(); - emitBrowserNewStarted(onEvent); - const browserCreateStartedAt = Date.now(); - const kb = await kernel.browsers.create({ invocation_id: ctx.invocation_id }); - emitBrowserNewDone(onEvent, browserCreateStartedAt, kb.browser_live_view_url); - emitSessionState(onEvent, kb.session_id, kb.browser_live_view_url); + const browser = await kernel.browsers.create({ + invocation_id: ctx.invocation_id, + viewport: { width: 1280, height: 800 }, + }); + console.log('Kernel browser live view url:', browser.browser_live_view_url); - const computer = new KernelComputer(kernel, kb.session_id, onEvent); - const replay = await maybeStartReplay(kernel, kb.session_id, { + const replay = await maybeStartReplay(kernel, browser.session_id, { enabled: payload.replay === true, - onEvent, }); let answer: string | null = null; let replayUrl: string | null = null; try { - await computer.goto('https://duckduckgo.com'); - - const agent = new Agent({ - model: 'gpt-5.4', - computer, - tools: [], - acknowledge_safety_check_callback: (m: string): boolean => { - console.log(`> safety check: ${m}`); - return true; + const agent = new CuaAgent({ + browser, + client: kernel, + // OpenAI's computer tool has no native URL navigation; this exposes a + // goto/back/forward/url helper so the model can open pages directly. + computerUseExtra: true, + // Set to true to expose a playwright_execute tool for DOM reads, form fills, and selector waits. + playwright: false, + initialState: { + model: 'openai:gpt-5.5', + systemPrompt: `You are operating a Chromium browser on a Kernel cloud VM. Use the navigation tool to open URLs directly, and review the screenshot after each action before continuing. The current date and time is ${new Date().toISOString()}.`, }, }); - const logs = await agent.runFullTurn({ - messages: [ - { - role: 'system', - content: `- Current date and time: ${new Date().toISOString()} (${new Date().toLocaleDateString( - 'en-US', - { weekday: 'long' }, - )})`, - }, - { - type: 'message', - role: 'user', - content: [{ type: 'input_text', text: payload.task }], - }, - ], - print_steps: true, - debug: false, - show_images: false, - onEvent, - }); - - const elapsed = parseFloat(((Date.now() - start) / 1000).toFixed(2)); + await agent.prompt(payload.task); - const messages = logs.filter( - (item): item is ResponseOutputMessage => - item.type === 'message' && - typeof (item as ResponseOutputMessage).role === 'string' && - Array.isArray((item as ResponseOutputMessage).content), - ); - const assistant = messages.find((m) => m.role === 'assistant'); - const lastContentIndex = assistant?.content?.length ? assistant.content.length - 1 : -1; - const lastContent = lastContentIndex >= 0 ? assistant?.content?.[lastContentIndex] : null; - answer = lastContent && 'text' in lastContent ? lastContent.text : null; + const lastAssistant = [...agent.state.messages] + .reverse() + .find((message): message is AssistantMessage => message.role === 'assistant'); + answer = lastAssistant?.content + .flatMap((block) => (block.type === 'text' ? [block.text] : [])) + .join('') || null; } catch (error) { console.error('Error in cua-task:', error); answer = null; } finally { - emitBrowserDeleteStarted(onEvent); - const browserDeleteStartedAt = Date.now(); - try { - replayUrl = await maybeStopReplay(kernel, kb.session_id, replay, { onEvent }); - await kernel.browsers.deleteByID(kb.session_id); - } finally { - emitBrowserDeleteDone(onEvent, browserDeleteStartedAt); - } + replayUrl = await maybeStopReplay(kernel, browser.session_id, replay); + await kernel.browsers.deleteByID(browser.session_id); } const elapsed = parseFloat(((Date.now() - start) / 1000).toFixed(2)); diff --git a/pkg/templates/typescript/openai-computer-use/lib/agent.ts b/pkg/templates/typescript/openai-computer-use/lib/agent.ts deleted file mode 100644 index 4fa11fcf..00000000 --- a/pkg/templates/typescript/openai-computer-use/lib/agent.ts +++ /dev/null @@ -1,369 +0,0 @@ -import { - type ResponseItem, - type ResponseInputItem, - type ResponseOutputMessage, - type ResponseFunctionToolCallItem, - type ResponseFunctionToolCallOutputItem, - type ResponseComputerToolCall, - type ResponseComputerToolCallOutputItem, - type Tool, -} from 'openai/resources/responses/responses'; - -import * as utils from './utils'; -import type { AgentEvent } from './log-events'; -import { describeAction, describeBatchActions } from './log-events'; -import { batchInstructions, batchComputerTool, computerUseExtraTool } from './toolset'; -import type { CuaAction, KernelComputer } from './kernel-computer'; - -const BATCH_FUNC_NAME = 'batch_computer_actions'; -const EXTRA_FUNC_NAME = 'computer_use_extra'; -const POST_ACTION_SETTLE_MS = 300; -// Keep this shape aligned with CUA and current OpenAI Responses API. -const OPENAI_COMPUTER_TOOL = { type: 'computer' } as unknown as Tool; - -export class Agent { - private model: string; - private computer: KernelComputer; - private tools: Tool[]; - private print_steps = true; - private debug = false; - private show_images = false; - private ackCb: (msg: string) => boolean; - private onEvent: ((event: AgentEvent) => void) | null = null; - private modelRequestStartedAt: number | null = null; - - constructor(opts: { - model?: string; - computer: KernelComputer; - tools?: Tool[]; - acknowledge_safety_check_callback?: (msg: string) => boolean; - }) { - this.model = opts.model ?? 'gpt-5.4'; - this.computer = opts.computer; - this.ackCb = opts.acknowledge_safety_check_callback ?? ((): boolean => true); - - this.tools = [ - OPENAI_COMPUTER_TOOL, - batchComputerTool, - computerUseExtraTool, - ...(opts.tools ?? []), - ]; - } - - private debugPrint(...args: unknown[]): void { - if (this.debug) { - try { - console.dir( - args.map((msg) => utils.sanitizeMessage(msg as ResponseItem)), - { depth: null }, - ); - } catch { - console.dir(args, { depth: null }); - } - } - } - - private emit(event: AgentEvent['event'], data: Record): void { - if (this.print_steps) this.onEvent?.({ event, data }); - } - - private currentModelElapsedMs(): number | null { - return this.modelRequestStartedAt === null ? null : Date.now() - this.modelRequestStartedAt; - } - - private async capturePostActionScreenshot(): Promise { - await new Promise((resolve) => setTimeout(resolve, POST_ACTION_SETTLE_MS)); - return this.computer.screenshot(); - } - - private extractReasoningText(item: Record): string { - const summary = item.summary; - if (!Array.isArray(summary)) return ''; - const chunks = summary - .map((part) => { - if (!part || typeof part !== 'object') return ''; - const text = (part as { text?: unknown }).text; - return typeof text === 'string' ? text : ''; - }) - .filter(Boolean); - return chunks.join(' ').trim(); - } - - private extractUserPrompt(item: ResponseInputItem): string | null { - const message = item as unknown as { role?: unknown; content?: unknown }; - if (message.role !== 'user') return null; - if (typeof message.content === 'string') return message.content; - if (!Array.isArray(message.content)) return null; - const pieces = message.content - .map((entry) => { - if (!entry || typeof entry !== 'object') return ''; - const text = (entry as { text?: unknown }).text; - return typeof text === 'string' ? text : ''; - }) - .filter(Boolean); - return pieces.length > 0 ? pieces.join(' ') : null; - } - - private async handleItem(item: ResponseItem): Promise { - const itemType = (item as { type?: string }).type; - if (itemType === 'reasoning') { - const text = this.extractReasoningText(item as unknown as Record); - if (text) this.emit('reasoning_delta', { text }); - } - - if (item.type === 'message') { - const msg = item as ResponseOutputMessage; - const c = msg.content; - if (msg.role === 'assistant' && Array.isArray(c)) { - for (const part of c) { - if (part && typeof part === 'object' && 'text' in part && typeof part.text === 'string') { - this.emit('text_delta', { text: part.text }); - } - } - this.emit('text_done', {}); - } - } - - if (item.type === 'function_call') { - const fc = item as ResponseFunctionToolCallItem; - const argsObj = JSON.parse(fc.arguments) as Record; - if (fc.name === BATCH_FUNC_NAME && Array.isArray(argsObj.actions)) { - const actions = argsObj.actions.filter( - (action): action is Record => - typeof action === 'object' && action !== null, - ); - const elapsedMs = this.currentModelElapsedMs(); - this.emit('action', { - action_type: 'batch', - description: describeBatchActions(actions), - action: { type: 'batch', actions }, - ...(elapsedMs === null ? {} : { elapsed_ms: elapsedMs }), - }); - } else { - const elapsedMs = this.currentModelElapsedMs(); - this.emit('action', { - action_type: fc.name, - description: `${fc.name}(${JSON.stringify(argsObj)})`, - action: argsObj, - ...(elapsedMs === null ? {} : { elapsed_ms: elapsedMs }), - }); - } - - if (fc.name === BATCH_FUNC_NAME) { - return this.handleBatchCall(fc.call_id, argsObj); - } - if (fc.name === EXTRA_FUNC_NAME) { - return this.handleExtraCall(fc.call_id, argsObj); - } - - return [ - { - type: 'function_call_output', - call_id: fc.call_id, - output: `Unsupported function call: ${fc.name}`, - } as unknown as ResponseFunctionToolCallOutputItem, - ]; - } - - if (item.type === 'computer_call') { - const cc = item as ResponseComputerToolCall & { - action?: Record; - actions?: Array>; - }; - const actionList = Array.isArray(cc.actions) - ? cc.actions - : cc.action - ? [cc.action] - : []; - - const elapsedMs = this.currentModelElapsedMs(); - const actionType = - actionList.length === 1 ? String(actionList[0]?.type ?? 'unknown') : 'batch'; - const description = - actionList.length === 1 - ? describeAction(actionType, actionList[0] ?? {}) - : describeBatchActions(actionList); - const actionPayload = - actionList.length === 1 ? (actionList[0] ?? {}) : { type: 'batch', actions: actionList }; - this.emit('action', { - action_type: actionType, - description, - action: actionPayload, - ...(elapsedMs === null ? {} : { elapsed_ms: elapsedMs }), - }); - await this.computer.batchActions(actionList as CuaAction[]); - - const screenshot = await this.capturePostActionScreenshot(); - this.emit('screenshot', { captured: true, bytes_base64: screenshot.length }); - - const pending = cc.pending_safety_checks ?? []; - for (const check of pending) { - const msg = check.message ?? ''; - if (!this.ackCb(msg)) throw new Error(`Safety check failed: ${msg}`); - } - - if (this.computer.getEnvironment() === 'browser') { - try { - const currentUrl = await this.computer.getCurrentUrl(); - utils.checkBlocklistedUrl(currentUrl); - } catch (error) { - this.emit('backend', { - op: 'get_current_url.skipped', - detail: error instanceof Error ? error.message : String(error), - }); - } - } - - const screenshotOutput = { - type: 'computer_screenshot', - image_url: `data:image/png;base64,${screenshot}`, - } as unknown as ResponseComputerToolCallOutputItem['output']; - - const out: Omit = { - type: 'computer_call_output', - call_id: cc.call_id, - acknowledged_safety_checks: pending, - output: screenshotOutput, - }; - return [out as ResponseItem]; - } - - return []; - } - - private async handleBatchCall( - callId: string, - argsObj: Record, - ): Promise { - const actions = Array.isArray(argsObj.actions) ? (argsObj.actions as CuaAction[]) : []; - await this.computer.batchActions(actions); - - let statusText = 'Actions executed successfully.'; - const terminalReadAction = this.batchTerminalReadAction(actions); - if (terminalReadAction === 'url') { - try { - const currentUrl = await this.computer.getCurrentUrl(); - statusText = `Actions executed successfully. Current URL: ${currentUrl}`; - } catch (error) { - statusText = `Actions executed, but url() failed: ${error instanceof Error ? error.message : String(error)}`; - } - } - - const screenshot = await this.capturePostActionScreenshot(); - const outputItems: Array> = [{ type: 'input_text', text: statusText }]; - outputItems.push({ - type: 'input_image', - image_url: `data:image/png;base64,${screenshot}`, - detail: 'original', - }); - return [ - { - type: 'function_call_output', - call_id: callId, - output: outputItems, - } as unknown as ResponseFunctionToolCallOutputItem, - ]; - } - - private async handleExtraCall( - callId: string, - argsObj: Record, - ): Promise { - const action = typeof argsObj.action === 'string' ? argsObj.action : ''; - const url = typeof argsObj.url === 'string' ? argsObj.url : ''; - let statusText = ''; - if (action === 'goto') { - await this.computer.batchActions([{ type: 'goto', url }]); - statusText = 'goto executed successfully.'; - } else if (action === 'back') { - await this.computer.batchActions([{ type: 'back' }]); - statusText = 'back executed successfully.'; - } else if (action === 'url') { - const currentUrl = await this.computer.getCurrentUrl(); - statusText = `Current URL: ${currentUrl}`; - } else { - statusText = `unknown ${EXTRA_FUNC_NAME} action: ${action}`; - } - - const screenshot = await this.capturePostActionScreenshot(); - const outputItems: Array> = [{ type: 'input_text', text: statusText }]; - outputItems.push({ - type: 'input_image', - image_url: `data:image/png;base64,${screenshot}`, - detail: 'original', - }); - return [ - { - type: 'function_call_output', - call_id: callId, - output: outputItems, - } as unknown as ResponseFunctionToolCallOutputItem, - ]; - } - - private batchTerminalReadAction(actions: CuaAction[]): '' | 'url' | 'screenshot' { - if (actions.length === 0) return ''; - const lastType = actions[actions.length - 1]?.type; - if (lastType === 'url' || lastType === 'screenshot') return lastType; - return ''; - } - - async runFullTurn(opts: { - messages: ResponseInputItem[]; - print_steps?: boolean; - debug?: boolean; - show_images?: boolean; - onEvent?: (event: AgentEvent) => void; - }): Promise { - this.print_steps = opts.print_steps ?? true; - this.debug = opts.debug ?? false; - this.show_images = opts.show_images ?? false; - this.onEvent = opts.onEvent ?? null; - const newItems: ResponseItem[] = []; - let turns = 0; - - for (const message of opts.messages) { - const prompt = this.extractUserPrompt(message); - if (prompt) this.emit('prompt', { text: prompt }); - } - - try { - while ( - newItems.length === 0 || - (newItems[newItems.length - 1] as ResponseItem & { role?: string }).role !== 'assistant' - ) { - turns += 1; - const inputMessages = [...opts.messages]; - - this.debugPrint(...inputMessages, ...newItems); - this.modelRequestStartedAt = Date.now(); - const response = await utils.createResponse({ - model: this.model, - input: [...inputMessages, ...newItems], - tools: this.tools, - truncation: 'auto', - reasoning: { - effort: 'low', - summary: 'concise', - }, - instructions: batchInstructions, - }); - if (!response.output) throw new Error('No output from model'); - for (const msg of response.output as ResponseItem[]) { - newItems.push(msg, ...(await this.handleItem(msg))); - } - this.modelRequestStartedAt = null; - this.emit('turn_done', { turn: turns }); - } - } catch (error) { - this.modelRequestStartedAt = null; - this.emit('error', { message: error instanceof Error ? error.message : String(error) }); - throw error; - } - this.emit('run_complete', { turns }); - - return !this.show_images - ? newItems.map((msg) => utils.sanitizeMessage(msg) as ResponseItem) - : newItems; - } -} diff --git a/pkg/templates/typescript/openai-computer-use/lib/kernel-computer.ts b/pkg/templates/typescript/openai-computer-use/lib/kernel-computer.ts deleted file mode 100644 index 94500ed0..00000000 --- a/pkg/templates/typescript/openai-computer-use/lib/kernel-computer.ts +++ /dev/null @@ -1,589 +0,0 @@ -import { Kernel } from '@onkernel/sdk'; -import { describeAction, type AgentEvent } from './log-events'; - -// CUA model key names -> X11 keysym names for the Kernel computer API -const KEYSYM_MAP: Record = { - ENTER: 'Return', - Enter: 'Return', - RETURN: 'Return', - BACKSPACE: 'BackSpace', - Backspace: 'BackSpace', - DELETE: 'Delete', - TAB: 'Tab', - ESCAPE: 'Escape', - Escape: 'Escape', - ESC: 'Escape', - SPACE: 'space', - Space: 'space', - UP: 'Up', - DOWN: 'Down', - LEFT: 'Left', - RIGHT: 'Right', - HOME: 'Home', - END: 'End', - PAGEUP: 'Prior', - PAGE_UP: 'Prior', - PageUp: 'Prior', - PAGEDOWN: 'Next', - PAGE_DOWN: 'Next', - PageDown: 'Next', - CAPS_LOCK: 'Caps_Lock', - CapsLock: 'Caps_Lock', - CTRL: 'Control_L', - Ctrl: 'Control_L', - CONTROL: 'Control_L', - Control: 'Control_L', - ALT: 'Alt_L', - Alt: 'Alt_L', - SHIFT: 'Shift_L', - Shift: 'Shift_L', - META: 'Super_L', - Meta: 'Super_L', - SUPER: 'Super_L', - Super: 'Super_L', - CMD: 'Super_L', - COMMAND: 'Super_L', - F1: 'F1', - F2: 'F2', - F3: 'F3', - F4: 'F4', - F5: 'F5', - F6: 'F6', - F7: 'F7', - F8: 'F8', - F9: 'F9', - F10: 'F10', - F11: 'F11', - F12: 'F12', - INSERT: 'Insert', - Insert: 'Insert', - PRINT: 'Print', - SCROLLLOCK: 'Scroll_Lock', - PAUSE: 'Pause', - NUMLOCK: 'Num_Lock', -}; - -const MODIFIER_KEYSYMS = new Set([ - 'Control_L', - 'Control_R', - 'Alt_L', - 'Alt_R', - 'Shift_L', - 'Shift_R', - 'Super_L', - 'Super_R', - 'Meta_L', - 'Meta_R', -]); -const GOTO_CHORD_DELAY_MS = 200; - -function translateKeys(keys: string[]): string[] { - return keys.map((k) => KEYSYM_MAP[k] ?? k); -} - -function expandComboKeys(keys: string[]): string[] { - const out: string[] = []; - for (const raw of keys) { - if (typeof raw !== 'string') continue; - const parts = raw.includes('+') ? raw.split('+') : [raw]; - for (const part of parts) { - const trimmed = part.trim(); - if (trimmed) out.push(trimmed); - } - } - return out; -} - -function normalizeKeypressPayload( - keys: string[] = [], - holdKeys: string[] = [], -): { keys: string[]; holdKeys: string[] } { - const translatedHoldKeys = translateKeys(expandComboKeys(holdKeys)); - const translatedKeyEntries = translateKeys(expandComboKeys(keys)); - - const holdFromKeys: string[] = []; - const primaryKeys: string[] = []; - for (const key of translatedKeyEntries) { - if (MODIFIER_KEYSYMS.has(key)) holdFromKeys.push(key); - else primaryKeys.push(key); - } - - if (primaryKeys.length === 0) { - return { keys: translatedKeyEntries, holdKeys: translatedHoldKeys }; - } - - const holdMerged = [...translatedHoldKeys, ...holdFromKeys]; - const dedupedHold: string[] = []; - for (const key of holdMerged) { - if (!dedupedHold.includes(key)) dedupedHold.push(key); - } - return { keys: primaryKeys, holdKeys: dedupedHold }; -} - -function pixelsToScrollTicks(delta: number | undefined): number { - const value = typeof delta === 'number' && Number.isFinite(delta) ? delta : 0; - return Math.trunc(value); -} - -export interface CuaAction { - type: string; - x?: number; - y?: number; - text?: string; - url?: string; - keys?: string[]; - hold_keys?: string[]; - button?: string | number; - scroll_x?: number; - scroll_y?: number; - ms?: number; - path?: Array<{ x: number; y: number }>; - [key: string]: unknown; -} - -type BatchAction = { - type: 'click_mouse' | 'move_mouse' | 'type_text' | 'press_key' | 'scroll' | 'drag_mouse' | 'sleep'; - click_mouse?: { x: number; y: number; button?: string; num_clicks?: number }; - move_mouse?: { x: number; y: number }; - type_text?: { text: string }; - press_key?: { keys: string[]; hold_keys?: string[] }; - scroll?: { x: number; y: number; delta_x?: number; delta_y?: number }; - drag_mouse?: { path: number[][] }; - sleep?: { duration_ms: number }; -}; - -function normalizeButton(button?: string | number): string { - if (button === undefined || button === null) return 'left'; - if (typeof button === 'number') { - switch (button) { - case 1: return 'left'; - case 2: return 'middle'; - case 3: return 'right'; - default: return 'left'; - } - } - return button; -} - -function normalizeDragPath(path: unknown): number[][] { - if (!Array.isArray(path)) return []; - - const points: Array<[number, number]> = []; - for (const point of path) { - if (Array.isArray(point) && point.length >= 2) { - const [x, y] = point; - if (typeof x === 'number' && Number.isFinite(x) && typeof y === 'number' && Number.isFinite(y)) { - points.push([Math.trunc(x), Math.trunc(y)]); - } - continue; - } - - if ( - point && - typeof point === 'object' && - typeof (point as { x?: unknown }).x === 'number' && - Number.isFinite((point as { x: number }).x) && - typeof (point as { y?: unknown }).y === 'number' && - Number.isFinite((point as { y: number }).y) - ) { - points.push([ - Math.trunc((point as { x: number }).x), - Math.trunc((point as { y: number }).y), - ]); - } - } - - return points; -} - -function validateDragPath(path: number[][]): void { - if (path.length >= 2) return; - throw new Error(`drag action requires path with at least two points; got ${JSON.stringify(path)}`); -} - -function translateCuaAction(action: CuaAction): BatchAction { - switch (action.type) { - case 'click': { - if (action.button === 'back') { - return { type: 'press_key', press_key: { hold_keys: ['Alt'], keys: ['Left'] } }; - } - if (action.button === 'forward') { - return { type: 'press_key', press_key: { hold_keys: ['Alt'], keys: ['Right'] } }; - } - if (action.button === 'wheel') { - return { - type: 'scroll', - scroll: { - x: action.x ?? 0, - y: action.y ?? 0, - delta_x: pixelsToScrollTicks(action.scroll_x), - delta_y: pixelsToScrollTicks(action.scroll_y), - }, - }; - } - return { - type: 'click_mouse', - click_mouse: { x: action.x ?? 0, y: action.y ?? 0, button: normalizeButton(action.button) }, - }; - } - case 'double_click': - return { - type: 'click_mouse', - click_mouse: { x: action.x ?? 0, y: action.y ?? 0, num_clicks: 2 }, - }; - case 'type': - return { type: 'type_text', type_text: { text: action.text ?? '' } }; - case 'keypress': { - const normalized = normalizeKeypressPayload(action.keys ?? [], action.hold_keys ?? []); - return { - type: 'press_key', - press_key: { - keys: normalized.keys, - ...(normalized.holdKeys.length > 0 ? { hold_keys: normalized.holdKeys } : {}), - }, - }; - } - case 'scroll': - return { - type: 'scroll', - scroll: { - x: action.x ?? 0, - y: action.y ?? 0, - delta_x: pixelsToScrollTicks(action.scroll_x), - delta_y: pixelsToScrollTicks(action.scroll_y), - }, - }; - case 'move': - return { type: 'move_mouse', move_mouse: { x: action.x ?? 0, y: action.y ?? 0 } }; - case 'drag': { - const path = normalizeDragPath(action.path); - validateDragPath(path); - return { type: 'drag_mouse', drag_mouse: { path } }; - } - case 'wait': - return { type: 'sleep', sleep: { duration_ms: action.ms ?? 1000 } }; - default: - throw new Error(`Unknown CUA action type: ${action.type}`); - } -} - -function isBatchComputerActionType(actionType: string): boolean { - return ['click', 'double_click', 'type', 'keypress', 'scroll', 'move', 'drag', 'wait'].includes( - actionType, - ); -} - -function pressKeyAction(keys: string[], holdKeys?: string[]): BatchAction { - const normalized = normalizeKeypressPayload(keys, holdKeys); - return { - type: 'press_key', - press_key: { - keys: normalized.keys, - ...(normalized.holdKeys.length > 0 ? { hold_keys: normalized.holdKeys } : {}), - }, - }; -} - -function gotoBatchActions(url: string): BatchAction[] { - return [ - pressKeyAction(['l'], ['Ctrl']), - { type: 'sleep', sleep: { duration_ms: GOTO_CHORD_DELAY_MS } }, - pressKeyAction(['a'], ['Ctrl']), - { type: 'type_text', type_text: { text: url } }, - pressKeyAction(['Return']), - ]; -} - -function backBatchActions(): BatchAction[] { - return [pressKeyAction(['Left'], ['Alt'])]; -} - -function forwardBatchActions(): BatchAction[] { - return [pressKeyAction(['Right'], ['Alt'])]; -} - -function currentUrlBatchActions(): BatchAction[] { - return [ - pressKeyAction(['l'], ['Ctrl']), - pressKeyAction(['a'], ['Ctrl']), - pressKeyAction(['c'], ['Ctrl']), - pressKeyAction(['Escape']), - ]; -} - -function validateBatchTerminalReadActions(actions: CuaAction[]): void { - let readIdx = -1; - let readType = ''; - actions.forEach((action, idx) => { - if (action.type !== 'url' && action.type !== 'screenshot') return; - if (readIdx >= 0) { - throw new Error( - `batch can include at most one return-value action (${readType} or ${action.type}); found ${readType} at index ${readIdx} and ${action.type} at index ${idx}`, - ); - } - if (idx !== actions.length - 1) { - throw new Error(`return-value action "${action.type}" must be last in batch`); - } - readIdx = idx; - readType = action.type; - }); -} - -function buildPendingBatch(actions: CuaAction[]): BatchAction[] { - const pending: BatchAction[] = []; - for (const action of actions) { - const actionType = action.type; - if (isBatchComputerActionType(actionType)) { - pending.push(translateCuaAction(action)); - continue; - } - if (actionType === 'goto') { - pending.push(...gotoBatchActions(action.url ?? '')); - continue; - } - if (actionType === 'back') { - pending.push(...backBatchActions()); - continue; - } - if (actionType === 'forward') { - pending.push(...forwardBatchActions()); - continue; - } - if (actionType === 'url' || actionType === 'screenshot') { - continue; - } - throw new Error(`Unknown CUA action type: ${actionType}`); - } - return pending; -} - -function truncateText(text: string, max = 30): string { - if (text.length <= max) return text; - return `${text.slice(0, max - 3)}...`; -} - -function describeTranslatedBatch(actions: BatchAction[]): string { - const parts = actions.map((action) => { - switch (action.type) { - case 'click_mouse': { - const click = action.click_mouse; - if (!click) return action.type; - if ((click.num_clicks ?? 0) > 1) return `double_click(${click.x},${click.y})`; - return `click(${click.x},${click.y})`; - } - case 'type_text': { - const text = action.type_text?.text ?? ''; - return `type(${JSON.stringify(truncateText(text))})`; - } - case 'press_key': - return `key(hold=${JSON.stringify(action.press_key?.hold_keys ?? [])}, keys=${JSON.stringify(action.press_key?.keys ?? [])})`; - case 'scroll': - return 'scroll'; - case 'move_mouse': - return 'move'; - case 'drag_mouse': - return 'drag'; - case 'sleep': - return `sleep(${action.sleep?.duration_ms ?? 0}ms)`; - default: - return action.type; - } - }); - return `batch[${parts.join(' -> ')}]`; -} - -export class KernelComputer { - private client: Kernel; - private sessionId: string; - private width = 1920; - private height = 1080; - private onEvent: ((event: AgentEvent) => void) | null; - - constructor(client: Kernel, sessionId: string, onEvent?: (event: AgentEvent) => void) { - this.client = client; - this.sessionId = sessionId; - this.onEvent = onEvent ?? null; - } - - getEnvironment(): 'browser' { - return 'browser'; - } - - getDimensions(): [number, number] { - return [this.width, this.height]; - } - - private emitBackend(op: string, detail?: string, elapsedMs?: number): void { - const data: Record = { op }; - if (detail) data.detail = detail; - if (typeof elapsedMs === 'number') data.elapsed_ms = elapsedMs; - this.onEvent?.({ event: 'backend', data }); - } - - private async traceCall( - op: string, - fn: () => Promise, - detail?: string | ((result: T) => string | undefined), - ): Promise { - this.emitBackend(op); - const started = Date.now(); - let result!: T; - let completed = false; - try { - result = await fn(); - completed = true; - return result; - } finally { - const elapsedMs = Date.now() - started; - let resolvedDetail: string | undefined; - if (completed) { - resolvedDetail = - typeof detail === 'function' ? detail(result) : detail; - } - this.emitBackend(`${op}.done`, resolvedDetail, elapsedMs); - } - } - - async screenshot(): Promise { - return this.traceCall('screenshot', async () => { - const resp = await this.client.browsers.computer.captureScreenshot(this.sessionId); - const buf = Buffer.from(await resp.arrayBuffer()); - return buf.toString('base64'); - }); - } - - async click(x: number, y: number, button: string | number = 'left'): Promise { - if (button === 'back') { - await this.back(); - return; - } - if (button === 'forward') { - await this.forward(); - return; - } - if (button === 'wheel') { - await this.scroll(x, y, 0, 0); - return; - } - const normalizedButton = normalizeButton(button) as 'left' | 'right' | 'middle'; - const op = describeAction('click', { x, y, button: normalizedButton }); - await this.traceCall(op, async () => { - await this.client.browsers.computer.clickMouse(this.sessionId, { - x, - y, - button: normalizedButton, - }); - }); - } - - async doubleClick(x: number, y: number): Promise { - const op = describeAction('double_click', { x, y }); - await this.traceCall(op, async () => { - await this.client.browsers.computer.clickMouse(this.sessionId, { x, y, num_clicks: 2 }); - }); - } - - async type(text: string): Promise { - const op = describeAction('type', { text }); - await this.traceCall(op, async () => { - await this.client.browsers.computer.typeText(this.sessionId, { text }); - }); - } - - async keypress(keys: string[], holdKeys: string[] = []): Promise { - const normalized = normalizeKeypressPayload(keys, holdKeys); - const op = describeAction('keypress', { - keys: normalized.keys, - ...(normalized.holdKeys.length > 0 ? { hold_keys: normalized.holdKeys } : {}), - }); - await this.traceCall(op, async () => { - await this.client.browsers.computer.pressKey( - this.sessionId, - { - keys: normalized.keys, - ...(normalized.holdKeys.length > 0 ? { hold_keys: normalized.holdKeys } : {}), - } as Parameters[1], - ); - }); - } - - async scroll(x: number, y: number, scrollX: number, scrollY: number): Promise { - const op = describeAction('scroll', { x, y, scroll_x: scrollX, scroll_y: scrollY }); - const tickX = pixelsToScrollTicks(scrollX); - const tickY = pixelsToScrollTicks(scrollY); - await this.traceCall(op, async () => { - await this.client.browsers.computer.scroll(this.sessionId, { - x, - y, - delta_x: tickX, - delta_y: tickY, - }); - }); - } - - async move(x: number, y: number): Promise { - const op = describeAction('move', { x, y }); - await this.traceCall(op, async () => { - await this.client.browsers.computer.moveMouse(this.sessionId, { x, y }); - }); - } - - async drag(path: Array<{ x: number; y: number }>): Promise { - const op = describeAction('drag', { path }); - await this.traceCall(op, async () => { - const normalizedPath = normalizeDragPath(path); - validateDragPath(normalizedPath); - await this.client.browsers.computer.dragMouse(this.sessionId, { path: normalizedPath }); - }); - } - - async wait(ms = 1000): Promise { - await new Promise((resolve) => setTimeout(resolve, ms)); - } - - async batchActions(actions: CuaAction[]): Promise { - validateBatchTerminalReadActions(actions); - const pending = buildPendingBatch(actions); - const op = describeTranslatedBatch(pending); - await this.traceCall(op, async () => { - if (pending.length === 0) return; - await this.client.browsers.computer.batch(this.sessionId, { - actions: pending as Parameters[1]['actions'], - }); - }); - } - - async goto(url: string): Promise { - await this.batchActions([{ type: 'goto', url }]); - } - - async back(): Promise { - await this.batchActions([{ type: 'back' }]); - } - - async forward(): Promise { - const forwardActions = forwardBatchActions(); - await this.traceCall(describeTranslatedBatch(forwardActions), async () => { - await this.client.browsers.computer.batch(this.sessionId, { - actions: forwardActions as Parameters[1]['actions'], - }); - }); - } - - async getCurrentUrl(): Promise { - return this.traceCall('get_current_url()', async () => { - const copyActions = currentUrlBatchActions(); - await this.traceCall(describeTranslatedBatch(copyActions), async () => { - await this.client.browsers.computer.batch(this.sessionId, { - actions: copyActions as Parameters[1]['actions'], - }); - }); - const result = await this.client.browsers.computer.readClipboard(this.sessionId); - const currentUrl = (result.text ?? '').trim(); - if (!currentUrl) { - throw new Error('clipboard URL was empty'); - } - return currentUrl; - }); - } -} diff --git a/pkg/templates/typescript/openai-computer-use/lib/log-events.ts b/pkg/templates/typescript/openai-computer-use/lib/log-events.ts deleted file mode 100644 index 87643472..00000000 --- a/pkg/templates/typescript/openai-computer-use/lib/log-events.ts +++ /dev/null @@ -1,84 +0,0 @@ -export type AgentEventName = - | 'session_state' - | 'backend' - | 'prompt' - | 'reasoning_delta' - | 'text_delta' - | 'text_done' - | 'action' - | 'screenshot' - | 'turn_done' - | 'run_complete' - | 'error'; - -export interface AgentEvent { - event: AgentEventName; - data: Record; -} - -function toInt(value: unknown): number { - if (typeof value === 'number' && Number.isFinite(value)) return Math.trunc(value); - return 0; -} - -function truncate(text: string, max = 60): string { - return text.length > max ? `${text.slice(0, max - 3)}...` : text; -} - -export function describeAction(actionType: string, actionArgs: Record): string { - switch (actionType) { - case 'click': { - const x = toInt(actionArgs.x); - const y = toInt(actionArgs.y); - const button = typeof actionArgs.button === 'string' ? actionArgs.button : 'left'; - return button === 'left' ? `click(${x}, ${y})` : `click(${x}, ${y}, ${button})`; - } - case 'double_click': - return `double_click(${toInt(actionArgs.x)}, ${toInt(actionArgs.y)})`; - case 'type': { - const text = typeof actionArgs.text === 'string' ? actionArgs.text : ''; - return `type(${JSON.stringify(truncate(text))})`; - } - case 'keypress': { - const keys = Array.isArray(actionArgs.keys) ? actionArgs.keys : []; - const holdKeys = Array.isArray(actionArgs.hold_keys) ? actionArgs.hold_keys : []; - const serializedKeys = keys.filter((k): k is string => typeof k === 'string'); - const serializedHoldKeys = holdKeys.filter((k): k is string => typeof k === 'string'); - if (serializedHoldKeys.length > 0) { - return `keypress(hold=${JSON.stringify(serializedHoldKeys)}, keys=${JSON.stringify(serializedKeys)})`; - } - return `keypress(${JSON.stringify(serializedKeys)})`; - } - case 'scroll': - return `scroll(${toInt(actionArgs.x)}, ${toInt(actionArgs.y)}, dx=${toInt(actionArgs.scroll_x)}, dy=${toInt(actionArgs.scroll_y)})`; - case 'move': - return `move(${toInt(actionArgs.x)}, ${toInt(actionArgs.y)})`; - case 'drag': - return 'drag(...)'; - case 'wait': { - const ms = typeof actionArgs.ms === 'number' ? Math.trunc(actionArgs.ms) : 1000; - return `wait(${ms}ms)`; - } - case 'goto': { - const url = typeof actionArgs.url === 'string' ? actionArgs.url : ''; - return `goto(${JSON.stringify(url)})`; - } - case 'back': - return 'back()'; - case 'url': - return 'url()'; - case 'screenshot': - return 'screenshot()'; - default: - return actionType; - } -} - -export function describeBatchActions(actions: Array>): string { - const pieces = actions.map((action) => { - const actionType = typeof action.type === 'string' ? action.type : 'unknown'; - const { type: _ignored, ...actionArgs } = action; - return describeAction(actionType, actionArgs); - }); - return `batch[${pieces.join(' -> ')}]`; -} diff --git a/pkg/templates/typescript/openai-computer-use/lib/logging.ts b/pkg/templates/typescript/openai-computer-use/lib/logging.ts deleted file mode 100644 index 77eaf3c6..00000000 --- a/pkg/templates/typescript/openai-computer-use/lib/logging.ts +++ /dev/null @@ -1,271 +0,0 @@ -import type { AgentEvent } from './log-events'; - -const MAX_LINE_WIDTH = 120; - -function timestamp(): string { - return new Date().toISOString().slice(11, 23); -} - -function asString(value: unknown): string { - return typeof value === 'string' ? value : ''; -} - -function asNumber(value: unknown): number | null { - return typeof value === 'number' && Number.isFinite(value) ? value : null; -} - -function truncateOneLine(text: string, max = 90): string { - const singleLine = text.replace(/\s+/g, ' ').trim(); - return singleLine.length > max ? `${singleLine.slice(0, max - 3)}...` : singleLine; -} - -function formatKernelOp(op: string): string { - if (!op) return op; - if (op.includes('(') || op.includes('[')) return op; - return `${op}()`; -} - -export function emitBrowserNewStarted(onEvent: (event: AgentEvent) => void): void { - onEvent({ event: 'backend', data: { op: 'browsers.new' } }); -} - -export function emitBrowserNewDone( - onEvent: (event: AgentEvent) => void, - startedAtMs: number, - liveViewUrl?: string | null, -): void { - onEvent({ - event: 'backend', - data: { - op: 'browsers.new.done', - detail: liveViewUrl ?? '', - elapsed_ms: Date.now() - startedAtMs, - }, - }); -} - -export function emitSessionState( - onEvent: (event: AgentEvent) => void, - sessionId: string, - liveViewUrl?: string | null, -): void { - onEvent({ - event: 'session_state', - data: { session_id: sessionId, live_view_url: liveViewUrl ?? '' }, - }); -} - -export function emitBrowserDeleteStarted(onEvent: (event: AgentEvent) => void): void { - onEvent({ event: 'backend', data: { op: 'browsers.delete' } }); -} - -export function emitBrowserDeleteDone( - onEvent: (event: AgentEvent) => void, - startedAtMs: number, -): void { - onEvent({ - event: 'backend', - data: { - op: 'browsers.delete.done', - elapsed_ms: Date.now() - startedAtMs, - }, - }); -} - -class ThinkingSpinner { - private active = false; - private timer: NodeJS.Timeout | null = null; - private frame = 0; - private startAt = 0; - private startTS = ''; - private reasoning = ''; - - constructor(private readonly enabled: boolean) {} - - start(): void { - if (!this.enabled || this.active) return; - this.active = true; - this.frame = 0; - this.reasoning = ''; - this.startAt = Date.now(); - this.startTS = timestamp(); - this.timer = setInterval(() => this.redraw(), 100); - } - - addReasoning(text: string): void { - if (!this.active) return; - this.reasoning += text; - } - - stop(action?: string, opts?: { elapsedSeconds?: number }): void { - const elapsedSeconds = opts?.elapsedSeconds; - if (!this.active) { - if (action) { - const elapsedPrefix = - typeof elapsedSeconds === 'number' ? `[${elapsedSeconds.toFixed(3)}s] ` : ''; - process.stdout.write(`${timestamp()} agent> ${elapsedPrefix}${action}\n`); - } - return; - } - this.active = false; - if (this.timer) clearInterval(this.timer); - this.timer = null; - - const elapsed = - typeof elapsedSeconds === 'number' - ? elapsedSeconds.toFixed(3) - : ((Date.now() - this.startAt) / 1000).toFixed(3); - if (this.reasoning.trim()) { - const thinkingText = truncateOneLine(this.reasoning, 70); - const suffix = action ? ` -> ${action}` : ''; - process.stdout.write(`\r\x1b[2K${this.startTS} agent> [${elapsed}s] ${thinkingText}${suffix}\n`); - } else if (action) { - process.stdout.write(`\r\x1b[2K${this.startTS} agent> [${elapsed}s] ${action}\n`); - } else { - process.stdout.write(`\r\x1b[2K${this.startTS} agent> [${elapsed}s] thinking...\n`); - } - } - - private redraw(): void { - if (!this.active) return; - this.frame += 1; - const elapsed = ((Date.now() - this.startAt) / 1000).toFixed(3); - if (this.reasoning.trim()) { - const prefix = `${this.startTS} agent> [${elapsed}s] `; - const maxReasoningLen = Math.max(20, MAX_LINE_WIDTH - prefix.length); - const text = truncateOneLine(this.reasoning, maxReasoningLen); - process.stdout.write(`\r\x1b[2K${prefix}${text}`); - return; - } - const dots = '.'.repeat((this.frame % 3) + 1).padEnd(3, ' '); - process.stdout.write(`\r\x1b[2K${this.startTS} agent> [${elapsed}s] thinking${dots}`); - } -} - -export function createEventLogger(opts?: { verbose?: boolean }): (event: AgentEvent) => void { - const verbose = opts?.verbose ?? false; - - let inText = false; - let lastLiveViewUrl = ''; - const spinner = new ThinkingSpinner(process.stdout.isTTY); - - return (event: AgentEvent): void => { - const data = event.data; - switch (event.event) { - case 'session_state': { - const liveUrl = asString(data.live_view_url); - if (liveUrl && liveUrl !== lastLiveViewUrl) { - process.stdout.write(`${timestamp()} kernel> live view: ${liveUrl}\n`); - lastLiveViewUrl = liveUrl; - } - break; - } - case 'backend': { - const op = asString(data.op); - if (!op) break; - - if (inText) { - process.stdout.write('\n'); - inText = false; - } - - if (op === 'live_url') { - const detail = asString(data.detail); - if (detail && detail !== lastLiveViewUrl) { - process.stdout.write(`${timestamp()} kernel> live view: ${detail}\n`); - lastLiveViewUrl = detail; - } - break; - } - - if (op.endsWith('.done')) { - const baseOp = op.slice(0, -'.done'.length); - const displayOp = formatKernelOp(baseOp); - const detail = asString(data.detail); - const elapsedMs = asNumber(data.elapsed_ms); - const elapsed = elapsedMs === null ? '' : `[${(elapsedMs / 1000).toFixed(3)}s] `; - process.stdout.write( - `${timestamp()} kernel> ${elapsed}${displayOp}${detail ? ` ${detail}` : ''}\n`, - ); - if (baseOp === 'browsers.new' && detail) { - lastLiveViewUrl = detail; - } - break; - } - - if (verbose) process.stdout.write(`${timestamp()} kernel> ${op}\n`); - break; - } - case 'prompt': { - const text = asString(data.text); - if (text) process.stdout.write(`${timestamp()} user> ${text}\n`); - break; - } - case 'reasoning_delta': { - const text = asString(data.text); - if (process.stdout.isTTY) { - spinner.start(); - spinner.addReasoning(text); - } else if (verbose && text) { - process.stdout.write(`${timestamp()} agent> thinking: ${truncateOneLine(text)}\n`); - } - break; - } - case 'text_delta': { - spinner.stop(); - const text = asString(data.text); - if (!text) break; - if (!inText) { - process.stdout.write(`${timestamp()} agent> `); - inText = true; - } - process.stdout.write(text); - break; - } - case 'text_done': { - if (inText) { - process.stdout.write('\n'); - inText = false; - } - break; - } - case 'action': { - const actionType = asString(data.action_type); - const description = asString(data.description) || actionType; - const elapsedMs = asNumber(data.elapsed_ms); - const elapsedSeconds = elapsedMs === null ? undefined : elapsedMs / 1000; - if (inText) { - process.stdout.write('\n'); - inText = false; - } - spinner.stop(description, { elapsedSeconds }); - break; - } - case 'screenshot': { - if (verbose) process.stdout.write(`${timestamp()} debug> screenshot captured\n`); - break; - } - case 'turn_done': - case 'run_complete': { - spinner.stop(); - if (inText) { - process.stdout.write('\n'); - inText = false; - } - break; - } - case 'error': { - const message = asString(data.message) || 'unknown error'; - spinner.stop(); - if (inText) { - process.stdout.write('\n'); - inText = false; - } - process.stderr.write(`${timestamp()} error> ${message}\n`); - break; - } - default: - break; - } - }; -} diff --git a/pkg/templates/typescript/openai-computer-use/lib/replay.ts b/pkg/templates/typescript/openai-computer-use/lib/replay.ts index 6858d9b7..3a19d21e 100644 --- a/pkg/templates/typescript/openai-computer-use/lib/replay.ts +++ b/pkg/templates/typescript/openai-computer-use/lib/replay.ts @@ -1,13 +1,10 @@ import type { Kernel } from '@onkernel/sdk'; -import type { AgentEvent } from './log-events'; const DEFAULT_REPLAY_GRACE_MS = 5000; const REPLAY_PROCESSING_DELAY_MS = 2000; const REPLAY_POLL_TIMEOUT_MS = 60000; const REPLAY_POLL_INTERVAL_MS = 1000; -type EventLogger = (event: AgentEvent) => void; - export interface ReplayState { enabled: boolean; replayId: string | null; @@ -17,10 +14,7 @@ export interface ReplayState { export async function maybeStartReplay( kernel: Kernel, sessionId: string, - opts?: { - enabled?: boolean; - onEvent?: EventLogger; - }, + opts?: { enabled?: boolean }, ): Promise { const enabled = opts?.enabled ?? false; const state: ReplayState = { @@ -31,19 +25,9 @@ export async function maybeStartReplay( if (!enabled) return state; - const startedAtMs = Date.now(); - opts?.onEvent?.({ event: 'backend', data: { op: 'browsers.replays.start' } }); try { const replay = await kernel.browsers.replays.start(sessionId); state.replayId = replay.replay_id ?? null; - opts?.onEvent?.({ - event: 'backend', - data: { - op: 'browsers.replays.start.done', - detail: state.replayId ?? '', - elapsed_ms: Date.now() - startedAtMs, - }, - }); } catch (error) { console.warn(`Warning: failed to start replay recording: ${String(error)}`); console.warn('Continuing without replay recording.'); @@ -57,10 +41,7 @@ export async function maybeStopReplay( kernel: Kernel, sessionId: string, replay: ReplayState, - opts?: { - onEvent?: EventLogger; - gracePeriodMs?: number; - }, + opts?: { gracePeriodMs?: number }, ): Promise { if (!replay.enabled || !replay.replayId) return replay.replayViewUrl; @@ -69,8 +50,6 @@ export async function maybeStopReplay( await sleep(gracePeriodMs); } - const startedAtMs = Date.now(); - opts?.onEvent?.({ event: 'backend', data: { op: 'browsers.replays.stop' } }); try { await kernel.browsers.replays.stop(replay.replayId, { id: sessionId }); await sleep(REPLAY_PROCESSING_DELAY_MS); @@ -90,15 +69,6 @@ export async function maybeStopReplay( await sleep(REPLAY_POLL_INTERVAL_MS); } - opts?.onEvent?.({ - event: 'backend', - data: { - op: 'browsers.replays.stop.done', - detail: replay.replayViewUrl ?? replay.replayId ?? '', - elapsed_ms: Date.now() - startedAtMs, - }, - }); - if (!replay.replayViewUrl) { console.warn('Warning: replay may still be processing.'); } diff --git a/pkg/templates/typescript/openai-computer-use/lib/toolset.ts b/pkg/templates/typescript/openai-computer-use/lib/toolset.ts deleted file mode 100644 index aa43b9f1..00000000 --- a/pkg/templates/typescript/openai-computer-use/lib/toolset.ts +++ /dev/null @@ -1,117 +0,0 @@ -export const batchInstructions = `You have three ways to perform actions: -1. The standard computer tool — use for single actions when you need screenshot feedback after each step. -2. batch_computer_actions — use to execute multiple actions at once when you can predict the outcome. -3. computer_use_extra — use high-level browser actions: goto, back, and url. - -ALWAYS prefer batch_computer_actions when performing predictable sequences like: -- Clicking a text field, typing text, and pressing Enter -- Any sequence where you don't need to see intermediate results - -Use computer_use_extra for: -- action="goto" only when changing the page URL -- action="back" to go back in history -- action="url" to read the exact current URL - -When interacting with page content (search boxes, forms, chat inputs): -- Click the target input first, then type. -- Do not use URL-navigation actions for in-page text entry. - -For drag actions in batch_computer_actions: -- Always include a path field. -- path must be an array of at least two points. -- If one drag is likely to change the position, order, or layout of other targets, do not batch multiple drags together. -- In those cases, prefer one drag at a time and inspect the updated screenshot before planning the next drag. -- Each point must be an object like {"x": 123, "y": 456}.`; - -export const batchComputerTool = { - type: 'function' as const, - name: 'batch_computer_actions', - description: - 'Execute multiple computer actions in sequence without waiting for ' + - 'screenshots between them. Use this when you can predict the outcome of a ' + - 'sequence of actions without needing intermediate visual feedback. After all ' + - 'actions execute, a single screenshot is taken and returned.\n\n' + - 'PREFER this over individual computer actions when:\n' + - '- Typing text followed by pressing Enter\n' + - '- Clicking a field and then typing into it\n' + - "- Any sequence where intermediate screenshots aren't needed\n\n" + - 'Constraint: return-value actions (url, screenshot) can appear at most once ' + - 'and only as the final action in the batch.', - parameters: { - type: 'object', - properties: { - actions: { - type: 'array', - description: 'Ordered list of actions to execute', - items: { - type: 'object', - properties: { - type: { - type: 'string', - enum: [ - 'click', - 'double_click', - 'type', - 'keypress', - 'scroll', - 'move', - 'drag', - 'wait', - 'goto', - 'back', - 'url', - 'screenshot', - ], - }, - x: { type: 'number' }, - y: { type: 'number' }, - text: { type: 'string' }, - url: { type: 'string' }, - keys: { type: 'array', items: { type: 'string' } }, - hold_keys: { type: 'array', items: { type: 'string' } }, - button: { type: 'string' }, - scroll_x: { type: 'number' }, - scroll_y: { type: 'number' }, - path: { - type: 'array', - description: 'Required for drag actions. Provide at least two points as objects with x/y coordinates.', - items: { - type: 'object', - properties: { - x: { type: 'number' }, - y: { type: 'number' }, - }, - required: ['x', 'y'], - }, - }, - }, - required: ['type'], - }, - }, - }, - required: ['actions'], - }, - strict: false, -}; - -export const computerUseExtraTool = { - type: 'function' as const, - name: 'computer_use_extra', - description: 'High-level browser actions for navigation and URL retrieval.', - parameters: { - type: 'object', - properties: { - action: { - type: 'string', - enum: ['goto', 'back', 'url'], - description: 'Action to perform: goto, back, or url.', - }, - url: { - type: 'string', - description: 'Required when action is goto. Fully qualified URL to navigate to.', - }, - }, - required: ['action'], - }, - strict: false, -}; diff --git a/pkg/templates/typescript/openai-computer-use/lib/utils.ts b/pkg/templates/typescript/openai-computer-use/lib/utils.ts deleted file mode 100644 index 9a3134bf..00000000 --- a/pkg/templates/typescript/openai-computer-use/lib/utils.ts +++ /dev/null @@ -1,124 +0,0 @@ -import * as dotenv from 'dotenv'; -import OpenAI from 'openai'; -import { type ResponseItem } from 'openai/resources/responses/responses'; - -dotenv.config({ override: true, quiet: true }); - -const openai = new OpenAI(); - -const BLOCKED_DOMAINS: readonly string[] = [ - 'maliciousbook.com', - 'evilvideos.com', - 'darkwebforum.com', - 'shadytok.com', - 'suspiciouspins.com', - 'ilanbigio.com', -] as const; - -export function sanitizeMessage(msg: ResponseItem): ResponseItem { - const sanitizedMsg = { ...msg } as ResponseItem; - if ( - sanitizedMsg.type === 'computer_call_output' && - typeof sanitizedMsg.output === 'object' && - sanitizedMsg.output !== null - ) { - sanitizedMsg.output = { ...sanitizedMsg.output }; - const output = sanitizedMsg.output as { image_url?: string }; - if (output.image_url) { - output.image_url = '[omitted]'; - } - } - if ( - sanitizedMsg.type === 'function_call_output' && - Array.isArray((sanitizedMsg as { output?: unknown }).output) - ) { - const outputItems = (sanitizedMsg as unknown as { output: Array<{ type?: unknown; image_url?: unknown }> }).output; - sanitizedMsg.output = outputItems.map((item) => { - if (item.type === 'input_image' && typeof item.image_url === 'string') { - return { ...item, image_url: '[omitted]' }; - } - return item; - }) as typeof sanitizedMsg.output; - } - return sanitizedMsg; -} - -export async function createResponse( - params: OpenAI.Responses.ResponseCreateParams, -): Promise<{ output?: OpenAI.Responses.ResponseOutputItem[] }> { - const maxAttempts = Number(process.env.OPENAI_RETRY_MAX_ATTEMPTS ?? '4'); - const baseDelaySeconds = Number(process.env.OPENAI_RETRY_BASE_DELAY_SECONDS ?? '0.5'); - - for (let attempt = 1; attempt <= maxAttempts; attempt += 1) { - try { - const response = await openai.responses.create(params); - return 'output' in response ? response : { output: undefined }; - } catch (err: unknown) { - const status = getErrorStatus(err); - const retryable = isRetryableError(err); - const message = getErrorMessage(err); - - if (!retryable || attempt >= maxAttempts) { - console.error(message); - throw err; - } - - const delayMs = baseDelaySeconds * 1000 * 2 ** (attempt - 1); - const label = status === null ? 'OpenAI request failed' : `OpenAI server error ${status}`; - console.warn( - `Warning: ${label}; retrying in ${(delayMs / 1000).toFixed(1)}s (${attempt}/${maxAttempts})`, - ); - await sleep(delayMs); - } - } - throw new Error('OpenAI request failed unexpectedly'); -} - -function getErrorStatus(err: unknown): number | null { - if (typeof err !== 'object' || err === null) return null; - if (!('status' in err)) return null; - const status = (err as { status?: unknown }).status; - return typeof status === 'number' ? status : null; -} - -function getErrorMessage(err: unknown): string { - if (err instanceof Error && err.message) return err.message; - return String(err); -} - -function isRetryableError(err: unknown): boolean { - const status = getErrorStatus(err); - if (status !== null) return status >= 500; - - const msg = getErrorMessage(err).toLowerCase(); - return ( - msg.includes('fetch failed') || - msg.includes('network') || - msg.includes('econnreset') || - msg.includes('etimedout') || - msg.includes('timeout') - ); -} - -function sleep(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -export function checkBlocklistedUrl(url: string): void { - try { - const host = new URL(url).hostname; - if (BLOCKED_DOMAINS.some((d) => host === d || host.endsWith(`.${d}`))) { - throw new Error(`Blocked URL: ${url}`); - } - } catch (error) { - if (error instanceof Error && error.message.startsWith('Blocked URL:')) { - throw error; - } - } -} - -export default { - sanitizeMessage, - createResponse, - checkBlocklistedUrl, -}; diff --git a/pkg/templates/typescript/openai-computer-use/package.json b/pkg/templates/typescript/openai-computer-use/package.json index b9371e19..70602bfc 100644 --- a/pkg/templates/typescript/openai-computer-use/package.json +++ b/pkg/templates/typescript/openai-computer-use/package.json @@ -2,17 +2,15 @@ "type": "module", "private": true, "scripts": { - "build": "tsc", - "test:local": "npx tsx run_local.ts" + "build": "tsc" }, "dependencies": { - "@onkernel/sdk": "^0.43.0", - "dotenv": "^17.2.3", - "openai": "^6.13.0" + "@onkernel/cua-agent": "^0.3.4", + "@onkernel/cua-ai": "^0.3.1", + "@onkernel/sdk": "0.49.0" }, "devDependencies": { "@types/node": "^22.15.17", - "tsx": "^4.19.0", "typescript": "^5.9.3" } } diff --git a/pkg/templates/typescript/openai-computer-use/pnpm-lock.yaml b/pkg/templates/typescript/openai-computer-use/pnpm-lock.yaml index 28304dd1..28933dcf 100644 --- a/pkg/templates/typescript/openai-computer-use/pnpm-lock.yaml +++ b/pkg/templates/typescript/openai-computer-use/pnpm-lock.yaml @@ -8,209 +8,490 @@ importers: .: dependencies: + '@onkernel/cua-agent': + specifier: ^0.3.4 + version: 0.3.4(ws@8.21.0)(zod@4.4.3) + '@onkernel/cua-ai': + specifier: ^0.3.1 + version: 0.3.1(ws@8.21.0)(zod@4.4.3) '@onkernel/sdk': - specifier: ^0.43.0 - version: 0.43.0 - dotenv: - specifier: ^17.2.3 - version: 17.3.1 - openai: - specifier: ^6.13.0 - version: 6.25.0 + specifier: 0.49.0 + version: 0.49.0 devDependencies: '@types/node': specifier: ^22.15.17 version: 22.19.11 - tsx: - specifier: ^4.19.0 - version: 4.21.0 typescript: specifier: ^5.9.3 version: 5.9.3 packages: - '@esbuild/aix-ppc64@0.27.3': - resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] + '@anthropic-ai/sdk@0.91.1': + resolution: {integrity: sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==} + hasBin: true + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + zod: + optional: true - '@esbuild/android-arm64@0.27.3': - resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} - '@esbuild/android-arm@0.27.3': - resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} - '@esbuild/android-x64@0.27.3': - resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-bedrock-runtime@3.1048.0': + resolution: {integrity: sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.974.23': + resolution: {integrity: sha512-MiWR/uWjxjFXGzrE0Ghc5lWxUxzHsUWFhV+OX7M4cR9SrmrnZs6TXavnCWnzzdwJeFri34xQo81rvGNzK3c4BQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.49': + resolution: {integrity: sha512-liB3yQNHCM9k/gu/w36XHMKPluT7HTlnGUhRbBGSISDQkcr/Sy1zsZabiuvQj8WG5yW573u9RehrBvvnIQ9OEQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.51': + resolution: {integrity: sha512-XET0H2oofciJ5lMRWNIvRjAP7Q3wv2XT+JtJJEdhPWUMwe3TvQ9qcxonpu7vXmNngncvFpi4E2It+Tamas/naA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.972.56': + resolution: {integrity: sha512-IAmc61hbgQiHht9U3x0tnRwz0lzdwOwD/i9voRgdJrKamF+JtmrBOsW9GwB7mfFonNWOWL4qARWYrF8veEMe3w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.55': + resolution: {integrity: sha512-hBBkANo3cDn+h2qxxzER4a+J8JCO9o9Z/YYmU7iky6AcaarX5RRdRcHNC6SLdwY0vAXQygn6soUbDqPn3GghaA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.58': + resolution: {integrity: sha512-OyCLVmSI7pZO8hxwNVX6pXhTVlJqRBTp+ijdEfJSUj0RyjHnF602OfAarOzGq6wkGodeFkYBt8MmJ6A6ycRgWw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.49': + resolution: {integrity: sha512-C8h36lBuC/RnBSsjlO+dn6xZm3KbAl5vpJaVPAfQnMmz2/OISmKOc8XZcqMQgO2ADwBYNRMM6Kf3vz9G/TulMQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.972.55': + resolution: {integrity: sha512-1FkOz74Ea5QGS9jtIoXp55T/IkSS3spv+nLTT07fRY/+T5xmEOqaYBVIaEmX4zTNvbV6g2lrtlaVKWEoNyJt3w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.55': + resolution: {integrity: sha512-g2BoECD1q01kTPByi56+VLVvdWDzMkKIcr77qixpqH0okw2t0U5CoPv+6S8v/D1Y2Wa6QKKtn6XAtDzP+Kfpvg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/eventstream-handler-node@3.972.22': + resolution: {integrity: sha512-tqPJv0dz4+O0hWGm1a6YekcMZyPhDFs/zH73Von7icaVT5n0Jqvm86typ3jRrG+qoUdPhALOnboRLTmnWQTlYQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-eventstream@3.972.18': + resolution: {integrity: sha512-OHpk8YoZi3yexPq8aFt1vN1IxA2zLKvsIR5GpWYylX/ve6kQmY7wxHNSFy/D3t2apMZ16rs76Co4dJWcDyIk3A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-websocket@3.972.31': + resolution: {integrity: sha512-ps1rumU1LybSFHaW9dTDgkhCMJLVaedEY78kKSzUDDY+b9974/g6aiaYYA0U9WV0oL4CJCJrVWG+EZ/qr4or7g==} + engines: {node: '>= 14.0.0'} + + '@aws-sdk/nested-clients@3.997.23': + resolution: {integrity: sha512-gO93ZPsI2bxeFZD42f1/qjDw6FAZkNZcKRO94LIiT03fzOmcJ9e/tunxjVjA1Rl69ClmVJzz8H3G9CdKef10PA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.996.35': + resolution: {integrity: sha512-6L/VWs+Wch2stHemCGTmUNqKLMzURxQDK5boNG3Jn3kAOp71meDUuS5sbObpEvFxHDq0uWeSLFDNSYsjNt+Dlg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1048.0': + resolution: {integrity: sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1074.0': + resolution: {integrity: sha512-pv80IzgGW4RnXWtft692chZOM9i6PhebVsLCcnaM4dBEPZva2fE6FXAHs76G7Rc7s3yGyX/68G0nZMrUy+Vmpg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.973.13': + resolution: {integrity: sha512-pEHZqRkAlHfnfAU9tK+WpKv/gBNjGJrHMgA3A0iYRGyswBS2t0pfez+lWlwktb3Bqa0ovh7w/QJTFwp3fDxLNg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-locate-window@3.965.8': + resolution: {integrity: sha512-uUbMs1cBZPafD0ohUj6EwNf0fPZ534NvBxHox4hjX+0Rxq5paSYUem7+hi833pYrzrcnBATKIYpR02MDXT5M9g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/xml-builder@3.972.31': + resolution: {integrity: sha512-SzE4Pgyl+hDF+BuyuzxUSpwnuUu9lJuO1YGgteG89/4Qv0+2IQiVQqdbPV32IozLvXWQChPQcdkk/sKvb1QHiQ==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.2.4': + resolution: {integrity: sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==} + engines: {node: '>=18.0.0'} + + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + + '@earendil-works/pi-agent-core@0.79.1': + resolution: {integrity: sha512-PBPjBa2YBm9jauiLtHAKaSfVJ4Dvm3/nK/bR/oHebLjwBCS2tGx3aQDX7MSGAOXi6BejlhzbB/z82BkyAyNjjQ==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-ai@0.79.1': + resolution: {integrity: sha512-UnORwrcsTNLm4StEvoM8iEom0u87Te7BXEWxhec3iNXygWD6eEBosUoq9ddcveqtj/QpUZBMPWUu81cCtZxzkQ==} + engines: {node: '>=22.19.0'} + hasBin: true + + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} - '@esbuild/darwin-arm64@0.27.3': - resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + '@google/genai@1.52.0': + resolution: {integrity: sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@modelcontextprotocol/sdk': ^1.25.2 + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.3': - resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} - engines: {node: '>=18'} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.3': - resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} - engines: {node: '>=18'} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] - os: [freebsd] + os: [darwin] - '@esbuild/freebsd-x64@0.27.3': - resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} - engines: {node: '>=18'} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] - os: [freebsd] + os: [darwin] - '@esbuild/linux-arm64@0.27.3': - resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} - engines: {node: '>=18'} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.3': - resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} - engines: {node: '>=18'} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.3': - resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.27.3': - resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.27.3': - resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.27.3': - resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} - engines: {node: '>=18'} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.3': - resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} - engines: {node: '>=18'} + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.3': - resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} - engines: {node: '>=18'} + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.3': - resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} - engines: {node: '>=18'} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.3': - resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} - engines: {node: '>=18'} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] - os: [netbsd] + os: [linux] - '@esbuild/netbsd-x64@0.27.3': - resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} - engines: {node: '>=18'} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] - os: [netbsd] + os: [linux] - '@esbuild/openbsd-arm64@0.27.3': - resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} - engines: {node: '>=18'} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] - os: [openbsd] + os: [linux] - '@esbuild/openbsd-x64@0.27.3': - resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} - engines: {node: '>=18'} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] - os: [openbsd] + os: [linux] - '@esbuild/openharmony-arm64@0.27.3': - resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} - engines: {node: '>=18'} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] - os: [openharmony] + os: [linux] - '@esbuild/sunos-x64@0.27.3': - resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} - engines: {node: '>=18'} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] - os: [sunos] + os: [linux] - '@esbuild/win32-arm64@0.27.3': - resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} - engines: {node: '>=18'} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.3': - resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} - engines: {node: '>=18'} + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.3': - resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} - engines: {node: '>=18'} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] - '@onkernel/sdk@0.43.0': - resolution: {integrity: sha512-pvveMdVCzjtVqNeLI+yk+VBTMaIvRe/jevvKJqnHl2svlDxvT7Z0mNFeiAWsDLeh1TQL92aWEKZoyEVxRniO9w==} + '@mistralai/mistralai@2.2.1': + resolution: {integrity: sha512-uKU8CZmL2RzYKmplsU01hii4p3pe4HqJefpWNRWXm1Tcm0Sm4xXfwSLIy4k7ZCPlbETCGcp69E7hZs+WOJ5itQ==} + + '@onkernel/cua-agent@0.3.4': + resolution: {integrity: sha512-MlSbxmd/HrYTM7ZEHs0fXgisLOKhM7JGG2hrDDNS8ZjDzu/BjcZ4Vq7h6BE+RRaXGO32wskqif/SH+6Wf3bePg==} + + '@onkernel/cua-ai@0.3.1': + resolution: {integrity: sha512-85w4GRzskuGho+prPKAFFCYpDyWjIUEkUiJqPU/CTW2+/Co7B4qmeqm1A2T+No+y7C+4vDnbW3Bvvy7Q1nFWYg==} + + '@onkernel/sdk@0.49.0': + resolution: {integrity: sha512-nsq5OfkaNKxRTCdXQF8BSTj/Wl0iBIqyWoI/ATgQt15pV+59E22MsZ+IHPiVwwb33tXLtnOqUe5ffOxm7l3GHg==} + + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.1': + resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} + + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.1': + resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==} + + '@smithy/core@3.26.0': + resolution: {integrity: sha512-mLUktFAn+Pa2agl1J7VgtYNFWCX8/b4GMJSK1hCu4YCvtBfM6F8Os3EP4ry+DFFlXOf3wyvlgXhuUdFoy52D3g==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.4.2': + resolution: {integrity: sha512-18UMDMyrAbDcpmL1gLUA7ww0fRTcdCrSjSJOi2Sbld+tVjwD/pW+OAwjlScFLR7vvBnhZrIPQ7kVuTf1mnJLug==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.5.2': + resolution: {integrity: sha512-Ei/UK/QMhq0rKaMqGPlOAkE2yS9DZeYmZdk1RAKc3vp3zxgleZHZyBLlZv8yLsxljX4svCRuMTD6u3LLIcU4Bg==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/node-http-handler@4.7.3': + resolution: {integrity: sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.8.2': + resolution: {integrity: sha512-wfl1uwrAqMH9/pi4kqBo5LBcFwrJLxuDLqL7p7qNcJIFcyZDUc6pzhYk4CYv+DP7fIUpQCZumwNnkhPKS52osQ==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.5.2': + resolution: {integrity: sha512-7xHpmPY4rt0IOmeAA8EfjgEH8isT+587TCdy9H6a7d4OMi5CQ0oEHhWllunvPu4j4Cq0vTFwdxXN/kABWPjdyA==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.15.0': + resolution: {integrity: sha512-Z5TAOxygoFvybJV3igo5SloFflSokHx2hu1eFA+DxDTcn+FtKxUSui+rbTRG1pAafMA888Z3MVvCWUuvCrTXjg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} '@types/node@22.19.11': resolution: {integrity: sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==} - dotenv@17.3.1: - resolution: {integrity: sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==} - engines: {node: '>=12'} + '@types/retry@0.12.0': + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + + '@tzafon/lightcone@0.7.2': + resolution: {integrity: sha512-jzXTAOeE77FuuzP8J2dtxXxlBnN3Jb1o/iF7taVLGsT4ch8EemztVKjHH6KOJtu+3KvQzSioYoJCIX6pJ35jTA==} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} - esbuild@0.27.3: - resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + gaxios@7.1.5: + resolution: {integrity: sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg==} engines: {node: '>=18'} - hasBin: true - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] + gcp-metadata@8.1.2: + resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} + engines: {node: '>=18'} - get-tsconfig@4.13.6: - resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} + google-auth-library@10.7.0: + resolution: {integrity: sha512-QpTAbNJ36TliZLx3TTtahR8HG0hN9RllL1e3FymOvQSIKK8JmgV58H924ub2wa2DsS3ANjjP1Aw1N+Ramc8hqQ==} + engines: {node: '>=18'} - openai@6.25.0: - resolution: {integrity: sha512-mEh6VZ2ds2AGGokWARo18aPISI1OhlgdEIC1ewhkZr8pSIT31dec0ecr9Nhxx0JlybyOgoAT1sWeKtwPZzJyww==} + google-logging-utils@1.1.3: + resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} + engines: {node: '>=14'} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + + json-schema-to-ts@3.1.1: + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} + + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + openai@6.26.0: + resolution: {integrity: sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==} hasBin: true peerDependencies: ws: ^8.18.0 @@ -221,14 +502,53 @@ packages: zod: optional: true - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + openai@6.44.0: + resolution: {integrity: sha512-09/gH+8jH0RgUwsgWHAaxsKGRT5zVZ95IaJUnqAWj6XejIBmnFRwq2WUIF37VtDEsmGrtPmvCs5+yBSeZGWvkA==} + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} - tsx@4.21.0: - resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} - engines: {node: '>=18.0.0'} + partial-json@0.1.7: + resolution: {integrity: sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==} + + protobufjs@7.6.4: + resolution: {integrity: sha512-RJJPTTpvFfHcWLkIa2JFWK4XvtSzS0yEWDmunqHXli1h3JlkbcQZXDZdcWxv+JK3Xsl5/UFDPZ0iGm7DAengYw==} + engines: {node: '>=12.0.0'} + + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} hasBin: true + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + ts-algebra@2.0.0: + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typebox@1.1.38: + resolution: {integrity: sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -237,141 +557,730 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + snapshots: - '@esbuild/aix-ppc64@0.27.3': - optional: true + '@anthropic-ai/sdk@0.91.1(zod@4.4.3)': + dependencies: + json-schema-to-ts: 3.1.1 + optionalDependencies: + zod: 4.4.3 - '@esbuild/android-arm64@0.27.3': + '@aws-crypto/crc32@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.13 + tslib: 2.8.1 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.13 + '@aws-sdk/util-locate-window': 3.965.8 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.13 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.973.13 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-bedrock-runtime@3.1048.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.974.23 + '@aws-sdk/credential-provider-node': 3.972.58 + '@aws-sdk/eventstream-handler-node': 3.972.22 + '@aws-sdk/middleware-eventstream': 3.972.18 + '@aws-sdk/middleware-websocket': 3.972.31 + '@aws-sdk/token-providers': 3.1048.0 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/fetch-http-handler': 5.5.2 + '@smithy/node-http-handler': 4.7.3 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/core@3.974.23': + dependencies: + '@aws-sdk/types': 3.973.13 + '@aws-sdk/xml-builder': 3.972.31 + '@aws/lambda-invoke-store': 0.2.4 + '@smithy/core': 3.26.0 + '@smithy/signature-v4': 5.5.2 + '@smithy/types': 4.15.0 + bowser: 2.14.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.972.49': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.972.51': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/fetch-http-handler': 5.5.2 + '@smithy/node-http-handler': 4.8.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.972.56': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/credential-provider-env': 3.972.49 + '@aws-sdk/credential-provider-http': 3.972.51 + '@aws-sdk/credential-provider-login': 3.972.55 + '@aws-sdk/credential-provider-process': 3.972.49 + '@aws-sdk/credential-provider-sso': 3.972.55 + '@aws-sdk/credential-provider-web-identity': 3.972.55 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/credential-provider-imds': 4.4.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-login@3.972.55': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-node@3.972.58': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.49 + '@aws-sdk/credential-provider-http': 3.972.51 + '@aws-sdk/credential-provider-ini': 3.972.56 + '@aws-sdk/credential-provider-process': 3.972.49 + '@aws-sdk/credential-provider-sso': 3.972.55 + '@aws-sdk/credential-provider-web-identity': 3.972.55 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/credential-provider-imds': 4.4.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-process@3.972.49': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.972.55': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/token-providers': 3.1074.0 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-web-identity@3.972.55': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/eventstream-handler-node@3.972.22': + dependencies: + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-eventstream@3.972.18': + dependencies: + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-websocket@3.972.31': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/fetch-http-handler': 5.5.2 + '@smithy/signature-v4': 5.5.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.997.23': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.974.23 + '@aws-sdk/signature-v4-multi-region': 3.996.35 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/fetch-http-handler': 5.5.2 + '@smithy/node-http-handler': 4.8.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.996.35': + dependencies: + '@aws-sdk/types': 3.973.13 + '@smithy/signature-v4': 5.5.2 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1048.0': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1074.0': + dependencies: + '@aws-sdk/core': 3.974.23 + '@aws-sdk/nested-clients': 3.997.23 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/types@3.973.13': + dependencies: + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.965.8': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.31': + dependencies: + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.2.4': {} + + '@babel/runtime@7.29.7': {} + + '@earendil-works/pi-agent-core@0.79.1(ws@8.21.0)(zod@4.4.3)': + dependencies: + '@earendil-works/pi-ai': 0.79.1(ws@8.21.0)(zod@4.4.3) + ignore: 7.0.5 + typebox: 1.1.38 + yaml: 2.9.0 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-ai@0.79.1(ws@8.21.0)(zod@4.4.3)': + dependencies: + '@anthropic-ai/sdk': 0.91.1(zod@4.4.3) + '@aws-sdk/client-bedrock-runtime': 3.1048.0 + '@google/genai': 1.52.0 + '@mistralai/mistralai': 2.2.1 + '@smithy/node-http-handler': 4.7.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + openai: 6.26.0(ws@8.21.0)(zod@4.4.3) + partial-json: 0.1.7 + typebox: 1.1.38 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 optional: true - '@esbuild/android-arm@0.27.3': + '@google/genai@1.52.0': + dependencies: + google-auth-library: 10.7.0 + p-retry: 4.6.2 + protobufjs: 7.6.4 + ws: 8.21.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - '@esbuild/android-x64@0.27.3': + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 optional: true - '@esbuild/darwin-arm64@0.27.3': + '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true - '@esbuild/darwin-x64@0.27.3': + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - '@esbuild/freebsd-arm64@0.27.3': + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - '@esbuild/freebsd-x64@0.27.3': + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@esbuild/linux-arm64@0.27.3': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@esbuild/linux-arm@0.27.3': + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@esbuild/linux-ia32@0.27.3': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@esbuild/linux-loong64@0.27.3': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@esbuild/linux-mips64el@0.27.3': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': optional: true - '@esbuild/linux-ppc64@0.27.3': + '@img/sharp-libvips-linuxmusl-x64@1.2.4': optional: true - '@esbuild/linux-riscv64@0.27.3': + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 optional: true - '@esbuild/linux-s390x@0.27.3': + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - '@esbuild/linux-x64@0.27.3': + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@esbuild/netbsd-arm64@0.27.3': + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@esbuild/netbsd-x64@0.27.3': + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@esbuild/openbsd-arm64@0.27.3': + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@esbuild/openbsd-x64@0.27.3': + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - '@esbuild/openharmony-arm64@0.27.3': + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 optional: true - '@esbuild/sunos-x64@0.27.3': + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.11.1 optional: true - '@esbuild/win32-arm64@0.27.3': + '@img/sharp-win32-arm64@0.34.5': optional: true - '@esbuild/win32-ia32@0.27.3': + '@img/sharp-win32-ia32@0.34.5': optional: true - '@esbuild/win32-x64@0.27.3': + '@img/sharp-win32-x64@0.34.5': optional: true - '@onkernel/sdk@0.43.0': {} + '@mistralai/mistralai@2.2.1': + dependencies: + ws: 8.21.0 + zod: 4.4.3 + zod-to-json-schema: 3.25.2(zod@4.4.3) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@onkernel/cua-agent@0.3.4(ws@8.21.0)(zod@4.4.3)': + dependencies: + '@earendil-works/pi-agent-core': 0.79.1(ws@8.21.0)(zod@4.4.3) + '@earendil-works/pi-ai': 0.79.1(ws@8.21.0)(zod@4.4.3) + '@onkernel/cua-ai': 0.3.1(ws@8.21.0)(zod@4.4.3) + '@onkernel/sdk': 0.49.0 + sharp: 0.34.5 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@onkernel/cua-ai@0.3.1(ws@8.21.0)(zod@4.4.3)': + dependencies: + '@earendil-works/pi-ai': 0.79.1(ws@8.21.0)(zod@4.4.3) + '@tzafon/lightcone': 0.7.2 + openai: 6.44.0(ws@8.21.0)(zod@4.4.3) + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@onkernel/sdk@0.49.0': {} + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.1': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.1': {} + + '@smithy/core@3.26.0': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.4.2': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.5.2': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/node-http-handler@4.7.3': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.8.2': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.5.2': + dependencies: + '@smithy/core': 3.26.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/types@4.15.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 '@types/node@22.19.11': dependencies: undici-types: 6.21.0 - dotenv@17.3.1: {} + '@types/retry@0.12.0': {} + + '@tzafon/lightcone@0.7.2': {} + + agent-base@7.1.4: {} + + base64-js@1.5.1: {} + + bignumber.js@9.3.1: {} + + bowser@2.14.1: {} + + buffer-equal-constant-time@1.0.1: {} + + data-uri-to-buffer@4.0.1: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + detect-libc@2.1.2: {} + + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + + extend@3.0.2: {} + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + + gaxios@7.1.5: + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + transitivePeerDependencies: + - supports-color + + gcp-metadata@8.1.2: + dependencies: + gaxios: 7.1.5 + google-logging-utils: 1.1.3 + json-bigint: 1.0.0 + transitivePeerDependencies: + - supports-color + + google-auth-library@10.7.0: + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.1.5 + gcp-metadata: 8.1.2 + google-logging-utils: 1.1.3 + jws: 4.0.1 + transitivePeerDependencies: + - supports-color + + google-logging-utils@1.1.3: {} + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ignore@7.0.5: {} + + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 + + json-schema-to-ts@3.1.1: + dependencies: + '@babel/runtime': 7.29.7 + ts-algebra: 2.0.0 + + jwa@2.0.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 - esbuild@0.27.3: + jws@4.0.1: + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + + long@5.3.2: {} + + ms@2.1.3: {} + + node-domexception@1.0.0: {} + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + + openai@6.26.0(ws@8.21.0)(zod@4.4.3): optionalDependencies: - '@esbuild/aix-ppc64': 0.27.3 - '@esbuild/android-arm': 0.27.3 - '@esbuild/android-arm64': 0.27.3 - '@esbuild/android-x64': 0.27.3 - '@esbuild/darwin-arm64': 0.27.3 - '@esbuild/darwin-x64': 0.27.3 - '@esbuild/freebsd-arm64': 0.27.3 - '@esbuild/freebsd-x64': 0.27.3 - '@esbuild/linux-arm': 0.27.3 - '@esbuild/linux-arm64': 0.27.3 - '@esbuild/linux-ia32': 0.27.3 - '@esbuild/linux-loong64': 0.27.3 - '@esbuild/linux-mips64el': 0.27.3 - '@esbuild/linux-ppc64': 0.27.3 - '@esbuild/linux-riscv64': 0.27.3 - '@esbuild/linux-s390x': 0.27.3 - '@esbuild/linux-x64': 0.27.3 - '@esbuild/netbsd-arm64': 0.27.3 - '@esbuild/netbsd-x64': 0.27.3 - '@esbuild/openbsd-arm64': 0.27.3 - '@esbuild/openbsd-x64': 0.27.3 - '@esbuild/openharmony-arm64': 0.27.3 - '@esbuild/sunos-x64': 0.27.3 - '@esbuild/win32-arm64': 0.27.3 - '@esbuild/win32-ia32': 0.27.3 - '@esbuild/win32-x64': 0.27.3 - - fsevents@2.3.3: - optional: true + ws: 8.21.0 + zod: 4.4.3 + + openai@6.44.0(ws@8.21.0)(zod@4.4.3): + optionalDependencies: + ws: 8.21.0 + zod: 4.4.3 - get-tsconfig@4.13.6: + p-retry@4.6.2: dependencies: - resolve-pkg-maps: 1.0.0 + '@types/retry': 0.12.0 + retry: 0.13.1 - openai@6.25.0: {} + partial-json@0.1.7: {} - resolve-pkg-maps@1.0.0: {} + protobufjs@7.6.4: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.1 + '@types/node': 22.19.11 + long: 5.3.2 + + retry@0.13.1: {} + + safe-buffer@5.2.1: {} - tsx@4.21.0: + semver@7.8.5: {} + + sharp@0.34.5: dependencies: - esbuild: 0.27.3 - get-tsconfig: 4.13.6 + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 optionalDependencies: - fsevents: 2.3.3 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + + ts-algebra@2.0.0: {} + + tslib@2.8.1: {} + + typebox@1.1.38: {} typescript@5.9.3: {} undici-types@6.21.0: {} + + web-streams-polyfill@3.3.3: {} + + ws@8.21.0: {} + + yaml@2.9.0: {} + + zod-to-json-schema@3.25.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@4.4.3: {} diff --git a/pkg/templates/typescript/openai-computer-use/run_local.ts b/pkg/templates/typescript/openai-computer-use/run_local.ts deleted file mode 100644 index e57382a9..00000000 --- a/pkg/templates/typescript/openai-computer-use/run_local.ts +++ /dev/null @@ -1,133 +0,0 @@ -import * as dotenv from 'dotenv'; -import { Kernel } from '@onkernel/sdk'; -import { resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { Agent } from './lib/agent'; -import { KernelComputer } from './lib/kernel-computer'; -import { maybeStartReplay, maybeStopReplay } from './lib/replay'; -import { - createEventLogger, - emitBrowserDeleteDone, - emitBrowserDeleteStarted, - emitBrowserNewDone, - emitBrowserNewStarted, - emitSessionState, -} from './lib/logging'; - -dotenv.config({ override: true, quiet: true }); - -/** - * Local test script that creates a remote Kernel browser and runs the CUA agent. - * No Kernel app deployment needed. - * - * Usage: - * KERNEL_API_KEY=... OPENAI_API_KEY=... npx tsx run_local.ts --task "go to example.com and summarize it" - */ - -const DEFAULT_TASK = 'go to example.com and summarize what the page says'; - -export async function runLocalTest(args: string[] = process.argv.slice(2)): Promise { - if (!process.env.KERNEL_API_KEY) throw new Error('KERNEL_API_KEY is not set'); - if (!process.env.OPENAI_API_KEY) throw new Error('OPENAI_API_KEY is not set'); - - const client = new Kernel({ apiKey: process.env.KERNEL_API_KEY }); - const task = parseTask(args); - const replayEnabled = parseReplay(args); - const debug = args.includes('--debug'); - const onEvent = createEventLogger({ verbose: debug }); - - emitBrowserNewStarted(onEvent); - const browserCreateStartedAt = Date.now(); - const browser = await client.browsers.create({ timeout_seconds: 300 }); - emitBrowserNewDone(onEvent, browserCreateStartedAt, browser.browser_live_view_url); - emitSessionState(onEvent, browser.session_id, browser.browser_live_view_url); - - const computer = new KernelComputer(client, browser.session_id, onEvent); - const replay = await maybeStartReplay(client, browser.session_id, { - enabled: replayEnabled, - onEvent, - }); - - try { - await computer.goto('https://duckduckgo.com'); - - const agent = new Agent({ - model: 'gpt-5.4', - computer, - tools: [], - acknowledge_safety_check_callback: (m: string): boolean => { - console.log(`> safety check: ${m}`); - return true; - }, - }); - - await agent.runFullTurn({ - messages: [ - { - role: 'system', - content: `- Current date and time: ${new Date().toISOString()} (${new Date().toLocaleDateString( - 'en-US', - { weekday: 'long' }, - )})`, - }, - { - type: 'message', - role: 'user', - content: [ - { - type: 'input_text', - text: task, - }, - ], - }, - ], - print_steps: true, - debug, - show_images: false, - onEvent, - }); - } finally { - emitBrowserDeleteStarted(onEvent); - const browserDeleteStartedAt = Date.now(); - try { - const replayUrl = await maybeStopReplay(client, browser.session_id, replay, { onEvent }); - if (replayUrl) { - console.log(`> Replay URL: ${replayUrl}`); - } - await client.browsers.deleteByID(browser.session_id); - } finally { - emitBrowserDeleteDone(onEvent, browserDeleteStartedAt); - } - console.log('> Browser session deleted'); - } -} - -function parseTask(args: string[]): string { - const taskFromEquals = args.find((arg) => arg.startsWith('--task='))?.slice('--task='.length).trim(); - const taskFlagIndex = args.findIndex((arg) => arg === '--task'); - const nextArg = taskFlagIndex >= 0 ? args[taskFlagIndex + 1] : undefined; - const taskFromNext = nextArg && !nextArg.startsWith('--') ? nextArg.trim() : undefined; - const task = taskFromEquals || taskFromNext; - return task && task.length > 0 ? task : DEFAULT_TASK; -} - -function parseReplay(args: string[]): boolean { - const replayFromEquals = args.find((arg) => arg.startsWith('--replay='))?.slice('--replay='.length).trim(); - if (replayFromEquals) { - return !['0', 'false', 'no', 'off'].includes(replayFromEquals.toLowerCase()); - } - return args.includes('--replay'); -} - -function isDirectRun(): boolean { - const entry = process.argv[1]; - if (!entry) return false; - return resolve(entry) === resolve(fileURLToPath(import.meta.url)); -} - -if (isDirectRun()) { - runLocalTest().catch((error) => { - console.error(error); - process.exit(1); - }); -}