From 7ae2b09fe4a17f7d1ab39d492e34518bbb53c12a Mon Sep 17 00:00:00 2001 From: rgarcia <72655+rgarcia@users.noreply.github.com> Date: Fri, 12 Jun 2026 06:02:15 +0000 Subject: [PATCH 1/2] PR 4: remove deprecated provider packages from workspace Deletes packages/cua-{translator,openai,anthropic,gemini,tzafon,yutori} now that cua-cli is fully migrated to CuaAgentHarness + pi 0.79. Updates the root package.json workspaces, root tsconfig references, README (workspace tree, mermaid, package table, How-it-works, project layout), docs/architecture.md, and the update-docs authoring skill to match. Registry-side `npm deprecate` of the published packages is an explicit manual follow-up; this PR is a clean local removal so the repo only ships cua-ai, cua-agent, cua-cli, and ptywright. --- .agents/skills/update-docs/SKILL.md | 20 +- README.md | 180 +- docs/architecture.md | 527 ++-- package-lock.json | 2285 +++++++++-------- package.json | 6 - packages/cua-anthropic/README.md | 258 -- packages/cua-anthropic/package.json | 43 - packages/cua-anthropic/src/batch-tool.ts | 60 - packages/cua-anthropic/src/batch.ts | 254 -- packages/cua-anthropic/src/computer-tool.ts | 36 - packages/cua-anthropic/src/computer.ts | 323 --- packages/cua-anthropic/src/context.ts | 17 - packages/cua-anthropic/src/cua-extras.ts | 22 - packages/cua-anthropic/src/index.ts | 63 - packages/cua-anthropic/src/model.ts | 191 -- packages/cua-anthropic/src/official.ts | 140 - packages/cua-anthropic/src/payload-hook.ts | 127 - packages/cua-anthropic/src/pi/index.ts | 40 - packages/cua-anthropic/src/stream-wrapper.ts | 75 - packages/cua-anthropic/src/system-prompt.ts | 61 - packages/cua-anthropic/tsconfig.json | 9 - packages/cua-gemini/README.md | 240 -- packages/cua-gemini/package.json | 43 - packages/cua-gemini/src/batch-tool.ts | 222 -- packages/cua-gemini/src/batch.ts | 203 -- packages/cua-gemini/src/computer-tool.ts | 394 --- packages/cua-gemini/src/computer.ts | 365 --- packages/cua-gemini/src/coords.ts | 11 - packages/cua-gemini/src/cua-extras.ts | 14 - packages/cua-gemini/src/index.ts | 51 - packages/cua-gemini/src/model.ts | 159 -- packages/cua-gemini/src/official.ts | 78 - packages/cua-gemini/src/pi/index.ts | 30 - packages/cua-gemini/src/system-prompt.ts | 50 - packages/cua-gemini/tsconfig.json | 9 - packages/cua-openai/README.md | 217 -- packages/cua-openai/package.json | 43 - packages/cua-openai/src/batch-tool.ts | 38 - packages/cua-openai/src/batch.ts | 202 -- packages/cua-openai/src/cua-extras.ts | 39 - packages/cua-openai/src/extra-tool.ts | 39 - packages/cua-openai/src/extra.ts | 102 - packages/cua-openai/src/index.ts | 55 - packages/cua-openai/src/model.ts | 327 --- packages/cua-openai/src/official.ts | 97 - packages/cua-openai/src/pi/index.ts | 30 - packages/cua-openai/src/system-prompt.ts | 59 - packages/cua-openai/tsconfig.json | 9 - packages/cua-translator/README.md | 117 - packages/cua-translator/package.json | 25 - .../cua-translator/src/browser-session.ts | 123 - packages/cua-translator/src/computer-use.ts | 80 - packages/cua-translator/src/cua-extras.ts | 78 - packages/cua-translator/src/index.ts | 12 - packages/cua-translator/src/keysym.ts | 169 -- packages/cua-translator/src/scroll.ts | 37 - packages/cua-translator/src/translator.ts | 556 ---- packages/cua-translator/src/types.ts | 160 -- packages/cua-translator/tsconfig.json | 8 - packages/cua-tzafon/README.md | 44 - packages/cua-tzafon/package.json | 43 - packages/cua-tzafon/src/computer.ts | 391 --- packages/cua-tzafon/src/coords.ts | 28 - packages/cua-tzafon/src/index.ts | 45 - packages/cua-tzafon/src/model.ts | 230 -- packages/cua-tzafon/src/official.ts | 35 - packages/cua-tzafon/src/pi/index.ts | 296 --- packages/cua-tzafon/src/system-prompt.ts | 25 - packages/cua-tzafon/tsconfig.json | 9 - packages/cua-yutori/README.md | 11 - packages/cua-yutori/package.json | 43 - packages/cua-yutori/src/computer-tool.ts | 37 - packages/cua-yutori/src/computer.ts | 340 --- packages/cua-yutori/src/coords.ts | 9 - packages/cua-yutori/src/index.ts | 36 - packages/cua-yutori/src/model.ts | 116 - packages/cua-yutori/src/official.ts | 41 - packages/cua-yutori/src/pi/index.ts | 51 - packages/cua-yutori/src/pi/provider.ts | 243 -- packages/cua-yutori/src/system-prompt.ts | 15 - packages/cua-yutori/tsconfig.json | 9 - tsconfig.json | 6 - 82 files changed, 1358 insertions(+), 9973 deletions(-) delete mode 100644 packages/cua-anthropic/README.md delete mode 100644 packages/cua-anthropic/package.json delete mode 100644 packages/cua-anthropic/src/batch-tool.ts delete mode 100644 packages/cua-anthropic/src/batch.ts delete mode 100644 packages/cua-anthropic/src/computer-tool.ts delete mode 100644 packages/cua-anthropic/src/computer.ts delete mode 100644 packages/cua-anthropic/src/context.ts delete mode 100644 packages/cua-anthropic/src/cua-extras.ts delete mode 100644 packages/cua-anthropic/src/index.ts delete mode 100644 packages/cua-anthropic/src/model.ts delete mode 100644 packages/cua-anthropic/src/official.ts delete mode 100644 packages/cua-anthropic/src/payload-hook.ts delete mode 100644 packages/cua-anthropic/src/pi/index.ts delete mode 100644 packages/cua-anthropic/src/stream-wrapper.ts delete mode 100644 packages/cua-anthropic/src/system-prompt.ts delete mode 100644 packages/cua-anthropic/tsconfig.json delete mode 100644 packages/cua-gemini/README.md delete mode 100644 packages/cua-gemini/package.json delete mode 100644 packages/cua-gemini/src/batch-tool.ts delete mode 100644 packages/cua-gemini/src/batch.ts delete mode 100644 packages/cua-gemini/src/computer-tool.ts delete mode 100644 packages/cua-gemini/src/computer.ts delete mode 100644 packages/cua-gemini/src/coords.ts delete mode 100644 packages/cua-gemini/src/cua-extras.ts delete mode 100644 packages/cua-gemini/src/index.ts delete mode 100644 packages/cua-gemini/src/model.ts delete mode 100644 packages/cua-gemini/src/official.ts delete mode 100644 packages/cua-gemini/src/pi/index.ts delete mode 100644 packages/cua-gemini/src/system-prompt.ts delete mode 100644 packages/cua-gemini/tsconfig.json delete mode 100644 packages/cua-openai/README.md delete mode 100644 packages/cua-openai/package.json delete mode 100644 packages/cua-openai/src/batch-tool.ts delete mode 100644 packages/cua-openai/src/batch.ts delete mode 100644 packages/cua-openai/src/cua-extras.ts delete mode 100644 packages/cua-openai/src/extra-tool.ts delete mode 100644 packages/cua-openai/src/extra.ts delete mode 100644 packages/cua-openai/src/index.ts delete mode 100644 packages/cua-openai/src/model.ts delete mode 100644 packages/cua-openai/src/official.ts delete mode 100644 packages/cua-openai/src/pi/index.ts delete mode 100644 packages/cua-openai/src/system-prompt.ts delete mode 100644 packages/cua-openai/tsconfig.json delete mode 100644 packages/cua-translator/README.md delete mode 100644 packages/cua-translator/package.json delete mode 100644 packages/cua-translator/src/browser-session.ts delete mode 100644 packages/cua-translator/src/computer-use.ts delete mode 100644 packages/cua-translator/src/cua-extras.ts delete mode 100644 packages/cua-translator/src/index.ts delete mode 100644 packages/cua-translator/src/keysym.ts delete mode 100644 packages/cua-translator/src/scroll.ts delete mode 100644 packages/cua-translator/src/translator.ts delete mode 100644 packages/cua-translator/src/types.ts delete mode 100644 packages/cua-translator/tsconfig.json delete mode 100644 packages/cua-tzafon/README.md delete mode 100644 packages/cua-tzafon/package.json delete mode 100644 packages/cua-tzafon/src/computer.ts delete mode 100644 packages/cua-tzafon/src/coords.ts delete mode 100644 packages/cua-tzafon/src/index.ts delete mode 100644 packages/cua-tzafon/src/model.ts delete mode 100644 packages/cua-tzafon/src/official.ts delete mode 100644 packages/cua-tzafon/src/pi/index.ts delete mode 100644 packages/cua-tzafon/src/system-prompt.ts delete mode 100644 packages/cua-tzafon/tsconfig.json delete mode 100644 packages/cua-yutori/README.md delete mode 100644 packages/cua-yutori/package.json delete mode 100644 packages/cua-yutori/src/computer-tool.ts delete mode 100644 packages/cua-yutori/src/computer.ts delete mode 100644 packages/cua-yutori/src/coords.ts delete mode 100644 packages/cua-yutori/src/index.ts delete mode 100644 packages/cua-yutori/src/model.ts delete mode 100644 packages/cua-yutori/src/official.ts delete mode 100644 packages/cua-yutori/src/pi/index.ts delete mode 100644 packages/cua-yutori/src/pi/provider.ts delete mode 100644 packages/cua-yutori/src/system-prompt.ts delete mode 100644 packages/cua-yutori/tsconfig.json diff --git a/.agents/skills/update-docs/SKILL.md b/.agents/skills/update-docs/SKILL.md index dce3af6e..a5a6c6ff 100644 --- a/.agents/skills/update-docs/SKILL.md +++ b/.agents/skills/update-docs/SKILL.md @@ -41,24 +41,20 @@ For every doc update: Start with these source-of-truth checks: - Package topology: `package.json`, `tsconfig.json`, and `packages/*/package.json`. -- Design invariants: provider package roots stay generic, provider `/pi` subpaths isolate `pi-agent-core` bindings, provider packages expose relatively consistent APIs, `@onkernel/cua-translator` owns canonical actions, and `@onkernel/cua-cli` gets provider-specific behavior through translator/provider packages while owning orchestration. -- Translator flow: `packages/cua-translator/src/types.ts`, `translator.ts`, `cua-extras.ts`, `browser-session.ts`, and `computer-use.ts`. -- Provider root surfaces: each provider's `src/index.ts`, `model.ts`, `official.ts`, `batch.ts`, `computer.ts` or `extra.ts`, `cua-extras.ts`, and `system-prompt.ts`. -- Provider `/pi` bindings: each provider's `src/pi/index.ts` plus `*-tool.ts`; for Anthropic also check `payload-hook.ts` and `stream-wrapper.ts`. -- CLI runtime flow: `packages/cua-cli/src/agent.ts`, `cli.ts`, `config.ts`, `skills.ts`, `sessions.ts`, `named-sessions.ts`, `output/jsonl.ts`, `action/`, and `tui/`. -- Supported models and routing: `packages/cua-cli/src/models.ts`, `cli.ts`, provider package READMEs, and the top-level `README.md`. +- Design invariants: `@onkernel/cua-ai` owns provider-specific policy (catalog, tool schemas, payload transforms); `@onkernel/cua-agent` is provider-neutral runtime glue around `pi-agent-core` (no provider names in `packages/agent/src`); every provider difference reaches the agent as data through `CuaRuntimeSpec`; `@onkernel/cua-cli` composes both for orchestration. +- Model layer: `packages/ai/src/index.ts`, `getCuaModel`/`listCuaModels`/`parseCuaModelRef`, `resolveCuaRuntimeSpec`, provider adapters, and `api-keys.ts`. +- Execution layer: `packages/agent/src/index.ts`, `CuaAgent` and `CuaAgentHarness` wiring, and the canonical CUA tool executors against `@onkernel/sdk`. +- CLI runtime flow: `packages/cua-cli/src/cli.ts`, `harness.ts`, `harness-browser.ts`, `harness-models.ts`, `harness-sessions.ts`, `harness-named-sessions.ts`, `harness-skills.ts`, `print.ts`, `output/harness-jsonl.ts`, `action/`, and `tui/`. - TUI test infrastructure: `packages/ptywright/package.json`, `src/index.ts`, `src/session.ts`, `src/terminal.ts`, and `README.md`. -- External drift: provider computer-use docs, provider SDK versions, `@earendil-works/pi-*` versions, and `@onkernel/sdk` versions in package manifests. +- External drift: provider computer-use docs, `@earendil-works/pi-*` versions, and `@onkernel/sdk` versions in package manifests. Questions `architecture.md` should answer after each update: -- What owns the canonical action vocabulary? -- Which packages are generic provider glue, and which entry points are `pi-agent-core` specific? -- Do provider packages expose consistent root and `/pi` APIs for the CLI to compose? +- What owns the canonical action vocabulary and the model catalog? +- Where is the cua-ai vs cua-agent ownership boundary, and how do provider differences reach the agent without provider conditionals in `packages/agent/src`? - Where does Kernel SDK browser execution happen? -- What does the CLI compose at runtime? +- What does the CLI compose at runtime via `buildCuaHarness`? - Which package is dev/test infrastructure only? -- Are root single-invocation flows clearly separate from the CLI's `pi-agent-core` loop? ## Validation diff --git a/README.md b/README.md index 578f3d89..7eeeb782 100644 --- a/README.md +++ b/README.md @@ -42,14 +42,9 @@ All of them expect you to: ``` packages/ -├── ai/ # @onkernel/cua-ai - CUA model catalog + tool schemas + provider adapters (on npm) -├── agent/ # @onkernel/cua-agent - CuaAgent/CuaAgentHarness Kernel-browser execution loop (on npm) -├── cua-translator/ # @onkernel/cua-translator - [deprecated] shared SDK types + translator + browser-session -├── cua-openai/ # @onkernel/cua-openai - [deprecated] gpt-* (batch_computer_actions + computer_use_extra) -├── cua-anthropic/ # @onkernel/cua-anthropic - [deprecated] claude-* (computer_20251124 + batch_computer_actions + onPayload) -├── cua-gemini/ # @onkernel/cua-gemini - [deprecated] gemini-* (predefined functions + batch_computer_actions) -├── cua-yutori/ # @onkernel/cua-yutori - [deprecated] n1* (Navigator browser actions) -└── cua-cli/ # @onkernel/cua-cli - the CLI; depends on the cua-* providers above +├── ai/ # @onkernel/cua-ai - CUA model catalog + tool schemas + provider adapters (on npm) +├── agent/ # @onkernel/cua-agent - CuaAgent/CuaAgentHarness Kernel-browser execution loop (on npm) +└── cua-cli/ # @onkernel/cua-cli - the `cua` binary; built on cua-agent + cua-ai ``` **Building your own agent? Start here:** [`packages/agent`](packages/agent) @@ -58,42 +53,29 @@ computer-use loop against a Kernel browser. It sits on [`packages/ai`](packages/ai) (`@onkernel/cua-ai`), the model layer with the curated computer-use model catalog, canonical tool schemas, and per-provider adapters on top of pi-ai; reach for cua-ai directly only when you bring your -own execution. Both are published to npm. The `cua-*` packages below are -deprecated — cua-ai/cua-agent are the canonical source now — and remain only -to back the `cua` CLI. +own execution. Both are published to npm. ```mermaid flowchart LR - trans[("@onkernel/cua-translator")] - oai[("@onkernel/cua-openai")] - ant[("@onkernel/cua-anthropic")] - gem[("@onkernel/cua-gemini")] - yut[("@onkernel/cua-yutori")] + ai[("@onkernel/cua-ai")] + agent[("@onkernel/cua-agent")] cli[("@onkernel/cua-cli")] pi[("pi-agent-core / pi-ai / pi-tui / pi-coding-agent")] sdk[("@onkernel/sdk")] - trans --> oai - trans --> ant - trans --> gem - trans --> yut - trans --> sdk - oai --> cli - ant --> cli - gem --> cli - yut --> cli + ai --> agent + agent --> cli + ai --> cli + pi --> agent pi --> cli + sdk --> agent + sdk --> cli ``` -| Package | What it ships | -| ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -| [`@onkernel/cua-ai`](packages/ai) | Computer-use model catalog (`getCuaModel`/`listCuaModels`), canonical CUA tool schemas, and provider adapters/runtime specs built on pi-ai. On npm. | -| [`@onkernel/cua-agent`](packages/agent) | `CuaAgent`/`CuaAgentHarness` classes that execute cua-ai tool calls against a Kernel browser, screenshot loop included. On npm. | -| [`@onkernel/cua-translator`](packages/cua-translator) | **Deprecated** (use `cua-ai`/`cua-agent`). Provider-agnostic `ComputerTranslator`, key/scroll/drag math, `goto`/`back`/`forward`/`url` builders, browser-session helper. | -| [`@onkernel/cua-openai`](packages/cua-openai) | **Deprecated** (use `cua-ai`/`cua-agent`). `batch_computer_actions` + `computer_use_extra` AgentTools and JSON Schemas for OpenAI computer-use models. | -| [`@onkernel/cua-anthropic`](packages/cua-anthropic) | **Deprecated** (use `cua-ai`/`cua-agent`). `computer` (built-in `computer_20251124`) + `batch_computer_actions` AgentTools, beta-header stream wrapper, payload hook. | -| [`@onkernel/cua-gemini`](packages/cua-gemini) | **Deprecated** (use `cua-ai`/`cua-agent`). 13 per-action AgentTools matching Gemini's predefined computer-use functions, plus `batch_computer_actions`. Coordinate denormalization. | -| [`@onkernel/cua-yutori`](packages/cua-yutori) | **Deprecated** (use `cua-ai`/`cua-agent`). AgentTools matching Yutori Navigator browser actions, with outbound payload filtering so Yutori uses its built-in action set. | -| [`@onkernel/cua-cli`](packages/cua-cli) | The `cua` binary: argv parsing, config, sessions, skills, JSONL output, pi-tui front-end. | +| Package | What it ships | +| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| [`@onkernel/cua-ai`](packages/ai) | Computer-use model catalog (`getCuaModel`/`listCuaModels`), canonical CUA tool schemas, and provider adapters/runtime specs built on pi-ai. On npm. | +| [`@onkernel/cua-agent`](packages/agent) | `CuaAgent`/`CuaAgentHarness` classes that execute cua-ai tool calls against a Kernel browser, screenshot loop included. On npm. | +| [`@onkernel/cua-cli`](packages/cua-cli) | The `cua` binary: argv parsing, sessions, skills, JSONL output, pi-tui front-end. | --- @@ -154,42 +136,26 @@ cua -p -o jsonl "open example.com and tell me the heading" ## How it works -1. **Agent loop** — `pi-agent-core`'s `Agent` owns the message - transcript, tool execution, and streaming. `pi-ai` handles the actual - HTTP call to OpenAI Responses, Anthropic Messages, or Google - Generative AI. -2. **Translator** — `@onkernel/cua-translator` exposes a canonical - `ModelAction` vocabulary (click/scroll/type/keypress/drag/wait, plus - the cua-added `goto`/`back`/`forward`/`url`) and translates batched - sequences into a single Kernel `browsers.computer.batch` call. Read - actions (`url`, `screenshot`) flush pending writes and return - structured results. -3. **Provider adapters** — one focused npm package per provider wraps - the translator with `pi-agent-core` `AgentTool`s shaped exactly the - way that provider expects. Each adapter ships: - - The official action vocabulary (with citations). - - The cua-added `batch_computer_actions` tool with the same canonical - action union, so users get one-round-trip multi-action calls - consistently across providers. - - Any provider-specific glue (Anthropic's `onPayload` tool-spec - injection + `computer-use-2025-11-24` beta header, Gemini's - 0-1000 coord denormalization, …). +1. **Model layer** — `@onkernel/cua-ai` owns the curated computer-use + model catalog (`getCuaModel`/`listCuaModels`), the canonical CUA + tool-call schemas, and per-provider adapters on top of `pi-ai` so + every model emits the same `CuaAction` vocabulary. +2. **Execution layer** — `@onkernel/cua-agent` wraps `pi-agent-core`'s + `Agent`/`AgentHarness`. `CuaAgentHarness` runs the + prompt/screenshot/tool loop against a Kernel browser: it dispatches + canonical CUA tool calls into Kernel SDK `browsers.computer.*` calls + and captures a fresh screenshot back to the model on every turn. +3. **CLI** — `@onkernel/cua-cli` assembles a `CuaAgentHarness` from + command-line flags, env-var-based API keys, a `JsonlSessionRepo` for + transcripts, and pi skills; renders the result either as plain text + (`--print`), JSONL events (`-o jsonl`), or an interactive pi-tui + front-end. 4. **Browser** — a fresh Kernel cloud browser session per run (or per resume) with optional named profile load/save. Every screenshot the model sees is a real PNG of a real browser tab. -Per-provider differences in one place: - -| | OpenAI gpt-5.5 | Anthropic claude-opus-4-7 | Google gemini-3-flash-preview | -| --------------------- | -------------------------------------------------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------- | -| Transport | HTTP SSE (`api.openai.com/v1/responses`) | HTTP SSE (`api.anthropic.com/v1/messages`) | HTTP SSE (`generativelanguage.googleapis.com`) | -| Beta header | none | `anthropic-beta: computer-use-2025-11-24` | none | -| Computer tool surface | `batch_computer_actions` + `computer_use_extra` (custom) | built-in `computer_20251124` + `batch_computer_actions` (cua-added) | 13 predefined functions + `batch_computer_actions` (cua-added) | -| Action shape | `{type:"click", x, y}`, `{type:"goto", url}` | `{action:"left_click", coordinate:[x,y]}` | per-function (`click_at {x, y}`, `navigate {url}`, …) — 0-1000 coords | -| Tool result | `function_call_output` w/ text + image | `tool_result` w/ text + image | `functionResponse` w/ text + image | - -All three flavors land in the same `ComputerTranslator` and the same -Kernel SDK calls. See [`docs/architecture.md`](docs/architecture.md). +See [`docs/architecture.md`](docs/architecture.md) for the full +end-to-end flow. --- @@ -349,93 +315,23 @@ ln -s "$(pwd)/skills/cua-cli" ~/.agents/skills/cua-cli --- -## Provider package details - -Each provider package documents its own action reference (official -per-provider actions vs cua extensions, with citations) and a -copy-pasteable "embed in your own agent" snippet: - -- [`@onkernel/cua-openai`](packages/cua-openai/README.md) -- [`@onkernel/cua-anthropic`](packages/cua-anthropic/README.md) -- [`@onkernel/cua-gemini`](packages/cua-gemini/README.md) -- [`@onkernel/cua-yutori`](packages/cua-yutori/README.md) - -The cua-added actions (`goto`, `back`, `forward`, `url`, plus the -`batch_computer_actions` tool itself) are clearly marked as "cua -extension, not in the provider's official set" in each package's README -and live in `src/cua-extras.ts` for easy removal. - ---- - ## Project layout ``` bin/ -└── cua # POSIX wrapper script (symlink into your $PATH) +└── cua # POSIX wrapper script (symlink into your $PATH) skills/ -└── cua-cli/SKILL.md # skill aimed at OTHER agents driving cua via shell +└── cua-cli/SKILL.md # skill aimed at OTHER agents driving cua via shell packages/ -├── ai/ # @onkernel/cua-ai — model layer (see packages/ai/README.md) -├── agent/ # @onkernel/cua-agent — Kernel-browser execution layer (see packages/agent/README.md) -├── cua-translator/ -│ └── src/ -│ ├── types.ts # ModelAction / BatchAction / errors -│ ├── keysym.ts # X11 keysym map + splitKeypress -│ ├── scroll.ts # pixel-delta ↔ wheel-tick helpers -│ ├── cua-extras.ts # goto/back/forward/url builders -│ ├── translator.ts # ComputerTranslator -│ └── browser-session.ts # @onkernel/sdk wrapper (open + attach) -├── cua-openai/ -│ └── src/ -│ ├── official.ts # OpenAI computer-use official 9 actions (TypeBox + JSDoc citations) -│ ├── cua-extras.ts # cua-added actions schema -│ ├── batch-tool.ts # batch_computer_actions AgentTool -│ ├── extra-tool.ts # computer_use_extra AgentTool -│ └── system-prompt.ts # OPENAI_BATCH_INSTRUCTIONS preamble -├── cua-anthropic/ -│ └── src/ -│ ├── official.ts # action shapes for computer_20241022/20250124/20251124 + spec const -│ ├── cua-extras.ts # cua-added actions for the batch tool -│ ├── computer-tool.ts # AgentTool that routes Anthropic tool_use blocks to translator -│ ├── batch-tool.ts # batch_computer_actions (Anthropic input_schema) -│ ├── stream-wrapper.ts # wrapAnthropicStream + registerAnthropicProvider -│ ├── payload-hook.ts # anthropicComputerOnPayload + composeOnPayload -│ └── system-prompt.ts # ANTHROPIC_COMPUTER_INSTRUCTIONS + batch nudge -├── cua-gemini/ -│ └── src/ -│ ├── official.ts # GeminiAction enum + PREDEFINED_COMPUTER_USE_FUNCTIONS + arg shapes -│ ├── coords.ts # denormalize 0-1000 → pixels -│ ├── cua-extras.ts # cua-added action types (just `url`) -│ ├── computer-tool.ts # 13 per-action AgentTools dispatching to translator.executeBatch -│ ├── batch-tool.ts # batch_computer_actions (Gemini FunctionDeclaration) -│ └── system-prompt.ts # GEMINI_COMPUTER_INSTRUCTIONS + batch nudge -├── cua-yutori/ -│ └── src/ -│ ├── official.ts # Yutori Navigator action enum + supported n1/n1.5 ids -│ ├── coords.ts # denormalize 0-1000 → pixels -│ ├── computer-tool.ts # per-action AgentTools dispatching to translator.executeBatch -│ └── system-prompt.ts # minimal Yutori runtime note -└── cua-cli/ - └── src/ - ├── cli.ts # argv parsing, mode dispatch - ├── config.ts # TOML loader (OpenAI + Anthropic + Gemini + Kernel) - ├── agent.ts # provider routing + agent factory + synthetic Gemini model fallback - ├── agent-prompt.ts # initial-screenshot wrapping for first user turn - ├── named-sessions.ts # `cua session start/stop/list` + `-s ` storage / liveness - ├── sessions.ts # SessionManager helpers (transcripts) - ├── skills.ts # skill discovery (~/.agents/skills) + /skill: expansion - ├── action/ # constrained subcommand prompts + runner - ├── output/jsonl.ts # JSONL event sink for -o jsonl - └── tui/ # pi-tui interactive front-end +├── ai/ # @onkernel/cua-ai — model layer (see packages/ai/README.md) +├── agent/ # @onkernel/cua-agent — Kernel-browser execution layer (see packages/agent/README.md) +└── cua-cli/ # @onkernel/cua-cli — the `cua` binary (see packages/cua-cli/README.md) ``` --- ## Roadmap -- Publish the remaining per-provider `@onkernel/cua-*` packages to npm - (`@onkernel/cua-ai` and `@onkernel/cua-agent` are already published) so - `kernel/cli` templates and other consumers can depend on them directly. - Auto-respawn dead Kernel sessions when `-s ` is used (today we refuse with a clear error and ask the user to re-`session start`). - `--local` Docker-backed browser as an alternative to Kernel cloud. diff --git a/docs/architecture.md b/docs/architecture.md index dc8f512c..53726355 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -5,31 +5,22 @@ someone who wants to read the code, contribute, or fork. ## Design goals and invariants +- `@onkernel/cua-ai` owns provider-specific policy: the curated + computer-use model catalog, canonical CUA tool-call schemas, provider + default system prompts, and provider payload transforms / protocol + quirks. - `@onkernel/cua-agent` is provider-neutral runtime glue around - `pi-agent-core`. It should never branch on provider identity directly. - Provider-specific behavior must come from `@onkernel/cua-ai`. -- Provider packages are generic glue between a model provider and Kernel - browsers. Their package roots expose provider-neutral helpers, tool - specs, and execution functions that can be embedded in non-`pi` loops. -- `pi-agent-core` integrations live behind explicit `/pi` subpaths: - `@onkernel/cua-openai/pi`, `@onkernel/cua-anthropic/pi`, and - `@onkernel/cua-gemini/pi`. Keep `AgentTool`, `pi-ai`, payload-hook, - and stream-wrapper compatibility code out of the package roots. -- `@onkernel/cua-translator` owns the canonical `ModelAction[]` - vocabulary and the Kernel SDK execution path. Provider packages adapt - provider-native action shapes into that vocabulary before dispatch. -- `@onkernel/cua-cli` should get provider-specific behavior only by - depending on `@onkernel/cua-translator` and the relevant - `@onkernel/cua-` package. Provider packages should expose - relatively consistent root and `/pi` APIs so CLI wiring stays - provider-shaped, not provider-special-cased. -- `@onkernel/cua-cli` owns orchestration: config, model routing, - provider `/pi` bindings, coding tools, skills, sessions, output modes, - and the TUI. It should compose providers, not define their wire - schemas. + `pi-agent-core`'s `Agent` / `AgentHarness`. It executes canonical CUA + tool calls against Kernel cloud browsers via `@onkernel/sdk` and never + branches on provider identity — every provider difference arrives as + data through `CuaRuntimeSpec`. +- `@onkernel/cua-cli` owns orchestration: argv parsing, env-var-based + auth, session and skill resolution, JSONL/plain-text output, and the + pi-tui interactive front-end. It composes `CuaAgentHarness` from + cua-agent and the model catalog from cua-ai. - `@onkernel/ptywright` is development/test infrastructure for terminal and TUI regression tests. It is part of the monorepo build graph, but - not part of the runtime browser/model/provider path. + not part of the runtime browser/model path. ## `cua-ai` vs `cua-agent` ownership boundary @@ -38,12 +29,13 @@ someone who wants to read the code, contribute, or fork. - `@onkernel/cua-ai` owns provider-specific policy: - provider model refs and provider resolution - provider default system prompts - - provider payload transforms and protocol quirks (for example, Yutori tool serialization policy) + - provider payload transforms and protocol quirks - canonical CUA tool-definition exports - `@onkernel/cua-agent` owns browser execution orchestration: - - `CuaAgent` / `CuaAgentHarness` class wiring around `@earendil-works/pi-agent-core` + - `CuaAgent` / `CuaAgentHarness` wiring around + `@earendil-works/pi-agent-core` - executing canonical CUA tool calls against Kernel browsers - - typed executor coverage and translator integration + - typed executor coverage and screenshot handling The boundary is a single data seam. Every provider difference arrives in `@onkernel/cua-agent` as data through `CuaRuntimeSpec` — `toolDefinitions`, @@ -57,16 +49,7 @@ decides *whether and how* to use a capability (policy), the agent decides The invariant: `packages/agent/src` contains no provider names and no provider conditionals. A new provider difference is a new or extended `CuaRuntimeSpec`/`CuaPayloadContext` field plus provider code in -`@onkernel/cua-ai` — never a branch in `@onkernel/cua-agent`. The grep test -is literal: searching agent `src/` for a provider name should only ever hit -doc comments. - -One deliberate exception to "push it upstream": generic model imprecision. -Models of every provider are loose about things like key naming -(`ctrl`/`cmd`/`ArrowLeft`/word-form punctuation), so the agent-side -translator absorbs that nondeterminism when mapping canonical actions to -Kernel's X11 key vocabulary. That is corrective plumbing for model output in -general, not provider policy, and it stays in `@onkernel/cua-agent`. +`@onkernel/cua-ai` — never a branch in `@onkernel/cua-agent`. ## Layers @@ -75,188 +58,116 @@ general, not provider policy, and it stays in `@onkernel/cua-agent`. ```text @onkernel/cua-cli (the binary) -├── @onkernel/cua-openai (root = generic; /pi = pi-agent-core bindings) -├── @onkernel/cua-anthropic (root = generic; /pi = pi-agent-core bindings) -├── @onkernel/cua-gemini (root = generic; /pi = pi-agent-core bindings) -└── @onkernel/cua-translator (the only package that talks to @onkernel/sdk directly) +├── @onkernel/cua-agent (CuaAgent/CuaAgentHarness; pi-agent-core wrapper) +│ └── @onkernel/cua-ai (model catalog, tool schemas, provider adapters) +└── @onkernel/cua-ai (also depended on directly for the model catalog) Dev/test: -└── @onkernel/ptywright (PTY-backed TUI regression harness) +└── @onkernel/ptywright (PTY-backed TUI regression harness) External: ├── @earendil-works/pi-agent-core # Agent loop, tool execution, streaming, steering -│ └── @earendil-works/pi-ai # Provider transport (OpenAI Responses, Anthropic Messages, Google GenAI) -├── @earendil-works/pi-coding-agent # bash / read / write / edit / grep / find / ls AgentTools + SessionManager + skills +│ └── @earendil-works/pi-ai # Provider transport (OpenAI Responses, Anthropic Messages, Google GenAI, Tzafon, Yutori) +├── @earendil-works/pi-coding-agent # bash / read / write / edit / grep / find / ls AgentTools ├── @earendil-works/pi-tui # Terminal, Editor, Image, differential renderer -├── openai / @anthropic-ai/sdk / @google/genai # provider SDKs for the provider-root single-invocation helpers -└── @onkernel/sdk # Kernel cloud browser API +└── @onkernel/sdk # Kernel cloud browser API ``` ```mermaid flowchart LR - trans[("@onkernel/cua-translator")] - oai[("@onkernel/cua-openai")] - ant[("@onkernel/cua-anthropic")] - gem[("@onkernel/cua-gemini")] + ai[("@onkernel/cua-ai")] + agent[("@onkernel/cua-agent")] cli[("@onkernel/cua-cli")] pty[("@onkernel/ptywright")] pi[("pi-agent-core / pi-ai / pi-tui / pi-coding-agent")] sdk[("@onkernel/sdk")] - trans --> oai - trans --> ant - trans --> gem - trans --> sdk - oai --> cli - ant --> cli - gem --> cli + ai --> agent + agent --> cli + ai --> cli + pi --> agent pi --> cli + sdk --> agent + sdk --> cli pty --> cli ``` `tsc -b` from the repo root builds packages in dependency order via -TypeScript project references, including `@onkernel/ptywright` before -`@onkernel/cua-cli`. `npm install` symlinks workspace packages so each -package's `@onkernel/cua-*` import resolves to the local `dist/`. +TypeScript project references. `npm install` symlinks workspace packages +so each package's `@onkernel/cua-*` import resolves to the local `dist/`. The root `npm run build` also runs `@onkernel/ptywright`'s native Ghostty-backed addon build when present. ## Per-package responsibilities -### `@onkernel/cua-translator` - -The provider-agnostic core. Everything else depends on it; it depends -only on `@onkernel/sdk`. - -- `types.ts` — `ModelAction`, `BatchAction*`, `BatchExecutionResult`, - `ActionValidationError`, `ALLOWED_MODEL_ACTION_TYPES`. -- `keysym.ts` — X11 keysym map + `splitKeypress`. -- `scroll.ts` — `modelScrollDeltaToWheelTicks`, - `wheelTicksFromAmount`. -- `cua-extras.ts` — the cua-added action builders that all providers - share: `gotoBatchActions`, `backBatchActions`, `forwardBatchActions`, - `currentUrlCopyActions`, plus ModelAction constructors. Clearly - labeled as "cua extension, not in any provider's official set". -- `translator.ts` — `ComputerTranslator` (executeBatch w/ read - coalescing, screenshotRaw/Base64, currentUrl), `translateToBatchAction`, - `toSdkAction`. -- `browser-session.ts` — `open()` for Kernel cloud browsers (with - optional profile lookup/create-if-missing). -- `computer-use.ts` — provider-neutral `ComputerUseModel` interface + - single-invocation `runComputerUse()` helper for non-`pi` consumers. - -The translator accepts a canonical `ModelAction[]`. Provider adapter -packages map their model's own action shape to `ModelAction` before -calling `executeBatch`. - -### `@onkernel/cua-openai` - -OpenAI adapter. - -- Package root is provider-neutral: `openai(modelId)`, tool specs, - execution helpers, official action schemas, and prompt constants. -- `/pi` subpath owns `pi-agent-core` bindings: - `createOpenAIComputerTools`. -- `official.ts` — TypeBox schemas + types for OpenAI's official 9 - computer actions (`click`, `double_click`, `scroll`, `type`, `wait`, - `keypress`, `drag`, `move`, `screenshot`) with the optional `keys` - modifier array. Cites - [platform.openai.com/docs/guides/tools-computer-use](https://platform.openai.com/docs/guides/tools-computer-use). -- `cua-extras.ts` — schema entries for the cua-added actions - (`goto`, `back`, `forward`, `url`). -- `batch.ts` / `extra.ts` — root, provider-neutral tool specs + - execution helpers for `batch_computer_actions` and - `computer_use_extra`. -- `model.ts` — root `openai(modelId)` factory for single-invocation - `runComputerUse()` calls. -- `system-prompt.ts` — prompt constants for both the root model path and - the `/pi` custom-tool path. -- `pi/index.ts` — `pi-agent-core` bindings: `createOpenAIComputerTools`. - -### `@onkernel/cua-anthropic` - -Anthropic Claude adapter. - -- Package root is provider-neutral: `anthropic(modelId)`, built-in - computer/batch execution helpers, tool specs, and prompt builders. -- `/pi` subpath owns `pi-agent-core` bindings and transport glue: - `createAnthropicComputerTools`, `anthropicComputerOnPayload`, - `composeOnPayload`, `wrapAnthropicStream`, and - `registerAnthropicProvider`. -- `official.ts` — action types for `computer_20241022`, - `computer_20250124`, `computer_20251124` plus `ANTHROPIC_COMPUTER_TOOL` - spec const + `ANTHROPIC_COMPUTER_USE_BETA` header value. Cites - [docs.claude.com/en/docs/agents-and-tools/computer-use](https://docs.claude.com/en/docs/agents-and-tools/computer-use). -- `cua-extras.ts` — `ANTHROPIC_CUA_EXTRA_ACTION_TYPES` (`goto`, - `back`, `forward`, `url`) for the batch tool. -- `computer.ts` / `batch.ts` — root, provider-neutral execution helpers - for Anthropic's built-in `computer` tool plus cua's - `batch_computer_actions`. -- `model.ts` — root `anthropic(modelId)` factory for single-invocation - `runComputerUse()` calls. -- `stream-wrapper.ts` / `payload-hook.ts` — `pi`-specific transport glue - used only from `@onkernel/cua-anthropic/pi`. -- `system-prompt.ts` — `ANTHROPIC_COMPUTER_INSTRUCTIONS` + - `ANTHROPIC_BATCH_INSTRUCTIONS`, joinable via - `buildAnthropicSystemPrompt`. -- `pi/index.ts` — `pi-agent-core` bindings: - `createAnthropicComputerTools`, payload hooks, stream wrapper. - -### `@onkernel/cua-gemini` - -Google Gemini adapter. - -- Package root is provider-neutral: `gemini(modelId)`, Gemini function - declarations, execution helpers, coordinate helpers, and prompt - builders. -- `/pi` subpath owns `pi-agent-core` bindings: - `createGeminiComputerTools`. -- `official.ts` — `GeminiAction` enum + - `PREDEFINED_COMPUTER_USE_FUNCTIONS` + `GeminiFunctionArgs`. Cites - [ai.google.dev/gemini-api/docs/computer-use](https://ai.google.dev/gemini-api/docs/computer-use). -- `coords.ts` — `denormalizeX` / `denormalizeY` (0-1000 → pixels - using the configured screen size). -- `cua-extras.ts` — `GEMINI_CUA_EXTRA_ACTION_TYPES` (only `url` — - Gemini's predefined set already covers `goto`/`back`/`forward`). -- `computer.ts` — root Gemini function declarations + - `executeGeminiFunctionCall()` for provider-neutral loops. -- `batch.ts` — root `batch_computer_actions` declaration + - execution helper. -- `model.ts` — root `gemini(modelId)` factory for single-invocation - `runComputerUse()` calls. -- `computer-tool.ts` / `batch-tool.ts` — `pi-agent-core` bindings kept - behind the `/pi` subpath. -- `batch.ts` uses **pixel coordinates** (NOT Gemini's 0-1000 - convention); the system prompt explicitly highlights this distinction. -- `system-prompt.ts` — `GEMINI_COMPUTER_INSTRUCTIONS` + - `GEMINI_BATCH_INSTRUCTIONS`, joinable via - `buildGeminiSystemPrompt`. -- `pi/index.ts` — `pi-agent-core` bindings: `createGeminiComputerTools`. +### `@onkernel/cua-ai` + +The model layer. Curates the supported computer-use model catalog and +the canonical CUA tool-call schemas every provider conforms to. + +- `getCuaModel(ref)` / `listCuaModels()` / `parseCuaModelRef(ref)` / + `CuaModelRef` — catalog lookup keyed on `provider:model` refs. +- `resolveCuaRuntimeSpec(model)` — returns the `CuaRuntimeSpec` + consumed by `@onkernel/cua-agent`: `toolDefinitions`, `toolExecutors`, + `defaultSystemPrompt`, `coordinateSystem`, `screenshot`, `onPayload`. +- Provider adapters on top of `pi-ai` for OpenAI, Anthropic, Google, + Tzafon, and Yutori — including each provider's payload transforms and + protocol quirks (Anthropic computer-use beta header, Gemini 0-1000 + coord denormalization, …). +- API-key env-var conventions: + `cuaApiKeyEnvVarsForProvider(provider)`, `getCuaEnvApiKey(provider)`, + `requireCuaEnvApiKey(provider)`, plus the `…ForModel(refOrModel)` + variants. + +### `@onkernel/cua-agent` + +The execution layer. Wraps `pi-agent-core` with Kernel-browser plumbing +for canonical CUA tools. + +- `CuaAgent` — direct `pi-agent-core` `Agent` integration for bounded + loops and raw message-state access. +- `CuaAgentHarness` — `pi-agent-core` `AgentHarness` integration with + session-backed transcripts (`prompt`, `subscribe`, `compact`, + `setModel`, `followUp`, `steer`, …). +- Re-exports the full `pi-agent-core` 0.79 surface that consumers (like + `cua-cli`) need: `JsonlSessionRepo`, `Session`, `loadSkills`, + `loadPromptTemplates`, `formatSkillsForSystemPrompt`, + `compact()` / `shouldCompact` / `estimateContextTokens`, + `NodeExecutionEnv`, and harness event types. +- Executes canonical CUA tool calls (the `CuaAction` vocabulary) against + the Kernel SDK: coalesces consecutive write actions, dispatches via + `client.browsers.computer.batch`, and captures fresh screenshots via + `client.browsers.computer.captureScreenshot` for the model to see. ### `@onkernel/cua-cli` -The `cua` binary itself. Wires the four packages above into a -`pi-agent-core` agent with a `pi-tui` interactive front-end. +The `cua` binary itself. Composes a `CuaAgentHarness` from argv flags, +env-var-based API keys, a `JsonlSessionRepo`, pi skills, and the pi +coding tools, then renders the result to text, JSONL, or pi-tui. - `cli.ts` — argv parsing, mode dispatch. -- `config.ts` — TOML loader (OpenAI + Anthropic + Gemini + Kernel, - per-provider/per-model knobs). -- `agent.ts` — provider routing + agent factory. Resolves the - provider from the model id, picks the right tool set + system prompt - + payload hook + `streamFn` wrapper per model. This package owns the - full `pi-agent-core` loop and imports the explicit `/pi` bindings from - each provider package. -- `agent-prompt.ts` — initial-screenshot wrapping for the first user - turn. -- `sessions.ts` — transcript persistence / replay via `SessionManager` - plus `cua-browser` custom entries. -- `named-sessions.ts` — persisted Kernel browser reuse metadata + - liveness checks for `cua session start|stop|list|show` and `-s `. -- `skills.ts` — skill discovery + `/skill:` expansion. -- `action/` — constrained one-shot prompts + bounded runner for `cua - open|click|type|press|observe|url|do`. -- `output/jsonl.ts` — JSONL event sink for `-o jsonl`. -- `tui/` — pi-tui Terminal + Editor + container layout, screenshot - widget, status line, capabilities banner, message list. +- `harness.ts` — `buildCuaHarness(opts)`: one assembly function that + produces the `CuaAgentHarness` shared by `--print`, action + subcommands, and the interactive TUI. +- `harness-browser.ts` — Kernel SDK browser lifecycle + (`client.browsers.create`/`retrieve`/`deleteByID`) with optional + named-profile load/save. +- `harness-models.ts` — `-m` / `--model` resolution over + `listCuaModels()`; `cua models` printer over the same catalog. +- `harness-sessions.ts` — `JsonlSessionRepo` wiring for `--continue`, + `--resume`, `--session `, and the `cua-browser` custom entry. +- `harness-named-sessions.ts` — persisted Kernel browser metadata for + `cua session start|stop|list|show` and `-s `. +- `harness-skills.ts` — pi `loadSkills` over `~/.agents/skills`, + `/.agents/skills`, and `--skill `; `/skill:` + expansion. +- `action/` — constrained one-shot prompts (`open|click|type|press|observe|url|screenshot|do`) + and a bounded harness-driven runner. +- `print.ts` — single-shot `--print` text output. +- `output/harness-jsonl.ts` — JSONL event sink for `-o jsonl`. +- `tui/` — pi-tui 0.79 interactive front-end: `Markdown` message list, + `Image` screenshot widget, status line, telemetry footer, `Editor` + with autocomplete-backed slash commands (`/model`, `/thinking`, + `/compact`, `/skill:`). ### `@onkernel/ptywright` @@ -272,219 +183,75 @@ browser or provider adapter. - `scripts/build-ghostty.mjs` — downloads, verifies, and builds the pinned Ghostty `libghostty-vt` source used by the native addon. -## The canonical `batch_computer_actions` action union - -The user-facing reason to put `batch_computer_actions` on every -provider: predictable multi-action sequences in one round-trip, with -optional inline reads. The architectural reason: it lets us define a -SINGLE canonical action union (in -[`@onkernel/cua-translator/src/types.ts`](../packages/cua-translator/src/types.ts)) -and re-emit it in each provider's tool-spec format: - -| Provider | Tool-spec shape | -| ------------ | -------------------------------------------------------------------------------------------- | -| OpenAI | `{type: "function", name: "batch_computer_actions", parameters: {...}}` (Responses API) | -| Anthropic | `{name: "batch_computer_actions", description: "...", input_schema: {...}}` (Messages API) | -| Gemini | `{name: "batch_computer_actions", description: "...", parameters: {...}}` (FunctionDeclaration) | - -The action type enum is the same in all three: `click`, `double_click`, -`type`, `keypress`, `scroll`, `move`, `drag`, `wait`, `screenshot` plus -the cua extensions `goto`, `back`, `forward`, `url`. Anthropic also -includes `triple_click` (mapped to 3× click before translator -dispatch). - -The execution path is identical across providers: - -``` -batch_computer_actions args - └─► AgentTool.execute() - └─► translator.executeBatch(actions) - ├─► coalesce consecutive write actions - ├─► flush via client.browsers.computer.batch - ├─► inline url() → readClipboard - └─► inline screenshot() → captureScreenshot - └─► return { content: [text, image, url, image, ...], details } - └─► fed back to model as tool result -``` - -To gate the batch tool out for any single provider: - -```typescript -import { createOpenAIComputerTools } from "@onkernel/cua-openai/pi"; -import { createAnthropicComputerTools } from "@onkernel/cua-anthropic/pi"; -import { createGeminiComputerTools } from "@onkernel/cua-gemini/pi"; - -createOpenAIComputerTools(translator, { includeBatch: false }); -createAnthropicComputerTools(translator, { includeBatch: false }); -createGeminiComputerTools(translator, { includeBatch: false }); -``` - -## Single-invocation Root API Flow - -Non-`pi` consumers bypass `cua-cli` entirely and wire the provider-root -packages straight into `runComputerUse()`: - -```text -runComputerUse({ model: openai(...) | anthropic(...) | gemini(...), browser }) - └─► provider-root model factory - ├─► OpenAI root: native {type:"computer"} tool - ├─► Anthropic root: built-in computer_20251124 tool (+ optional batch) - └─► Gemini root: predefined functionDeclarations (+ optional batch) - └─► provider SDK loop - └─► provider execution helper - └─► translator.executeBatch(...) -``` - -This is separate from the `cua-cli` runtime: the root helpers are -bounded, single-invocation loops, while `cua-cli` continues to own the -full `pi-agent-core` agent/session/TUI workflow. - ## Per-turn flow ```text user prompt └─► /skill: expansion (if matched) - └─► agent.prompt({role:"user", content:[text, image?]}) + └─► harness.prompt(text, { images }) ├─► (first turn only, fresh transcript) attach a Kernel screenshot └─► pi-agent-core agentLoop - ├─► onPayload hook (chained per-provider) - │ ├─► OpenAI: inject context_management compaction (if configured) - │ ├─► Anthropic: replace function-tool entry "computer" with computer_20251124 spec - │ └─► Gemini: no-op - ├─► streamFn wrapper - │ ├─► Anthropic: merge "anthropic-beta: computer-use-2025-11-24" into headers - │ └─► all: delegate to pi-ai's streamSimple - └─► provider HTTP SSE (api.openai.com / api.anthropic.com / generativelanguage.googleapis.com) - ├─► tool calls - │ ├─► OpenAI: batch_computer_actions / computer_use_extra - │ ├─► Anthropic: computer (built-in) + batch_computer_actions - │ └─► Gemini: 13 predefined functions + batch_computer_actions - │ └─► AgentTool.execute → translator.executeBatch - │ ├─► coalesce writes; flush via client.browsers.computer.batch - │ ├─► inline url() → readClipboard - │ └─► inline screenshot() → captureScreenshot - └─► assistant text deltas → TUI / stdout / JSONL + ├─► resolveCuaRuntimeSpec(model) provides toolDefinitions, + │ toolExecutors, defaultSystemPrompt, onPayload, … + ├─► onPayload (cua-ai) — provider payload transforms + ├─► pi-ai streamSimple → provider HTTP SSE + │ (OpenAI Responses / Anthropic Messages / Google GenAI / Tzafon / Yutori) + ├─► tool_call events carry canonical CuaAction args + │ └─► cua-agent executor + │ ├─► coalesce writes; flush via client.browsers.computer.batch + │ ├─► inline url() / read actions + │ └─► fresh screenshot via captureScreenshot + └─► assistant text + harness events → TUI / stdout / JSONL ``` -The seam is in `packages/cua-cli/src/agent.ts:createCuaAgent`, which: - -1. Resolves the provider from the exact supported model table in - `packages/cua-cli/src/models.ts`. -2. Loads the `Model` from `pi-ai`'s registry when present, or from - CUA's conservative dynamic fallback while `pi-ai` catches up to new - provider model IDs. -3. Builds the per-provider tool list via the explicit `/pi` bindings: - `@onkernel/cua-openai/pi`, - `@onkernel/cua-anthropic/pi`, - `@onkernel/cua-gemini/pi`. -4. Builds the per-provider system prompt from the matching - `*_BATCH_INSTRUCTIONS` / `buildAnthropicSystemPrompt` / - `buildGeminiSystemPrompt` exports + `appendSkillsToSystemPrompt`. -5. Composes the per-provider `onPayload` hooks and wraps `streamSimple` - with `wrapAnthropicStream`. - -That seam is intentionally `pi`-specific. Consumers that do not want the -`pi-agent-core` loop should use package-root helpers such as -`openai(...)`, `anthropic(...)`, or `gemini(...)` with -`runComputerUse()` instead of importing from `/pi`. +The CLI's `buildCuaHarness` in `packages/cua-cli/src/harness.ts`: + +1. Resolves the model via `getCuaModel(ref)` / `listCuaModels()` from + `@onkernel/cua-ai`. +2. Wires `JsonlSessionRepo` and a `Session` for transcript persistence + and resume. +3. Loads pi skills from `~/.agents/skills`, `/.agents/skills`, and + any `--skill ` flags and exposes them via `resources.skills`. +4. Provides `extraTools` from `createCodingTools(cwd)` + (`@earendil-works/pi-coding-agent`) for bash/read/edit/write/grep/find/ls. +5. Resolves the API key via `requireCuaEnvApiKeyForModel(ref)` and + spreads any `_BASE_URL` env override onto the model object. +6. Composes the `systemPrompt` callback from + `resolveCuaRuntimeSpec(model).defaultSystemPrompt` plus + `formatSkillsForSystemPrompt(resources.skills)` so it stays correct + across `setModel()`. ## Component map ```mermaid flowchart LR cli["cua-cli/src/cli.ts"] - cli --> cfg["cua-cli/src/config.ts"] - cli --> sess["cua-translator/src/browser-session.ts"] - sess --> sdk[("@onkernel/sdk")] - cli --> agentMod["cua-cli/src/agent.ts"] - agentMod --> piAgent["pi-agent-core Agent"] - piAgent --> piAi["pi-ai streamSimple wrapped by wrapAnthropicStream"] + cli --> harness["cua-cli/src/harness.ts (buildCuaHarness)"] + harness --> browserMod["cua-cli/src/harness-browser.ts"] + browserMod --> sdk[("@onkernel/sdk")] + harness --> agentPkg["cua-agent: CuaAgentHarness"] + agentPkg --> piHarness["pi-agent-core AgentHarness"] + piHarness --> piAi["pi-ai streamSimple"] piAi -->|"openai-responses"| openai[("api.openai.com /v1/responses")] piAi -->|"anthropic-messages + beta header"| anthro[("api.anthropic.com /v1/messages")] piAi -->|"google-generative-ai"| gemini[("generativelanguage.googleapis.com")] - agentMod -->|"openai"| oaiTools["cua-openai/pi: batch_computer_actions + computer_use_extra"] - agentMod -->|"anthropic"| antTools["cua-anthropic/pi: computer + batch_computer_actions"] - agentMod -->|"gemini"| gemTools["cua-gemini/pi: 13 predefined + batch_computer_actions"] - agentMod --> coding["bash/read/edit/write/... (pi-coding-agent)"] - oaiTools --> translator["cua-translator: ComputerTranslator"] - antTools --> translator - gemTools --> translator - translator --> sdk + piAi -->|"tzafon / yutori"| others[("provider HTTP APIs")] + agentPkg --> sdk + harness --> aiPkg["cua-ai: getCuaModel / resolveCuaRuntimeSpec"] + aiPkg --> piAi + harness --> coding["bash/read/edit/write/... (pi-coding-agent)"] + harness --> sessions["JsonlSessionRepo (re-exported from cua-agent)"] + harness --> skillsMod["loadSkills (re-exported from cua-agent)"] cli --> tui["cua-cli/src/tui/main.ts (pi-tui)"] - tui --> piTui[("pi-tui Terminal/Editor/Container/Image")] - cli --> sessionsMod["cua-cli/src/sessions.ts (SessionManager)"] - cli --> namedSessionsMod["cua-cli/src/named-sessions.ts"] - cli --> skillsMod["cua-cli/src/skills.ts (loadSkills)"] - cli --> jsonl["cua-cli/src/output/jsonl.ts"] + cli --> jsonl["cua-cli/src/output/harness-jsonl.ts"] pty["ptywright (dev/test only)"] --> tui ``` -## Provider-specific gotchas - -### OpenAI: root native path vs `/pi` compatibility path - -The repo now has two OpenAI integration paths: - -1. The provider-root path (`openai(modelId)` + `runComputerUse()`) - uses OpenAI's native `{type:"computer"}` tool through the official - OpenAI SDK. -2. The `@onkernel/cua-openai/pi` path used by `cua-cli` keeps the - custom `batch_computer_actions` / `computer_use_extra` tools. - -Why keep the custom tools on the `/pi` path? Because `pi-ai`'s OpenAI -Responses provider only emits `type:"function"` tool specs -(`convertResponsesTools`) and only handles `reasoning` / `message` / -`function_call` output items (`processResponsesStream`). A -`computer_call` item from the model would be silently dropped. To -support the built-in `{type:"computer"}` inside `pi-agent-core`, we'd -need to fork or replace pi-ai's response parser. - -So the current split is intentional: - -- provider root: prefer the native OpenAI computer tool. -- `/pi` binding: prefer `batch_computer_actions` (more expressive in the - current `pi-ai` transport) plus `computer_use_extra` for one-shot - `goto` / `back` / `url`. - -### Anthropic claude-opus-4-7: built-in tool injection - -Anthropic's built-in `computer_20251124` tool emits standard `tool_use` -blocks — pi-ai parses those natively. The trick is that pi-ai's tool -serialization expects function tools (`name` + `input_schema`), not -Anthropic's special built-in tool spec -(`{type: "computer_20251124", name: "computer", display_width_px, -display_height_px, ...}`). - -We work around it with two pieces: - -1. Register a "computer" `AgentTool` with a permissive schema so - pi-agent-core knows how to route incoming `tool_use` blocks named - `computer` to our `execute()`. -2. An `onPayload` hook (`anthropicComputerOnPayload`) rewrites the - wire payload's `tools[]` array, replacing the function-tool entry - for "computer" with the built-in `computer_20251124` spec. - -The required beta header (`anthropic-beta: computer-use-2025-11-24`) -is merged in by `wrapAnthropicStream` (alongside whatever beta tokens -pi-ai is already sending for fine-grained tool streaming). - -### Gemini: per-action tools via `functionDeclarations` - -For Gemini we send the predefined computer-use functions as ordinary -`functionDeclarations` (with the trained-name `name` field) plus our -cua-added `batch_computer_actions` declaration in the same tool list. - -That keeps Gemini's trained function names (`click_at`, `type_text_at`, -`navigate`, …) while still letting us expose custom batching behavior in -the same request. - ## Out of scope (today) -| Feature | Status | Notes | -| -------------------------------------------------- | -------- | --------------------------------------------------------------------- | -| Anthropic `hold_key` / `left_mouse_down`/`up` / `zoom` | deferred | AgentTool returns `is_error` so the model adapts | -| `--local` Docker-backed browser | deferred | Remote cloud only | -| pi-tui `SelectList`-based session picker for `-r` | deferred | Plain readline picker today | -| Publishing `@onkernel/cua-*` to npm | deferred | Package boundaries are stable; `0.1.0` versions ready | - -Each is a small follow-up given the architecture is already in place. +| Feature | Status | Notes | +| -------------------------------------------------- | -------- | ------------------------------------------------- | +| Anthropic `hold_key` / `zoom` | deferred | Translator returns errors so the model adapts | +| `--local` Docker-backed browser | deferred | Remote Kernel cloud only | +| pi-tui `SelectList`-based session picker for `-r` | deferred | Plain readline picker today | +| Auto-compaction in the harness run loop | deferred | Manual `/compact` from the TUI; `shouldCompact` + `estimateContextTokens` are available from cua-agent re-exports for a future auto-trigger | diff --git a/package-lock.json b/package-lock.json index b81a6724..f17dc641 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,12 +10,6 @@ "workspaces": [ "packages/ai", "packages/agent", - "packages/cua-translator", - "packages/cua-openai", - "packages/cua-anthropic", - "packages/cua-gemini", - "packages/cua-tzafon", - "packages/cua-yutori", "packages/ptywright", "packages/cua-cli" ], @@ -29,9 +23,9 @@ } }, "node_modules/@anthropic-ai/sdk": { - "version": "0.90.0", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.90.0.tgz", - "integrity": "sha512-MzZtPabJF1b0FTDl6Z6H5ljphPwACLGP13lu8MTiB8jXaW/YXlpOp+Po2cVou3MPM5+f5toyLnul9whKCy7fBg==", + "version": "0.91.1", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", + "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", "license": "MIT", "dependencies": { "json-schema-to-ts": "^3.1.1" @@ -204,19 +198,19 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.972.52", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.52.tgz", - "integrity": "sha512-szg1nnebqC+Svv6Vfsdf6P/QK8x5g/ghG2CKa/1WkHifRnq0BBmDELj2Qnqk9nPsUvEu/OEcYic97CPLpKqF9g==", + "version": "3.972.53", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.53.tgz", + "integrity": "sha512-ZfdhIOR41q8TcWEnUac+gCOb+O2LBWdHLmjedXpXz4IEFW2ppNuFcm6p0sMTavpM+zD5TYfpH5Gp7guRyqSgsQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.20", "@aws-sdk/credential-provider-env": "^3.972.46", "@aws-sdk/credential-provider-http": "^3.972.48", - "@aws-sdk/credential-provider-login": "^3.972.51", + "@aws-sdk/credential-provider-login": "^3.972.52", "@aws-sdk/credential-provider-process": "^3.972.46", - "@aws-sdk/credential-provider-sso": "^3.972.51", - "@aws-sdk/credential-provider-web-identity": "^3.972.51", - "@aws-sdk/nested-clients": "^3.997.19", + "@aws-sdk/credential-provider-sso": "^3.972.52", + "@aws-sdk/credential-provider-web-identity": "^3.972.52", + "@aws-sdk/nested-clients": "^3.997.20", "@aws-sdk/types": "^3.973.12", "@smithy/core": "^3.24.6", "@smithy/credential-provider-imds": "^4.3.7", @@ -228,13 +222,13 @@ } }, "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.51", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.51.tgz", - "integrity": "sha512-csHFsH+/VjnI40oqm1l1OqMY4B4kza36DbfcbHcgcbobgjebasqUbTU34xvwUkvtoNGGizbfyMSlMzJWUPv3dQ==", + "version": "3.972.52", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.52.tgz", + "integrity": "sha512-9hu2oR0qH7Fst5Tzdx+UWxm+w5zCXtErTLtOOW5hwwQc170CLwOeniRxyFY6s9mHfGEfC5zFukNBdKBwJR8mhQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.20", - "@aws-sdk/nested-clients": "^3.997.19", + "@aws-sdk/nested-clients": "^3.997.20", "@aws-sdk/types": "^3.973.12", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", @@ -245,17 +239,17 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.54", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.54.tgz", - "integrity": "sha512-vinTSQtziNHxi2nqXF+76jr2sO44q88Ind1qFFVaotNgBaC1rcWDjBug8yoE8n0ov33s21xks9WY5XDHH9SENw==", + "version": "3.972.55", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.55.tgz", + "integrity": "sha512-zMGLa/dhESVqmCD7mmIFFKSwSFrJGScvCXcjvBZEVOOMauFS5JRQvLTMukFpMEFWiV6dTAlsen2ATDBulLPtbg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.46", "@aws-sdk/credential-provider-http": "^3.972.48", - "@aws-sdk/credential-provider-ini": "^3.972.52", + "@aws-sdk/credential-provider-ini": "^3.972.53", "@aws-sdk/credential-provider-process": "^3.972.46", - "@aws-sdk/credential-provider-sso": "^3.972.51", - "@aws-sdk/credential-provider-web-identity": "^3.972.51", + "@aws-sdk/credential-provider-sso": "^3.972.52", + "@aws-sdk/credential-provider-web-identity": "^3.972.52", "@aws-sdk/types": "^3.973.12", "@smithy/core": "^3.24.6", "@smithy/credential-provider-imds": "^4.3.7", @@ -283,14 +277,14 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.972.51", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.51.tgz", - "integrity": "sha512-60qhpQcSDIKIr0AuBlmJezKX0b5nbJPCINiR49N9yJXrEI5tTRwsXVBr0IdSvvsNJyqgiINyoBd++Ed0yvggbw==", + "version": "3.972.52", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.52.tgz", + "integrity": "sha512-nb2/n4o/HQf+FVpVbZe9vCTFngmuDoIsltMgLAtjixaKzvzhB4J8WSDFyWgnErgLHk55ctWH+I4PU+LIHhyffg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.20", - "@aws-sdk/nested-clients": "^3.997.19", - "@aws-sdk/token-providers": "3.1065.0", + "@aws-sdk/nested-clients": "^3.997.20", + "@aws-sdk/token-providers": "3.1066.0", "@aws-sdk/types": "^3.973.12", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", @@ -301,13 +295,13 @@ } }, "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { - "version": "3.1065.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1065.0.tgz", - "integrity": "sha512-qdHQntq82gMqG6Tf8xrgmhJxacaYkxW4PEeDg/ISMVJ84EWe7iD6JyCTgbyox3uNDH6vqEJ8GUiTaXCq307zVw==", + "version": "3.1066.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1066.0.tgz", + "integrity": "sha512-UqEUJq7dqa44hneLDUcX7UJy95cg8YqEWyakRpvIPnrNS3Mq+UlQHgCDGu5pvwAPtlIW4qcYbvW6reG6++FyvA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.20", - "@aws-sdk/nested-clients": "^3.997.19", + "@aws-sdk/nested-clients": "^3.997.20", "@aws-sdk/types": "^3.973.12", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", @@ -318,13 +312,13 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.51", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.51.tgz", - "integrity": "sha512-0X5eWsUIp8ItRJeJBBrhQAPzc9AQelDetRTVTsycCAISCCzM17R4hs/vFAPeQ0o0B35sciLiqe/Pwmml909cZA==", + "version": "3.972.52", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.52.tgz", + "integrity": "sha512-lKj6aRSGbqLmpYmM24bY7a1Xmfcq2vkE3hv8CSPYfc1yCu0BPu/XEJ1L4Fm61MsU6ULLNSG8UGsffNoFUBjESA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.20", - "@aws-sdk/nested-clients": "^3.997.19", + "@aws-sdk/nested-clients": "^3.997.20", "@aws-sdk/types": "^3.973.12", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", @@ -383,15 +377,15 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.19", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.19.tgz", - "integrity": "sha512-P2Otgf15GBJMKzG6j5Ddf7w+Kz6z2jvesMy874TD3jlMfDWNK7clJeUd7hgigdeVOotjoUP4emcTWVdS9sfZDw==", + "version": "3.997.20", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.20.tgz", + "integrity": "sha512-IYJuLpXp2DEILVQpQOy0PMpkftv0AHEOCn52o0atyOaumA0CdWQ3klPyXdViGYLbNpESsVFMVybvHUeZAuiGxA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.20", - "@aws-sdk/signature-v4-multi-region": "^3.996.33", + "@aws-sdk/signature-v4-multi-region": "^3.996.34", "@aws-sdk/types": "^3.973.12", "@smithy/core": "^3.24.6", "@smithy/fetch-http-handler": "^5.4.6", @@ -418,9 +412,9 @@ } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.33", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.33.tgz", - "integrity": "sha512-Hn0RThJEbyOZWV2PV9Z4YD3nitGPxybmyU17dSe9b61WOBcKnqS0WTtM3c1zyZq9WnGiyrfi/i+UBPUk7cM8Ug==", + "version": "3.996.34", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.34.tgz", + "integrity": "sha512-mx1L5qlumSOt/nKM3BFaHE2HVkWwz0i4Bw0pyYO42FfX/FeLlo8YI6csC0gSPprEk6fTIqI+CZN9RwUwKd5krQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.12", @@ -552,7 +546,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.29.2", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -611,37 +607,27 @@ "node": ">=22.19.0" } }, - "node_modules/@earendil-works/pi-ai/node_modules/@anthropic-ai/sdk": { - "version": "0.91.1", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", - "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", - "license": "MIT", - "dependencies": { - "json-schema-to-ts": "^3.1.1" - }, + "node_modules/@earendil-works/pi-ai/node_modules/openai": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.26.0.tgz", + "integrity": "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==", + "license": "Apache-2.0", "bin": { - "anthropic-ai-sdk": "bin/cli" + "openai": "bin/cli" }, "peerDependencies": { - "zod": "^3.25.0 || ^4.0.0" + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" }, "peerDependenciesMeta": { + "ws": { + "optional": true + }, "zod": { "optional": true } } }, - "node_modules/@earendil-works/pi-ai/node_modules/@mistralai/mistralai": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-2.2.1.tgz", - "integrity": "sha512-uKU8CZmL2RzYKmplsU01hii4p3pe4HqJefpWNRWXm1Tcm0Sm4xXfwSLIy4k7ZCPlbETCGcp69E7hZs+WOJ5itQ==", - "license": "Apache-2.0", - "dependencies": { - "ws": "^8.18.0", - "zod": "^3.25.0 || ^4.0.0", - "zod-to-json-schema": "^3.25.0" - } - }, "node_modules/@earendil-works/pi-coding-agent": { "version": "0.79.1", "resolved": "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.79.1.tgz", @@ -2440,21 +2426,21 @@ } }, "node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.0.tgz", + "integrity": "sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.1", + "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.0.tgz", + "integrity": "sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==", "license": "MIT", "optional": true, "dependencies": { @@ -2462,9 +2448,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", "dev": true, "license": "MIT", "optional": true, @@ -2473,9 +2459,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", - "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ "ppc64" ], @@ -2490,9 +2476,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", - "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ "arm" ], @@ -2507,9 +2493,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", - "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ "arm64" ], @@ -2524,9 +2510,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", - "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", "cpu": [ "x64" ], @@ -2541,9 +2527,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", - "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], @@ -2558,9 +2544,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", - "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], @@ -2575,9 +2561,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", - "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], @@ -2592,9 +2578,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", - "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], @@ -2609,9 +2595,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", - "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], @@ -2626,9 +2612,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", - "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], @@ -2643,9 +2629,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", - "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ "ia32" ], @@ -2660,9 +2646,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", - "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ "loong64" ], @@ -2677,9 +2663,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", - "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ "mips64el" ], @@ -2694,9 +2680,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", - "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ "ppc64" ], @@ -2711,9 +2697,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", - "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ "riscv64" ], @@ -2728,9 +2714,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", - "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ "s390x" ], @@ -2745,9 +2731,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", - "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ "x64" ], @@ -2762,9 +2748,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", - "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], @@ -2779,9 +2765,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", - "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ "x64" ], @@ -2796,9 +2782,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", - "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ "arm64" ], @@ -2813,9 +2799,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", - "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ "x64" ], @@ -2830,9 +2816,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", - "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", "cpu": [ "arm64" ], @@ -2847,9 +2833,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", - "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], @@ -2864,9 +2850,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", - "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", "cpu": [ "arm64" ], @@ -2881,9 +2867,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", - "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", "cpu": [ "ia32" ], @@ -2898,9 +2884,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", - "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", "cpu": [ "x64" ], @@ -3442,53 +3428,15 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@mariozechner/pi-agent-core": { - "version": "0.67.6", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@mariozechner/pi-ai": "^0.67.6" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@mariozechner/pi-ai": { - "version": "0.67.6", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@anthropic-ai/sdk": "^0.90.0", - "@aws-sdk/client-bedrock-runtime": "^3.1030.0", - "@google/genai": "^1.40.0", - "@mistralai/mistralai": "1.14.1", - "@sinclair/typebox": "^0.34.41", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "chalk": "^5.6.2", - "openai": "6.26.0", - "partial-json": "^0.1.7", - "proxy-agent": "^6.5.0", - "undici": "^7.19.1", - "zod-to-json-schema": "^3.24.6" - }, - "bin": { - "pi-ai": "dist/cli.js" - }, - "engines": { - "node": ">=20.0.0" - } - }, "node_modules/@mistralai/mistralai": { - "version": "1.14.1", - "optional": true, - "peer": true, + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-2.2.1.tgz", + "integrity": "sha512-uKU8CZmL2RzYKmplsU01hii4p3pe4HqJefpWNRWXm1Tcm0Sm4xXfwSLIy4k7ZCPlbETCGcp69E7hZs+WOJ5itQ==", + "license": "Apache-2.0", "dependencies": { "ws": "^8.18.0", "zod": "^3.25.0 || ^4.0.0", - "zod-to-json-schema": "^3.24.1" + "zod-to-json-schema": "^3.25.0" } }, "node_modules/@napi-rs/wasm-runtime": { @@ -3511,9 +3459,9 @@ } }, "node_modules/@nodable/entities": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.1.tgz", - "integrity": "sha512-Pig3HxDIoMgjdEH8OCf/dkcTmLFjJRjWuq8jSnklu284/TKOPibSRERmOykiwmyXTtv61mP+44f3GMx0tLAyjg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==", "funding": [ { "type": "github", @@ -3530,46 +3478,24 @@ "resolved": "packages/ai", "link": true }, - "node_modules/@onkernel/cua-anthropic": { - "resolved": "packages/cua-anthropic", - "link": true - }, "node_modules/@onkernel/cua-cli": { "resolved": "packages/cua-cli", "link": true }, - "node_modules/@onkernel/cua-gemini": { - "resolved": "packages/cua-gemini", - "link": true - }, - "node_modules/@onkernel/cua-openai": { - "resolved": "packages/cua-openai", - "link": true - }, - "node_modules/@onkernel/cua-translator": { - "resolved": "packages/cua-translator", - "link": true - }, - "node_modules/@onkernel/cua-tzafon": { - "resolved": "packages/cua-tzafon", - "link": true - }, - "node_modules/@onkernel/cua-yutori": { - "resolved": "packages/cua-yutori", - "link": true - }, "node_modules/@onkernel/ptywright": { "resolved": "packages/ptywright", "link": true }, "node_modules/@onkernel/sdk": { "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@onkernel/sdk/-/sdk-0.49.0.tgz", + "integrity": "sha512-nsq5OfkaNKxRTCdXQF8BSTj/Wl0iBIqyWoI/ATgQt15pV+59E22MsZ+IHPiVwwb33tXLtnOqUe5ffOxm7l3GHg==", "license": "Apache-2.0" }, "node_modules/@oxc-project/types": { - "version": "0.134.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.134.0.tgz", - "integrity": "sha512-T0xuRRKrQFmocH8y+jGfpmSkGcheaJExY9lEihmR1Gm2aH+75B8CzgU2rABRQSzzDxLjZ15Sc0bRVLj5lVeNXQ==", + "version": "0.135.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.135.0.tgz", + "integrity": "sha512-wR+xRdFkUBMvcAjBJ2q2kcZM6d+DKu2NgoOyxZgYwZdLhmiv6+rnO8PZ/P68kMiZtIKm+pW7zyEJ4kSOs0vo+Q==", "dev": true, "license": "MIT", "funding": { @@ -3578,46 +3504,65 @@ }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/codegen": { - "version": "2.0.4", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/fetch": { - "version": "1.1.0", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", "license": "BSD-3-Clause", "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" + "@protobufjs/aspromise": "^1.1.1" } }, "node_modules/@protobufjs/float": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/inquire": { - "version": "1.1.0", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.2.tgz", + "integrity": "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/path": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/pool": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/utf8": { - "version": "1.1.0", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", + "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", "license": "BSD-3-Clause" }, "node_modules/@quansync/fs": { @@ -3634,9 +3579,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.0.tgz", - "integrity": "sha512-gCYzGOSkYY6Z034suzd20euvds7lPzMEEla62DJGE/ZAlR4OMBnNbvnBSsIGUCAr52gaWMsloGxP4tVGtN5aCA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.1.tgz", + "integrity": "sha512-BLf9Wak/gfwVb7NQTQW4wBgL3oAfPy7ArEkhwV543OVw/uY6B47z5xYsqPSZ9PDOorvURPinws6ThaFuNgGLgA==", "cpu": [ "arm64" ], @@ -3651,9 +3596,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.0.tgz", - "integrity": "sha512-JQBD77MNgu+4Z6RAyg69acugdrhhVoWesr3l47zohYZ2YV2fwkWMArkN/2p4l6Ei+Sno7W5q+UsKdVWq5Ens0w==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.1.tgz", + "integrity": "sha512-rRZRPy/Ynb+Mxu0O6tfPldHeDgAn0sRij+IOUy6sFdUlv3hArGW/DloE3GfAxtqpOJuRNgF74Nr5gM4xBeU2jQ==", "cpu": [ "arm64" ], @@ -3668,9 +3613,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.0.tgz", - "integrity": "sha512-p/8cXUTK4Sob604e+xxPhVSbDFf29E6J0l/xESM9rdCfn3aDai3nEs6TnMHUsdD5aNlFz0+gDbiGlozLKGa2YA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.1.tgz", + "integrity": "sha512-/MtefPxhKPyWWFM8L45OWiEqRf+eSU2Qv9ZAyTaoZOoGcoPKxbbhjTJO2/U2IThv0uDZ4NWHc3/oTsR6IEOtww==", "cpu": [ "x64" ], @@ -3685,9 +3630,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.0.tgz", - "integrity": "sha512-KbtOSlVv6fElujiZWMcC3aQYhEwLVVf073RcwlSmpGQvIsKZFUqc0ef4sjUuurRwfbiI6JJXji9DQn+86hawmQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.1.tgz", + "integrity": "sha512-202K+cpIi1kx/Zn7AtxBi4LTXSY67Aszb2K9rNsuW7FeBeh0nqoNmYLOSZidV0p88VPBzMmTZcHAdPNo3kRYzQ==", "cpu": [ "x64" ], @@ -3702,9 +3647,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.0.tgz", - "integrity": "sha512-9fZ9i0o0/MQaw7om6Z6TsT7tfCk0jtbEFtC+aPqZL5RNsGWNcHvn6EHgL3dAprjq+AZzPTAQjg2JtpJaMt+6pg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.1.tgz", + "integrity": "sha512-wl9NfeXNUwrXtUc063tddmZFUI6qiNs1CNOwni0OL4vC7MqVSYugra3ZgtDmtVy8e0DluJTENmzIv2BwqLzT4Q==", "cpu": [ "arm" ], @@ -3719,9 +3664,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.0.tgz", - "integrity": "sha512-+tog7T66i+yFyIuuAnjL6xmW182W/qTBOUt6BtQ6lBIM1Eikh/fSMz4HGgvuCp5uU0zuIVWng7kDYthjCMOHcg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.1.tgz", + "integrity": "sha512-at2EO4o7D/PJLC4Xik16bU4CcjQE2tSv1LfqMA0TRYQYQihRm3gZeDB8xaX28A9SFedibcAk5DeMCKt4REKG0A==", "cpu": [ "arm64" ], @@ -3736,9 +3681,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.0.tgz", - "integrity": "sha512-4b7yruLIIj/oZ3GpcLOvxcLCLDMraohn3IhQfN2hBP4w9UekG0DTIajWguJosRGfySf/+h/NwRUiMKoCpxCrqQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.1.tgz", + "integrity": "sha512-5PUjZx366h9tkJTPJF5eibxOlK3sGoeRiBJLLjjEB5/kLDuhr6qB3LkhqLz1smXNgsX+pBhnbcJBrPE30HznAA==", "cpu": [ "arm64" ], @@ -3753,9 +3698,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.0.tgz", - "integrity": "sha512-QRDOVZd0bhQ5jLsUsCC3dUxDWdTSVY9WMznowZgCGOrZfLLgctWpelhUASEiBwsXfat/JwYnVd1EaxMhqyT+UQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.1.tgz", + "integrity": "sha512-1WK84XPeio3tjP1sM/TMXiC0G1i1iq1qGZ71KfNQjEFLU1kwD+Cv5T8nGySg/JUFwLbaScu6ve9DmeXlmqpkFA==", "cpu": [ "ppc64" ], @@ -3770,9 +3715,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.0.tgz", - "integrity": "sha512-ypxT+Hq76NFG7woFbNbySnGEajFuYuIXeKz/jfCU+lXUoxfi3zLE6OG/ZQNeK3RpZSYJlAe2bokpsQ046CaieQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.1.tgz", + "integrity": "sha512-1nS1X5z1uMJ369RU25hTpKCFvUwXZp12dIzlzk4S+UxCTcSVGsAE6tzkOSufv/7jnmAtK0ZlrsJxh2fGmsnVSw==", "cpu": [ "s390x" ], @@ -3787,9 +3732,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.0.tgz", - "integrity": "sha512-IdovCmfROFmpTLahdecTDFL74aLERVYN68F/mLZjfVh6LfoplPfI6deyHNMTcVujbokDV5k05XrFO22zfv+qjg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.1.tgz", + "integrity": "sha512-NwX/wspnq4vYyMFsqbYvzums3ki/Tk8FZbMzMAovPDp3OfLeYKby/D+9osokadXuYEV3OvpeHlwnr/bG8QMixA==", "cpu": [ "x64" ], @@ -3804,9 +3749,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.0.tgz", - "integrity": "sha512-pcA8xlFp2tyk9T2R6Fi/rPe3bQ1MA+sSMDNUU5Ogu80GHOatkE4P8YCreGAvZErm5Ho2YRXnyvNrWiRncfVysQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.1.tgz", + "integrity": "sha512-+n46LhDrJFQM+229y4oXtVpj1G50U/+XuHMlpnisFTEXhrg9f/YIjp/HymX+PVJjBEr7XHRs3CFLelV464pqwA==", "cpu": [ "x64" ], @@ -3821,9 +3766,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.0.tgz", - "integrity": "sha512-4+fexHayrLCWpriPh4c6dNvL4an34DEZCG7zOM/FD5QNF6h8DT+bDXzyB/kfC8lDJbaFb7jKShtnjDQFXVQEjg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.1.tgz", + "integrity": "sha512-qGwEu47zOWYo7LdRHhCWTNhzwGtxXpdY6CERs8QEOqC0PXGGics/e3vHnyEUKt8xK6YkbZXFUCeklrpB6js8ag==", "cpu": [ "arm64" ], @@ -3838,9 +3783,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.0.tgz", - "integrity": "sha512-SbL++MNmOw6QamrwIGDMSSfM4ceTzFr+RjbOExJSLLBinScU4WI5OdA413h1qwPw2yH7lVF1+H4svQ+6mSXKTQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.1.tgz", + "integrity": "sha512-qczfgEH8u0wHGGOXtA7UMAybNKuQjjEXairyQaw4WzjiMztfbgatG1h4OKays/smhtwbWltpKCRGtVhU6h40Sg==", "cpu": [ "wasm32" ], @@ -3848,18 +3793,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" + "@emnapi/core": "1.11.0", + "@emnapi/runtime": "1.11.0", + "@napi-rs/wasm-runtime": "^1.1.5" }, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.0.tgz", - "integrity": "sha512-+xTE6XC7wBgk0VKRXGG+QAnyW5S9b8vfsFpiMjf0waQTmSQSU8onsH/beyZ8X4aXVveJnotiy7VDjLOaW8bTrg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.1.tgz", + "integrity": "sha512-4psXSh63mSbwJF+mB8/9yfUUEzBiHYcUjxa32EO9ZwKy0Ypwjcg4F10D8SvVXgd+isy2UUUjF9HJJnDu1T/4Gg==", "cpu": [ "arm64" ], @@ -3874,9 +3819,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.0.tgz", - "integrity": "sha512-Ogji1TQNqH3ACLnYr+1Ns1nyrJ0CO2P585u9Hsh02pXvtFiFpgtgT2b3P4PnCOU86VVCvqtAeCN4OftMT8KU4w==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.1.tgz", + "integrity": "sha512-MUvC/HLXVjzkQkWiExdVTEEWf0py+GfWm8WKSZsekG3ih6a21iy0BHPF07X3JIf3ifoklZXTIaHTLPBgH1C3dw==", "cpu": [ "x64" ], @@ -3898,9 +3843,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz", - "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.61.1.tgz", + "integrity": "sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==", "cpu": [ "arm" ], @@ -3912,9 +3857,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz", - "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.61.1.tgz", + "integrity": "sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==", "cpu": [ "arm64" ], @@ -3926,9 +3871,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz", - "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.61.1.tgz", + "integrity": "sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==", "cpu": [ "arm64" ], @@ -3940,9 +3885,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz", - "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.61.1.tgz", + "integrity": "sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==", "cpu": [ "x64" ], @@ -3954,9 +3899,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz", - "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.61.1.tgz", + "integrity": "sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==", "cpu": [ "arm64" ], @@ -3968,9 +3913,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz", - "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.61.1.tgz", + "integrity": "sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==", "cpu": [ "x64" ], @@ -3982,9 +3927,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz", - "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.61.1.tgz", + "integrity": "sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==", "cpu": [ "arm" ], @@ -3996,9 +3941,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz", - "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.61.1.tgz", + "integrity": "sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==", "cpu": [ "arm" ], @@ -4010,9 +3955,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz", - "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.61.1.tgz", + "integrity": "sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==", "cpu": [ "arm64" ], @@ -4024,9 +3969,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz", - "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.61.1.tgz", + "integrity": "sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==", "cpu": [ "arm64" ], @@ -4038,9 +3983,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz", - "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.61.1.tgz", + "integrity": "sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==", "cpu": [ "loong64" ], @@ -4052,9 +3997,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz", - "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.61.1.tgz", + "integrity": "sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==", "cpu": [ "loong64" ], @@ -4066,9 +4011,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz", - "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.61.1.tgz", + "integrity": "sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==", "cpu": [ "ppc64" ], @@ -4080,9 +4025,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz", - "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.61.1.tgz", + "integrity": "sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==", "cpu": [ "ppc64" ], @@ -4094,9 +4039,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz", - "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.61.1.tgz", + "integrity": "sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==", "cpu": [ "riscv64" ], @@ -4108,9 +4053,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz", - "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.61.1.tgz", + "integrity": "sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==", "cpu": [ "riscv64" ], @@ -4122,9 +4067,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz", - "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.61.1.tgz", + "integrity": "sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==", "cpu": [ "s390x" ], @@ -4136,9 +4081,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", - "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.1.tgz", + "integrity": "sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==", "cpu": [ "x64" ], @@ -4150,9 +4095,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz", - "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.61.1.tgz", + "integrity": "sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==", "cpu": [ "x64" ], @@ -4164,9 +4109,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz", - "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.61.1.tgz", + "integrity": "sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==", "cpu": [ "x64" ], @@ -4178,9 +4123,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz", - "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.61.1.tgz", + "integrity": "sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==", "cpu": [ "arm64" ], @@ -4192,9 +4137,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz", - "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.61.1.tgz", + "integrity": "sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==", "cpu": [ "arm64" ], @@ -4206,9 +4151,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz", - "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.61.1.tgz", + "integrity": "sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==", "cpu": [ "ia32" ], @@ -4220,9 +4165,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz", - "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.61.1.tgz", + "integrity": "sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==", "cpu": [ "x64" ], @@ -4234,9 +4179,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz", - "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.1.tgz", + "integrity": "sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==", "cpu": [ "x64" ], @@ -4247,10 +4192,6 @@ "win32" ] }, - "node_modules/@sinclair/typebox": { - "version": "0.34.49", - "license": "MIT" - }, "node_modules/@smithy/core": { "version": "3.24.6", "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.24.6.tgz", @@ -4371,12 +4312,6 @@ "node": ">=14.0.0" } }, - "node_modules/@tootallnate/quickjs-emscripten": { - "version": "0.23.0", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/@tybys/wasm-util": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", @@ -4407,9 +4342,9 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true, "license": "MIT" }, @@ -4422,6 +4357,8 @@ }, "node_modules/@types/node": { "version": "22.18.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.4.tgz", + "integrity": "sha512-UJdblFqXymSBhmZf96BnbisoFIr8ooiiBRMolQgg77Ea+VM37jXw76C2LQr9n8wm9+i/OvlUlW6xSvqwzwqznw==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -4429,6 +4366,8 @@ }, "node_modules/@types/retry": { "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "license": "MIT" }, "node_modules/@tzafon/lightcone": { @@ -4438,15 +4377,15 @@ "license": "Apache-2.0" }, "node_modules/@vitest/expect": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", - "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.6.tgz", + "integrity": "sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==", "dev": true, "license": "MIT", "dependencies": { "@types/chai": "^5.2.2", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" }, @@ -4455,13 +4394,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", - "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.6.tgz", + "integrity": "sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.2.4", + "@vitest/spy": "3.2.6", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, @@ -4482,9 +4421,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", - "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.6.tgz", + "integrity": "sha512-lb7XXXzmm2h2ASzFnRvQpDo6onT1NmMJA3tkGTWiBFtRJ9lxGY3d3mm/Apt36gej2bkkOVLL/yTOtufDaFa/jA==", "dev": true, "license": "MIT", "dependencies": { @@ -4495,13 +4434,13 @@ } }, "node_modules/@vitest/runner": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", - "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.6.tgz", + "integrity": "sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.2.4", + "@vitest/utils": "3.2.6", "pathe": "^2.0.3", "strip-literal": "^3.0.0" }, @@ -4510,13 +4449,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", - "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.6.tgz", + "integrity": "sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.4", + "@vitest/pretty-format": "3.2.6", "magic-string": "^0.30.17", "pathe": "^2.0.3" }, @@ -4525,9 +4464,9 @@ } }, "node_modules/@vitest/spy": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", - "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.6.tgz", + "integrity": "sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg==", "dev": true, "license": "MIT", "dependencies": { @@ -4538,13 +4477,13 @@ } }, "node_modules/@vitest/utils": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", - "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.6.tgz", + "integrity": "sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.4", + "@vitest/pretty-format": "3.2.6", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" }, @@ -4554,44 +4493,13 @@ }, "node_modules/agent-base": { "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "license": "MIT", "engines": { "node": ">= 14" } }, - "node_modules/ajv": { - "version": "8.18.0", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, "node_modules/ansis": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.3.1.tgz", @@ -4642,20 +4550,10 @@ "url": "https://github.com/sponsors/sxzz" } }, - "node_modules/ast-types": { - "version": "0.13.4", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/base64-js": { "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -4672,17 +4570,10 @@ ], "license": "MIT" }, - "node_modules/basic-ftp": { - "version": "5.3.0", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/bignumber.js": { "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", "license": "MIT", "engines": { "node": "*" @@ -4706,16 +4597,18 @@ }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", "license": "BSD-3-Clause" }, "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cac/-/cac-7.0.0.tgz", + "integrity": "sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=20.19.0" } }, "node_modules/chai": { @@ -4735,18 +4628,6 @@ "node": ">=18" } }, - "node_modules/chalk": { - "version": "5.6.2", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/check-error": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", @@ -4759,6 +4640,8 @@ }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", "license": "MIT", "engines": { "node": ">= 12" @@ -4766,6 +4649,8 @@ }, "node_modules/debug": { "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4796,20 +4681,6 @@ "dev": true, "license": "MIT" }, - "node_modules/degenerator": { - "version": "5.0.1", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "ast-types": "^0.13.4", - "escodegen": "^2.1.0", - "esprima": "^4.0.1" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -4842,6 +4713,8 @@ }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" @@ -4865,9 +4738,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", - "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4878,75 +4751,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.7", - "@esbuild/android-arm": "0.27.7", - "@esbuild/android-arm64": "0.27.7", - "@esbuild/android-x64": "0.27.7", - "@esbuild/darwin-arm64": "0.27.7", - "@esbuild/darwin-x64": "0.27.7", - "@esbuild/freebsd-arm64": "0.27.7", - "@esbuild/freebsd-x64": "0.27.7", - "@esbuild/linux-arm": "0.27.7", - "@esbuild/linux-arm64": "0.27.7", - "@esbuild/linux-ia32": "0.27.7", - "@esbuild/linux-loong64": "0.27.7", - "@esbuild/linux-mips64el": "0.27.7", - "@esbuild/linux-ppc64": "0.27.7", - "@esbuild/linux-riscv64": "0.27.7", - "@esbuild/linux-s390x": "0.27.7", - "@esbuild/linux-x64": "0.27.7", - "@esbuild/netbsd-arm64": "0.27.7", - "@esbuild/netbsd-x64": "0.27.7", - "@esbuild/openbsd-arm64": "0.27.7", - "@esbuild/openbsd-x64": "0.27.7", - "@esbuild/openharmony-arm64": "0.27.7", - "@esbuild/sunos-x64": "0.27.7", - "@esbuild/win32-arm64": "0.27.7", - "@esbuild/win32-ia32": "0.27.7", - "@esbuild/win32-x64": "0.27.7" - } - }, - "node_modules/escodegen": { - "version": "2.1.0", - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "engines": { - "node": ">=4.0" + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, "node_modules/estree-walker": { @@ -4959,15 +4789,6 @@ "@types/estree": "^1.0.0" } }, - "node_modules/esutils": { - "version": "2.0.3", - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/expect-type": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", @@ -4980,30 +4801,10 @@ }, "node_modules/extend": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause", - "optional": true, - "peer": true - }, "node_modules/fast-xml-builder": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", @@ -5061,6 +4862,8 @@ }, "node_modules/fetch-blob": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", "funding": [ { "type": "github", @@ -5082,6 +4885,8 @@ }, "node_modules/formdata-polyfill": { "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", "license": "MIT", "dependencies": { "fetch-blob": "^3.1.2" @@ -5106,7 +4911,9 @@ } }, "node_modules/gaxios": { - "version": "7.1.4", + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.5.tgz", + "integrity": "sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg==", "license": "Apache-2.0", "dependencies": { "extend": "^3.0.2", @@ -5119,6 +4926,8 @@ }, "node_modules/gcp-metadata": { "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", "license": "Apache-2.0", "dependencies": { "gaxios": "^7.0.0", @@ -5142,43 +4951,25 @@ } }, "node_modules/get-tsconfig": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", - "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "version": "5.0.0-beta.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.5.tgz", + "integrity": "sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ==", "dev": true, "license": "MIT", "dependencies": { "resolve-pkg-maps": "^1.0.0" }, + "engines": { + "node": ">=20.20.0" + }, "funding": { "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/get-uri": { - "version": "6.0.5", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^6.0.2", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/get-uri/node_modules/data-uri-to-buffer": { - "version": "6.0.2", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 14" - } - }, "node_modules/google-auth-library": { - "version": "10.6.2", + "version": "10.7.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.7.0.tgz", + "integrity": "sha512-QpTAbNJ36TliZLx3TTtahR8HG0hN9RllL1e3FymOvQSIKK8JmgV58H924ub2wa2DsS3ANjjP1Aw1N+Ramc8hqQ==", "license": "Apache-2.0", "dependencies": { "base64-js": "^1.3.0", @@ -5194,6 +4985,8 @@ }, "node_modules/google-logging-utils": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", "license": "Apache-2.0", "engines": { "node": ">=14" @@ -5208,6 +5001,8 @@ }, "node_modules/http-proxy-agent": { "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "license": "MIT", "dependencies": { "agent-base": "^7.1.0", @@ -5219,6 +5014,8 @@ }, "node_modules/https-proxy-agent": { "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -5230,6 +5027,8 @@ }, "node_modules/ignore": { "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "license": "MIT", "engines": { "node": ">= 4" @@ -5248,15 +5047,6 @@ "url": "https://github.com/sponsors/sxzz" } }, - "node_modules/ip-address": { - "version": "10.1.0", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 12" - } - }, "node_modules/js-tokens": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", @@ -5279,6 +5069,8 @@ }, "node_modules/json-bigint": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", "license": "MIT", "dependencies": { "bignumber.js": "^9.0.0" @@ -5286,6 +5078,8 @@ }, "node_modules/json-schema-to-ts": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", @@ -5295,14 +5089,10 @@ "node": ">=16" } }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/jwa": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", "dependencies": { "buffer-equal-constant-time": "^1.0.1", @@ -5312,6 +5102,8 @@ }, "node_modules/jws": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { "jwa": "^2.0.1", @@ -5320,6 +5112,8 @@ }, "node_modules/long": { "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", "license": "Apache-2.0" }, "node_modules/loupe": { @@ -5329,15 +5123,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lru-cache": { - "version": "7.18.3", - "license": "ISC", - "optional": true, - "peer": true, - "engines": { - "node": ">=12" - } - }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -5350,6 +5135,8 @@ }, "node_modules/marked": { "version": "15.0.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", + "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -5360,6 +5147,8 @@ }, "node_modules/ms": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/nanoid": { @@ -5381,19 +5170,10 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/netmask": { - "version": "2.1.1", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/node-addon-api": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", - "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.8.0.tgz", + "integrity": "sha512-c5Ko1fZJIJmzhFIkhRN76WTq+fC6tWnGy9CXA0fA+XygsWZmEwG8vmbkNqxMyoaa0Tin4djul49NzdVcJJcjeA==", "license": "MIT", "engines": { "node": "^18 || ^20 || >= 21" @@ -5401,6 +5181,9 @@ }, "node_modules/node-domexception": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", "funding": [ { "type": "github", @@ -5418,6 +5201,8 @@ }, "node_modules/node-fetch": { "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "license": "MIT", "dependencies": { "data-uri-to-buffer": "^4.0.0", @@ -5463,11 +5248,10 @@ } }, "node_modules/openai": { - "version": "6.26.0", + "version": "6.42.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.42.0.tgz", + "integrity": "sha512-1WFEt/uXMXOLhYRNkgJWo08Y2YNvNwpVU72K7ibrWgWpNOXd4VojXLbe6SQ4bLiUQ3Y8jz4IiyVkylJCL1DtZg==", "license": "Apache-2.0", - "bin": { - "openai": "bin/cli" - }, "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" @@ -5483,6 +5267,8 @@ }, "node_modules/p-retry": { "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "license": "MIT", "dependencies": { "@types/retry": "0.12.0", @@ -5492,40 +5278,10 @@ "node": ">=8" } }, - "node_modules/pac-proxy-agent": { - "version": "7.2.0", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@tootallnate/quickjs-emscripten": "^0.23.0", - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "get-uri": "^6.0.1", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.6", - "pac-resolver": "^7.0.1", - "socks-proxy-agent": "^8.0.5" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/pac-resolver": { - "version": "7.0.1", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "degenerator": "^5.0.0", - "netmask": "^2.0.2" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/partial-json": { "version": "0.1.7", + "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", + "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", "license": "MIT" }, "node_modules/path-expression-matcher": { @@ -5581,9 +5337,9 @@ } }, "node_modules/postcss": { - "version": "8.5.13", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.13.tgz", - "integrity": "sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "dev": true, "funding": [ { @@ -5601,7 +5357,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -5610,52 +5366,29 @@ } }, "node_modules/protobufjs": { - "version": "7.5.5", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.3.tgz", + "integrity": "sha512-+k0vdJKNdW+Vu+dYe8tZA/VvQb6XKNWexC6URwBFXxNnjLJz9nQJCemGyNgRAWD+B7+nGNc9qMPGwcD7s4nzUw==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", + "@protobufjs/inquire": "^1.1.2", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", - "long": "^5.0.0" + "long": "^5.3.2" }, "engines": { "node": ">=12.0.0" } }, - "node_modules/proxy-agent": { - "version": "6.5.0", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "http-proxy-agent": "^7.0.1", - "https-proxy-agent": "^7.0.6", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.1.0", - "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.5" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/quansync": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/quansync/-/quansync-1.0.0.tgz", @@ -5673,15 +5406,6 @@ ], "license": "MIT" }, - "node_modules/require-from-string": { - "version": "2.0.2", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -5694,19 +5418,21 @@ }, "node_modules/retry": { "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/rolldown": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.0.tgz", - "integrity": "sha512-zpMvlJhs5PkXRTtKc0CaLBVI9AR/VDiJFpM+kx//hgToEca7FgMlGjaRIisXBcb19T76LswgmKECSQ96hjWr5A==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.1.tgz", + "integrity": "sha512-IN750c0p+s3jqJIsFLRZrQazmbAB1kkQDTtQjSt/gbS2ywLhlv4R5Shazer0FZKmuo/BsO3/w2UoYnUjuOZqHg==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.134.0", + "@oxc-project/types": "=0.135.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -5716,21 +5442,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.1.0", - "@rolldown/binding-darwin-arm64": "1.1.0", - "@rolldown/binding-darwin-x64": "1.1.0", - "@rolldown/binding-freebsd-x64": "1.1.0", - "@rolldown/binding-linux-arm-gnueabihf": "1.1.0", - "@rolldown/binding-linux-arm64-gnu": "1.1.0", - "@rolldown/binding-linux-arm64-musl": "1.1.0", - "@rolldown/binding-linux-ppc64-gnu": "1.1.0", - "@rolldown/binding-linux-s390x-gnu": "1.1.0", - "@rolldown/binding-linux-x64-gnu": "1.1.0", - "@rolldown/binding-linux-x64-musl": "1.1.0", - "@rolldown/binding-openharmony-arm64": "1.1.0", - "@rolldown/binding-wasm32-wasi": "1.1.0", - "@rolldown/binding-win32-arm64-msvc": "1.1.0", - "@rolldown/binding-win32-x64-msvc": "1.1.0" + "@rolldown/binding-android-arm64": "1.1.1", + "@rolldown/binding-darwin-arm64": "1.1.1", + "@rolldown/binding-darwin-x64": "1.1.1", + "@rolldown/binding-freebsd-x64": "1.1.1", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.1", + "@rolldown/binding-linux-arm64-gnu": "1.1.1", + "@rolldown/binding-linux-arm64-musl": "1.1.1", + "@rolldown/binding-linux-ppc64-gnu": "1.1.1", + "@rolldown/binding-linux-s390x-gnu": "1.1.1", + "@rolldown/binding-linux-x64-gnu": "1.1.1", + "@rolldown/binding-linux-x64-musl": "1.1.1", + "@rolldown/binding-openharmony-arm64": "1.1.1", + "@rolldown/binding-wasm32-wasi": "1.1.1", + "@rolldown/binding-win32-arm64-msvc": "1.1.1", + "@rolldown/binding-win32-x64-msvc": "1.1.1" } }, "node_modules/rolldown-plugin-dts": { @@ -5777,30 +5503,14 @@ } } }, - "node_modules/rolldown-plugin-dts/node_modules/get-tsconfig": { - "version": "5.0.0-beta.5", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.5.tgz", - "integrity": "sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ==", + "node_modules/rollup": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.61.1.tgz", + "integrity": "sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==", "dev": true, "license": "MIT", "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "engines": { - "node": ">=20.20.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/rollup": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz", - "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" + "@types/estree": "1.0.9" }, "bin": { "rollup": "dist/bin/rollup" @@ -5810,36 +5520,38 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.60.2", - "@rollup/rollup-android-arm64": "4.60.2", - "@rollup/rollup-darwin-arm64": "4.60.2", - "@rollup/rollup-darwin-x64": "4.60.2", - "@rollup/rollup-freebsd-arm64": "4.60.2", - "@rollup/rollup-freebsd-x64": "4.60.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", - "@rollup/rollup-linux-arm-musleabihf": "4.60.2", - "@rollup/rollup-linux-arm64-gnu": "4.60.2", - "@rollup/rollup-linux-arm64-musl": "4.60.2", - "@rollup/rollup-linux-loong64-gnu": "4.60.2", - "@rollup/rollup-linux-loong64-musl": "4.60.2", - "@rollup/rollup-linux-ppc64-gnu": "4.60.2", - "@rollup/rollup-linux-ppc64-musl": "4.60.2", - "@rollup/rollup-linux-riscv64-gnu": "4.60.2", - "@rollup/rollup-linux-riscv64-musl": "4.60.2", - "@rollup/rollup-linux-s390x-gnu": "4.60.2", - "@rollup/rollup-linux-x64-gnu": "4.60.2", - "@rollup/rollup-linux-x64-musl": "4.60.2", - "@rollup/rollup-openbsd-x64": "4.60.2", - "@rollup/rollup-openharmony-arm64": "4.60.2", - "@rollup/rollup-win32-arm64-msvc": "4.60.2", - "@rollup/rollup-win32-ia32-msvc": "4.60.2", - "@rollup/rollup-win32-x64-gnu": "4.60.2", - "@rollup/rollup-win32-x64-msvc": "4.60.2", + "@rollup/rollup-android-arm-eabi": "4.61.1", + "@rollup/rollup-android-arm64": "4.61.1", + "@rollup/rollup-darwin-arm64": "4.61.1", + "@rollup/rollup-darwin-x64": "4.61.1", + "@rollup/rollup-freebsd-arm64": "4.61.1", + "@rollup/rollup-freebsd-x64": "4.61.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.61.1", + "@rollup/rollup-linux-arm-musleabihf": "4.61.1", + "@rollup/rollup-linux-arm64-gnu": "4.61.1", + "@rollup/rollup-linux-arm64-musl": "4.61.1", + "@rollup/rollup-linux-loong64-gnu": "4.61.1", + "@rollup/rollup-linux-loong64-musl": "4.61.1", + "@rollup/rollup-linux-ppc64-gnu": "4.61.1", + "@rollup/rollup-linux-ppc64-musl": "4.61.1", + "@rollup/rollup-linux-riscv64-gnu": "4.61.1", + "@rollup/rollup-linux-riscv64-musl": "4.61.1", + "@rollup/rollup-linux-s390x-gnu": "4.61.1", + "@rollup/rollup-linux-x64-gnu": "4.61.1", + "@rollup/rollup-linux-x64-musl": "4.61.1", + "@rollup/rollup-openbsd-x64": "4.61.1", + "@rollup/rollup-openharmony-arm64": "4.61.1", + "@rollup/rollup-win32-arm64-msvc": "4.61.1", + "@rollup/rollup-win32-ia32-msvc": "4.61.1", + "@rollup/rollup-win32-x64-gnu": "4.61.1", + "@rollup/rollup-win32-x64-msvc": "4.61.1", "fsevents": "~2.3.2" } }, "node_modules/safe-buffer": { "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -5919,53 +5631,6 @@ "dev": true, "license": "ISC" }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.7", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "8.0.5", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "license": "BSD-3-Clause", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -5985,6 +5650,8 @@ }, "node_modules/std-env": { "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", "dev": true, "license": "MIT" }, @@ -6024,11 +5691,14 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/tinyglobby": { "version": "0.2.17", @@ -6089,6 +5759,8 @@ }, "node_modules/ts-algebra": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", "license": "MIT" }, "node_modules/tsdown": { @@ -6164,39 +5836,20 @@ } } }, - "node_modules/tsdown/node_modules/cac": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cac/-/cac-7.0.0.tgz", - "integrity": "sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/tsdown/node_modules/tinyexec": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", - "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/tslib": { "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/tsx": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz", + "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" + "esbuild": "~0.28.0" }, "bin": { "tsx": "dist/cli.mjs" @@ -6216,6 +5869,8 @@ }, "node_modules/typescript": { "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -6240,23 +5895,16 @@ "url": "https://github.com/sponsors/antfu" } }, - "node_modules/undici": { - "version": "7.25.0", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=20.18.1" - } - }, "node_modules/undici-types": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "license": "MIT" }, "node_modules/vite": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", - "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.5.tgz", + "integrity": "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==", "dev": true, "license": "MIT", "dependencies": { @@ -6351,161 +5999,670 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/vitest": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", - "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "node_modules/vite-node/node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, "license": "MIT", - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/expect": "3.2.4", - "@vitest/mocker": "3.2.4", - "@vitest/pretty-format": "^3.2.4", - "@vitest/runner": "3.2.4", - "@vitest/snapshot": "3.2.4", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", - "chai": "^5.2.0", - "debug": "^4.4.1", - "expect-type": "^1.2.1", - "magic-string": "^0.30.17", - "pathe": "^2.0.3", - "picomatch": "^4.0.2", - "std-env": "^3.9.0", - "tinybench": "^2.9.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.14", - "tinypool": "^1.1.1", - "tinyrainbow": "^2.0.0", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", - "vite-node": "3.2.4", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/debug": "^4.1.12", - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.2.4", - "@vitest/ui": "3.2.4", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/debug": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } + "node": ">=8" } }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">= 8" + "node": ">=18" } }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/ws": { - "version": "8.20.0", + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "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 - } + "node": ">=18" } }, - "node_modules/xml-naming": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", - "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=16.0.0" + "node": ">=18" } }, - "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" + "node": ">=18" } }, - "node_modules/zod": { - "version": "4.3.6", - "license": "MIT", - "funding": { + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/vitest": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.6.tgz", + "integrity": "sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.6", + "@vitest/mocker": "3.2.6", + "@vitest/pretty-format": "^3.2.6", + "@vitest/runner": "3.2.6", + "@vitest/snapshot": "3.2.6", + "@vitest/spy": "3.2.6", + "@vitest/utils": "3.2.6", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.6", + "@vitest/ui": "3.2.6", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "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 + } + } + }, + "node_modules/xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "license": "MIT", + "funding": { "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/zod-to-json-schema": { "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", "license": "ISC", "peerDependencies": { "zod": "^3.25.28 || ^4" @@ -6541,27 +6698,6 @@ "vitest": "^3.2.4" } }, - "packages/cua-anthropic": { - "name": "@onkernel/cua-anthropic", - "version": "0.1.0", - "dependencies": { - "@anthropic-ai/sdk": "^0.90.0", - "@onkernel/cua-translator": "0.1.0", - "@sinclair/typebox": "0.34.49" - }, - "peerDependencies": { - "@mariozechner/pi-agent-core": "0.67.6", - "@mariozechner/pi-ai": "0.67.6" - }, - "peerDependenciesMeta": { - "@mariozechner/pi-agent-core": { - "optional": true - }, - "@mariozechner/pi-ai": { - "optional": true - } - } - }, "packages/cua-cli": { "name": "@onkernel/cua-cli", "version": "0.1.0", @@ -6580,97 +6716,6 @@ "vitest": "^3.2.4" } }, - "packages/cua-gemini": { - "name": "@onkernel/cua-gemini", - "version": "0.1.0", - "dependencies": { - "@google/genai": "^1.50.1", - "@onkernel/cua-translator": "0.1.0", - "@sinclair/typebox": "0.34.49" - }, - "peerDependencies": { - "@mariozechner/pi-agent-core": "0.67.6", - "@mariozechner/pi-ai": "0.67.6" - }, - "peerDependenciesMeta": { - "@mariozechner/pi-agent-core": { - "optional": true - }, - "@mariozechner/pi-ai": { - "optional": true - } - } - }, - "packages/cua-openai": { - "name": "@onkernel/cua-openai", - "version": "0.1.0", - "dependencies": { - "@onkernel/cua-translator": "0.1.0", - "@sinclair/typebox": "0.34.49", - "openai": "^6.26.0" - }, - "peerDependencies": { - "@mariozechner/pi-agent-core": "0.67.6", - "@mariozechner/pi-ai": "0.67.6" - }, - "peerDependenciesMeta": { - "@mariozechner/pi-agent-core": { - "optional": true - }, - "@mariozechner/pi-ai": { - "optional": true - } - } - }, - "packages/cua-translator": { - "name": "@onkernel/cua-translator", - "version": "0.1.0", - "dependencies": { - "@onkernel/sdk": "0.49.0" - } - }, - "packages/cua-tzafon": { - "name": "@onkernel/cua-tzafon", - "version": "0.1.0", - "dependencies": { - "@onkernel/cua-translator": "0.1.0", - "@sinclair/typebox": "0.34.49", - "@tzafon/lightcone": "^0.7.0" - }, - "peerDependencies": { - "@mariozechner/pi-agent-core": "0.67.6", - "@mariozechner/pi-ai": "0.67.6" - }, - "peerDependenciesMeta": { - "@mariozechner/pi-agent-core": { - "optional": true - }, - "@mariozechner/pi-ai": { - "optional": true - } - } - }, - "packages/cua-yutori": { - "name": "@onkernel/cua-yutori", - "version": "0.1.0", - "dependencies": { - "@onkernel/cua-translator": "0.1.0", - "@sinclair/typebox": "0.34.49", - "openai": "^6.26.0" - }, - "peerDependencies": { - "@mariozechner/pi-agent-core": "0.67.6", - "@mariozechner/pi-ai": "0.67.6" - }, - "peerDependenciesMeta": { - "@mariozechner/pi-agent-core": { - "optional": true - }, - "@mariozechner/pi-ai": { - "optional": true - } - } - }, "packages/ptywright": { "name": "@onkernel/ptywright", "version": "0.1.0", diff --git a/package.json b/package.json index 7e8b2ae6..3e972964 100644 --- a/package.json +++ b/package.json @@ -7,12 +7,6 @@ "workspaces": [ "packages/ai", "packages/agent", - "packages/cua-translator", - "packages/cua-openai", - "packages/cua-anthropic", - "packages/cua-gemini", - "packages/cua-tzafon", - "packages/cua-yutori", "packages/ptywright", "packages/cua-cli" ], diff --git a/packages/cua-anthropic/README.md b/packages/cua-anthropic/README.md deleted file mode 100644 index 3ebcbbc2..00000000 --- a/packages/cua-anthropic/README.md +++ /dev/null @@ -1,258 +0,0 @@ -# `@onkernel/cua-anthropic` - -Provider-neutral Anthropic computer-use helpers backed by -[`@onkernel/cua-translator`](../cua-translator). - -## Entry points - -- `@onkernel/cua-anthropic` — provider-neutral root surface: - `anthropic(modelId)`, built-in computer/batch execution helpers, - Anthropic tool specs, and prompt builders. -- `@onkernel/cua-anthropic/pi` — `pi-agent-core` bindings: - `createAnthropicComputerTools()`, `anthropicComputerOnPayload()`, - `composeOnPayload()`, `wrapAnthropicStream()`, and - `registerAnthropicProvider()`. - -## Install - -```bash -npm install @onkernel/cua-anthropic @onkernel/cua-translator @onkernel/sdk -``` - -If you want the `pi-agent-core` bindings too: - -```bash -npm install @earendil-works/pi-agent-core @earendil-works/pi-ai -``` - -## Quick start (`runComputerUse`) - -```typescript -import { browserSession, runComputerUse } from "@onkernel/cua-translator"; -import { anthropic } from "@onkernel/cua-anthropic"; - -const browser = await browserSession.open({ apiKey: process.env.KERNEL_API_KEY! }); - -const result = await runComputerUse({ - model: anthropic("claude-opus-4-7"), - browser, - prompt: "Open https://example.com and tell me the heading.", -}); - -console.log(result.text); -``` - -## Quick start (with `pi-agent-core`) - -```typescript -import { Agent, type StreamFn } from "@earendil-works/pi-agent-core"; -import { getModel, streamSimple } from "@earendil-works/pi-ai"; -import { - ComputerTranslator, - browserSession, -} from "@onkernel/cua-translator"; -import { - buildAnthropicSystemPrompt, -} from "@onkernel/cua-anthropic"; -import { - anthropicComputerOnPayload, - composeOnPayload, - createAnthropicComputerTools, - registerAnthropicProvider, - wrapAnthropicStream, -} from "@onkernel/cua-anthropic/pi"; - -registerAnthropicProvider(); - -const browser = await browserSession.open({ apiKey: process.env.KERNEL_API_KEY! }); -const translator = new ComputerTranslator({ - client: browser.client, - sessionId: browser.sessionId, -}); - -const agent = new Agent({ - initialState: { - systemPrompt: buildAnthropicSystemPrompt(), - model: getModel("anthropic", "claude-opus-4-7"), - tools: createAnthropicComputerTools(translator), - thinkingLevel: "low", - }, - getApiKey: () => process.env.ANTHROPIC_API_KEY, - streamFn: wrapAnthropicStream(streamSimple as unknown as StreamFn), - onPayload: composeOnPayload(anthropicComputerOnPayload), -}); - -await agent.prompt("Open https://example.com and tell me the heading."); -``` - -## Action reference - -### Anthropic's built-in `computer` tool - -Source of truth: Anthropic's -[Computer Use docs](https://docs.claude.com/en/docs/agents-and-tools/computer-use). -We register the latest `computer_20251124` tool spec; the model emits -`tool_use` blocks the `computer` AgentTool routes to Kernel. - -| Action | Source | Since version | Notes | -| ----------------- | ------------------------------- | ------------------- | ------------------------------------------------------------ | -| `key` | official (Anthropic) | `computer_20241022` | `{text: "ctrl+l"}` etc. | -| `type` | official (Anthropic) | `computer_20241022` | `{text}`. | -| `mouse_move` | official (Anthropic) | `computer_20241022` | `{coordinate: [x, y]}`. | -| `left_click` | official (Anthropic) | `computer_20241022` | `{coordinate, text?}`. Optional `text` is held modifiers. | -| `left_click_drag` | official (Anthropic) | `computer_20241022` | `{start_coordinate, coordinate}`. | -| `right_click` | official (Anthropic) | `computer_20241022` | `{coordinate, text?}`. | -| `middle_click` | official (Anthropic) | `computer_20241022` | `{coordinate, text?}`. | -| `double_click` | official (Anthropic) | `computer_20241022` | `{coordinate}`. | -| `screenshot` | official (Anthropic) | `computer_20241022` | Returns a fresh PNG. | -| `cursor_position` | official (Anthropic) | `computer_20241022` | **Not supported** by this build (Kernel doesn't expose it). | -| `scroll` | official (Anthropic) | `computer_20250124` | `{coordinate, scroll_direction, scroll_amount}`. | -| `hold_key` | official (Anthropic) | `computer_20250124` | **Not supported** by this build. | -| `wait` | official (Anthropic) | `computer_20250124` | `{duration}` in seconds. | -| `triple_click` | official (Anthropic) | `computer_20250124` | `{coordinate}`. Implemented as 3× click. | -| `left_mouse_down` | official (Anthropic) | `computer_20250124` | **Not supported** by this build. | -| `left_mouse_up` | official (Anthropic) | `computer_20250124` | **Not supported** by this build. | -| `zoom` | official (Anthropic) | `computer_20251124` | **Not supported** by this build (`enable_zoom: false`). | - -### `batch_computer_actions` (cua-added) - -Same canonical action union as the OpenAI / Gemini batch tools. Uses -`{x, y}` pixel pairs (NOT Anthropic's `coordinate: [x, y]` tuple). The -system prompt nudges the model to prefer this tool for predictable -sequences. - -| Action | Source | Notes | -| ------------------ | ---------------------------- | --------------------------------------------------------- | -| `click` | official (Anthropic) — re-shaped | Pixel `{x, y, button?, hold_keys?}`. | -| `double_click` | official (Anthropic) — re-shaped | `{x, y, hold_keys?}`. | -| `triple_click` | official (Anthropic) — re-shaped | `{x, y}`. Expands to 3× click before translator dispatch. | -| `move` | official (Anthropic) — re-shaped | `{x, y}`. | -| `scroll` | official (Anthropic) — re-shaped | `{x, y, scroll_x?, scroll_y?, hold_keys?}` in pixel deltas. | -| `type` | official (Anthropic) — re-shaped | `{text}`. | -| `keypress` | official (Anthropic) — re-shaped | `{keys: string[]}`. | -| `drag` | official (Anthropic) — re-shaped | `{path: {x, y}[]}`. | -| `wait` | official (Anthropic) — re-shaped | `{ms?}`. | -| `screenshot` | official (Anthropic) — re-shaped | Read step. | -| `goto` | cua extension | `{url}`. Compiles to ctrl+l → ctrl+a → type → Enter. | -| `back` | cua extension | Alt+Left. | -| `forward` | cua extension | Alt+Right. | -| `url` | cua extension | Read step. Compiles to ctrl+l → ctrl+c → readClipboard. | - -The cua extensions live in `src/cua-extras.ts` — delete that file (and -trim the action-type enum in `src/batch.ts`) to drop them. - -## Wire-format dump - -The `computer_20251124` tool spec we send via `anthropicComputerOnPayload`: - -```json -{ - "type": "computer_20251124", - "name": "computer", - "display_width_px": 1920, - "display_height_px": 1080, - "display_number": 1, - "enable_zoom": false -} -``` - -The `batch_computer_actions` tool spec (rendered from -`AnthropicBatchSchema` via `ANTHROPIC_BATCH_TOOL_WIRE_SPEC`): - -```json -{ - "name": "batch_computer_actions", - "description": "Execute multiple computer actions in sequence...", - "input_schema": { - "type": "object", - "properties": { - "actions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "click", "double_click", "triple_click", "type", - "keypress", "scroll", "move", "drag", "wait", - "goto", "back", "forward", "url", "screenshot" - ] - }, - "x": { "type": "number" }, - "y": { "type": "number" }, - "text": { "type": "string" }, - "url": { "type": "string" }, - "keys": { "type": "array", "items": { "type": "string" } }, - "button": { "type": "string" }, - "hold_keys": { "type": "array", "items": { "type": "string" } }, - "scroll_x": { "type": "number" }, - "scroll_y": { "type": "number" }, - "ms": { "type": "number" }, - "path": { - "type": "array", - "items": { - "type": "object", - "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, - "required": ["x", "y"] - } - } - }, - "required": ["type"], - "additionalProperties": false - } - } - }, - "required": ["actions"] - } -} -``` - -The required beta header (`anthropic-beta: computer-use-2025-11-24`) is -merged in by `wrapAnthropicStream`. - -## Embed in your own agent loop - -```typescript -import Anthropic from "@anthropic-ai/sdk"; -import { - ComputerTranslator, - browserSession, -} from "@onkernel/cua-translator"; -import { - ANTHROPIC_COMPUTER_TOOL, - ANTHROPIC_COMPUTER_USE_BETA, - ANTHROPIC_BATCH_TOOL_WIRE_SPEC, - executeAnthropicBatch, - executeAnthropicComputerAction, -} from "@onkernel/cua-anthropic"; - -const browser = await browserSession.open({ apiKey: process.env.KERNEL_API_KEY! }); -const translator = new ComputerTranslator({ client: browser.client, sessionId: browser.sessionId }); - -const anthropic = new Anthropic({ defaultHeaders: { "anthropic-beta": ANTHROPIC_COMPUTER_USE_BETA } }); -const response = await anthropic.messages.create({ - model: "claude-opus-4-7", - max_tokens: 4096, - tools: [ - ANTHROPIC_COMPUTER_TOOL, - ANTHROPIC_BATCH_TOOL_WIRE_SPEC, - ], - messages: [{ role: "user", content: "Open https://example.com" }], -}); - -for (const block of response.content) { - if (block.type === "tool_use" && block.name === "computer") { - const result = await executeAnthropicComputerAction(translator, block.input as any); - // feed result.content back as a tool_result block - } - if (block.type === "tool_use" && block.name === "batch_computer_actions") { - const result = await executeAnthropicBatch(translator, block.input as any); - // feed result.content back as a tool_result block - } -} -``` - -## License - -MIT. diff --git a/packages/cua-anthropic/package.json b/packages/cua-anthropic/package.json deleted file mode 100644 index c0df7b33..00000000 --- a/packages/cua-anthropic/package.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "@onkernel/cua-anthropic", - "version": "0.1.0", - "description": "Provider-neutral Anthropic computer-use helpers with explicit /pi bindings", - "type": "module", - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "import": "./dist/index.js" - }, - "./pi": { - "types": "./dist/pi/index.d.ts", - "import": "./dist/pi/index.js" - } - }, - "files": [ - "dist", - "README.md" - ], - "scripts": { - "build": "tsc -b", - "clean": "tsc -b --clean" - }, - "dependencies": { - "@anthropic-ai/sdk": "^0.90.0", - "@onkernel/cua-translator": "0.1.0", - "@sinclair/typebox": "0.34.49" - }, - "peerDependencies": { - "@mariozechner/pi-agent-core": "0.67.6", - "@mariozechner/pi-ai": "0.67.6" - }, - "peerDependenciesMeta": { - "@mariozechner/pi-agent-core": { - "optional": true - }, - "@mariozechner/pi-ai": { - "optional": true - } - } -} diff --git a/packages/cua-anthropic/src/batch-tool.ts b/packages/cua-anthropic/src/batch-tool.ts deleted file mode 100644 index d8dbd40c..00000000 --- a/packages/cua-anthropic/src/batch-tool.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core"; -import type { ImageContent, TextContent } from "@mariozechner/pi-ai"; -import type { ComputerTranslator } from "@onkernel/cua-translator"; -import { - AnthropicBatchSchema, - type AnthropicBatchToolDetails, - executeAnthropicBatch, - ANTHROPIC_BATCH_DESCRIPTION, - ANTHROPIC_BATCH_TOOL_NAME, -} from "./batch"; - -/** - * Anthropic-flavored `batch_computer_actions` tool. - * - * Anthropic accepts custom function tools with a JSON Schema `input_schema` - * field on the Messages API. We reuse the SAME canonical action union as - * the OpenAI batch tool (with the `keys` modifier renamed appropriately - * for action shapes that match Anthropic's vocabulary), so a single - * `ComputerTranslator.executeBatch` call can service the actions. - * - * The schema covers BOTH: - * - Anthropic's official `computer_20251124` action vocabulary (so the - * model can express the same things via batch as via the built-in - * tool, but in one round-trip). - * - cua extension actions (`goto`, `back`, `forward`, `url`). - * - * Coordinate convention here matches the OpenAI/canonical convention: - * `x` and `y` numbers, NOT Anthropic's `coordinate: [x, y]` tuple. The - * batch tool's preamble in `system-prompt.ts` documents this so the - * model picks the right shape. - */ - -/** - * Build the `batch_computer_actions` AgentTool for Anthropic. Registered - * alongside the built-in `computer` tool — the system prompt nudges the - * model towards this one for predictable sequences. - * - * Set `enabled: false` (or omit from the tool list) to ship Anthropic - * with only the built-in `computer` tool. - */ -export function createAnthropicBatchTool( - translator: ComputerTranslator, -): AgentTool { - return { - name: ANTHROPIC_BATCH_TOOL_NAME, - label: ANTHROPIC_BATCH_TOOL_NAME, - description: ANTHROPIC_BATCH_DESCRIPTION, - parameters: AnthropicBatchSchema, - async execute(_id, params): Promise> { - const result = await executeAnthropicBatch(translator, params); - const content = result.content as (TextContent | ImageContent)[]; - const details = result.details; - if (result.isError) { - const message = details.error ?? details.statusText; - throw Object.assign(new Error(message), { details, content }); - } - return { content, details }; - }, - }; -} diff --git a/packages/cua-anthropic/src/batch.ts b/packages/cua-anthropic/src/batch.ts deleted file mode 100644 index be2572a0..00000000 --- a/packages/cua-anthropic/src/batch.ts +++ /dev/null @@ -1,254 +0,0 @@ -import type { ComputerTranslator, ComputerUseToolResult, ModelAction } from "@onkernel/cua-translator"; -import { type Static, Type } from "@sinclair/typebox"; -import { ANTHROPIC_CUA_EXTRA_ACTION_TYPES } from "./cua-extras"; -import { ANTHROPIC_OFFICIAL_ACTION_TYPES } from "./official"; - -const COORD_PAIR = Type.Object({ x: Type.Number(), y: Type.Number() }, { additionalProperties: false }); - -const Action = Type.Object( - { - type: Type.String({ - description: "Action type", - enum: [ - "click", - "double_click", - "triple_click", - "type", - "keypress", - "scroll", - "move", - "drag", - "wait", - "goto", - "back", - "forward", - "url", - "screenshot", - ], - }), - x: Type.Optional(Type.Number()), - y: Type.Optional(Type.Number()), - text: Type.Optional(Type.String()), - url: Type.Optional(Type.String({ description: "URL to navigate to when type is goto" })), - keys: Type.Optional(Type.Array(Type.String())), - button: Type.Optional(Type.String()), - hold_keys: Type.Optional(Type.Array(Type.String())), - scroll_x: Type.Optional(Type.Number()), - scroll_y: Type.Optional(Type.Number()), - ms: Type.Optional(Type.Number({ description: "Optional wait duration in milliseconds when type is wait" })), - path: Type.Optional( - Type.Array(COORD_PAIR, { - description: "Required when type is drag. At least two points.", - }), - ), - }, - { additionalProperties: false }, -); - -export const AnthropicBatchSchema = Type.Object({ - actions: Type.Array(Action, { description: "Ordered list of actions to execute" }), -}); - -export type AnthropicBatchToolInput = Static; - -export interface AnthropicBatchToolDetails { - statusText: string; - actionDescriptions: string[]; - readResults: Array<{ type: "url"; url: string } | { type: "screenshot"; bytes: number } | { type: "cursor_position"; x: number; y: number }>; - error?: string; -} - -const SETTLE_MS_AFTER_BATCH = 300; - -function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -export const ANTHROPIC_BATCH_DESCRIPTION = [ - "Execute multiple computer actions in sequence, including ordered read steps like url() and screenshot() anywhere in the batch.", - "Coordinates use {x, y} pixels. Modifier keys go in the optional `hold_keys` array on click/scroll/move actions.", - "Consecutive write actions are flushed together; each url()/screenshot() step returns output in the order it was requested.", - "If no explicit read step is included, the tool returns one fresh screenshot after execution.", - "", - "PREFER this over the built-in `computer` tool when:", - "- Typing text followed by pressing Enter", - "- Clicking a field and then typing into it", - "- Navigating with goto (cua extension that focuses the address bar, types the URL, presses Enter)", - "- Using back/forward (cua extensions for keyboard back/forward)", - "- Reading the current URL via url() — returns the address bar contents", - "", - "Drag format: when type is drag, include path as an ordered array of {x, y} points (at least two).", - "If a drag is likely to change the position or layout of other targets, do not batch multiple drags together.", - "Wait format: when type is wait, you may include ms to control the pause duration in milliseconds.", -].join("\n"); - -export const ANTHROPIC_BATCH_TOOL_NAME = "batch_computer_actions"; - -/** - * Anthropic Messages API `tools[]` entry for the batch tool, in the exact - * shape Anthropic expects. - */ -export const ANTHROPIC_BATCH_TOOL_WIRE_SPEC = { - name: ANTHROPIC_BATCH_TOOL_NAME, - description: ANTHROPIC_BATCH_DESCRIPTION, - input_schema: AnthropicBatchSchema, -} as const; - -/** - * Re-exported for documentation. The action `type` enum on the wire is the - * union of official Anthropic computer actions that fit the canonical shape - * plus the cua extension actions. - */ -export const ANTHROPIC_BATCH_ACTION_TYPES = [ - "click", - "double_click", - "triple_click", - "type", - "keypress", - "scroll", - "move", - "drag", - "wait", - "screenshot", - ...ANTHROPIC_CUA_EXTRA_ACTION_TYPES, -] as const; - -export async function executeAnthropicBatch( - translator: ComputerTranslator, - params: AnthropicBatchToolInput, -): Promise> { - const rawActions = (params.actions ?? []) as ModelAction[]; - const actions = expandTripleClick(rawActions); - const actionDescriptions = rawActions.map(describeShort); - const content: ComputerUseToolResult["content"] = []; - let statusText: string; - let execErr: Error | undefined; - const readResults: AnthropicBatchToolDetails["readResults"] = []; - - let hasScreenshotInResults = false; - try { - const result = await translator.executeBatch(actions); - for (const r of result.readResults) { - if (r.type === "url") { - readResults.push({ type: "url", url: r.url }); - } else if (r.type === "screenshot") { - readResults.push({ type: "screenshot", bytes: r.pngBytes.length }); - hasScreenshotInResults = true; - } else { - readResults.push({ type: "cursor_position", x: r.x, y: r.y }); - } - } - statusText = "Actions executed successfully."; - content.push({ type: "text", text: statusText }); - for (const r of result.readResults) { - if (r.type === "url") { - content.push({ type: "text", text: `url(): ${r.url}` }); - } else if (r.type === "screenshot") { - content.push({ - type: "image", - data: r.pngBytes.toString("base64"), - mimeType: "image/png", - }); - } else { - content.push({ type: "text", text: `cursor_position(): ${r.x},${r.y}` }); - } - } - } catch (err) { - execErr = err instanceof Error ? err : new Error(String(err)); - statusText = `Actions failed: ${execErr.message}`; - content.push({ type: "text", text: statusText }); - } - - const needFallback = readResults.length === 0 || (execErr && !hasScreenshotInResults); - if (needFallback) { - if (!execErr) await delay(SETTLE_MS_AFTER_BATCH); - try { - const png = await translator.screenshotRaw(); - content.push({ type: "image", data: png.toString("base64"), mimeType: "image/png" }); - readResults.push({ type: "screenshot", bytes: png.length }); - } catch (shotErr) { - content[0] = { - type: "text", - text: `${statusText} Screenshot unavailable: ${(shotErr as Error).message}`, - }; - } - } - - const details: AnthropicBatchToolDetails = { - statusText, - actionDescriptions, - readResults, - ...(execErr ? { error: execErr.message } : {}), - }; - - return { - content, - details, - ...(execErr ? { isError: true } : {}), - }; -} - -function describeShort(action: ModelAction): string { - const t = typeof action.type === "string" ? action.type : ""; - switch (t) { - case "click": - case "double_click": - case "triple_click": - return `${t}(${num(action.x)}, ${num(action.y)})`; - case "type": { - const text = typeof action.text === "string" ? action.text : ""; - const trimmed = text.length > 30 ? `${text.slice(0, 27)}...` : text; - return `type(${JSON.stringify(trimmed)})`; - } - case "keypress": { - const keys = Array.isArray(action.keys) ? (action.keys as string[]) : []; - return `keypress(${JSON.stringify(keys)})`; - } - case "scroll": - return `scroll(${num(action.x)}, ${num(action.y)})`; - case "move": - return `move(${num(action.x)}, ${num(action.y)})`; - case "drag": - return "drag(...)"; - case "wait": - return "wait"; - case "goto": - return `goto(${JSON.stringify(typeof action.url === "string" ? action.url : "")})`; - case "back": - return "back()"; - case "forward": - return "forward()"; - case "url": - return "url()"; - case "screenshot": - return "screenshot()"; - default: - return t || ""; - } -} - -function num(v: unknown): number { - if (typeof v === "number" && Number.isFinite(v)) return Math.trunc(v); - return 0; -} - -// triple_click handling at translator boundary: -// translator's translateToBatchAction doesn't natively accept "triple_click", -// so map it to three sequential clicks before passing in. -export function expandTripleClick(actions: ModelAction[]): ModelAction[] { - const expanded: ModelAction[] = []; - for (const a of actions) { - if (typeof a.type === "string" && a.type === "triple_click") { - const x = num(a.x); - const y = num(a.y); - expanded.push( - { type: "click", x, y, button: "left" }, - { type: "click", x, y, button: "left" }, - { type: "click", x, y, button: "left" }, - ); - } else { - expanded.push(a); - } - } - return expanded; -} diff --git a/packages/cua-anthropic/src/computer-tool.ts b/packages/cua-anthropic/src/computer-tool.ts deleted file mode 100644 index d3cb0d48..00000000 --- a/packages/cua-anthropic/src/computer-tool.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core"; -import type { ImageContent, TextContent } from "@mariozechner/pi-ai"; -import type { ComputerTranslator } from "@onkernel/cua-translator"; -import { - ComputerSchema, - type AnthropicComputerDetails, - executeAnthropicComputerAction, -} from "./computer"; - -/** - * Build the `computer` AgentTool for Anthropic. The provider payload hook - * swaps this function tool for Anthropic's built-in `computer_20251124` - * spec on the wire; locally we route the tool use through the shared - * Kernel-backed execution helper. - */ -export function createAnthropicComputerTool( - translator: ComputerTranslator, -): AgentTool { - return { - name: "computer", - label: "computer", - description: - "Anthropic built-in computer use tool. Spec is injected by the provider; this AgentTool routes tool_use blocks to our Kernel-backed translator.", - parameters: ComputerSchema, - async execute(_id, params): Promise> { - const result = await executeAnthropicComputerAction(translator, params); - const content = result.content as (TextContent | ImageContent)[]; - const details = result.details; - if (result.isError) { - const message = details.error ?? details.statusText; - throw Object.assign(new Error(message), { details, content }); - } - return { content, details }; - }, - }; -} diff --git a/packages/cua-anthropic/src/computer.ts b/packages/cua-anthropic/src/computer.ts deleted file mode 100644 index 1e980a03..00000000 --- a/packages/cua-anthropic/src/computer.ts +++ /dev/null @@ -1,323 +0,0 @@ -import type { ComputerTranslator, ComputerUseToolResult, ModelAction } from "@onkernel/cua-translator"; -import { type Static, Type } from "@sinclair/typebox"; - -/** - * Permissive schema for the built-in Anthropic `computer` tool. - * - * Anthropic's `computer` tool is schema-less on the wire (the model knows - * the action shape internally; we only get `tool_use` blocks named - * "computer" with arbitrary input). - */ -const Coordinate = Type.Tuple([Type.Number(), Type.Number()]); - -export const ComputerSchema = Type.Object( - { - action: Type.String({ - description: - "Anthropic computer action: screenshot, left_click, right_click, middle_click, double_click, triple_click, mouse_move, left_click_drag, type, key, scroll, hold_key, wait, left_mouse_down, left_mouse_up, zoom", - }), - coordinate: Type.Optional(Coordinate), - start_coordinate: Type.Optional(Coordinate), - text: Type.Optional(Type.String()), - duration: Type.Optional(Type.Number()), - scroll_direction: Type.Optional(Type.String()), - scroll_amount: Type.Optional(Type.Number()), - region: Type.Optional( - Type.Tuple([Type.Number(), Type.Number(), Type.Number(), Type.Number()]), - ), - }, - { additionalProperties: true }, -); - -export type AnthropicComputerInput = Static; - -export interface AnthropicComputerDetails { - action: string; - statusText: string; - error?: string; -} - -const SETTLE_MS = 300; -const DEFAULT_HOLD_KEY_MS = 1000; - -function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -export async function executeAnthropicComputerAction( - translator: ComputerTranslator, - params: AnthropicComputerInput, -): Promise> { - const action = String(params.action ?? ""); - const content: ComputerUseToolResult["content"] = []; - let statusText = "ok"; - let execErr: Error | undefined; - let skipScreenshot = false; - - try { - const actions = translateAnthropicAction(action, params); - if (actions === "unsupported") { - throw new Error(`computer action "${action}" is not supported by this cua build`); - } - if (actions.length === 0) { - skipScreenshot = true; - } else { - const result = await translator.executeBatch(actions); - for (const r of result.readResults) { - if (r.type === "screenshot") { - content.push({ type: "text", text: "screenshot:" }); - content.push({ - type: "image", - data: r.pngBytes.toString("base64"), - mimeType: "image/png", - }); - skipScreenshot = true; - } else if (r.type === "url") { - content.push({ type: "text", text: `url: ${r.url}` }); - skipScreenshot = true; - } else if (r.type === "cursor_position") { - content.push({ type: "text", text: `cursor_position: ${r.x},${r.y}` }); - skipScreenshot = true; - } - } - } - } catch (err) { - execErr = err instanceof Error ? err : new Error(String(err)); - statusText = `failed: ${execErr.message}`; - } - - content.unshift({ type: "text", text: statusText }); - - if (!execErr && !skipScreenshot) { - await delay(SETTLE_MS); - try { - const png = await translator.screenshotRaw(); - content.push({ - type: "image", - data: png.toString("base64"), - mimeType: "image/png", - }); - } catch (shotErr) { - content[0] = { - type: "text", - text: `${statusText} (screenshot unavailable: ${(shotErr as Error).message})`, - }; - } - } - - const details: AnthropicComputerDetails = { - action, - statusText, - ...(execErr ? { error: execErr.message } : {}), - }; - - return { - content, - details, - ...(execErr ? { isError: true } : {}), - }; -} - -type TranslateResult = ModelAction[] | "unsupported"; - -export function translateAnthropicAction(action: string, params: Record): TranslateResult { - switch (normalizeAction(action)) { - case "screenshot": - return [{ type: "screenshot" }]; - - case "left_click": { - const coord = readCoord(params.coordinate); - return modifiedClick("left", coord, params.text); - } - case "right_click": { - const coord = readCoord(params.coordinate); - return modifiedClick("right", coord, params.text); - } - case "middle_click": { - const coord = readCoord(params.coordinate); - return modifiedClick("middle", coord, params.text); - } - case "double_click": { - const coord = readCoord(params.coordinate); - return [{ type: "double_click", ...(coord ? { x: coord[0], y: coord[1] } : {}) }]; - } - case "triple_click": { - const coord = readCoord(params.coordinate); - const click = coord ? { x: coord[0], y: coord[1], button: "left" } : { button: "left" }; - return [ - { type: "click", ...click }, - { type: "click", ...click }, - { type: "click", ...click }, - ]; - } - - case "mouse_move": { - const coord = readCoord(params.coordinate); - if (!coord) throw new Error("mouse_move requires `coordinate`"); - return [{ type: "move", x: coord[0], y: coord[1] }]; - } - - case "left_click_drag": { - const start = readCoord(params.start_coordinate); - const end = readCoord(params.coordinate); - if (!end) throw new Error("left_click_drag requires `coordinate`"); - const firstPoint = start ? { x: start[0], y: start[1] } : { current: true }; - return [ - { - type: "drag", - path: [ - firstPoint, - { x: end[0], y: end[1] }, - ], - }, - ]; - } - - case "type": { - const text = readString(params.text); - if (text === undefined) throw new Error("type requires `text`"); - return [{ type: "type", text }]; - } - - case "key": { - const text = readString(params.text); - if (!text) throw new Error("key requires `text`"); - return [{ type: "keypress", keys: parseKeyCombo(text) }]; - } - - case "scroll": { - const coord = readCoord(params.coordinate); - const direction = readString(params.scroll_direction) ?? "down"; - const amount = typeof params.scroll_amount === "number" ? params.scroll_amount : 3; - const magnitude = Math.max(1, Math.trunc(Math.abs(amount))) * 120; - let scrollX = 0; - let scrollY = 0; - switch (direction) { - case "up": - scrollY = -magnitude; - break; - case "down": - scrollY = magnitude; - break; - case "left": - scrollX = -magnitude; - break; - case "right": - scrollX = magnitude; - break; - default: - throw new Error(`scroll: unknown direction "${direction}"`); - } - const modifiers = parseModifierList(params.text); - const modelAction: ModelAction = { - type: "scroll", - scroll_x: scrollX, - scroll_y: scrollY, - ...(coord ? { x: coord[0], y: coord[1] } : {}), - ...(modifiers.length > 0 ? { hold_keys: modifiers } : {}), - }; - return [modelAction]; - } - - case "wait": { - const duration = typeof params.duration === "number" ? params.duration : 1; - return [{ type: "wait", ms: Math.max(0, Math.trunc(duration * 1000)) }]; - } - - case "hold_key": { - const text = readString(params.text); - if (!text) throw new Error("hold_key requires `text`"); - const duration = typeof params.duration === "number" ? Math.max(0, Math.trunc(params.duration * 1000)) : DEFAULT_HOLD_KEY_MS; - return [{ type: "keypress", keys: parseKeyCombo(text), duration_ms: duration }]; - } - case "left_mouse_down": { - const coord = readCoord(params.coordinate); - return [{ type: "mouse_down", button: "left", ...(coord ? { x: coord[0], y: coord[1] } : {}) }]; - } - case "left_mouse_up": { - const coord = readCoord(params.coordinate); - return [{ type: "mouse_up", button: "left", ...(coord ? { x: coord[0], y: coord[1] } : {}) }]; - } - case "zoom": - return "unsupported"; - case "cursor_position": - return [{ type: "cursor_position" }]; - - default: - throw new Error(`unknown computer action: ${action}`); - } -} - -function normalizeAction(action: string): string { - const trimmed = action.trim().toLowerCase().replace(/\s+/g, "_"); - const aliases: Record = { - click: "left_click", - left_click: "left_click", - left_mouse_click: "left_click", - right_click: "right_click", - right_mouse_click: "right_click", - }; - return aliases[trimmed] ?? trimmed; -} - -function readCoord(value: unknown): [number, number] | null { - if (!Array.isArray(value) || value.length < 2) return null; - const x = Number(value[0]); - const y = Number(value[1]); - if (!Number.isFinite(x) || !Number.isFinite(y)) return null; - return [Math.trunc(x), Math.trunc(y)]; -} - -function readString(value: unknown): string | undefined { - if (typeof value === "string") return value; - return undefined; -} - -function parseKeyCombo(text: string): string[] { - return text - .split("+") - .map((s) => normalizeKey(s.trim())) - .filter(Boolean); -} - -function parseModifierList(value: unknown): string[] { - const text = readString(value); - if (!text) return []; - return text - .split("+") - .map((s) => normalizeKey(s.trim())) - .filter(Boolean); -} - -function normalizeKey(key: string): string { - const lower = key.toLowerCase(); - const aliases: Record = { - escape: "Escape", - esc: "Escape", - page_down: "PageDown", - pagedown: "PageDown", - page_up: "PageUp", - pageup: "PageUp", - super_l: "Super", - super: "Super", - cmd: "Meta", - command: "Meta", - return: "Enter", - }; - return aliases[lower] ?? key; -} - -function modifiedClick( - button: "left" | "right" | "middle", - coord: [number, number] | null, - modifierText: unknown, -): ModelAction[] { - const modifiers = parseModifierList(modifierText); - const click: ModelAction = { - type: "click", - button, - ...(coord ? { x: coord[0], y: coord[1] } : {}), - ...(modifiers.length > 0 ? { hold_keys: modifiers } : {}), - }; - return [click]; -} diff --git a/packages/cua-anthropic/src/context.ts b/packages/cua-anthropic/src/context.ts deleted file mode 100644 index 80ed77d3..00000000 --- a/packages/cua-anthropic/src/context.ts +++ /dev/null @@ -1,17 +0,0 @@ -export function hasAnthropicCompactionBlock(message: unknown): boolean { - if (!message || typeof message !== "object") return false; - const content = (message as { content?: unknown }).content; - if (!Array.isArray(content)) return false; - return content.some((block) => Boolean(block && typeof block === "object" && (block as { type?: unknown }).type === "compaction")); -} - -export function compactAnthropicMessagesForRequest(messages: T[]): T[] { - let start = -1; - for (let i = messages.length - 1; i >= 0; i--) { - if (hasAnthropicCompactionBlock(messages[i])) { - start = i; - break; - } - } - return start < 0 ? messages : messages.slice(start); -} diff --git a/packages/cua-anthropic/src/cua-extras.ts b/packages/cua-anthropic/src/cua-extras.ts deleted file mode 100644 index e560b215..00000000 --- a/packages/cua-anthropic/src/cua-extras.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * cua extension actions that show up alongside Anthropic's official action - * set in our `batch_computer_actions` tool. Anthropic's built-in `computer` - * tool does NOT define a navigation verb (`goto`, `back`, `forward`, `url`) - * — every computer-use template has to invent its own way to drive the - * address bar via keyboard chords. - * - * We expose them in two places: - * 1. The `batch_computer_actions` tool (Anthropic-flavored, in - * `./batch-tool.ts`) accepts these action names alongside the - * official ones. - * 2. The system prompt nudges the model to prefer them over manual - * "click address bar → ctrl+a → type → enter" choreography. - * - * To remove these from a deployment, delete this file and trim - * {@link ANTHROPIC_CUA_EXTRA_ACTION_TYPES} out of `batch-tool.ts`'s - * input_schema enum. - */ - -export const ANTHROPIC_CUA_EXTRA_ACTION_TYPES = ["goto", "back", "forward", "url"] as const; - -export type AnthropicCuaExtraActionType = (typeof ANTHROPIC_CUA_EXTRA_ACTION_TYPES)[number]; diff --git a/packages/cua-anthropic/src/index.ts b/packages/cua-anthropic/src/index.ts deleted file mode 100644 index 179072a5..00000000 --- a/packages/cua-anthropic/src/index.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @onkernel/cua-anthropic - * - * Provider-neutral Anthropic computer-use helpers backed by - * `@onkernel/cua-translator`. - * - * The package root exports: - * - Anthropic model factory for single-invocation `runComputerUse()` calls - * - plain computer/batch execution helpers for non-pi loops - * - Anthropic built-in tool specs and prompt builders - * - * `pi-agent-core` bindings live under `@onkernel/cua-anthropic/pi`. - */ - -export { - AnthropicBatchSchema, - ANTHROPIC_BATCH_ACTION_TYPES, - ANTHROPIC_BATCH_DESCRIPTION, - ANTHROPIC_BATCH_TOOL_NAME, - ANTHROPIC_BATCH_TOOL_WIRE_SPEC, - executeAnthropicBatch, - expandTripleClick, -} from "./batch"; -export type { - AnthropicBatchToolDetails, - AnthropicBatchToolInput, -} from "./batch"; -export { - ComputerSchema, - executeAnthropicComputerAction, - translateAnthropicAction, -} from "./computer"; -export type { AnthropicComputerInput, AnthropicComputerDetails } from "./computer"; -export { - ANTHROPIC_COMPUTER_TOOL, - ANTHROPIC_COMPACTION_BETA, - ANTHROPIC_COMPACTION_EDIT_TYPE, - ANTHROPIC_COMPACTION_MIN_TRIGGER_TOKENS, - ANTHROPIC_DISPLAY, - ANTHROPIC_COMPUTER_USE_BETA, - ANTHROPIC_OFFICIAL_ACTION_TYPES, - anthropicSupportsCompaction, -} from "./official"; -export type { - AnthropicComputerToolVersion, - AnthropicOfficialActionType, -} from "./official"; -export { ANTHROPIC_CUA_EXTRA_ACTION_TYPES } from "./cua-extras"; -export type { AnthropicCuaExtraActionType } from "./cua-extras"; -export { anthropic } from "./model"; -export type { - AnthropicModelOptions, - AnthropicModelRunDetails, -} from "./model"; -export { - compactAnthropicMessagesForRequest, - hasAnthropicCompactionBlock, -} from "./context"; -export { - buildAnthropicSystemPrompt, - ANTHROPIC_INSTRUCTIONS_RAW, -} from "./system-prompt"; -export type { AnthropicSystemPromptOptions } from "./system-prompt"; diff --git a/packages/cua-anthropic/src/model.ts b/packages/cua-anthropic/src/model.ts deleted file mode 100644 index 4cdc2374..00000000 --- a/packages/cua-anthropic/src/model.ts +++ /dev/null @@ -1,191 +0,0 @@ -import type { - ComputerTranslator, - ComputerUseModel, - ComputerUseRunResult, - ComputerUseToolResult, -} from "@onkernel/cua-translator"; -import { Anthropic } from "@anthropic-ai/sdk"; -import { ANTHROPIC_BATCH_TOOL_WIRE_SPEC, executeAnthropicBatch } from "./batch"; -import { - type AnthropicComputerInput, - executeAnthropicComputerAction, -} from "./computer"; -import { - anthropicComputerToolForModel, - anthropicComputerUseBetaForModel, - ANTHROPIC_COMPACTION_BETA, - ANTHROPIC_COMPACTION_EDIT_TYPE, - ANTHROPIC_COMPACTION_MIN_TRIGGER_TOKENS, - anthropicSupportsCompaction, -} from "./official"; -import { compactAnthropicMessagesForRequest } from "./context"; -import { buildAnthropicSystemPrompt } from "./system-prompt"; - -export interface AnthropicModelOptions { - apiKey?: string; - baseUrl?: string; - systemPromptSuffix?: string; - includeBatchTool?: boolean; - maxTokens?: number; - thinkingBudgetTokens?: number; - compactThreshold?: number | false; -} - -export interface AnthropicModelRunDetails { - stopReason?: string; -} - -export function anthropic(modelId: string, opts: AnthropicModelOptions = {}): ComputerUseModel { - return { - provider: "anthropic", - modelId, - async run({ prompt, translator, maxTurns = 50 }): Promise> { - const apiKey = opts.apiKey || process.env.ANTHROPIC_API_KEY; - if (!apiKey) { - throw new Error("missing Anthropic API key"); - } - const client = new Anthropic({ - apiKey, - maxRetries: 4, - ...(opts.baseUrl ? { baseURL: opts.baseUrl } : {}), - }); - - const messages: any[] = [{ role: "user", content: prompt }]; - const systemText = buildAnthropicSystemPrompt({ - includeBatchNudge: opts.includeBatchTool !== false, - }); - const system = opts.systemPromptSuffix ? `${systemText}\n\n${opts.systemPromptSuffix}` : systemText; - const computerTool = anthropicComputerToolForModel(modelId); - const computerBeta = anthropicComputerUseBetaForModel(modelId); - const useCompaction = opts.compactThreshold !== false && anthropicSupportsCompaction(modelId); - - for (let turn = 0; turn < maxTurns; turn++) { - const response: any = await client.beta.messages.create({ - model: modelId, - max_tokens: opts.maxTokens ?? 4096, - messages: compactAnthropicMessagesForRequest(messages), - system: [{ type: "text", text: system }], - tools: - opts.includeBatchTool === false - ? [computerTool] - : [computerTool, ANTHROPIC_BATCH_TOOL_WIRE_SPEC], - betas: useCompaction ? [computerBeta, ANTHROPIC_COMPACTION_BETA] : [computerBeta], - ...(useCompaction - ? { - context_management: anthropicCompactionContextManagement( - typeof opts.compactThreshold === "number" ? opts.compactThreshold : undefined, - ), - } - : {}), - ...(opts.thinkingBudgetTokens - ? { thinking: { type: "enabled", budget_tokens: opts.thinkingBudgetTokens } } - : {}), - }); - - messages.push({ - role: "assistant", - content: response.content, - }); - - if (response.stop_reason === "end_turn") { - return { - text: extractAnthropicText(response.content), - provider: "anthropic", - modelId, - turns: turn + 1, - details: { stopReason: response.stop_reason }, - }; - } - - const toolResults: any[] = []; - for (const block of response.content ?? []) { - if (!block || block.type !== "tool_use") continue; - if (block.name === "computer") { - const result = await executeAnthropicComputerAction( - translator, - block.input as AnthropicComputerInput, - ); - toolResults.push(toAnthropicToolResult(block.id, result)); - continue; - } - if (block.name === ANTHROPIC_BATCH_TOOL_WIRE_SPEC.name) { - const result = await executeAnthropicBatch(translator, block.input); - toolResults.push(toAnthropicToolResult(block.id, result)); - continue; - } - } - - if (toolResults.length === 0) { - return { - text: extractAnthropicText(response.content) || "(no response)", - provider: "anthropic", - modelId, - turns: turn + 1, - details: { stopReason: response.stop_reason }, - }; - } - - messages.push({ - role: "user", - content: toolResults, - }); - } - - return { - text: "(max turns reached)", - provider: "anthropic", - modelId, - turns: maxTurns, - }; - }, - }; -} - -function anthropicCompactionContextManagement(compactThreshold: number | undefined): Record { - const edit: Record = { type: ANTHROPIC_COMPACTION_EDIT_TYPE }; - if (typeof compactThreshold === "number" && Number.isFinite(compactThreshold)) { - edit.trigger = { - type: "input_tokens", - value: Math.max(ANTHROPIC_COMPACTION_MIN_TRIGGER_TOKENS, Math.trunc(compactThreshold)), - }; - } - return { edits: [edit] }; -} - -function toAnthropicToolResult( - toolUseId: string, - result: ComputerUseToolResult, -): Record { - return { - type: "tool_result", - tool_use_id: toolUseId, - content: result.content.map((part) => - part.type === "text" - ? { - type: "text", - text: part.text, - } - : { - type: "image", - source: { - type: "base64", - media_type: part.mimeType, - data: part.data, - }, - }, - ), - ...(result.isError ? { is_error: true } : {}), - }; -} - -function extractAnthropicText(content: unknown): string { - if (!Array.isArray(content)) return ""; - return content - .filter( - (block): block is { type: "text"; text: string } => - typeof block === "object" && block !== null && (block as { type?: unknown }).type === "text" && typeof (block as { text?: unknown }).text === "string", - ) - .map((block) => block.text) - .join("") - .trim(); -} diff --git a/packages/cua-anthropic/src/official.ts b/packages/cua-anthropic/src/official.ts deleted file mode 100644 index 6816a4f4..00000000 --- a/packages/cua-anthropic/src/official.ts +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Anthropic computer-use action set. - * - * Source of truth: Anthropic's "Computer use" docs. - * https://docs.claude.com/en/docs/agents-and-tools/computer-use - * https://docs.claude.com/en/docs/agents-and-tools/tool-use/overview#computer-use - * - * Anthropic ships THREE versions of the built-in `computer` tool. The action - * vocabulary grows monotonically across versions. We register the latest - * compatible version for each model and translate every action up through - * `zoom` (with a few we mark unsupported because the Kernel browser does not - * expose them today). - * - * Model → tool version pairing (per Anthropic docs): - * computer_20241022 → claude-3-5-sonnet (oct 22) - * computer_20250124 → claude-3-7-sonnet, claude-sonnet-4, claude-opus-4, - * claude-opus-4-1, claude-sonnet-4-5, claude-haiku-4-5 - * computer_20251124 → claude-opus-4-5+, claude-opus-4-6+, claude-opus-4-7+, - * claude-sonnet-4-6+ - * - * The beta header is automatically merged in by {@link wrapAnthropicStream}. - */ - -export type AnthropicComputerToolVersion = - | "computer_20241022" - | "computer_20250124" - | "computer_20251124"; - -/** - * Action types the LATEST (`computer_20251124`) Anthropic computer tool - * accepts. Earlier tool versions are subsets — see the comments next to - * each action for which version introduced it. - */ -export const ANTHROPIC_OFFICIAL_ACTION_TYPES = [ - // Original (computer_20241022) - "key", // press a key combo (e.g. "ctrl+l") - "type", // type text - "mouse_move", - "left_click", - "left_click_drag", - "right_click", - "middle_click", - "double_click", - "screenshot", - "cursor_position", - // Added in computer_20250124 - "scroll", - "hold_key", - "wait", - "triple_click", - "left_mouse_down", - "left_mouse_up", - // Added in computer_20251124 - "zoom", -] as const; - -export type AnthropicOfficialActionType = (typeof ANTHROPIC_OFFICIAL_ACTION_TYPES)[number]; - -/** - * Default display dimensions advertised to Anthropic's computer tool. - * Matches Kernel cloud browser's default 1920×1080 viewport. - */ -export const ANTHROPIC_DISPLAY = { - width: 1920, - height: 1080, - number: 1, -} as const; - -function buildAnthropicComputerTool(type: AnthropicComputerToolVersion) { - return { - type, - name: "computer", - display_width_px: ANTHROPIC_DISPLAY.width, - display_height_px: ANTHROPIC_DISPLAY.height, - display_number: ANTHROPIC_DISPLAY.number, - ...(type === "computer_20251124" ? { enable_zoom: false } : {}), - } as const; -} - -export const ANTHROPIC_COMPUTER_TOOL_20250124 = buildAnthropicComputerTool("computer_20250124"); -export const ANTHROPIC_COMPUTER_TOOL_20251124 = buildAnthropicComputerTool("computer_20251124"); - -/** - * Default built-in computer tool spec. Sent in the Anthropic Messages API - * `tools` array. Not a JSON schema — Anthropic accepts a small fixed set - * of named built-in tools; the model knows the per-action shape internally. - */ -export const ANTHROPIC_COMPUTER_TOOL = ANTHROPIC_COMPUTER_TOOL_20251124; - -export function anthropicComputerToolForModel(modelId: string): typeof ANTHROPIC_COMPUTER_TOOL_20250124 | typeof ANTHROPIC_COMPUTER_TOOL_20251124 { - return anthropicComputerToolVersionForModel(modelId) === "computer_20251124" - ? ANTHROPIC_COMPUTER_TOOL_20251124 - : ANTHROPIC_COMPUTER_TOOL_20250124; -} - -export function anthropicComputerToolVersionForModel(modelId: string): Exclude { - const id = modelId.toLowerCase(); - if ( - id.startsWith("claude-opus-4-7") || - id.startsWith("claude-opus-4-6") || - id.startsWith("claude-opus-4-5") || - id.startsWith("claude-sonnet-4-6") - ) { - return "computer_20251124"; - } - return "computer_20250124"; -} - -/** - * Computer-use beta headers. The value must match the selected built-in - * computer tool version for the target model. - */ -export const ANTHROPIC_COMPUTER_USE_BETA_20250124 = "computer-use-2025-01-24"; -export const ANTHROPIC_COMPUTER_USE_BETA_20251124 = "computer-use-2025-11-24"; -export const ANTHROPIC_COMPACTION_BETA = "compact-2026-01-12"; -export const ANTHROPIC_COMPACTION_EDIT_TYPE = "compact_20260112"; -export const ANTHROPIC_COMPACTION_MIN_TRIGGER_TOKENS = 50_000; - -export function anthropicComputerUseBetaForModel(modelId: string): typeof ANTHROPIC_COMPUTER_USE_BETA_20250124 | typeof ANTHROPIC_COMPUTER_USE_BETA_20251124 { - return anthropicComputerToolVersionForModel(modelId) === "computer_20251124" - ? ANTHROPIC_COMPUTER_USE_BETA_20251124 - : ANTHROPIC_COMPUTER_USE_BETA_20250124; -} - -/** - * Latest computer-use beta header value. Kept for callers that do not have a - * model ID available; runtime paths should prefer - * {@link anthropicComputerUseBetaForModel}. - */ -export const ANTHROPIC_COMPUTER_USE_BETA = ANTHROPIC_COMPUTER_USE_BETA_20251124; - -export function anthropicSupportsCompaction(modelId: string): boolean { - const id = modelId.toLowerCase(); - return ( - id.startsWith("claude-mythos-preview") || - id.startsWith("claude-opus-4-7") || - id.startsWith("claude-opus-4-6") || - id.startsWith("claude-sonnet-4-6") - ); -} diff --git a/packages/cua-anthropic/src/payload-hook.ts b/packages/cua-anthropic/src/payload-hook.ts deleted file mode 100644 index 69c67b3d..00000000 --- a/packages/cua-anthropic/src/payload-hook.ts +++ /dev/null @@ -1,127 +0,0 @@ -import type { Api, Model } from "@mariozechner/pi-ai"; -import { compactAnthropicMessagesForRequest } from "./context"; -import { anthropicComputerToolForModel } from "./official"; -import { - ANTHROPIC_COMPACTION_EDIT_TYPE, - ANTHROPIC_COMPACTION_MIN_TRIGGER_TOKENS, - anthropicSupportsCompaction, -} from "./official"; - -/** - * onPayload hook for Anthropic Messages requests. - * - * Replaces the locally registered `computer` function tool entry on the - * wire with Anthropic's model-compatible built-in computer spec, so the - * model emits real `tool_use` blocks for the `computer` tool and we get - * the documented action vocabulary. - * - * Returning `undefined` for non-Anthropic providers leaves the payload - * untouched. For Anthropic, returns a shallow-copied payload with `tools` - * rewritten so the registered `computer` AgentTool entry is replaced (or - * appended if missing). - */ -export function anthropicComputerOnPayload(payload: unknown, model: Model): unknown { - if (model.api !== "anthropic-messages") return undefined; - if (!payload || typeof payload !== "object") return undefined; - const next = { ...(payload as Record) }; - const computerTool = anthropicComputerToolForModel(model.id); - const tools = Array.isArray(next.tools) ? [...(next.tools as unknown[])] : []; - const idx = tools.findIndex((t) => isToolNamed(t, "computer")); - if (idx >= 0) { - tools[idx] = computerTool; - } else { - tools.push(computerTool); - } - next.tools = tools; - return next; -} - -export interface AnthropicContextManagementOptions { - compactThreshold?: number | false; -} - -export function createAnthropicContextManagementOnPayload( - opts: AnthropicContextManagementOptions = {}, -): (payload: unknown, model: Model) => unknown | undefined { - return (payload: unknown, model: Model): unknown | undefined => { - if (model.api !== "anthropic-messages") return undefined; - if (!payload || typeof payload !== "object") return undefined; - - const source = payload as Record; - const next = { ...source }; - let changed = false; - - if (Array.isArray(source.messages)) { - const compacted = compactAnthropicMessagesForRequest(source.messages); - if (compacted.length !== source.messages.length) { - next.messages = compacted; - changed = true; - } - } - - if (opts.compactThreshold !== false && anthropicSupportsCompaction(model.id)) { - next.context_management = mergeCompactionContextManagement(source.context_management, opts.compactThreshold); - changed = true; - } - - return changed ? next : undefined; - }; -} - -function isToolNamed(tool: unknown, name: string): boolean { - if (!tool || typeof tool !== "object") return false; - const n = (tool as { name?: unknown }).name; - return typeof n === "string" && n === name; -} - -function mergeCompactionContextManagement(existing: unknown, compactThreshold: number | undefined): Record { - const current = existing && typeof existing === "object" ? (existing as Record) : {}; - const edits = Array.isArray(current.edits) ? [...current.edits] : []; - if (!edits.some(isCompactionEdit)) { - edits.push(compactionEdit(compactThreshold)); - } - return { - ...current, - edits, - }; -} - -function isCompactionEdit(edit: unknown): boolean { - return Boolean(edit && typeof edit === "object" && (edit as { type?: unknown }).type === ANTHROPIC_COMPACTION_EDIT_TYPE); -} - -function compactionEdit(compactThreshold: number | undefined): Record { - const edit: Record = { type: ANTHROPIC_COMPACTION_EDIT_TYPE }; - if (typeof compactThreshold === "number" && Number.isFinite(compactThreshold)) { - edit.trigger = { - type: "input_tokens", - value: Math.max(ANTHROPIC_COMPACTION_MIN_TRIGGER_TOKENS, Math.trunc(compactThreshold)), - }; - } - return edit; -} - -/** - * Compose multiple onPayload hooks into a single one. Each hook sees the - * latest payload from previous hooks (or the original if none modified - * it). Returns `undefined` if no hooks are active or none modified the - * payload. - */ -export function composeOnPayload( - ...hooks: Array<((payload: unknown, model: Model) => unknown | undefined | Promise) | undefined> -): ((payload: unknown, model: Model) => Promise) | undefined { - const active = hooks.filter((h): h is NonNullable => typeof h === "function"); - if (active.length === 0) return undefined; - return async (payload: unknown, model: Model): Promise => { - let current: unknown = payload; - let changed = false; - for (const hook of active) { - const next = await hook(current, model); - if (next !== undefined) { - current = next; - changed = true; - } - } - return changed ? current : undefined; - }; -} diff --git a/packages/cua-anthropic/src/pi/index.ts b/packages/cua-anthropic/src/pi/index.ts deleted file mode 100644 index c1709271..00000000 --- a/packages/cua-anthropic/src/pi/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { AgentTool } from "@mariozechner/pi-agent-core"; -import type { ComputerTranslator } from "@onkernel/cua-translator"; -import { createAnthropicBatchTool } from "../batch-tool"; -import { createAnthropicComputerTool } from "../computer-tool"; - -export interface AnthropicComputerToolsOptions { - /** Set false to omit the built-in `computer` tool. Defaults to true. */ - includeComputer?: boolean; - /** Set false to omit the cua-added `batch_computer_actions` tool. Defaults to true. */ - includeBatch?: boolean; -} - -/** - * Build the Anthropic computer-use tool set for `pi-agent-core`. - * Pair with root prompt/system helpers and the Anthropic-specific stream hooks. - */ -export function createAnthropicComputerTools( - translator: ComputerTranslator, - opts: AnthropicComputerToolsOptions = {}, -): AgentTool[] { - const tools: AgentTool[] = []; - if (opts.includeComputer !== false) tools.push(createAnthropicComputerTool(translator)); - if (opts.includeBatch !== false) tools.push(createAnthropicBatchTool(translator)); - return tools; -} - -export { createAnthropicComputerTool } from "../computer-tool"; -export type { AnthropicComputerDetails, AnthropicComputerInput } from "../computer"; -export { createAnthropicBatchTool } from "../batch-tool"; -export type { AnthropicBatchToolDetails, AnthropicBatchToolInput } from "../batch"; -export { - registerAnthropicProvider, - wrapAnthropicStream, -} from "../stream-wrapper"; -export { - anthropicComputerOnPayload, - composeOnPayload, - createAnthropicContextManagementOnPayload, -} from "../payload-hook"; -export type { AnthropicContextManagementOptions } from "../payload-hook"; diff --git a/packages/cua-anthropic/src/stream-wrapper.ts b/packages/cua-anthropic/src/stream-wrapper.ts deleted file mode 100644 index 29f427ff..00000000 --- a/packages/cua-anthropic/src/stream-wrapper.ts +++ /dev/null @@ -1,75 +0,0 @@ -import type { StreamFn } from "@mariozechner/pi-agent-core"; -import { - registerApiProvider, - streamAnthropic, - streamSimpleAnthropic, -} from "@mariozechner/pi-ai"; -import { - ANTHROPIC_COMPACTION_BETA, - anthropicComputerUseBetaForModel, - anthropicSupportsCompaction, -} from "./official"; -import type { AnthropicContextManagementOptions } from "./payload-hook"; - -/** - * Eagerly register the Anthropic Messages provider with `pi-ai`. pi-ai - * lazily resolves provider implementations via dynamic import which can - * fail under bundlers; calling this once at module load time is the safe - * pattern. Idempotent. - */ -let registered = false; -export function registerAnthropicProvider(): void { - if (registered) return; - registerApiProvider({ - api: "anthropic-messages", - stream: streamAnthropic, - streamSimple: streamSimpleAnthropic, - }); - registered = true; -} - -/** - * Wrap a `StreamFn` so that Anthropic requests carry the model-compatible - * computer-use beta header merged with whatever beta tokens pi-ai is - * already sending (e.g. fine-grained tool streaming). - * - * Other providers (OpenAI etc.) pass through unchanged. - * - * The Anthropic API accepts comma-separated beta tokens in a single - * header. pi-ai's `mergeHeaders` is "later wins", so to keep both we - * compose the combined value here and overwrite. - */ -export function wrapAnthropicStream(base: StreamFn, opts: AnthropicContextManagementOptions = {}): StreamFn { - return ((model, context, options) => { - if (model.api !== "anthropic-messages") { - return base(model, context, options); - } - const existing = options?.headers?.["anthropic-beta"]; - const computerBeta = anthropicComputerUseBetaForModel(model.id); - const compactionBeta = - opts.compactThreshold !== false && anthropicSupportsCompaction(model.id) - ? ANTHROPIC_COMPACTION_BETA - : undefined; - const merged = combineBetas(existing, computerBeta, compactionBeta, "fine-grained-tool-streaming-2025-05-14"); - const nextOptions = { - ...options, - headers: { - ...(options?.headers ?? {}), - "anthropic-beta": merged, - }, - }; - return base(model, context, nextOptions); - }) as StreamFn; -} - -function combineBetas(...values: Array): string { - const seen = new Set(); - for (const v of values) { - if (!v) continue; - for (const tok of v.split(",")) { - const t = tok.trim(); - if (t) seen.add(t); - } - } - return [...seen].join(","); -} diff --git a/packages/cua-anthropic/src/system-prompt.ts b/packages/cua-anthropic/src/system-prompt.ts deleted file mode 100644 index 4d314e8a..00000000 --- a/packages/cua-anthropic/src/system-prompt.ts +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Anthropic Claude system-prompt preamble for the `computer` + - * `batch_computer_actions` tool surface. - * - * Two preambles, joined automatically by {@link buildAnthropicSystemPrompt}: - * - * 1. The action-vocabulary preamble (matches Anthropic's documented - * `computer_20251124` action shapes and reinforces the - * verify-by-screenshot pattern). - * 2. A short nudge towards the cua-added `batch_computer_actions` tool - * for predictable sequences (mirrors the OpenAI nudge so model - * behaviour is consistent across providers). - */ - -const ANTHROPIC_COMPUTER_INSTRUCTIONS = `You control a 1920x1080 cloud browser through the built-in \`computer\` tool. The tool returns a fresh screenshot after every action so you can verify the result before planning the next step. - -Action conventions: -- Coordinates are pixels in [x, y] form, top-left origin. -- Use \`screenshot\` first when you need to see the current state. -- Use \`left_click\` for navigation and \`double_click\` for opening files / selecting words. -- Use \`type\` to enter text into a focused field; click first to focus. -- Use \`key\` for individual keys or combos like "Return", "ctrl+l", "alt+Left". -- Use \`scroll\` with \`coordinate\`, \`scroll_direction\`, and \`scroll_amount\` (in clicks/lines). -- Use \`left_click_drag\` between two coordinates for drag-and-drop. -- Use \`wait\` (seconds) to let UI settle after asynchronous changes. - -Verification pattern: after multi-step changes, take a screenshot and explicitly -confirm what you see ("I see X, so step Y succeeded") before continuing. Do not -assume an action worked just because you sent it. - -To navigate by URL, focus the address bar with key="ctrl+l", then type the URL, -then press key="Return".`; - -const ANTHROPIC_BATCH_INSTRUCTIONS = `You also have a \`batch_computer_actions\` tool that bundles multiple actions -into a single call (with optional inline url() and screenshot() reads). -PREFER \`batch_computer_actions\` over the built-in \`computer\` tool for -predictable sequences such as: -- Clicking a text field, typing text, and pressing Enter -- Typing a URL and pressing Enter (use the \`goto\` action — the cua - extension that focuses the address bar, types, and presses Enter) -- Using \`back\` / \`forward\` (cua extensions for keyboard back/forward) -- Reading the current URL via \`url\` (returns the address-bar value) - -When unsure between \`computer\` and \`batch_computer_actions\`, prefer the -batch tool — it is one round-trip and produces predictable read order.`; - -export interface AnthropicSystemPromptOptions { - /** Set false to omit the batch nudge (e.g. when batch is disabled). Defaults to true. */ - includeBatchNudge?: boolean; -} - -/** Build the Anthropic-flavored CUA system preamble. */ -export function buildAnthropicSystemPrompt(opts: AnthropicSystemPromptOptions = {}): string { - if (opts.includeBatchNudge === false) return ANTHROPIC_COMPUTER_INSTRUCTIONS; - return `${ANTHROPIC_COMPUTER_INSTRUCTIONS}\n\n${ANTHROPIC_BATCH_INSTRUCTIONS}`; -} - -export const ANTHROPIC_INSTRUCTIONS_RAW = { - computer: ANTHROPIC_COMPUTER_INSTRUCTIONS, - batch: ANTHROPIC_BATCH_INSTRUCTIONS, -}; diff --git a/packages/cua-anthropic/tsconfig.json b/packages/cua-anthropic/tsconfig.json deleted file mode 100644 index c2e66df0..00000000 --- a/packages/cua-anthropic/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./dist", - "rootDir": "./src" - }, - "include": ["src/**/*"], - "references": [{ "path": "../cua-translator" }] -} diff --git a/packages/cua-gemini/README.md b/packages/cua-gemini/README.md deleted file mode 100644 index d7159e25..00000000 --- a/packages/cua-gemini/README.md +++ /dev/null @@ -1,240 +0,0 @@ -# `@onkernel/cua-gemini` - -Provider-neutral Gemini computer-use helpers backed by -[`@onkernel/cua-translator`](../cua-translator). - -## Entry points - -- `@onkernel/cua-gemini` — provider-neutral root surface: - `gemini(modelId)`, Gemini function declarations, execution helpers, - and prompt builders. -- `@onkernel/cua-gemini/pi` — `pi-agent-core` bindings: - `createGeminiComputerTools()`. - -## Install - -```bash -npm install @onkernel/cua-gemini @onkernel/cua-translator @onkernel/sdk -``` - -If you want the `pi-agent-core` bindings too: - -```bash -npm install @earendil-works/pi-agent-core @earendil-works/pi-ai -``` - -## Quick start (`runComputerUse`) - -```typescript -import { browserSession, runComputerUse } from "@onkernel/cua-translator"; -import { gemini } from "@onkernel/cua-gemini"; - -const browser = await browserSession.open({ apiKey: process.env.KERNEL_API_KEY! }); - -const result = await runComputerUse({ - model: gemini("gemini-3-flash-preview"), - browser, - prompt: "Open https://example.com and tell me the heading.", -}); - -console.log(result.text); -``` - -## Quick start (with `pi-agent-core`) - -```typescript -import { Agent } from "@earendil-works/pi-agent-core"; -import { - getModel, - registerApiProvider, - streamGoogle, - streamSimpleGoogle, -} from "@earendil-works/pi-ai"; -import { - ComputerTranslator, - browserSession, -} from "@onkernel/cua-translator"; -import { - buildGeminiSystemPrompt, -} from "@onkernel/cua-gemini"; -import { - createGeminiComputerTools, -} from "@onkernel/cua-gemini/pi"; - -registerApiProvider({ - api: "google-generative-ai", - stream: streamGoogle, - streamSimple: streamSimpleGoogle, -}); - -const browser = await browserSession.open({ apiKey: process.env.KERNEL_API_KEY! }); -const translator = new ComputerTranslator({ - client: browser.client, - sessionId: browser.sessionId, -}); - -const agent = new Agent({ - initialState: { - systemPrompt: buildGeminiSystemPrompt(), - model: getModel("google", "gemini-3-flash-preview"), - tools: createGeminiComputerTools(translator), - thinkingLevel: "low", - }, - getApiKey: () => process.env.GOOGLE_API_KEY, -}); - -await agent.prompt("Open https://example.com and tell me the heading."); -``` - -## Action reference - -### Gemini's predefined computer-use functions - -Source of truth: Google's -[Gemini Computer Use docs](https://ai.google.dev/gemini-api/docs/computer-use). -ALL `x` / `y` arguments are 0-1000 normalized. - -| Action | Source | Args | Maps to canonical | -| ------------------- | ------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------ | -| `open_web_browser` | official (Gemini) | — | `[screenshot]` (browser is already open). | -| `click_at` | official (Gemini) | `{x, y}` | `[click(denormX, denormY)]`. | -| `hover_at` | official (Gemini) | `{x, y}` | `[move]`. | -| `type_text_at` | official (Gemini) | `{x, y, text, press_enter?, clear_before_typing?}` | `[click, optional ctrl+a, type, optional Return]`. | -| `scroll_document` | official (Gemini) | `{direction, magnitude?}` | `[scroll(centerX, centerY, dx, dy)]` with magnitude→notch math. | -| `scroll_at` | official (Gemini) | `{x, y, direction, magnitude?}` | Same as `scroll_document` at given coords. | -| `wait_5_seconds` | official (Gemini) | — | `[wait(5000)]`. | -| `go_back` | official (Gemini) | — | `backBatchActions()` from translator (Alt+Left). | -| `go_forward` | official (Gemini) | — | `forwardBatchActions()` from translator (Alt+Right). | -| `search` | official (Gemini) | — | `[keypress(["ctrl", "l"])]` (focus address bar). | -| `navigate` | official (Gemini) | `{url}` | `gotoBatchActions(url)` from translator. | -| `key_combination` | official (Gemini) | `{keys: "ctrl+l"}` | `[keypress(keys.split('+'))]`. | -| `drag_and_drop` | official (Gemini) | `{x, y, destination_x, destination_y}` | `[drag(path=[start, end])]`. | - -### `batch_computer_actions` (cua-added) - -Same canonical action union as the OpenAI / Anthropic batch tools. -**Pixel coordinates** (NOT Gemini's 0-1000 convention). The system -prompt explicitly highlights this distinction. - -| Action | Source | Notes | -| --------------- | ------------------ | ------------------------------------------------------ | -| `click` | re-shaped | `{x, y, button?, hold_keys?}` in pixels. | -| `double_click` | re-shaped | `{x, y, hold_keys?}`. | -| `move` | re-shaped | `{x, y}`. | -| `scroll` | re-shaped | `{x, y, scroll_x?, scroll_y?, hold_keys?}` in pixels. | -| `type` | re-shaped | `{text}`. | -| `keypress` | re-shaped | `{keys: string[]}`. | -| `drag` | re-shaped | `{path: {x, y}[]}`. | -| `wait` | re-shaped | `{ms?}`. | -| `screenshot` | re-shaped | Read step. | -| `goto` | cua extension | `{url}`. The only nav verb Gemini doesn't ship natively. | -| `back` | cua extension | Mirrors `go_back`. | -| `forward` | cua extension | Mirrors `go_forward`. | -| `url` | cua extension | Read step. Gemini's predefined set has no URL-read verb. | - -The cua extensions live in `src/cua-extras.ts` (Gemini only needs -`url`); the rest are mirrored convenience verbs in the batch tool. - -## Wire-format dump - -The 13 predefined functions are sent as `functionDeclarations`, alongside -our custom `batch_computer_actions` declaration. - -```json -{ - "tools": [ - { - "functionDeclarations": [ - { "name": "open_web_browser", "description": "...", "parameters": { "type": "object", "properties": {} } }, - { "name": "click_at", "description": "...", "parameters": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": ["x", "y"] } }, - { "name": "type_text_at", "description": "...", "parameters": { /* x, y, text, press_enter?, clear_before_typing? */ } }, - // ... 10 more ... - { - "name": "batch_computer_actions", - "description": "Execute multiple computer actions in sequence...", - "parameters": { - "type": "object", - "properties": { - "actions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { "type": "string", "enum": ["click", "double_click", "type", "keypress", "scroll", "move", "drag", "wait", "goto", "back", "forward", "url", "screenshot"] }, - "x": { "type": "number" }, "y": { "type": "number" }, - "text": { "type": "string" }, "url": { "type": "string" }, - "keys": { "type": "array", "items": { "type": "string" } }, - "button": { "type": "string" }, - "hold_keys": { "type": "array", "items": { "type": "string" } }, - "scroll_x": { "type": "number" }, "scroll_y": { "type": "number" }, - "ms": { "type": "number" }, - "path": { "type": "array", "items": { "type": "object", "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, "required": ["x", "y"] } } - }, - "required": ["type"], - "additionalProperties": false - } - } - }, - "required": ["actions"] - } - } - ] - } - ] -} -``` - -The exported `GEMINI_BATCH_FUNCTION_DECLARATION` constant ships the -`batch_computer_actions` entry verbatim. - -## Embed in your own agent loop - -```typescript -import { GoogleGenAI } from "@google/genai"; -import { - ComputerTranslator, - browserSession, -} from "@onkernel/cua-translator"; -import { - executeGeminiBatch, - executeGeminiFunctionCall, - GEMINI_BATCH_FUNCTION_DECLARATION, - GEMINI_FUNCTION_DECLARATIONS, -} from "@onkernel/cua-gemini"; - -const browser = await browserSession.open({ apiKey: process.env.KERNEL_API_KEY! }); -const translator = new ComputerTranslator({ client: browser.client, sessionId: browser.sessionId }); - -const ai = new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY! }); -const response = await ai.models.generateContent({ - model: "gemini-3-flash-preview", - contents: [{ role: "user", parts: [{ text: "Open https://example.com" }] }], - config: { - tools: [{ - functionDeclarations: [ - ...GEMINI_FUNCTION_DECLARATIONS as any, - GEMINI_BATCH_FUNCTION_DECLARATION, - ], - }], - }, -}); - -for (const part of response.candidates?.[0]?.content?.parts ?? []) { - if (!("functionCall" in part) || !part.functionCall?.name) continue; - if (part.functionCall.name === "batch_computer_actions") { - const toolResult = await executeGeminiBatch(translator, part.functionCall.args as any); - // feed toolResult.content back as a functionResponse - continue; - } - const toolResult = await executeGeminiFunctionCall({ - translator, - name: part.functionCall.name, - input: part.functionCall.args as any, - }); - // feed toolResult.content back as a functionResponse -} -``` - -## License - -MIT. diff --git a/packages/cua-gemini/package.json b/packages/cua-gemini/package.json deleted file mode 100644 index fc534429..00000000 --- a/packages/cua-gemini/package.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "@onkernel/cua-gemini", - "version": "0.1.0", - "description": "Provider-neutral Gemini computer-use helpers with explicit /pi bindings", - "type": "module", - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "import": "./dist/index.js" - }, - "./pi": { - "types": "./dist/pi/index.d.ts", - "import": "./dist/pi/index.js" - } - }, - "files": [ - "dist", - "README.md" - ], - "scripts": { - "build": "tsc -b", - "clean": "tsc -b --clean" - }, - "dependencies": { - "@google/genai": "^1.50.1", - "@onkernel/cua-translator": "0.1.0", - "@sinclair/typebox": "0.34.49" - }, - "peerDependencies": { - "@mariozechner/pi-agent-core": "0.67.6", - "@mariozechner/pi-ai": "0.67.6" - }, - "peerDependenciesMeta": { - "@mariozechner/pi-agent-core": { - "optional": true - }, - "@mariozechner/pi-ai": { - "optional": true - } - } -} diff --git a/packages/cua-gemini/src/batch-tool.ts b/packages/cua-gemini/src/batch-tool.ts deleted file mode 100644 index 95b4c6c7..00000000 --- a/packages/cua-gemini/src/batch-tool.ts +++ /dev/null @@ -1,222 +0,0 @@ -import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core"; -import type { ImageContent, TextContent } from "@mariozechner/pi-ai"; -import { type ComputerTranslator, type ModelAction } from "@onkernel/cua-translator"; -import { type Static, Type } from "@sinclair/typebox"; - -/** - * Gemini-flavored `batch_computer_actions` tool. - * - * Registered alongside the predefined per-action tools (see - * `./computer-tool.ts`) as one more `functionDeclaration` Gemini can - * call. Reuses the SAME canonical action union as the OpenAI / Anthropic - * batch tools, so a single `ComputerTranslator.executeBatch` call - * services the actions. - * - * IMPORTANT: unlike the per-action tools (which use Gemini's 0-1000 - * normalized coordinate convention), this batch tool uses PIXEL - * coordinates (the canonical translator convention). The system prompt - * documents this distinction so the model picks the right shape. - */ - -const COORD_PAIR = Type.Object({ x: Type.Number(), y: Type.Number() }, { additionalProperties: false }); - -const Action = Type.Object( - { - type: Type.String({ - description: "Action type.", - enum: [ - "click", - "double_click", - "type", - "keypress", - "scroll", - "move", - "drag", - "wait", - "goto", - "back", - "forward", - "url", - "screenshot", - ], - }), - x: Type.Optional(Type.Number({ description: "Pixel X (NOT 0-1000)." })), - y: Type.Optional(Type.Number({ description: "Pixel Y (NOT 0-1000)." })), - text: Type.Optional(Type.String()), - url: Type.Optional(Type.String({ description: "URL when type=goto." })), - keys: Type.Optional(Type.Array(Type.String(), { description: "Keys for keypress." })), - button: Type.Optional(Type.String()), - hold_keys: Type.Optional(Type.Array(Type.String())), - scroll_x: Type.Optional(Type.Number({ description: "Horizontal scroll in pixels (~120/tick)." })), - scroll_y: Type.Optional(Type.Number({ description: "Vertical scroll in pixels (~120/tick)." })), - ms: Type.Optional(Type.Number({ description: "Wait duration in ms when type=wait." })), - path: Type.Optional( - Type.Array(COORD_PAIR, { description: "Required when type=drag. Two or more {x, y} points." }), - ), - }, - { additionalProperties: false }, -); - -export const GeminiBatchSchema = Type.Object({ - actions: Type.Array(Action, { description: "Ordered list of actions to execute." }), -}); - -export type GeminiBatchToolInput = Static; - -export interface GeminiBatchToolDetails { - statusText: string; - actionDescriptions: string[]; - readResults: Array<{ type: "url"; url: string } | { type: "screenshot"; bytes: number } | { type: "cursor_position"; x: number; y: number }>; - error?: string; -} - -const SETTLE_MS_AFTER_BATCH = 300; - -function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -const BATCH_DESCRIPTION = [ - "Execute multiple computer actions in sequence, including ordered read steps like url() and screenshot() anywhere in the batch.", - "Coordinates use PIXEL units (NOT 0-1000 normalized). Use this tool when you can plan several actions ahead.", - "Consecutive write actions are flushed together; each url()/screenshot() step returns output in the order it was requested.", - "If no explicit read step is included, the tool returns one fresh screenshot after execution.", - "", - "PREFER this over the per-action tools when:", - "- Typing text into a field followed by pressing Enter", - "- Clicking a field and then typing into it", - "- Navigating with goto (focuses the address bar, types the URL, presses Enter)", - "- Using back/forward (cua extensions for keyboard back/forward)", - "- Reading the current URL via url() — returns the address bar contents", - "", - "Drag format: when type=drag, include path as an ordered array of {x, y} pixel points (at least two).", - "Wait format: when type=wait, you may include ms to control the pause duration in milliseconds.", -].join("\n"); - -export function createGeminiBatchTool( - translator: ComputerTranslator, -): AgentTool { - return { - name: "batch_computer_actions", - label: "batch_computer_actions", - description: BATCH_DESCRIPTION, - parameters: GeminiBatchSchema, - async execute(_id, params): Promise> { - const actions = (params.actions ?? []) as ModelAction[]; - const actionDescriptions = actions.map(describeShort); - const content: (TextContent | ImageContent)[] = []; - let statusText: string; - let execErr: Error | undefined; - const readResults: GeminiBatchToolDetails["readResults"] = []; - - let hasScreenshotInResults = false; - try { - const result = await translator.executeBatch(actions); - for (const r of result.readResults) { - if (r.type === "url") { - readResults.push({ type: "url", url: r.url }); - } else if (r.type === "screenshot") { - readResults.push({ type: "screenshot", bytes: r.pngBytes.length }); - hasScreenshotInResults = true; - } else { - readResults.push({ type: "cursor_position", x: r.x, y: r.y }); - } - } - statusText = "Actions executed successfully."; - content.push({ type: "text", text: statusText }); - for (const r of result.readResults) { - if (r.type === "url") { - content.push({ type: "text", text: `url(): ${r.url}` }); - } else if (r.type === "screenshot") { - content.push({ - type: "image", - data: r.pngBytes.toString("base64"), - mimeType: "image/png", - }); - } else { - content.push({ type: "text", text: `cursor_position(): ${r.x},${r.y}` }); - } - } - } catch (err) { - execErr = err instanceof Error ? err : new Error(String(err)); - statusText = `Actions failed: ${execErr.message}`; - content.push({ type: "text", text: statusText }); - } - - const needFallback = readResults.length === 0 || (execErr && !hasScreenshotInResults); - if (needFallback) { - if (!execErr) await delay(SETTLE_MS_AFTER_BATCH); - try { - const png = await translator.screenshotRaw(); - content.push({ type: "image", data: png.toString("base64"), mimeType: "image/png" }); - readResults.push({ type: "screenshot", bytes: png.length }); - } catch (shotErr) { - content[0] = { - type: "text", - text: `${statusText} Screenshot unavailable: ${(shotErr as Error).message}`, - }; - } - } - - const details: GeminiBatchToolDetails = { - statusText, - actionDescriptions, - readResults, - ...(execErr ? { error: execErr.message } : {}), - }; - - if (execErr) throw Object.assign(execErr, { details, content }); - return { content, details }; - }, - }; -} - -/** Wire-format Gemini FunctionDeclaration for hand-rolled (non-pi) consumers. */ -export const GEMINI_BATCH_FUNCTION_DECLARATION = { - name: "batch_computer_actions", - description: BATCH_DESCRIPTION, - parameters: GeminiBatchSchema, -} as const; - -function describeShort(action: ModelAction): string { - const t = typeof action.type === "string" ? action.type : ""; - switch (t) { - case "click": - case "double_click": - return `${t}(${num(action.x)}, ${num(action.y)})`; - case "type": { - const text = typeof action.text === "string" ? action.text : ""; - const trimmed = text.length > 30 ? `${text.slice(0, 27)}...` : text; - return `type(${JSON.stringify(trimmed)})`; - } - case "keypress": { - const keys = Array.isArray(action.keys) ? (action.keys as string[]) : []; - return `keypress(${JSON.stringify(keys)})`; - } - case "scroll": - return `scroll(${num(action.x)}, ${num(action.y)})`; - case "move": - return `move(${num(action.x)}, ${num(action.y)})`; - case "drag": - return "drag(...)"; - case "wait": - return "wait"; - case "goto": - return `goto(${JSON.stringify(typeof action.url === "string" ? action.url : "")})`; - case "back": - return "back()"; - case "forward": - return "forward()"; - case "url": - return "url()"; - case "screenshot": - return "screenshot()"; - default: - return t || ""; - } -} - -function num(v: unknown): number { - if (typeof v === "number" && Number.isFinite(v)) return Math.trunc(v); - return 0; -} diff --git a/packages/cua-gemini/src/batch.ts b/packages/cua-gemini/src/batch.ts deleted file mode 100644 index 67228cc1..00000000 --- a/packages/cua-gemini/src/batch.ts +++ /dev/null @@ -1,203 +0,0 @@ -import type { ComputerTranslator, ComputerUseToolResult, ModelAction } from "@onkernel/cua-translator"; -import { type Static, Type } from "@sinclair/typebox"; - -const COORD_PAIR = Type.Object({ x: Type.Number(), y: Type.Number() }, { additionalProperties: false }); - -const Action = Type.Object( - { - type: Type.String({ - description: "Action type.", - enum: [ - "click", - "double_click", - "type", - "keypress", - "scroll", - "move", - "drag", - "wait", - "goto", - "back", - "forward", - "url", - "screenshot", - ], - }), - x: Type.Optional(Type.Number({ description: "Pixel X (NOT 0-1000)." })), - y: Type.Optional(Type.Number({ description: "Pixel Y (NOT 0-1000)." })), - text: Type.Optional(Type.String()), - url: Type.Optional(Type.String({ description: "URL when type=goto." })), - keys: Type.Optional(Type.Array(Type.String(), { description: "Keys for keypress." })), - button: Type.Optional(Type.String()), - hold_keys: Type.Optional(Type.Array(Type.String())), - scroll_x: Type.Optional(Type.Number({ description: "Horizontal scroll in pixels (~120/tick)." })), - scroll_y: Type.Optional(Type.Number({ description: "Vertical scroll in pixels (~120/tick)." })), - ms: Type.Optional(Type.Number({ description: "Wait duration in ms when type=wait." })), - path: Type.Optional( - Type.Array(COORD_PAIR, { description: "Required when type=drag. Two or more {x, y} points." }), - ), - }, - { additionalProperties: false }, -); - -export const GeminiBatchSchema = Type.Object({ - actions: Type.Array(Action, { description: "Ordered list of actions to execute." }), -}); - -export type GeminiBatchToolInput = Static; - -export interface GeminiBatchToolDetails { - statusText: string; - actionDescriptions: string[]; - readResults: Array<{ type: "url"; url: string } | { type: "screenshot"; bytes: number } | { type: "cursor_position"; x: number; y: number }>; - error?: string; -} - -const SETTLE_MS_AFTER_BATCH = 300; - -function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -export const GEMINI_BATCH_DESCRIPTION = [ - "Execute multiple computer actions in sequence, including ordered read steps like url() and screenshot() anywhere in the batch.", - "Coordinates use PIXEL units (NOT 0-1000 normalized). Use this tool when you can plan several actions ahead.", - "Consecutive write actions are flushed together; each url()/screenshot() step returns output in the order it was requested.", - "If no explicit read step is included, the tool returns one fresh screenshot after execution.", - "", - "PREFER this over the per-action tools when:", - "- Typing text into a field followed by pressing Enter", - "- Clicking a field and then typing into it", - "- Navigating with goto (focuses the address bar, types the URL, presses Enter)", - "- Using back/forward (cua extensions for keyboard back/forward)", - "- Reading the current URL via url() — returns the address bar contents", - "", - "Drag format: when type=drag, include path as an ordered array of {x, y} pixel points (at least two).", - "Wait format: when type=wait, you may include ms to control the pause duration in milliseconds.", -].join("\n"); - -export const GEMINI_BATCH_TOOL_NAME = "batch_computer_actions"; - -/** Wire-format Gemini FunctionDeclaration for hand-rolled (non-pi) consumers. */ -export const GEMINI_BATCH_FUNCTION_DECLARATION = { - name: GEMINI_BATCH_TOOL_NAME, - description: GEMINI_BATCH_DESCRIPTION, - parameters: GeminiBatchSchema, -} as const; - -export async function executeGeminiBatch( - translator: ComputerTranslator, - params: GeminiBatchToolInput, -): Promise> { - const actions = (params.actions ?? []) as ModelAction[]; - const actionDescriptions = actions.map(describeShort); - const content: ComputerUseToolResult["content"] = []; - let statusText: string; - let execErr: Error | undefined; - const readResults: GeminiBatchToolDetails["readResults"] = []; - - let hasScreenshotInResults = false; - try { - const result = await translator.executeBatch(actions); - for (const r of result.readResults) { - if (r.type === "url") { - readResults.push({ type: "url", url: r.url }); - } else if (r.type === "screenshot") { - readResults.push({ type: "screenshot", bytes: r.pngBytes.length }); - hasScreenshotInResults = true; - } else { - readResults.push({ type: "cursor_position", x: r.x, y: r.y }); - } - } - statusText = "Actions executed successfully."; - content.push({ type: "text", text: statusText }); - for (const r of result.readResults) { - if (r.type === "url") { - content.push({ type: "text", text: `url(): ${r.url}` }); - } else if (r.type === "screenshot") { - content.push({ - type: "image", - data: r.pngBytes.toString("base64"), - mimeType: "image/png", - }); - } else { - content.push({ type: "text", text: `cursor_position(): ${r.x},${r.y}` }); - } - } - } catch (err) { - execErr = err instanceof Error ? err : new Error(String(err)); - statusText = `Actions failed: ${execErr.message}`; - content.push({ type: "text", text: statusText }); - } - - const needFallback = readResults.length === 0 || (execErr && !hasScreenshotInResults); - if (needFallback) { - if (!execErr) await delay(SETTLE_MS_AFTER_BATCH); - try { - const png = await translator.screenshotRaw(); - content.push({ type: "image", data: png.toString("base64"), mimeType: "image/png" }); - readResults.push({ type: "screenshot", bytes: png.length }); - } catch (shotErr) { - content[0] = { - type: "text", - text: `${statusText} Screenshot unavailable: ${(shotErr as Error).message}`, - }; - } - } - - const details: GeminiBatchToolDetails = { - statusText, - actionDescriptions, - readResults, - ...(execErr ? { error: execErr.message } : {}), - }; - - return { - content, - details, - ...(execErr ? { isError: true } : {}), - }; -} - -function describeShort(action: ModelAction): string { - const t = typeof action.type === "string" ? action.type : ""; - switch (t) { - case "click": - case "double_click": - return `${t}(${num(action.x)}, ${num(action.y)})`; - case "type": { - const text = typeof action.text === "string" ? action.text : ""; - const trimmed = text.length > 30 ? `${text.slice(0, 27)}...` : text; - return `type(${JSON.stringify(trimmed)})`; - } - case "keypress": { - const keys = Array.isArray(action.keys) ? (action.keys as string[]) : []; - return `keypress(${JSON.stringify(keys)})`; - } - case "scroll": - return `scroll(${num(action.x)}, ${num(action.y)})`; - case "move": - return `move(${num(action.x)}, ${num(action.y)})`; - case "drag": - return "drag(...)"; - case "wait": - return "wait"; - case "goto": - return `goto(${JSON.stringify(typeof action.url === "string" ? action.url : "")})`; - case "back": - return "back()"; - case "forward": - return "forward()"; - case "url": - return "url()"; - case "screenshot": - return "screenshot()"; - default: - return t || ""; - } -} - -function num(v: unknown): number { - if (typeof v === "number" && Number.isFinite(v)) return Math.trunc(v); - return 0; -} diff --git a/packages/cua-gemini/src/computer-tool.ts b/packages/cua-gemini/src/computer-tool.ts deleted file mode 100644 index ba78c46e..00000000 --- a/packages/cua-gemini/src/computer-tool.ts +++ /dev/null @@ -1,394 +0,0 @@ -import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core"; -import type { ImageContent, TextContent } from "@mariozechner/pi-ai"; -import { - type ComputerTranslator, - type ModelAction, - backModelAction, - forwardModelAction, -} from "@onkernel/cua-translator"; -import { type Static, Type } from "@sinclair/typebox"; -import { denormalizeX, denormalizeY } from "./coords"; -import { DEFAULT_GEMINI_SCREEN_SIZE, GeminiAction, type GeminiScreenSize } from "./official"; - -/** - * One AgentTool per predefined Gemini computer-use function. - * - * Each tool's name matches the Gemini-trained function name (e.g. `click_at`) - * so a Gemini computer-use model emits `functionCall` parts with the right - * tool name. The `execute()` body translates the Gemini argument shape - * (normalized 0–1000 coords, magnitude in pixels, etc.) into canonical - * `ModelAction` sequences and dispatches via - * {@link ComputerTranslator.executeBatch}, then attaches a screenshot to - * the tool result so the model sees the new state. - */ - -const SCREENSHOT_DELAY_MS = 500; -const PX_PER_NOTCH = 60; -const MAX_NOTCHES_PER_ACTION = 17; - -function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -export interface GeminiComputerToolsOptions { - /** Screen size used for 0–1000 coord denormalization. Defaults to Kernel cloud browser default. */ - screenSize?: GeminiScreenSize; - /** When true, append a fresh screenshot after every successful action. Default true. */ - attachScreenshot?: boolean; -} - -interface BuildContext { - translator: ComputerTranslator; - screen: GeminiScreenSize; - attachScreenshot: boolean; -} - -export interface GeminiToolDetails { - action: string; - statusText: string; - error?: string; -} - -// ─── Per-action AgentTool builders ──────────────────────────────────────── - -function makeTool>(opts: { - name: GeminiAction; - description: string; - parameters: S; - exec: (params: Static) => Promise; - ctx: BuildContext; -}): AgentTool { - return { - name: opts.name, - label: opts.name, - description: opts.description, - parameters: opts.parameters, - async execute(_id, params): Promise> { - const content: (TextContent | ImageContent)[] = []; - let statusText = "ok"; - let execErr: Error | undefined; - let skipScreenshot = false; - - try { - const actions = await opts.exec(params); - if (actions.length === 0) { - skipScreenshot = true; - } else { - const result = await opts.ctx.translator.executeBatch(actions); - for (const r of result.readResults) { - if (r.type === "screenshot") { - content.push({ type: "text", text: "screenshot:" }); - content.push({ - type: "image", - data: r.pngBytes.toString("base64"), - mimeType: "image/png", - }); - skipScreenshot = true; - } else if (r.type === "url") { - content.push({ type: "text", text: `url: ${r.url}` }); - } - } - } - } catch (err) { - execErr = err instanceof Error ? err : new Error(String(err)); - statusText = `failed: ${execErr.message}`; - } - - content.unshift({ type: "text", text: statusText }); - - if (!execErr && !skipScreenshot && opts.ctx.attachScreenshot) { - await delay(SCREENSHOT_DELAY_MS); - try { - const png = await opts.ctx.translator.screenshotRaw(); - content.push({ - type: "image", - data: png.toString("base64"), - mimeType: "image/png", - }); - } catch (shotErr) { - content[0] = { - type: "text", - text: `${statusText} (screenshot unavailable: ${(shotErr as Error).message})`, - }; - } - } - - const details: GeminiToolDetails = { - action: opts.name, - statusText, - ...(execErr ? { error: execErr.message } : {}), - }; - - if (execErr) throw Object.assign(execErr, { details, content }); - return { content, details }; - }, - }; -} - -// ─── Schemas (one per Gemini function) ──────────────────────────────────── - -const NormalizedXY = { - x: Type.Number({ description: "X in 0-1000 normalized coords." }), - y: Type.Number({ description: "Y in 0-1000 normalized coords." }), -} as const; - -const OpenWebBrowserSchema = Type.Object({}, { additionalProperties: false }); -const ClickAtSchema = Type.Object({ ...NormalizedXY }, { additionalProperties: false }); -const HoverAtSchema = Type.Object({ ...NormalizedXY }, { additionalProperties: false }); -const TypeTextAtSchema = Type.Object( - { - ...NormalizedXY, - text: Type.String({ description: "Text to type after focusing the field at (x, y)." }), - press_enter: Type.Optional(Type.Boolean({ description: "Press Enter after typing." })), - clear_before_typing: Type.Optional( - Type.Boolean({ description: "Select-all + delete before typing. Defaults to true." }), - ), - }, - { additionalProperties: false }, -); -const ScrollDocumentSchema = Type.Object( - { - direction: Type.String({ description: "Scroll direction.", enum: ["up", "down", "left", "right"] }), - magnitude: Type.Optional(Type.Number({ description: "Scroll magnitude in pixels. Default 400." })), - }, - { additionalProperties: false }, -); -const ScrollAtSchema = Type.Object( - { - ...NormalizedXY, - direction: Type.String({ enum: ["up", "down", "left", "right"] }), - magnitude: Type.Optional(Type.Number()), - }, - { additionalProperties: false }, -); -const Wait5SecondsSchema = Type.Object({}, { additionalProperties: false }); -const GoBackSchema = Type.Object({}, { additionalProperties: false }); -const GoForwardSchema = Type.Object({}, { additionalProperties: false }); -const SearchSchema = Type.Object({}, { additionalProperties: false }); -const NavigateSchema = Type.Object( - { - url: Type.String({ description: "Fully-qualified URL to navigate to." }), - }, - { additionalProperties: false }, -); -const KeyCombinationSchema = Type.Object( - { - keys: Type.String({ - description: "Key combo joined with '+' (e.g. 'ctrl+l', 'shift+Tab', 'Return').", - }), - }, - { additionalProperties: false }, -); -const DragAndDropSchema = Type.Object( - { - x: Type.Number({ description: "Start X (0-1000)." }), - y: Type.Number({ description: "Start Y (0-1000)." }), - destination_x: Type.Number({ description: "End X (0-1000)." }), - destination_y: Type.Number({ description: "End Y (0-1000)." }), - }, - { additionalProperties: false }, -); - -// ─── Public factory ─────────────────────────────────────────────────────── - -/** - * Build the AgentTool array for Gemini's predefined computer-use functions. - * Pair with {@link GEMINI_SYSTEM_INSTRUCTIONS} as the system prompt and - * (optionally) {@link createGeminiBatchTool} for predictable multi-action - * sequences. - */ -export function createGeminiPerActionTools( - translator: ComputerTranslator, - opts: GeminiComputerToolsOptions = {}, -): AgentTool[] { - const ctx: BuildContext = { - translator, - screen: opts.screenSize ?? DEFAULT_GEMINI_SCREEN_SIZE, - attachScreenshot: opts.attachScreenshot !== false, - }; - - return [ - makeTool({ - name: GeminiAction.OPEN_WEB_BROWSER, - description: - "Acknowledge that the web browser is already open. Returns a fresh screenshot of the current page.", - parameters: OpenWebBrowserSchema, - ctx, - async exec() { - return [{ type: "screenshot" }]; - }, - }), - makeTool({ - name: GeminiAction.CLICK_AT, - description: "Left-click at the given (x, y) coordinates (0-1000 normalized).", - parameters: ClickAtSchema, - ctx, - async exec({ x, y }) { - return [ - { - type: "click", - x: denormalizeX(x, ctx.screen), - y: denormalizeY(y, ctx.screen), - button: "left", - }, - ]; - }, - }), - makeTool({ - name: GeminiAction.HOVER_AT, - description: "Move the mouse cursor to the given (x, y) coordinates without clicking.", - parameters: HoverAtSchema, - ctx, - async exec({ x, y }) { - return [{ type: "move", x: denormalizeX(x, ctx.screen), y: denormalizeY(y, ctx.screen) }]; - }, - }), - makeTool({ - name: GeminiAction.TYPE_TEXT_AT, - description: "Click at (x, y), optionally clear the field, then type text. Optionally press Enter.", - parameters: TypeTextAtSchema, - ctx, - async exec(params) { - const px = denormalizeX(params.x, ctx.screen); - const py = denormalizeY(params.y, ctx.screen); - const actions: ModelAction[] = [ - { type: "click", x: px, y: py, button: "left" }, - ]; - if (params.clear_before_typing !== false) { - actions.push({ type: "keypress", keys: ["ctrl", "a"] }); - } - actions.push({ type: "type", text: params.text }); - if (params.press_enter) { - actions.push({ type: "keypress", keys: ["Return"] }); - } - return actions; - }, - }), - makeTool({ - name: GeminiAction.SCROLL_DOCUMENT, - description: - "Scroll the document by `magnitude` pixels in `direction`. Anchors at the screen center.", - parameters: ScrollDocumentSchema, - ctx, - async exec({ direction, magnitude }) { - const centerX = Math.round(ctx.screen.width / 2); - const centerY = Math.round(ctx.screen.height / 2); - const px = scrollMagnitudePx(magnitude); - const { sx, sy } = directionDelta(direction, px); - return [{ type: "scroll", x: centerX, y: centerY, scroll_x: sx, scroll_y: sy }]; - }, - }), - makeTool({ - name: GeminiAction.SCROLL_AT, - description: "Scroll at a specific (x, y) location by `magnitude` pixels in `direction`.", - parameters: ScrollAtSchema, - ctx, - async exec({ x, y, direction, magnitude }) { - const px = denormalizeX(x, ctx.screen); - const py = denormalizeY(y, ctx.screen); - const m = scrollMagnitudePx(magnitude); - const { sx, sy } = directionDelta(direction, m); - return [{ type: "scroll", x: px, y: py, scroll_x: sx, scroll_y: sy }]; - }, - }), - makeTool({ - name: GeminiAction.WAIT_5_SECONDS, - description: "Sleep for 5 seconds (e.g. to let the page settle after async navigation).", - parameters: Wait5SecondsSchema, - ctx, - async exec() { - return [{ type: "wait", ms: 5000 }]; - }, - }), - makeTool({ - name: GeminiAction.GO_BACK, - description: "Navigate back in browser history (Alt+Left).", - parameters: GoBackSchema, - ctx, - async exec() { - return [backModelAction()]; - }, - }), - makeTool({ - name: GeminiAction.GO_FORWARD, - description: "Navigate forward in browser history (Alt+Right).", - parameters: GoForwardSchema, - ctx, - async exec() { - return [forwardModelAction()]; - }, - }), - makeTool({ - name: GeminiAction.SEARCH, - description: "Focus the address bar (Ctrl+L).", - parameters: SearchSchema, - ctx, - async exec() { - return [{ type: "keypress", keys: ["ctrl", "l"] }]; - }, - }), - makeTool({ - name: GeminiAction.NAVIGATE, - description: "Navigate the browser to a fully-qualified URL via the address bar.", - parameters: NavigateSchema, - ctx, - async exec({ url }) { - return [{ type: "goto", url }]; - }, - }), - makeTool({ - name: GeminiAction.KEY_COMBINATION, - description: "Press a key or key combination joined by '+' (e.g. 'ctrl+l', 'Return', 'shift+Tab').", - parameters: KeyCombinationSchema, - ctx, - async exec({ keys }) { - const split = keys - .split("+") - .map((s: string) => s.trim()) - .filter(Boolean); - return [{ type: "keypress", keys: split }]; - }, - }), - makeTool({ - name: GeminiAction.DRAG_AND_DROP, - description: - "Drag from (x, y) to (destination_x, destination_y) using a left-button drag. Coordinates are 0-1000.", - parameters: DragAndDropSchema, - ctx, - async exec({ x, y, destination_x, destination_y }) { - return [ - { - type: "drag", - path: [ - { x: denormalizeX(x, ctx.screen), y: denormalizeY(y, ctx.screen) }, - { x: denormalizeX(destination_x, ctx.screen), y: denormalizeY(destination_y, ctx.screen) }, - ], - }, - ]; - }, - }), - ]; -} - -// ─── Helpers ────────────────────────────────────────────────────────────── - -function scrollMagnitudePx(magnitude: number | undefined): number { - const px = magnitude ?? 400; - const notches = Math.min(MAX_NOTCHES_PER_ACTION, Math.max(1, Math.round(px / PX_PER_NOTCH))); - return notches * 120; -} - -function directionDelta(direction: string, magnitudePx: number): { sx: number; sy: number } { - switch (direction) { - case "down": - return { sx: 0, sy: magnitudePx }; - case "up": - return { sx: 0, sy: -magnitudePx }; - case "right": - return { sx: magnitudePx, sy: 0 }; - case "left": - return { sx: -magnitudePx, sy: 0 }; - default: - throw new Error(`unknown scroll direction: ${direction}`); - } -} diff --git a/packages/cua-gemini/src/computer.ts b/packages/cua-gemini/src/computer.ts deleted file mode 100644 index 287283ad..00000000 --- a/packages/cua-gemini/src/computer.ts +++ /dev/null @@ -1,365 +0,0 @@ -import type { - ComputerTranslator, - ComputerUseToolResult, - ModelAction, -} from "@onkernel/cua-translator"; -import { - backModelAction, - forwardModelAction, -} from "@onkernel/cua-translator"; -import { type TObject, Type } from "@sinclair/typebox"; -import { denormalizeX, denormalizeY } from "./coords"; -import { - DEFAULT_GEMINI_SCREEN_SIZE, - GeminiAction, - type GeminiScreenSize, -} from "./official"; - -const SCREENSHOT_DELAY_MS = 500; -const PX_PER_NOTCH = 60; -const MAX_NOTCHES_PER_ACTION = 17; - -function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -export interface GeminiComputerToolsOptions { - screenSize?: GeminiScreenSize; - attachScreenshot?: boolean; -} - -export interface GeminiToolDetails { - action: string; - statusText: string; - error?: string; -} - -interface RunContext { - translator: ComputerTranslator; - screen: GeminiScreenSize; - attachScreenshot: boolean; -} - -interface GeminiDefinition { - name: GeminiAction; - description: string; - parameters: S; - exec: (params: any, ctx: RunContext) => Promise; -} - -const NormalizedXY = { - x: Type.Number({ description: "X in 0-1000 normalized coords." }), - y: Type.Number({ description: "Y in 0-1000 normalized coords." }), -} as const; - -const OpenWebBrowserSchema = Type.Object({}, { additionalProperties: false }); -const ClickAtSchema = Type.Object({ ...NormalizedXY }, { additionalProperties: false }); -const HoverAtSchema = Type.Object({ ...NormalizedXY }, { additionalProperties: false }); -const TypeTextAtSchema = Type.Object( - { - ...NormalizedXY, - text: Type.String({ description: "Text to type after focusing the field at (x, y)." }), - press_enter: Type.Optional(Type.Boolean({ description: "Press Enter after typing." })), - clear_before_typing: Type.Optional( - Type.Boolean({ description: "Select-all + delete before typing. Defaults to true." }), - ), - }, - { additionalProperties: false }, -); -const ScrollDocumentSchema = Type.Object( - { - direction: Type.String({ description: "Scroll direction.", enum: ["up", "down", "left", "right"] }), - magnitude: Type.Optional(Type.Number({ description: "Scroll magnitude in pixels. Default 400." })), - }, - { additionalProperties: false }, -); -const ScrollAtSchema = Type.Object( - { - ...NormalizedXY, - direction: Type.String({ enum: ["up", "down", "left", "right"] }), - magnitude: Type.Optional(Type.Number()), - }, - { additionalProperties: false }, -); -const Wait5SecondsSchema = Type.Object({}, { additionalProperties: false }); -const GoBackSchema = Type.Object({}, { additionalProperties: false }); -const GoForwardSchema = Type.Object({}, { additionalProperties: false }); -const SearchSchema = Type.Object({}, { additionalProperties: false }); -const NavigateSchema = Type.Object( - { - url: Type.String({ description: "Fully-qualified URL to navigate to." }), - }, - { additionalProperties: false }, -); -const KeyCombinationSchema = Type.Object( - { - keys: Type.String({ - description: "Key combo joined with '+' (e.g. 'ctrl+l', 'shift+Tab', 'Return').", - }), - }, - { additionalProperties: false }, -); -const DragAndDropSchema = Type.Object( - { - x: Type.Number({ description: "Start X (0-1000)." }), - y: Type.Number({ description: "Start Y (0-1000)." }), - destination_x: Type.Number({ description: "End X (0-1000)." }), - destination_y: Type.Number({ description: "End Y (0-1000)." }), - }, - { additionalProperties: false }, -); - -const GEMINI_DEFINITIONS: GeminiDefinition[] = [ - { - name: GeminiAction.OPEN_WEB_BROWSER, - description: - "Acknowledge that the web browser is already open. Returns a fresh screenshot of the current page.", - parameters: OpenWebBrowserSchema, - async exec() { - return [{ type: "screenshot" }]; - }, - }, - { - name: GeminiAction.CLICK_AT, - description: "Left-click at the given (x, y) coordinates (0-1000 normalized).", - parameters: ClickAtSchema, - async exec({ x, y }, ctx) { - return [{ type: "click", x: denormalizeX(x, ctx.screen), y: denormalizeY(y, ctx.screen), button: "left" }]; - }, - }, - { - name: GeminiAction.HOVER_AT, - description: "Move the mouse cursor to the given (x, y) coordinates without clicking.", - parameters: HoverAtSchema, - async exec({ x, y }, ctx) { - return [{ type: "move", x: denormalizeX(x, ctx.screen), y: denormalizeY(y, ctx.screen) }]; - }, - }, - { - name: GeminiAction.TYPE_TEXT_AT, - description: "Click at (x, y), optionally clear the field, then type text. Optionally press Enter.", - parameters: TypeTextAtSchema, - async exec(params, ctx) { - const px = denormalizeX(params.x, ctx.screen); - const py = denormalizeY(params.y, ctx.screen); - const actions: ModelAction[] = [{ type: "click", x: px, y: py, button: "left" }]; - if (params.clear_before_typing !== false) { - actions.push({ type: "keypress", keys: ["ctrl", "a"] }); - } - actions.push({ type: "type", text: params.text }); - if (params.press_enter) { - actions.push({ type: "keypress", keys: ["Return"] }); - } - return actions; - }, - }, - { - name: GeminiAction.SCROLL_DOCUMENT, - description: "Scroll the document by `magnitude` pixels in `direction`. Anchors at the screen center.", - parameters: ScrollDocumentSchema, - async exec({ direction, magnitude }, ctx) { - const centerX = Math.round(ctx.screen.width / 2); - const centerY = Math.round(ctx.screen.height / 2); - const px = scrollMagnitudePx(magnitude); - const { sx, sy } = directionDelta(direction, px); - return [{ type: "scroll", x: centerX, y: centerY, scroll_x: sx, scroll_y: sy }]; - }, - }, - { - name: GeminiAction.SCROLL_AT, - description: "Scroll at a specific (x, y) location by `magnitude` pixels in `direction`.", - parameters: ScrollAtSchema, - async exec({ x, y, direction, magnitude }, ctx) { - const px = denormalizeX(x, ctx.screen); - const py = denormalizeY(y, ctx.screen); - const m = scrollMagnitudePx(magnitude); - const { sx, sy } = directionDelta(direction, m); - return [{ type: "scroll", x: px, y: py, scroll_x: sx, scroll_y: sy }]; - }, - }, - { - name: GeminiAction.WAIT_5_SECONDS, - description: "Sleep for 5 seconds (e.g. to let the page settle after async navigation).", - parameters: Wait5SecondsSchema, - async exec() { - return [{ type: "wait", ms: 5000 }]; - }, - }, - { - name: GeminiAction.GO_BACK, - description: "Navigate back in browser history (Alt+Left).", - parameters: GoBackSchema, - async exec() { - return [backModelAction()]; - }, - }, - { - name: GeminiAction.GO_FORWARD, - description: "Navigate forward in browser history (Alt+Right).", - parameters: GoForwardSchema, - async exec() { - return [forwardModelAction()]; - }, - }, - { - name: GeminiAction.SEARCH, - description: "Focus the address bar (Ctrl+L).", - parameters: SearchSchema, - async exec() { - return [{ type: "keypress", keys: ["ctrl", "l"] }]; - }, - }, - { - name: GeminiAction.NAVIGATE, - description: "Navigate the browser to a fully-qualified URL via the address bar.", - parameters: NavigateSchema, - async exec({ url }) { - return [{ type: "goto", url }]; - }, - }, - { - name: GeminiAction.KEY_COMBINATION, - description: "Press a key or key combination joined by '+' (e.g. 'ctrl+l', 'Return', 'shift+Tab').", - parameters: KeyCombinationSchema, - async exec({ keys }) { - return [{ type: "keypress", keys: keys.split("+").map((s: string) => s.trim()).filter(Boolean) }]; - }, - }, - { - name: GeminiAction.DRAG_AND_DROP, - description: - "Drag from (x, y) to (destination_x, destination_y) using a left-button drag. Coordinates are 0-1000.", - parameters: DragAndDropSchema, - async exec({ x, y, destination_x, destination_y }, ctx) { - return [ - { - type: "drag", - path: [ - { x: denormalizeX(x, ctx.screen), y: denormalizeY(y, ctx.screen) }, - { x: denormalizeX(destination_x, ctx.screen), y: denormalizeY(destination_y, ctx.screen) }, - ], - }, - ]; - }, - }, -]; - -export const GEMINI_FUNCTION_DECLARATIONS = GEMINI_DEFINITIONS.map((definition) => ({ - name: definition.name, - description: definition.description, - parameters: definition.parameters, -})); - -export async function executeGeminiFunctionCall(args: { - translator: ComputerTranslator; - name: string; - input: Record; - options?: GeminiComputerToolsOptions; -}): Promise> { - const definition = GEMINI_DEFINITIONS.find((entry) => entry.name === args.name); - if (!definition) { - return { - content: [{ type: "text", text: `failed: unknown Gemini function "${args.name}"` }], - details: { - action: args.name, - statusText: `failed: unknown Gemini function "${args.name}"`, - error: `unknown Gemini function "${args.name}"`, - }, - isError: true, - }; - } - const ctx: RunContext = { - translator: args.translator, - screen: args.options?.screenSize ?? DEFAULT_GEMINI_SCREEN_SIZE, - attachScreenshot: args.options?.attachScreenshot !== false, - }; - return executeDefinition(definition, args.input, ctx); -} - -async function executeDefinition( - definition: GeminiDefinition, - params: Record, - ctx: RunContext, -): Promise> { - const content: ComputerUseToolResult["content"] = []; - let statusText = "ok"; - let execErr: Error | undefined; - let skipScreenshot = false; - - try { - const actions = await definition.exec(params, ctx); - if (actions.length === 0) { - skipScreenshot = true; - } else { - const result = await ctx.translator.executeBatch(actions); - for (const r of result.readResults) { - if (r.type === "screenshot") { - content.push({ type: "text", text: "screenshot:" }); - content.push({ - type: "image", - data: r.pngBytes.toString("base64"), - mimeType: "image/png", - }); - skipScreenshot = true; - } else if (r.type === "url") { - content.push({ type: "text", text: `url: ${r.url}` }); - } - } - } - } catch (err) { - execErr = err instanceof Error ? err : new Error(String(err)); - statusText = `failed: ${execErr.message}`; - } - - content.unshift({ type: "text", text: statusText }); - - if (!execErr && !skipScreenshot && ctx.attachScreenshot) { - await delay(SCREENSHOT_DELAY_MS); - try { - const png = await ctx.translator.screenshotRaw(); - content.push({ - type: "image", - data: png.toString("base64"), - mimeType: "image/png", - }); - } catch (shotErr) { - content[0] = { - type: "text", - text: `${statusText} (screenshot unavailable: ${(shotErr as Error).message})`, - }; - } - } - - const details: GeminiToolDetails = { - action: definition.name, - statusText, - ...(execErr ? { error: execErr.message } : {}), - }; - - return { - content, - details, - ...(execErr ? { isError: true } : {}), - }; -} - -function scrollMagnitudePx(magnitude: number | undefined): number { - const px = magnitude ?? 400; - const notches = Math.min(MAX_NOTCHES_PER_ACTION, Math.max(1, Math.round(px / PX_PER_NOTCH))); - return notches * 120; -} - -function directionDelta(direction: string, magnitudePx: number): { sx: number; sy: number } { - switch (direction) { - case "down": - return { sx: 0, sy: magnitudePx }; - case "up": - return { sx: 0, sy: -magnitudePx }; - case "right": - return { sx: magnitudePx, sy: 0 }; - case "left": - return { sx: -magnitudePx, sy: 0 }; - default: - throw new Error(`unknown scroll direction: ${direction}`); - } -} diff --git a/packages/cua-gemini/src/coords.ts b/packages/cua-gemini/src/coords.ts deleted file mode 100644 index 961ae65f..00000000 --- a/packages/cua-gemini/src/coords.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { GEMINI_COORDINATE_SCALE, type GeminiScreenSize } from "./official"; - -/** Convert Gemini's 0–1000 normalized X to pixels for the given screen. */ -export function denormalizeX(x: number, screen: GeminiScreenSize): number { - return Math.round((x / GEMINI_COORDINATE_SCALE) * screen.width); -} - -/** Convert Gemini's 0–1000 normalized Y to pixels for the given screen. */ -export function denormalizeY(y: number, screen: GeminiScreenSize): number { - return Math.round((y / GEMINI_COORDINATE_SCALE) * screen.height); -} diff --git a/packages/cua-gemini/src/cua-extras.ts b/packages/cua-gemini/src/cua-extras.ts deleted file mode 100644 index 63842e2f..00000000 --- a/packages/cua-gemini/src/cua-extras.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * cua extension actions for Gemini. - * - * Most navigation verbs Gemini's official action set already covers - * (`go_back`, `go_forward`, `navigate`, `search`). The only cua-added - * one we need on top is `url` — read-the-current-URL — because Gemini's - * predefined actions don't expose it. We surface it via the cua-added - * `batch_computer_actions` tool's action union, NOT as a standalone - * Gemini predefined function. - */ - -export const GEMINI_CUA_EXTRA_ACTION_TYPES = ["url"] as const; - -export type GeminiCuaExtraActionType = (typeof GEMINI_CUA_EXTRA_ACTION_TYPES)[number]; diff --git a/packages/cua-gemini/src/index.ts b/packages/cua-gemini/src/index.ts deleted file mode 100644 index dca7d47a..00000000 --- a/packages/cua-gemini/src/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @onkernel/cua-gemini - * - * Provider-neutral Gemini computer-use helpers backed by - * `@onkernel/cua-translator`. - * - * The package root exports: - * - Gemini model factory for single-invocation `runComputerUse()` calls - * - plain function declarations / execution helpers for non-pi loops - * - Gemini action enums, coordinate helpers, and prompt builders - * - * `pi-agent-core` bindings live under `@onkernel/cua-gemini/pi`. - */ - -export { - executeGeminiBatch, - GeminiBatchSchema, - GEMINI_BATCH_DESCRIPTION, - GEMINI_BATCH_FUNCTION_DECLARATION, - GEMINI_BATCH_TOOL_NAME, -} from "./batch"; -export type { GeminiBatchToolInput, GeminiBatchToolDetails } from "./batch"; -export { - executeGeminiFunctionCall, - GEMINI_FUNCTION_DECLARATIONS, -} from "./computer"; -export type { GeminiComputerToolsOptions, GeminiToolDetails } from "./computer"; -export { - GeminiAction, - PREDEFINED_COMPUTER_USE_FUNCTIONS, - DEFAULT_GEMINI_SCREEN_SIZE, - GEMINI_COORDINATE_SCALE, -} from "./official"; -export type { - GeminiFunctionArgs, - GeminiScreenSize, - ScrollDirection, -} from "./official"; -export { gemini } from "./model"; -export type { - GeminiModelOptions, - GeminiModelRunDetails, -} from "./model"; -export { denormalizeX, denormalizeY } from "./coords"; -export { GEMINI_CUA_EXTRA_ACTION_TYPES } from "./cua-extras"; -export type { GeminiCuaExtraActionType } from "./cua-extras"; -export { - buildGeminiSystemPrompt, - GEMINI_INSTRUCTIONS_RAW, -} from "./system-prompt"; -export type { GeminiSystemPromptOptions } from "./system-prompt"; diff --git a/packages/cua-gemini/src/model.ts b/packages/cua-gemini/src/model.ts deleted file mode 100644 index f0234a82..00000000 --- a/packages/cua-gemini/src/model.ts +++ /dev/null @@ -1,159 +0,0 @@ -import type { - ComputerUseModel, - ComputerUseRunResult, - ComputerUseToolResult, -} from "@onkernel/cua-translator"; -import { GoogleGenAI } from "@google/genai"; -import { - executeGeminiBatch, - GEMINI_BATCH_FUNCTION_DECLARATION, - GEMINI_BATCH_TOOL_NAME, -} from "./batch"; -import { - type GeminiComputerToolsOptions, - type GeminiToolDetails, - executeGeminiFunctionCall, - GEMINI_FUNCTION_DECLARATIONS, -} from "./computer"; -import { buildGeminiSystemPrompt } from "./system-prompt"; - -export interface GeminiModelOptions extends GeminiComputerToolsOptions { - apiKey?: string; - systemPromptSuffix?: string; - includeBatchTool?: boolean; -} - -export interface GeminiModelRunDetails { - finishReason?: string; -} - -export function gemini(modelId: string, opts: GeminiModelOptions = {}): ComputerUseModel { - return { - provider: "gemini", - modelId, - async run({ prompt, translator, maxTurns = 50 }): Promise> { - const apiKey = opts.apiKey || process.env.GOOGLE_API_KEY; - if (!apiKey) { - throw new Error("missing Google API key"); - } - - const ai = new GoogleGenAI({ apiKey }); - const contents: any[] = [{ role: "user", parts: [{ text: prompt }] }]; - const systemText = buildGeminiSystemPrompt({ - includeBatchNudge: opts.includeBatchTool !== false, - }); - const systemInstruction = opts.systemPromptSuffix - ? `${systemText}\n\n${opts.systemPromptSuffix}` - : systemText; - - for (let turn = 0; turn < maxTurns; turn++) { - const response: any = await ai.models.generateContent({ - model: modelId, - contents, - config: { - systemInstruction, - tools: [ - { - functionDeclarations: - opts.includeBatchTool === false - ? (GEMINI_FUNCTION_DECLARATIONS as any) - : ([...GEMINI_FUNCTION_DECLARATIONS, GEMINI_BATCH_FUNCTION_DECLARATION] as any), - }, - ], - thinkingConfig: { includeThoughts: true }, - }, - }); - - const candidateContent = response.candidates?.[0]?.content; - if (!candidateContent) break; - contents.push(candidateContent); - - const text = extractGeminiText(candidateContent.parts); - const functionCalls = (candidateContent.parts ?? []) - .filter( - (part: unknown): part is { functionCall: { name?: string; args?: Record } } => - typeof part === "object" && part !== null && "functionCall" in part, - ) - .map((part: { functionCall: { name?: string; args?: Record } }) => part.functionCall) - .filter( - (call: { name?: string; args?: Record }): call is { name: string; args?: Record } => - typeof call.name === "string", - ); - - if (functionCalls.length === 0) { - return { - text: text || "(no response)", - provider: "gemini", - modelId, - turns: turn + 1, - details: { finishReason: response.candidates?.[0]?.finishReason }, - }; - } - - const parts: any[] = []; - for (const call of functionCalls) { - const result = - call.name === GEMINI_BATCH_TOOL_NAME - ? await executeGeminiBatch(translator, (call.args ?? {}) as any) - : await executeGeminiFunctionCall({ - translator, - name: call.name, - input: call.args ?? {}, - options: opts, - }); - parts.push(toGeminiFunctionResponse(call.name, result)); - } - - contents.push({ role: "user", parts }); - } - - return { - text: "(max turns reached)", - provider: "gemini", - modelId, - turns: maxTurns, - }; - }, - }; -} - -function toGeminiFunctionResponse( - name: string, - result: ComputerUseToolResult, -): Record { - const responseParts = result.content - .filter((part) => part.type === "image") - .map((part) => ({ - inlineData: { - mimeType: part.mimeType, - data: part.data, - }, - })); - const text = result.content - .filter((part): part is { type: "text"; text: string } => part.type === "text") - .map((part) => part.text) - .join("\n") - .trim(); - return { - functionResponse: { - name, - response: { - text, - ...(result.isError ? { error: text || "tool execution failed" } : {}), - }, - ...(responseParts.length > 0 ? { parts: responseParts } : {}), - }, - }; -} - -function extractGeminiText(parts: unknown): string { - if (!Array.isArray(parts)) return ""; - return parts - .filter( - (part): part is { text: string } => - typeof part === "object" && part !== null && "text" in part && typeof (part as { text?: unknown }).text === "string", - ) - .map((part) => part.text) - .join(" ") - .trim(); -} diff --git a/packages/cua-gemini/src/official.ts b/packages/cua-gemini/src/official.ts deleted file mode 100644 index ec628e37..00000000 --- a/packages/cua-gemini/src/official.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Google Gemini Computer Use action set. - * - * Source of truth: Google's Gemini Computer Use docs / preview. - * https://ai.google.dev/gemini-api/docs/computer-use - * - * Gemini's computer-use preview tool exposes a fixed list of "predefined" - * functions that the model has been trained to call. We register the - * SAME named functions as ordinary `functionDeclarations` so any current - * Gemini model (with or without the preview computer-use mode enabled) - * can call them. - * - * Coordinate convention: ALL `x` / `y` arguments are normalized to the - * 0–1000 range. The model emits 0–1000; the Kernel browser expects pixels. - * `./coords.ts` does the conversion using the screen size advertised at - * tool construction time (default 1920×1080 to match Kernel cloud - * browsers). - */ - -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", -} - -/** - * The complete list of predefined computer-use function names. Order - * matches Google's docs. - */ -export const PREDEFINED_COMPUTER_USE_FUNCTIONS: GeminiAction[] = Object.values(GeminiAction); - -export type ScrollDirection = "up" | "down" | "left" | "right"; - -/** - * The argument bag any of the predefined functions can carry. Each function - * uses a subset of fields (see `./computer-tool.ts`). - */ -export interface GeminiFunctionArgs { - x?: number; - y?: number; - text?: string; - press_enter?: boolean; - clear_before_typing?: boolean; - direction?: ScrollDirection; - magnitude?: number; - url?: string; - keys?: string; - destination_x?: number; - destination_y?: number; - safety_decision?: { - decision: string; - explanation: string; - }; -} - -export interface GeminiScreenSize { - width: number; - height: number; -} - -/** Default Kernel cloud browser viewport. */ -export const DEFAULT_GEMINI_SCREEN_SIZE: GeminiScreenSize = { - width: 1920, - height: 1080, -}; - -/** Coordinate normalization scale Gemini uses for `x` / `y` (0–1000). */ -export const GEMINI_COORDINATE_SCALE = 1000; diff --git a/packages/cua-gemini/src/pi/index.ts b/packages/cua-gemini/src/pi/index.ts deleted file mode 100644 index cf682d7a..00000000 --- a/packages/cua-gemini/src/pi/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { AgentTool } from "@mariozechner/pi-agent-core"; -import type { ComputerTranslator } from "@onkernel/cua-translator"; -import { createGeminiBatchTool } from "../batch-tool"; -import { - createGeminiPerActionTools, - type GeminiComputerToolsOptions as PerActionOptions, -} from "../computer-tool"; - -export interface GeminiComputerToolsOptions extends PerActionOptions { - includeBatch?: boolean; -} - -/** - * Build the full Gemini computer-use tool set for `pi-agent-core`. - */ -export function createGeminiComputerTools( - translator: ComputerTranslator, - opts: GeminiComputerToolsOptions = {}, -): AgentTool[] { - const tools = createGeminiPerActionTools(translator, opts); - if (opts.includeBatch !== false) { - tools.push(createGeminiBatchTool(translator)); - } - return tools; -} - -export { createGeminiPerActionTools } from "../computer-tool"; -export type { GeminiToolDetails } from "../computer-tool"; -export { createGeminiBatchTool } from "../batch-tool"; -export type { GeminiBatchToolInput, GeminiBatchToolDetails } from "../batch"; diff --git a/packages/cua-gemini/src/system-prompt.ts b/packages/cua-gemini/src/system-prompt.ts deleted file mode 100644 index b84e3db8..00000000 --- a/packages/cua-gemini/src/system-prompt.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Gemini system-prompt preamble for the predefined computer-use functions - * + cua-added `batch_computer_actions` tool surface. - */ - -const GEMINI_COMPUTER_INSTRUCTIONS = `You control a 1920x1080 cloud browser through a set of computer-use tools. -Each tool returns a fresh screenshot after the action completes so you can -verify the result before planning the next step. - -Predefined tools (Gemini computer-use functions): -- All x / y arguments are normalized to the 0-1000 range (NOT pixels). -- click_at, hover_at, type_text_at, scroll_at, drag_and_drop take normalized (x, y). -- type_text_at can clear the field first (clear_before_typing, default true) and press Enter (press_enter). -- scroll_document scrolls the viewport from its center; magnitude is in pixels. -- navigate {url} opens a fresh page (focuses the address bar, types, presses Enter). -- go_back / go_forward use Alt+Left / Alt+Right. -- key_combination accepts a single string like "ctrl+l", "Return", or "shift+Tab". -- wait_5_seconds sleeps 5s for asynchronous UI to settle. - -Verification pattern: after multi-step changes, take a screenshot and explicitly -confirm what you see ("I see X, so step Y succeeded") before continuing.`; - -const GEMINI_BATCH_INSTRUCTIONS = `You also have a \`batch_computer_actions\` tool that bundles multiple actions -into a single call (with optional inline url() and screenshot() reads). -PREFER \`batch_computer_actions\` over the predefined per-action tools for -predictable sequences such as: -- Clicking a text field, typing text, and pressing Enter -- Dragging an item with mid-batch screenshot reads -- Reading the current URL via url() (the cua-added action — Gemini's - predefined functions don't expose this) - -IMPORTANT: \`batch_computer_actions\` uses PIXEL coordinates (x and y in -pixels), NOT the 0-1000 normalized coordinates the predefined tools use. -Mixing the two will not work — pick one tool per call and follow its -coordinate convention.`; - -export interface GeminiSystemPromptOptions { - /** Set false to omit the batch nudge (e.g. when batch is disabled). Defaults to true. */ - includeBatchNudge?: boolean; -} - -export function buildGeminiSystemPrompt(opts: GeminiSystemPromptOptions = {}): string { - if (opts.includeBatchNudge === false) return GEMINI_COMPUTER_INSTRUCTIONS; - return `${GEMINI_COMPUTER_INSTRUCTIONS}\n\n${GEMINI_BATCH_INSTRUCTIONS}`; -} - -export const GEMINI_INSTRUCTIONS_RAW = { - computer: GEMINI_COMPUTER_INSTRUCTIONS, - batch: GEMINI_BATCH_INSTRUCTIONS, -}; diff --git a/packages/cua-gemini/tsconfig.json b/packages/cua-gemini/tsconfig.json deleted file mode 100644 index c2e66df0..00000000 --- a/packages/cua-gemini/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./dist", - "rootDir": "./src" - }, - "include": ["src/**/*"], - "references": [{ "path": "../cua-translator" }] -} diff --git a/packages/cua-openai/README.md b/packages/cua-openai/README.md deleted file mode 100644 index ac0a4c8e..00000000 --- a/packages/cua-openai/README.md +++ /dev/null @@ -1,217 +0,0 @@ -# `@onkernel/cua-openai` - -Provider-neutral OpenAI computer-use helpers backed by -[`@onkernel/cua-translator`](../cua-translator). - -## Entry points - -- `@onkernel/cua-openai` — provider-neutral root surface: - `openai(modelId)`, `openaiTools()`, `executeOpenAIToolCall()`, raw - schemas, and prompt constants. -- `@onkernel/cua-openai/pi` — `pi-agent-core` bindings: - `createOpenAIComputerTools()`. - -The root `openai(modelId)` helper uses OpenAI's native `computer` tool -for single-invocation `runComputerUse()` flows. The `/pi` entrypoint -keeps today's custom `batch_computer_actions` / `computer_use_extra` -tools because `pi-ai`'s OpenAI Responses parser still doesn't surface -native `computer_call` items directly. - -`openai(modelId)` uses `previous_response_id` chaining by default inside -the tool loop, disables parallel tool calls, and enables OpenAI -server-side compaction with a 200k token threshold. Pass -`usePreviousResponseId: false` for stateless input-array chaining, -`previousResponseId` to resume an existing chain, or -`compactThreshold: false` to disable server-side compaction. - -## Install - -```bash -npm install @onkernel/cua-openai @onkernel/cua-translator @onkernel/sdk -``` - -If you want the `pi-agent-core` bindings too: - -```bash -npm install @earendil-works/pi-agent-core @earendil-works/pi-ai -``` - -## Quick start (`runComputerUse`) - -```typescript -import { browserSession, runComputerUse } from "@onkernel/cua-translator"; -import { openai } from "@onkernel/cua-openai"; - -const browser = await browserSession.open({ apiKey: process.env.KERNEL_API_KEY! }); - -const result = await runComputerUse({ - model: openai("gpt-5.5", { - // Optional: tune or disable server-side compaction. - compactThreshold: 200_000, - }), - browser, - prompt: "Open https://example.com and tell me the heading.", -}); - -console.log(result.text); -``` - -## Quick start (with `pi-agent-core`) - -```typescript -import { Agent } from "@earendil-works/pi-agent-core"; -import { getModel } from "@earendil-works/pi-ai"; -import { - ComputerTranslator, - browserSession, -} from "@onkernel/cua-translator"; -import { - OPENAI_BATCH_INSTRUCTIONS, -} from "@onkernel/cua-openai"; -import { - createOpenAIComputerTools, -} from "@onkernel/cua-openai/pi"; - -const browser = await browserSession.open({ apiKey: process.env.KERNEL_API_KEY! }); -const translator = new ComputerTranslator({ - client: browser.client, - sessionId: browser.sessionId, -}); - -const agent = new Agent({ - initialState: { - systemPrompt: OPENAI_BATCH_INSTRUCTIONS, - model: getModel("openai", "gpt-5.4"), - tools: createOpenAIComputerTools(translator), - thinkingLevel: "low", - }, - getApiKey: () => process.env.OPENAI_API_KEY, -}); - -await agent.prompt("Open https://example.com and tell me the heading."); -``` - -## Action reference - -| Action | Source | Notes | -| -------------- | ----------------------- | ---------------------------------------------------------------------------------------------- | -| `click` | official (OpenAI) | `{x, y, button?, hold_keys?}`. [Docs](https://platform.openai.com/docs/guides/tools-computer-use). | -| `double_click` | official (OpenAI) | `{x, y, hold_keys?}`. | -| `scroll` | official (OpenAI) | `{x, y, scroll_x?, scroll_y?, hold_keys?}`. Pixel deltas (~120 per wheel notch). | -| `type` | official (OpenAI) | `{text}`. | -| `wait` | official (OpenAI) | `{ms?}`. Default 1000ms. | -| `keypress` | official (OpenAI) | `{keys: string[]}`. Right-most non-modifier becomes primary; rest are modifiers. | -| `drag` | official (OpenAI) | `{path: {x, y}[]}`. Two or more points. | -| `move` | official (OpenAI) | `{x, y}`. Hover. | -| `screenshot` | official (OpenAI) | Read step. Returns a fresh PNG in tool result. | -| `goto` | cua extension | `{url}`. Compiles to ctrl+l → ctrl+a → type → Enter. | -| `back` | cua extension | Alt+Left. | -| `forward` | cua extension | Alt+Right. | -| `url` | cua extension | Read step. Compiles to ctrl+l → ctrl+c → readClipboard. | - -Citations: OpenAI's official action set is documented at -[platform.openai.com/docs/guides/tools-computer-use](https://platform.openai.com/docs/guides/tools-computer-use) -and the [Responses API reference](https://platform.openai.com/docs/api-reference/responses/object#tools-computer). - -The cua extensions live in `src/cua-extras.ts` — delete that file (and -trim the action-type enum in `src/batch.ts`) to drop them. - -## Wire-format dump - -The `batch_computer_actions` tool spec sent to OpenAI Responses looks -like the following (rendered from `src/batch.ts:BatchSchema`): - -```json -{ - "type": "function", - "name": "batch_computer_actions", - "description": "Execute multiple computer actions in sequence...", - "parameters": { - "type": "object", - "properties": { - "actions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "click", "double_click", "scroll", "type", "wait", - "keypress", "drag", "move", "screenshot", - "goto", "back", "forward", "url" - ] - }, - "x": { "type": "number" }, - "y": { "type": "number" }, - "text": { "type": "string" }, - "url": { "type": "string" }, - "keys": { "type": "array", "items": { "type": "string" } }, - "button": { "type": "string" }, - "hold_keys": { "type": "array", "items": { "type": "string" } }, - "scroll_x": { "type": "number" }, - "scroll_y": { "type": "number" }, - "ms": { "type": "number" }, - "path": { - "type": "array", - "items": { - "type": "object", - "properties": { "x": { "type": "number" }, "y": { "type": "number" } }, - "required": ["x", "y"] - } - } - }, - "required": ["type"], - "additionalProperties": false - } - } - }, - "required": ["actions"] - } -} -``` - -`computer_use_extra` ships an analogous spec with three actions -(`goto` / `back` / `url`) and an optional `url` field. - -## Embed in your own agent loop - -If you don't use `pi-agent-core`, the root package exports raw tool specs -and execution helpers: - -```typescript -import OpenAI from "openai"; -import { - ComputerTranslator, - browserSession, -} from "@onkernel/cua-translator"; -import { - executeOpenAIToolCall, - openaiTools, -} from "@onkernel/cua-openai"; - -const browser = await browserSession.open({ apiKey: process.env.KERNEL_API_KEY! }); -const translator = new ComputerTranslator({ client: browser.client, sessionId: browser.sessionId }); - -const openai = new OpenAI(); -const response = await openai.responses.create({ - model: "gpt-5.5", - tools: openaiTools({ includeNativeComputer: false }) as any, - input: [{ role: "user", content: "Open https://example.com" }], -}); - -for (const item of response.output ?? []) { - if (item.type === "function_call") { - const result = await executeOpenAIToolCall({ - translator, - name: item.name, - arguments: item.arguments, - }); - // feed result.content back as a function_call_output - } -} -``` - -## License - -MIT. diff --git a/packages/cua-openai/package.json b/packages/cua-openai/package.json deleted file mode 100644 index a47c26cf..00000000 --- a/packages/cua-openai/package.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "@onkernel/cua-openai", - "version": "0.1.0", - "description": "Provider-neutral OpenAI computer-use helpers with explicit /pi bindings", - "type": "module", - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "import": "./dist/index.js" - }, - "./pi": { - "types": "./dist/pi/index.d.ts", - "import": "./dist/pi/index.js" - } - }, - "files": [ - "dist", - "README.md" - ], - "scripts": { - "build": "tsc -b", - "clean": "tsc -b --clean" - }, - "dependencies": { - "@onkernel/cua-translator": "0.1.0", - "@sinclair/typebox": "0.34.49", - "openai": "^6.26.0" - }, - "peerDependencies": { - "@mariozechner/pi-agent-core": "0.67.6", - "@mariozechner/pi-ai": "0.67.6" - }, - "peerDependenciesMeta": { - "@mariozechner/pi-agent-core": { - "optional": true - }, - "@mariozechner/pi-ai": { - "optional": true - } - } -} diff --git a/packages/cua-openai/src/batch-tool.ts b/packages/cua-openai/src/batch-tool.ts deleted file mode 100644 index 00ee9edb..00000000 --- a/packages/cua-openai/src/batch-tool.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core"; -import type { ImageContent, TextContent } from "@mariozechner/pi-ai"; -import type { ComputerTranslator } from "@onkernel/cua-translator"; -import { - BatchSchema, - type BatchToolDetails, - executeOpenAIBatch, - OPENAI_BATCH_DESCRIPTION, - OPENAI_BATCH_TOOL_NAME, -} from "./batch"; - -/** - * Build the `batch_computer_actions` AgentTool for OpenAI computer-use models. - * - * The tool's parameter schema is the union of OpenAI's official action set - * ({@link OPENAI_OFFICIAL_ACTION_TYPES}) and the cua extension actions - * ({@link OPENAI_CUA_EXTRA_ACTION_TYPES}). The tool's `execute` hands the - * actions to the shared {@link ComputerTranslator}, which coalesces writes - * into Kernel batch calls and interleaves `url()` / `screenshot()` reads. - */ -export function createBatchTool(translator: ComputerTranslator): AgentTool { - return { - name: OPENAI_BATCH_TOOL_NAME, - label: OPENAI_BATCH_TOOL_NAME, - description: OPENAI_BATCH_DESCRIPTION, - parameters: BatchSchema, - async execute(_toolCallId, params): Promise> { - const result = await executeOpenAIBatch(translator, params); - const content = result.content as (TextContent | ImageContent)[]; - const details = result.details; - if (result.isError) { - const message = details.error ?? details.statusText; - throw Object.assign(new Error(message), { details, content }); - } - return { content, details }; - }, - }; -} diff --git a/packages/cua-openai/src/batch.ts b/packages/cua-openai/src/batch.ts deleted file mode 100644 index 1a81b776..00000000 --- a/packages/cua-openai/src/batch.ts +++ /dev/null @@ -1,202 +0,0 @@ -import type { ComputerTranslator, ComputerUseToolResult, ModelAction } from "@onkernel/cua-translator"; -import { type Static, Type } from "@sinclair/typebox"; -import { OPENAI_CUA_EXTRA_ACTION_TYPES } from "./cua-extras"; -import { OPENAI_OFFICIAL_ACTION_TYPES } from "./official"; - -export const OPENAI_BATCH_TOOL_NAME = "batch_computer_actions"; - -export const OPENAI_BATCH_DESCRIPTION = [ - "Execute multiple computer actions in sequence, including ordered read steps like url() and screenshot() anywhere in the batch.", - "Consecutive write actions are executed together, and each url()/screenshot() step returns output in the same order it was requested.", - "If no explicit read step is included, the tool returns one fresh screenshot after execution.", - "", - "PREFER this over individual computer actions when:", - "- Typing text followed by pressing Enter", - "- Clicking a field and then typing into it", - "- Dragging an item from one location to another using a drag path", - "- Any sequence where you can plan several steps at once, even if you need occasional url() or screenshot() readbacks between them", - "", - "Drag format: when type is drag, include path as an array of at least two points like [{\"x\":120,\"y\":340},{\"x\":520,\"y\":340}] or a longer path for curved movement.", - "If one drag is likely to change the position, order, or layout of other targets, do not batch multiple drags together; perform one drag, inspect the updated screenshot, then plan the next drag.", - "Wait format: when type is wait, you may include ms to control the pause duration.", -].join("\n"); - -const Action = Type.Object( - { - type: Type.String({ - description: "Action type", - enum: [...OPENAI_OFFICIAL_ACTION_TYPES, ...OPENAI_CUA_EXTRA_ACTION_TYPES], - }), - x: Type.Optional(Type.Number()), - y: Type.Optional(Type.Number()), - text: Type.Optional(Type.String()), - url: Type.Optional(Type.String({ description: "URL to navigate to when type is goto" })), - keys: Type.Optional(Type.Array(Type.String())), - button: Type.Optional(Type.String()), - hold_keys: Type.Optional(Type.Array(Type.String())), - scroll_x: Type.Optional(Type.Number()), - scroll_y: Type.Optional(Type.Number()), - ms: Type.Optional(Type.Number({ description: "Optional wait duration in milliseconds when type is wait" })), - path: Type.Optional( - Type.Array( - Type.Object( - { - x: Type.Number(), - y: Type.Number(), - }, - { additionalProperties: false }, - ), - { - description: - "Required when type is drag. Drag path as an ordered array of points with at least two entries.", - }, - ), - ), - }, - { additionalProperties: false }, -); - -export const BatchSchema = Type.Object({ - actions: Type.Array(Action, { description: "Ordered list of actions to execute" }), -}); - -export type BatchToolInput = Static; - -export interface BatchToolDetails { - statusText: string; - actionDescriptions: string[]; - readResults: Array<{ type: "url"; url: string } | { type: "screenshot"; bytes: number } | { type: "cursor_position"; x: number; y: number }>; - error?: string; -} - -export const OPENAI_BATCH_TOOL = { - type: "function", - name: OPENAI_BATCH_TOOL_NAME, - description: OPENAI_BATCH_DESCRIPTION, - parameters: BatchSchema, - strict: false, -} as const; - -const SETTLE_MS_AFTER_BATCH = 300; - -function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -export async function executeOpenAIBatch( - translator: ComputerTranslator, - params: BatchToolInput, -): Promise> { - const actions = (params.actions ?? []) as ModelAction[]; - const actionDescriptions = actions.map(describeShort); - const content: ComputerUseToolResult["content"] = []; - let statusText: string; - let execErr: Error | undefined; - const readResults: BatchToolDetails["readResults"] = []; - - let hasScreenshotInResults = false; - try { - const result = await translator.executeBatch(actions); - for (const r of result.readResults) { - if (r.type === "url") { - readResults.push({ type: "url", url: r.url }); - } else if (r.type === "screenshot") { - readResults.push({ type: "screenshot", bytes: r.pngBytes.length }); - hasScreenshotInResults = true; - } else { - readResults.push({ type: "cursor_position", x: r.x, y: r.y }); - } - } - statusText = "Actions executed successfully."; - content.push({ type: "text", text: statusText }); - for (const r of result.readResults) { - if (r.type === "url") { - content.push({ type: "text", text: `url(): ${r.url}` }); - } else if (r.type === "screenshot") { - content.push({ - type: "image", - data: r.pngBytes.toString("base64"), - mimeType: "image/png", - }); - } else { - content.push({ type: "text", text: `cursor_position(): ${r.x},${r.y}` }); - } - } - } catch (err) { - execErr = err instanceof Error ? err : new Error(String(err)); - statusText = `Actions failed: ${execErr.message}`; - content.push({ type: "text", text: statusText }); - } - - const needFallback = readResults.length === 0 || (execErr && !hasScreenshotInResults); - if (needFallback) { - if (!execErr) await delay(SETTLE_MS_AFTER_BATCH); - try { - const png = await translator.screenshotRaw(); - content.push({ type: "image", data: png.toString("base64"), mimeType: "image/png" }); - readResults.push({ type: "screenshot", bytes: png.length }); - } catch (shotErr) { - content[0] = { - type: "text", - text: `${statusText} Screenshot unavailable: ${(shotErr as Error).message}`, - }; - } - } - - const details: BatchToolDetails = { - statusText, - actionDescriptions, - readResults, - ...(execErr ? { error: execErr.message } : {}), - }; - - return { - content, - details, - ...(execErr ? { isError: true } : {}), - }; -} - -function describeShort(action: ModelAction): string { - const t = typeof action.type === "string" ? action.type : ""; - switch (t) { - case "click": - return `click(${num(action.x)}, ${num(action.y)})`; - case "double_click": - return `double_click(${num(action.x)}, ${num(action.y)})`; - case "type": { - const text = typeof action.text === "string" ? action.text : ""; - const trimmed = text.length > 30 ? `${text.slice(0, 27)}...` : text; - return `type(${JSON.stringify(trimmed)})`; - } - case "keypress": { - const keys = Array.isArray(action.keys) ? (action.keys as string[]) : []; - return `keypress(${JSON.stringify(keys)})`; - } - case "scroll": - return `scroll(${num(action.x)}, ${num(action.y)})`; - case "move": - return `move(${num(action.x)}, ${num(action.y)})`; - case "drag": - return "drag(...)"; - case "wait": - return "wait"; - case "goto": - return `goto(${JSON.stringify(typeof action.url === "string" ? action.url : "")})`; - case "back": - return "back()"; - case "forward": - return "forward()"; - case "url": - return "url()"; - case "screenshot": - return "screenshot()"; - default: - return t || ""; - } -} - -function num(v: unknown): number { - if (typeof v === "number" && Number.isFinite(v)) return Math.trunc(v); - return 0; -} diff --git a/packages/cua-openai/src/cua-extras.ts b/packages/cua-openai/src/cua-extras.ts deleted file mode 100644 index 241c05dd..00000000 --- a/packages/cua-openai/src/cua-extras.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * cua extension actions for the OpenAI batch tool. - * - * These four actions (`goto`, `back`, `forward`, `url`) are NOT part of - * OpenAI's official `computer` tool action set — they are convenience - * verbs we add on top because every browser-automation prompt needs them. - * They compile down to ordinary keyboard chords and (for `url`) a - * clipboard read against the same Kernel `browsers.computer.*` endpoints. - * - * To drop these from a deployment, omit the union members from your - * tool's parameter schema and (optionally) gate them out of the - * translator's `executeBatch` switch. - */ - -import { type Static, Type } from "@sinclair/typebox"; - -export const OPENAI_CUA_EXTRA_ACTION_TYPES = ["goto", "back", "forward", "url"] as const; - -export type OpenAICuaExtraActionType = (typeof OPENAI_CUA_EXTRA_ACTION_TYPES)[number]; - -/** - * Schema for one cua-added action when emitted as part of a - * batch_computer_actions call. Matches the canonical model action shape - * `ComputerTranslator.executeBatch` understands. - */ -export const OpenAICuaExtraActionSchema = Type.Object( - { - type: Type.String({ - description: "cua extension action (not part of OpenAI's official computer-use action set).", - enum: [...OPENAI_CUA_EXTRA_ACTION_TYPES], - }), - url: Type.Optional( - Type.String({ description: "Required when type='goto'. Fully qualified URL to navigate to." }), - ), - }, - { additionalProperties: false }, -); - -export type OpenAICuaExtraAction = Static; diff --git a/packages/cua-openai/src/extra-tool.ts b/packages/cua-openai/src/extra-tool.ts deleted file mode 100644 index 9060e047..00000000 --- a/packages/cua-openai/src/extra-tool.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core"; -import type { ImageContent, TextContent } from "@mariozechner/pi-ai"; -import type { ComputerTranslator } from "@onkernel/cua-translator"; -import { - executeOpenAIExtraAction, - ExtraSchema, - type ExtraToolDetails, - OPENAI_EXTRA_TOOL_DESCRIPTION, - OPENAI_EXTRA_TOOL_NAME, -} from "./extra"; - -/** - * Build the `computer_use_extra` AgentTool. High-level browser navigation - * convenience wrapper for the cua-added actions: `goto`, `back`, and - * `url`. Each call returns a screenshot of the resulting page so the - * model can see what happened. - * - * This tool is NOT part of OpenAI's official `computer` tool surface — it - * is registered alongside `batch_computer_actions` for situations where - * the model just needs one navigation verb without batching. - */ -export function createExtraTool(translator: ComputerTranslator): AgentTool { - return { - name: OPENAI_EXTRA_TOOL_NAME, - label: OPENAI_EXTRA_TOOL_NAME, - description: OPENAI_EXTRA_TOOL_DESCRIPTION, - parameters: ExtraSchema, - async execute(_id, params): Promise> { - const result = await executeOpenAIExtraAction(translator, params); - const content = result.content as (TextContent | ImageContent)[]; - const details = result.details; - if (result.isError) { - const message = details.error ?? details.statusText; - throw Object.assign(new Error(message), { details, content }); - } - return { content, details }; - }, - }; -} diff --git a/packages/cua-openai/src/extra.ts b/packages/cua-openai/src/extra.ts deleted file mode 100644 index 8d9ead4f..00000000 --- a/packages/cua-openai/src/extra.ts +++ /dev/null @@ -1,102 +0,0 @@ -import type { ComputerTranslator, ComputerUseToolResult } from "@onkernel/cua-translator"; -import { type Static, Type } from "@sinclair/typebox"; - -export const OPENAI_EXTRA_TOOL_NAME = "computer_use_extra"; - -export const OPENAI_EXTRA_TOOL_DESCRIPTION = "High-level browser actions for navigation and URL retrieval."; - -export const ExtraSchema = Type.Object( - { - action: Type.Union([Type.Literal("goto"), Type.Literal("back"), Type.Literal("url")], { - description: "Action to perform: goto, back, or url.", - }), - url: Type.Optional( - Type.String({ - description: "Required when action is goto. Fully qualified URL to navigate to.", - }), - ), - }, - { additionalProperties: false }, -); - -export type ExtraToolInput = Static; - -export interface ExtraToolDetails { - action: "goto" | "back" | "url"; - url?: string; - statusText: string; - error?: string; -} - -export const OPENAI_EXTRA_TOOL = { - type: "function", - name: OPENAI_EXTRA_TOOL_NAME, - description: OPENAI_EXTRA_TOOL_DESCRIPTION, - parameters: ExtraSchema, - strict: false, -} as const; - -const SETTLE_MS = 300; - -function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -export async function executeOpenAIExtraAction( - translator: ComputerTranslator, - params: ExtraToolInput, -): Promise> { - const action = params.action; - let statusText = "Action executed successfully."; - let resolvedUrl: string | undefined; - let execErr: Error | undefined; - const content: ComputerUseToolResult["content"] = []; - - try { - if (action === "goto") { - const url = (params.url ?? "").trim(); - if (!url) throw new Error('action="goto" requires a url'); - await translator.executeBatch([{ type: "goto", url }]); - statusText = "goto executed successfully."; - resolvedUrl = url; - } else if (action === "back") { - await translator.executeBatch([{ type: "back" }]); - statusText = "back executed successfully."; - } else if (action === "url") { - const url = await translator.currentUrl(); - statusText = `Current URL: ${url}`; - resolvedUrl = url; - } else { - throw new Error(`unknown computer_use_extra action: ${action satisfies never}`); - } - } catch (err) { - execErr = err instanceof Error ? err : new Error(String(err)); - statusText = `${action} failed: ${execErr.message}`; - } - - content.push({ type: "text", text: statusText }); - - if (!execErr) await delay(SETTLE_MS); - try { - const png = await translator.screenshotRaw(); - content.push({ type: "image", data: png.toString("base64"), mimeType: "image/png" }); - } catch (shotErr) { - content[0] = { - type: "text", - text: `${statusText} Screenshot unavailable: ${(shotErr as Error).message}`, - }; - } - - const details: ExtraToolDetails = { - action, - statusText, - ...(resolvedUrl ? { url: resolvedUrl } : {}), - ...(execErr ? { error: execErr.message } : {}), - }; - - return { - content, - details, - ...(execErr ? { isError: true } : {}), - }; -} diff --git a/packages/cua-openai/src/index.ts b/packages/cua-openai/src/index.ts deleted file mode 100644 index 20d68bd6..00000000 --- a/packages/cua-openai/src/index.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @onkernel/cua-openai - * - * Provider-neutral OpenAI computer-use helpers backed by - * `@onkernel/cua-translator`. The package root exports: - * - * - OpenAI model factory for single-invocation `runComputerUse()` calls - * - plain tool specs / execution helpers for hand-rolled non-pi loops - * - official action enums / schemas and prompt constants - * - * `pi-agent-core` bindings live under `@onkernel/cua-openai/pi`. - */ - -export { - BatchSchema, - executeOpenAIBatch, - OPENAI_BATCH_DESCRIPTION, - OPENAI_BATCH_TOOL, - OPENAI_BATCH_TOOL_NAME, -} from "./batch"; -export type { BatchToolDetails, BatchToolInput } from "./batch"; -export { - executeOpenAIExtraAction, - ExtraSchema, - OPENAI_EXTRA_TOOL, - OPENAI_EXTRA_TOOL_DESCRIPTION, - OPENAI_EXTRA_TOOL_NAME, -} from "./extra"; -export type { ExtraToolDetails, ExtraToolInput } from "./extra"; -export { - OPENAI_OFFICIAL_ACTION_TYPES, - OpenAIOfficialActionSchema, - OpenAIPointSchema, -} from "./official"; -export type { OpenAIOfficialAction, OpenAIOfficialActionType, OpenAIPoint } from "./official"; -export { - OPENAI_CUA_EXTRA_ACTION_TYPES, - OpenAICuaExtraActionSchema, -} from "./cua-extras"; -export type { OpenAICuaExtraAction, OpenAICuaExtraActionType } from "./cua-extras"; -export { - executeOpenAIToolCall, - openai, - openaiTools, -} from "./model"; -export type { - OpenAIModelOptions, - OpenAIModelRunDetails, - OpenAIToolCallResultDetails, - OpenAIToolSpec, -} from "./model"; -export { - OPENAI_BATCH_INSTRUCTIONS, - OPENAI_NATIVE_COMPUTER_INSTRUCTIONS, -} from "./system-prompt"; diff --git a/packages/cua-openai/src/model.ts b/packages/cua-openai/src/model.ts deleted file mode 100644 index 9b1f0758..00000000 --- a/packages/cua-openai/src/model.ts +++ /dev/null @@ -1,327 +0,0 @@ -import type { - ComputerTranslator, - ComputerUseModel, - ComputerUseRunResult, - ComputerUseToolResult, - ModelAction, -} from "@onkernel/cua-translator"; -import OpenAI from "openai"; -import type { - ResponseComputerToolCall, - ResponseComputerToolCallOutputItem, - ResponseFunctionToolCallItem, - ResponseFunctionToolCallOutputItem, - Response, - ResponseInputItem, - ResponseItem, - ResponseOutputMessage, - Tool, -} from "openai/resources/responses/responses"; -import { type BatchToolDetails, type BatchToolInput, executeOpenAIBatch, OPENAI_BATCH_TOOL } from "./batch"; -import { type ExtraToolDetails, type ExtraToolInput, executeOpenAIExtraAction, OPENAI_EXTRA_TOOL } from "./extra"; -import { OPENAI_BATCH_INSTRUCTIONS, OPENAI_NATIVE_COMPUTER_INSTRUCTIONS } from "./system-prompt"; - -const OPENAI_COMPUTER_TOOL = { type: "computer" } as const; -const POST_ACTION_SETTLE_MS = 300; -const DEFAULT_COMPACT_THRESHOLD = 200_000; -const OPENAI_BATCH_ONLY_INSTRUCTIONS = `You also have batch_computer_actions for predictable multi-step sequences. - -Prefer batch_computer_actions when: -- Typing text followed by pressing Enter -- Clicking a field and then typing into it -- Dragging an item from one location to another -- Mixing writes with explicit url() or screenshot() readbacks - -Use explicit url() and screenshot() steps inside batch_computer_actions when you need -intermediate readbacks. If you do not include explicit read steps, the batch -tool still returns one fresh screenshot after execution.`; -const OPENAI_EXTRA_ONLY_INSTRUCTIONS = `You also have computer_use_extra for high-level browser actions: -- action="goto" with url to navigate via keyboard-only browser navigation -- action="back" to go back in history -- action="url" to read the exact current URL`; - -export interface OpenAIModelOptions { - apiKey?: string; - baseUrl?: string; - instructions?: string; - includeBatchTool?: boolean; - includeExtraTool?: boolean; - reasoningEffort?: "low" | "medium" | "high"; - /** Seed a Responses API chain. Use the prior response id returned in run details. */ - previousResponseId?: string; - /** Set false to use stateless input-array chaining. Defaults to true. */ - usePreviousResponseId?: boolean; - /** Server-side compaction threshold in rendered tokens. Set false to disable. Defaults to 200000. */ - compactThreshold?: number | false; - /** Forwarded to OpenAI Responses. Leave undefined to use the API default. */ - store?: boolean; -} - -export interface OpenAIToolCallResultDetails { - toolName: string; - toolDetails?: BatchToolDetails | ExtraToolDetails; -} - -export interface OpenAIModelRunDetails { - responseId?: string; -} - -export type OpenAIToolSpec = typeof OPENAI_COMPUTER_TOOL | typeof OPENAI_BATCH_TOOL | typeof OPENAI_EXTRA_TOOL; - -export function openaiTools(opts: { - includeNativeComputer?: boolean; - includeBatchTool?: boolean; - includeExtraTool?: boolean; -} = {}): OpenAIToolSpec[] { - const tools: OpenAIToolSpec[] = []; - if (opts.includeNativeComputer !== false) tools.push(OPENAI_COMPUTER_TOOL); - if (opts.includeBatchTool !== false) tools.push(OPENAI_BATCH_TOOL); - if (opts.includeExtraTool !== false) tools.push(OPENAI_EXTRA_TOOL); - return tools; -} - -export async function executeOpenAIToolCall(args: { - translator: ComputerTranslator; - name: string; - arguments: unknown; -}): Promise> { - const parsed = parseFunctionArguments(args.arguments); - switch (args.name) { - case OPENAI_BATCH_TOOL.name: - return executeOpenAIBatch(args.translator, parsed as BatchToolInput); - case OPENAI_EXTRA_TOOL.name: - return executeOpenAIExtraAction(args.translator, parsed as ExtraToolInput); - default: - throw new Error(`unknown OpenAI tool call "${args.name}"`); - } -} - -export function openai(modelId: string, opts: OpenAIModelOptions = {}): ComputerUseModel { - return { - provider: "openai", - modelId, - async run({ prompt, translator, maxTurns = 50 }): Promise> { - const apiKey = opts.apiKey || process.env.OPENAI_API_KEY; - if (!apiKey) { - throw new Error("missing OpenAI API key"); - } - const client = new OpenAI({ - apiKey, - ...(opts.baseUrl ? { baseURL: opts.baseUrl } : {}), - }); - - const instructions = composeInstructions(opts); - const initialInput: ResponseInputItem[] = [ - { - role: "user", - content: [makeTextInput(prompt)], - } as unknown as ResponseInputItem, - ]; - const statelessInput = initialInput; - const followUps: ResponseItem[] = []; - const usePreviousResponseId = opts.usePreviousResponseId !== false; - let previousResponseId = opts.previousResponseId; - let nextInput = initialInput; - - for (let turn = 0; turn < maxTurns; turn++) { - const request = { - model: modelId, - instructions, - input: usePreviousResponseId ? nextInput : ([...statelessInput, ...followUps] as ResponseInputItem[]), - tools: openaiTools({ - includeNativeComputer: true, - includeBatchTool: opts.includeBatchTool !== false, - includeExtraTool: opts.includeExtraTool !== false, - }) as unknown as Tool[], - parallel_tool_calls: false, - truncation: "auto", - reasoning: { - effort: opts.reasoningEffort ?? "low", - summary: "concise", - }, - ...(usePreviousResponseId && previousResponseId ? { previous_response_id: previousResponseId } : {}), - ...(opts.store !== undefined ? { store: opts.store } : {}), - ...contextManagementOption(opts.compactThreshold), - }; - - const response = (await client.responses.create( - request as Parameters[0], - )) as Response; - if (response.id) previousResponseId = response.id; - nextInput = []; - - const output = response.output ?? []; - let sawToolCall = false; - - for (const item of output) { - if (!usePreviousResponseId) followUps.push(item as ResponseItem); - if (item.type === "computer_call") { - sawToolCall = true; - const toolOutputs = await handleComputerCall(translator, item as ResponseComputerToolCall); - if (usePreviousResponseId) { - nextInput.push(...(toolOutputs as unknown as ResponseInputItem[])); - } else { - followUps.push(...toolOutputs); - } - continue; - } - if (item.type === "function_call") { - sawToolCall = true; - const toolOutput = await handleFunctionCall(translator, item as ResponseFunctionToolCallItem); - if (usePreviousResponseId) { - nextInput.push(toolOutput as unknown as ResponseInputItem); - } else { - followUps.push(toolOutput); - } - } - } - - if (!sawToolCall) { - return { - text: response.output_text || extractTextFromOutput(output), - provider: "openai", - modelId, - turns: turn + 1, - details: response.id ? { responseId: response.id } : undefined, - }; - } - } - - return { - text: "(max turns reached)", - provider: "openai", - modelId, - turns: maxTurns, - }; - }, - }; -} - -function contextManagementOption(compactThreshold: OpenAIModelOptions["compactThreshold"]): Record { - if (compactThreshold === false) return {}; - return { - context_management: [ - { - type: "compaction", - compact_threshold: compactThreshold ?? DEFAULT_COMPACT_THRESHOLD, - }, - ], - }; -} - -function composeInstructions(opts: OpenAIModelOptions): string { - const sections = [OPENAI_NATIVE_COMPUTER_INSTRUCTIONS]; - const includeBatch = opts.includeBatchTool !== false; - const includeExtra = opts.includeExtraTool !== false; - if (includeBatch && includeExtra) { - sections.push(OPENAI_BATCH_INSTRUCTIONS); - } else { - if (includeBatch) sections.push(OPENAI_BATCH_ONLY_INSTRUCTIONS); - if (includeExtra) sections.push(OPENAI_EXTRA_ONLY_INSTRUCTIONS); - } - const trimmed = (opts.instructions ?? "").trim(); - if (trimmed) sections.push(trimmed); - return sections.join("\n\n"); -} - -function makeTextInput(text: string): { type: "input_text"; text: string } { - return { type: "input_text", text }; -} - -function parseFunctionArguments(value: unknown): Record { - if (typeof value === "string" && value.trim()) { - return JSON.parse(value) as Record; - } - if (value && typeof value === "object") { - return value as Record; - } - return {}; -} - -async function handleFunctionCall( - translator: ComputerTranslator, - item: ResponseFunctionToolCallItem, -): Promise { - const result = await executeOpenAIToolCall({ - translator, - name: item.name, - arguments: item.arguments, - }); - return { - type: "function_call_output", - call_id: item.call_id, - output: toOpenAIInputParts(result), - } as unknown as ResponseFunctionToolCallOutputItem; -} - -async function handleComputerCall( - translator: ComputerTranslator, - item: ResponseComputerToolCall, -): Promise { - const call = item as ResponseComputerToolCall & { - action?: Record; - actions?: Array>; - pending_safety_checks?: unknown[]; - }; - const actions = Array.isArray(call.actions) ? call.actions : call.action ? [call.action] : []; - if (actions.length > 0) { - await translator.executeBatch(actions as ModelAction[]); - } - await delay(POST_ACTION_SETTLE_MS); - const screenshot = await translator.screenshotBase64(); - return [ - { - type: "computer_call_output", - call_id: call.call_id, - acknowledged_safety_checks: Array.isArray(call.pending_safety_checks) ? call.pending_safety_checks : [], - output: { - type: "computer_screenshot", - image_url: `data:image/png;base64,${screenshot}`, - }, - } as unknown as ResponseComputerToolCallOutputItem, - ]; -} - -function toOpenAIInputParts(result: ComputerUseToolResult): Array> { - return result.content.map((part) => - part.type === "text" - ? { - type: "input_text", - text: part.text, - } - : { - type: "input_image", - image_url: `data:${part.mimeType};base64,${part.data}`, - detail: "original", - }, - ); -} - -function extractTextFromOutput( - output: ReadonlyArray< - | ResponseItem - | { - type?: string; - role?: string; - content?: unknown[]; - } - | undefined - >, -): string { - const pieces: string[] = []; - for (const item of output) { - if (!item || item.type !== "message") continue; - const message = item as ResponseOutputMessage; - if (message.role !== "assistant") continue; - for (const block of message.content ?? []) { - if (block && typeof block === "object" && "text" in block && typeof block.text === "string") { - pieces.push(block.text); - } - } - } - return pieces.join("\n").trim(); -} - -function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} diff --git a/packages/cua-openai/src/official.ts b/packages/cua-openai/src/official.ts deleted file mode 100644 index 6066508a..00000000 --- a/packages/cua-openai/src/official.ts +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Official OpenAI computer-use action set. - * - * Source of truth: OpenAI's "Computer Use" docs. - * https://platform.openai.com/docs/guides/tools-computer-use - * https://platform.openai.com/docs/api-reference/responses/object#tools-computer - * - * The root `openai()` helper registers the Responses-API-native - * `{type:"computer"}` tool and handles `computer_call` output directly. - * The `/pi` binding still exposes the same action vocabulary as custom - * function tools (`batch_computer_actions` / `computer_use_extra`) because - * pi-ai's stock OpenAI Responses parser does not surface native - * `computer_call` items via SSE. - * - * The nine actions OpenAI documents are: - * click, double_click, scroll, type, wait, keypress, drag, move, screenshot - * Each click/scroll-style action also accepts an optional `keys` modifier - * array (modifier keys held during the action — e.g. shift for range - * select). - */ - -import { type Static, Type } from "@sinclair/typebox"; - -/** - * The action `type` enum field on every OpenAI computer action. All nine - * actions are documented at the URLs above. - */ -export const OPENAI_OFFICIAL_ACTION_TYPES = [ - "click", - "double_click", - "scroll", - "type", - "wait", - "keypress", - "drag", - "move", - "screenshot", -] as const; - -export type OpenAIOfficialActionType = (typeof OPENAI_OFFICIAL_ACTION_TYPES)[number]; - -/** Modifier keys held during click/scroll/etc. Optional. */ -export const OpenAIHoldKeysSchema = Type.Optional( - Type.Array(Type.String(), { - description: "Modifier keys to hold during this action (e.g. ['shift'] for range select).", - }), -); - -/** Single point shape used by drag paths. */ -export const OpenAIPointSchema = Type.Object( - { x: Type.Number(), y: Type.Number() }, - { additionalProperties: false }, -); -export type OpenAIPoint = Static; - -/** - * Schema for ONE official OpenAI computer action. Used as one - * member of the `batch_computer_actions.actions[]` array in our custom - * function tool. The fields are a superset of all per-action fields the - * native `computer` tool defines, gated by the `type` discriminator at - * runtime. - */ -export const OpenAIOfficialActionSchema = Type.Object( - { - type: Type.String({ - description: "Official OpenAI computer-use action.", - enum: [...OPENAI_OFFICIAL_ACTION_TYPES], - }), - x: Type.Optional(Type.Number({ description: "Pixel x for click/double_click/scroll/move." })), - y: Type.Optional(Type.Number({ description: "Pixel y for click/double_click/scroll/move." })), - button: Type.Optional( - Type.String({ - description: "Mouse button for click. Defaults to 'left'.", - enum: ["left", "right", "middle", "back", "forward"], - }), - ), - text: Type.Optional(Type.String({ description: "Text to type when type='type'." })), - keys: Type.Optional( - Type.Array(Type.String(), { - description: - "Keys to press for type='keypress'. The right-most non-modifier becomes the primary key, the rest are modifiers.", - }), - ), - hold_keys: OpenAIHoldKeysSchema, - scroll_x: Type.Optional(Type.Number({ description: "Horizontal scroll delta in pixels (~120 per wheel tick)." })), - scroll_y: Type.Optional(Type.Number({ description: "Vertical scroll delta in pixels (~120 per wheel tick)." })), - ms: Type.Optional(Type.Number({ description: "Wait duration in milliseconds when type='wait'." })), - path: Type.Optional( - Type.Array(OpenAIPointSchema, { - description: "Required when type='drag'. Two or more points defining the drag path.", - }), - ), - }, - { additionalProperties: false }, -); - -export type OpenAIOfficialAction = Static; diff --git a/packages/cua-openai/src/pi/index.ts b/packages/cua-openai/src/pi/index.ts deleted file mode 100644 index e76c011b..00000000 --- a/packages/cua-openai/src/pi/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { AgentTool } from "@mariozechner/pi-agent-core"; -import type { ComputerTranslator } from "@onkernel/cua-translator"; -import { createBatchTool } from "../batch-tool"; -import { createExtraTool } from "../extra-tool"; - -export interface OpenAIComputerToolsOptions { - /** Set false to omit `batch_computer_actions`. Defaults to true. */ - includeBatch?: boolean; - /** Set false to omit `computer_use_extra`. Defaults to true. */ - includeExtra?: boolean; -} - -/** - * Build the OpenAI computer-use tool set for `pi-agent-core`. - * Pair with `OPENAI_BATCH_INSTRUCTIONS` from the root package. - */ -export function createOpenAIComputerTools( - translator: ComputerTranslator, - opts: OpenAIComputerToolsOptions = {}, -): AgentTool[] { - const tools: AgentTool[] = []; - if (opts.includeBatch !== false) tools.push(createBatchTool(translator)); - if (opts.includeExtra !== false) tools.push(createExtraTool(translator)); - return tools; -} - -export { createBatchTool } from "../batch-tool"; -export type { BatchToolDetails, BatchToolInput } from "../batch"; -export { createExtraTool } from "../extra-tool"; -export type { ExtraToolDetails, ExtraToolInput } from "../extra"; diff --git a/packages/cua-openai/src/system-prompt.ts b/packages/cua-openai/src/system-prompt.ts deleted file mode 100644 index 50f62b7a..00000000 --- a/packages/cua-openai/src/system-prompt.ts +++ /dev/null @@ -1,59 +0,0 @@ -/** - * OpenAI computer-use system-prompt preamble for the batch_computer_actions / - * computer_use_extra tool surface. - * - * Why a preamble at all? The root `openai()` helper registers OpenAI's - * native `computer` tool and can optionally register our custom function - * tools too. The preamble teaches the model when to use those helper tools, - * when to prefer batched actions, and how to read intermediate state via - * `url()` and `screenshot()` reads embedded in a batch. - */ - -export const OPENAI_BATCH_INSTRUCTIONS = `You have two ways to perform actions: -1. batch_computer_actions — the primary tool for browser interaction. Use it for click, double_click, type, keypress, scroll, move, drag, wait, goto, back, url, and screenshot whenever possible. -2. computer_use_extra — convenience wrapper for 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 -- Typing a URL and pressing Enter -- Dragging an item from one location to another using a drag path -- Any sequence where you want to mix writes with explicit url() or screenshot() readbacks - -Drag planning rules: -- If one drag is likely to change the position, order, or layout of other targets, do not batch multiple drags together. -- In those cases, perform one drag at a time and inspect the updated screenshot before planning the next drag. - -Use explicit url() and screenshot() steps inside batch_computer_actions whenever you need -intermediate readbacks. If you do not include explicit read steps, the batch -tool still returns one fresh screenshot after execution. -Do not request screenshot-only batches repeatedly. Use screenshot() exactly -where you need an updated view, especially after waiting or another -asynchronous UI change. - -When navigating long pages or lists, STRONGLY prefer keyboard navigation with -Page_Down, Page_Up, Home, and End before using mouse-wheel scrolling. For -small adjustments, prefer Up and Down arrow keys before using mouse-wheel -scrolling. Use mouse-wheel scrolling only when keyboard navigation does not -affect the specific container you need to move. - -Use computer_use_extra for: -- action="goto" with url to navigate via keyboard-only browser navigation -- action="back" to go back in history -- action="url" to read the exact current URL`; - -export const OPENAI_NATIVE_COMPUTER_INSTRUCTIONS = `You control a cloud browser through OpenAI's built-in computer tool. - -Use the computer tool to inspect the current page, click targets, type text, -press keys, scroll, and navigate. - -When interacting with inputs and forms: -- Click to focus before typing. -- Use keyboard navigation for predictable address-bar navigation. - -When navigating long pages or lists, STRONGLY prefer keyboard navigation with -Page_Down, Page_Up, Home, and End before using mouse-wheel scrolling. For -small adjustments, prefer Up and Down arrow keys before using mouse-wheel -scrolling. Use mouse-wheel scrolling only when keyboard navigation does not -affect the specific container you need to move. - -Verify results after actions that may change the page state.`; diff --git a/packages/cua-openai/tsconfig.json b/packages/cua-openai/tsconfig.json deleted file mode 100644 index c2e66df0..00000000 --- a/packages/cua-openai/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./dist", - "rootDir": "./src" - }, - "include": ["src/**/*"], - "references": [{ "path": "../cua-translator" }] -} diff --git a/packages/cua-translator/README.md b/packages/cua-translator/README.md deleted file mode 100644 index 9562606d..00000000 --- a/packages/cua-translator/README.md +++ /dev/null @@ -1,117 +0,0 @@ -# `@onkernel/cua-translator` - -The provider-agnostic core of the [`cua`](../../README.md) monorepo. -Translates a canonical "model action" vocabulary into -[`@onkernel/sdk`](https://www.npmjs.com/package/@onkernel/sdk) -`browsers.computer.*` calls, with read coalescing for `url()` and -`screenshot()` steps. - -The provider adapter packages -([`@onkernel/cua-openai`](../cua-openai), -[`@onkernel/cua-anthropic`](../cua-anthropic), -[`@onkernel/cua-gemini`](../cua-gemini)) all normalize their model's -own action shape to the `ModelAction` shape this package defines, then -hand it to `ComputerTranslator.executeBatch`. - -## Install - -```bash -npm install @onkernel/cua-translator @onkernel/sdk -``` - -## Quick start - -```typescript -import Kernel from "@onkernel/sdk"; -import { browserSession, ComputerTranslator } from "@onkernel/cua-translator"; - -const browser = await browserSession.open({ - apiKey: process.env.KERNEL_API_KEY!, - timeoutSeconds: 300, -}); - -const translator = new ComputerTranslator({ - client: browser.client, - sessionId: browser.sessionId, -}); - -await translator.executeBatch([ - { type: "goto", url: "https://news.ycombinator.com" }, - { type: "screenshot" }, -]); - -await browser.close(); -``` - -## Action vocabulary - -`ComputerTranslator.executeBatch(actions: ModelAction[])` accepts the -following action shapes. The provider-official vs cua-added split is -documented in each provider package's README; this package covers the -union. - -| `type` | Source | Fields | Notes | -| -------------- | -------------- | --------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | -| `click` | provider | `x`, `y`, `button?`, `hold_keys?` | Pixel coordinates. | -| `double_click` | provider | `x`, `y`, `hold_keys?` | | -| `move` | provider | `x`, `y` | Hover. | -| `scroll` | provider | `x`, `y`, `scroll_x?`, `scroll_y?`, `hold_keys?` | `scroll_x` / `scroll_y` are pixel deltas; ~120 per wheel notch. | -| `type` | provider | `text` | Types into the focused element. | -| `keypress` | provider | `keys: string[]` | Right-most non-modifier becomes the primary key; the rest are held as modifiers. | -| `drag` | provider | `path: {x, y}[]` | Two or more points. Validated. | -| `wait` | provider | `ms?` | Default 1000ms. | -| `screenshot` | provider | — | Read step. Flushes pending writes, then captures and returns PNG bytes via `BatchReadResult`. | -| `goto` | cua extension | `url` | Compiles to ctrl+l → ctrl+a → type → Enter. | -| `back` | cua extension | — | Alt+Left. | -| `forward` | cua extension | — | Alt+Right. | -| `url` | cua extension | — | Read step. Compiles to ctrl+l → ctrl+c → readClipboard. | - -To drop the cua extensions, restrict the input to actions you accept -before calling `executeBatch` (the translator throws -`ActionValidationError` for unknown action types). - -## Key sub-modules - -- `types.ts` — `ModelAction`, `BatchAction*`, `BatchExecutionResult`, - `ActionValidationError`, `ALLOWED_MODEL_ACTION_TYPES`. -- `keysym.ts` — `KEYSYM_MAP`, `PRINTABLE_KEYSYM_MAP`, `translateKeys`, - `splitKeypress`, `isModifierKey`, `MODIFIER_KEYS`. -- `scroll.ts` — `modelScrollDeltaToWheelTicks` (pixels → ticks), - `wheelTicksFromAmount` (notch count → ticks). -- `cua-extras.ts` — `gotoBatchActions`, `backBatchActions`, - `forwardBatchActions`, `currentUrlCopyActions`, plus - `gotoModelAction` / `backModelAction` / etc. constructors. -- `translator.ts` — `ComputerTranslator`, `translateToBatchAction`, - `toSdkAction`, `describeBatch`, `describeSingleAction`. -- `browser-session.ts` — `open(opts)`: provision a Kernel cloud - browser session, optional profile lookup/create-if-missing. - -## Embed in your own agent loop - -The `ComputerTranslator` doesn't depend on -[`pi-agent-core`](https://www.npmjs.com/package/@earendil-works/pi-agent-core) -or any LLM. Use it directly in any agent runtime: - -```typescript -const translator = new ComputerTranslator({ client, sessionId }); - -while (true) { - const llmResponse = await yourLLMCall({ /* ... */ }); - if (!llmResponse.toolCalls?.length) break; - for (const call of llmResponse.toolCalls) { - if (call.name === "computer") { - const actions = adaptYourActionShape(call.args); - const result = await translator.executeBatch(actions); - // forward `result.readResults` back into your conversation - } - } -} -``` - -The provider adapter packages (`@onkernel/cua-{openai,anthropic,gemini}`) -ship full pi-agent-core `AgentTool` implementations that wrap exactly -this pattern. - -## License - -MIT. diff --git a/packages/cua-translator/package.json b/packages/cua-translator/package.json deleted file mode 100644 index dccfe72a..00000000 --- a/packages/cua-translator/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "@onkernel/cua-translator", - "version": "0.1.0", - "description": "Provider-agnostic translator from canonical computer-use actions to @onkernel/sdk browsers.computer.* calls", - "type": "module", - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "import": "./dist/index.js" - } - }, - "files": [ - "dist", - "README.md" - ], - "scripts": { - "build": "tsc -b", - "clean": "tsc -b --clean" - }, - "dependencies": { - "@onkernel/sdk": "0.49.0" - } -} diff --git a/packages/cua-translator/src/browser-session.ts b/packages/cua-translator/src/browser-session.ts deleted file mode 100644 index be309e51..00000000 --- a/packages/cua-translator/src/browser-session.ts +++ /dev/null @@ -1,123 +0,0 @@ -import Kernel, { NotFoundError } from "@onkernel/sdk"; - -export interface BrowserSessionOptions { - apiKey: string; - baseUrl?: string; - timeoutSeconds?: number; - /** Profile id or name. If a name is supplied that doesn't exist, it is created. */ - profileSelector?: string; - /** Explicit profile id (skips lookup). */ - profileId?: string; - /** Whether to save changes back to the profile when the session ends. */ - saveChanges?: boolean; -} - -export interface BrowserSession { - readonly client: Kernel; - readonly sessionId: string; - readonly liveUrl?: string; - readonly profileId?: string; - close(): Promise; -} - -const CUID2_LENGTH = 24; -const CUID2_PATTERN = /^[a-z][a-z0-9]{23}$/; - -function looksLikeProfileId(selector: string): boolean { - const trimmed = selector.trim(); - return trimmed.length === CUID2_LENGTH && CUID2_PATTERN.test(trimmed); -} - -async function resolveProfileId(client: Kernel, selector: string): Promise { - const trimmed = selector.trim(); - if (!trimmed) throw new Error("profile selector is empty"); - - try { - const existing = await client.profiles.retrieve(trimmed); - return existing.id; - } catch (err) { - if (!(err instanceof NotFoundError)) { - throw new Error(`looking up browser profile "${trimmed}": ${(err as Error).message}`, { cause: err }); - } - if (looksLikeProfileId(trimmed)) { - throw new Error(`browser profile "${trimmed}" was not found`); - } - const created = await client.profiles.create({ name: trimmed }); - return created.id; - } -} - -/** Provision a fresh Kernel cloud browser session and return a handle. */ -export async function open(opts: BrowserSessionOptions): Promise { - const client = new Kernel({ - apiKey: opts.apiKey, - ...(opts.baseUrl ? { baseURL: opts.baseUrl } : {}), - }); - - const timeoutSeconds = opts.timeoutSeconds && opts.timeoutSeconds > 0 ? opts.timeoutSeconds : 300; - - let profileId = (opts.profileId ?? "").trim(); - if (!profileId && opts.profileSelector && opts.profileSelector.trim()) { - profileId = await resolveProfileId(client, opts.profileSelector); - } - - const params: Parameters[0] = { - stealth: true, - timeout_seconds: timeoutSeconds, - }; - if (profileId) { - params.profile = { - id: profileId, - save_changes: opts.saveChanges ?? false, - }; - } - - const browser = await client.browsers.create(params); - - return { - client, - sessionId: browser.session_id, - liveUrl: browser.browser_live_view_url, - profileId: profileId || undefined, - async close(): Promise { - await client.browsers.deleteByID(browser.session_id); - }, - }; -} - -export interface AttachBrowserSessionOptions { - apiKey: string; - baseUrl?: string; - /** Existing Kernel browser session id to attach to. */ - sessionId: string; - /** Optional cached live-view URL from when the session was first created. */ - liveUrl?: string; - /** Optional profile id the session was started with. */ - profileId?: string; -} - -/** - * Attach to an existing Kernel cloud browser session by id, without - * calling `client.browsers.create`. The returned handle's `close()` is a - * NO-OP — use `client.browsers.deleteByID(sessionId)` directly when you - * actually want to tear the session down. - * - * Liveness is the caller's responsibility: a freshly-attached handle may - * still talk to a session that has timed out server-side. Run - * `client.browsers.retrieve(sessionId)` first to check. - */ -export function attach(opts: AttachBrowserSessionOptions): BrowserSession { - const client = new Kernel({ - apiKey: opts.apiKey, - ...(opts.baseUrl ? { baseURL: opts.baseUrl } : {}), - }); - return { - client, - sessionId: opts.sessionId, - liveUrl: opts.liveUrl, - profileId: opts.profileId, - async close(): Promise { - // no-op: attached sessions are not torn down on handle close. - }, - }; -} diff --git a/packages/cua-translator/src/computer-use.ts b/packages/cua-translator/src/computer-use.ts deleted file mode 100644 index 763d623a..00000000 --- a/packages/cua-translator/src/computer-use.ts +++ /dev/null @@ -1,80 +0,0 @@ -import type { BrowserSession } from "./browser-session"; -import { ComputerTranslator, type ComputerLogger } from "./translator"; - -export interface ComputerUseTextPart { - type: "text"; - text: string; -} - -export interface ComputerUseImagePart { - type: "image"; - data: string; - mimeType: string; -} - -export type ComputerUseContentPart = ComputerUseTextPart | ComputerUseImagePart; - -export interface ComputerUseToolResult { - content: ComputerUseContentPart[]; - details: TDetails; - isError?: boolean; -} - -export interface ComputerUseRunResult { - text: string; - provider: string; - modelId: string; - details?: TDetails; - turns?: number; -} - -export interface ComputerUseModel { - readonly provider: string; - readonly modelId: string; - run(args: { - prompt: string; - translator: ComputerTranslator; - maxTurns?: number; - signal?: AbortSignal; - }): Promise>; -} - -export interface RunComputerUseOptions { - model: ComputerUseModel; - prompt: string; - maxTurns?: number; - signal?: AbortSignal; - translator?: ComputerTranslator; - browser?: Pick; - logger?: ComputerLogger; -} - -/** - * Single-invocation helper similar in spirit to AI SDK's `generateText()`. - * - * It does NOT manage a long-lived agent/session runtime. It only wires a - * provider-specific ComputerUseModel to a Kernel browser session (or an - * existing ComputerTranslator) for one prompt invocation. - */ -export async function runComputerUse( - opts: RunComputerUseOptions, -): Promise> { - const translator = - opts.translator ?? - (opts.browser - ? new ComputerTranslator({ - client: opts.browser.client, - sessionId: opts.browser.sessionId, - logger: opts.logger, - }) - : undefined); - if (!translator) { - throw new Error("runComputerUse requires either `translator` or `browser`"); - } - return opts.model.run({ - prompt: opts.prompt, - translator, - maxTurns: opts.maxTurns, - signal: opts.signal, - }); -} diff --git a/packages/cua-translator/src/cua-extras.ts b/packages/cua-translator/src/cua-extras.ts deleted file mode 100644 index 4b574b78..00000000 --- a/packages/cua-translator/src/cua-extras.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * cua-added action helpers. - * - * These actions are NOT part of any provider's official computer-use action - * set. We add them because they're useful enough that every provider - * adapter wants them — `goto`, `back`, `forward`, `url` (read current page - * URL) — and because they compile down to keyboard chords plus optional - * clipboard read against the same Kernel `browsers.computer.*` endpoints. - * - * Two flavors: - * - `BatchActions()` returns canonical `BatchAction[]` ready to send - * to the Kernel batch endpoint. Use these in provider code that wants - * fine-grained control over which actions get batched. - * - `ModelAction()` returns a `ModelAction` you can drop into the - * list passed to `ComputerTranslator.executeBatch`. Use these when - * talking to the high-level translator API. - */ - -import { translateKeys } from "./keysym"; -import type { BatchAction, ModelAction } from "./types"; - -// ─── BatchAction-level builders ──────────────────────────────────────────── - -/** Address-bar focus → select-all → type URL → Enter. */ -export function gotoBatchActions(url: string): BatchAction[] { - return [ - { type: "press_key", pressKey: { holdKeys: translateKeys(["CTRL"]), keys: translateKeys(["l"]) } }, - { type: "press_key", pressKey: { holdKeys: translateKeys(["CTRL"]), keys: translateKeys(["a"]) } }, - { type: "type_text", typeText: { text: url } }, - { type: "press_key", pressKey: { keys: translateKeys(["ENTER"]) } }, - ]; -} - -/** Browser back: Alt+Left. */ -export function backBatchActions(): BatchAction[] { - return [{ type: "press_key", pressKey: { holdKeys: translateKeys(["ALT"]), keys: translateKeys(["LEFT"]) } }]; -} - -/** Browser forward: Alt+Right. */ -export function forwardBatchActions(): BatchAction[] { - return [ - { type: "press_key", pressKey: { holdKeys: translateKeys(["ALT"]), keys: translateKeys(["RIGHT"]) } }, - ]; -} - -/** - * Address-bar focus → Ctrl+C. Pair with `client.browsers.computer.readClipboard` - * to capture the current URL (the `ComputerTranslator.currentUrl()` helper does - * this for you). - */ -export function currentUrlCopyActions(): BatchAction[] { - return [ - { type: "press_key", pressKey: { holdKeys: translateKeys(["CTRL"]), keys: translateKeys(["l"]) } }, - { type: "press_key", pressKey: { holdKeys: translateKeys(["CTRL"]), keys: translateKeys(["c"]) } }, - ]; -} - -// ─── ModelAction-level constructors ──────────────────────────────────────── - -export function gotoModelAction(url: string): ModelAction { - return { type: "goto", url }; -} - -export function backModelAction(): ModelAction { - return { type: "back" }; -} - -export function forwardModelAction(): ModelAction { - return { type: "forward" }; -} - -export function urlModelAction(): ModelAction { - return { type: "url" }; -} - -export function screenshotModelAction(): ModelAction { - return { type: "screenshot" }; -} diff --git a/packages/cua-translator/src/index.ts b/packages/cua-translator/src/index.ts deleted file mode 100644 index b8b7ebef..00000000 --- a/packages/cua-translator/src/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -export * from "./types"; -export * from "./keysym"; -export * from "./scroll"; -export * from "./cua-extras"; -export * from "./translator"; -export * from "./computer-use"; -export * as browserSession from "./browser-session"; -export type { - AttachBrowserSessionOptions, - BrowserSession, - BrowserSessionOptions, -} from "./browser-session"; diff --git a/packages/cua-translator/src/keysym.ts b/packages/cua-translator/src/keysym.ts deleted file mode 100644 index f066981b..00000000 --- a/packages/cua-translator/src/keysym.ts +++ /dev/null @@ -1,169 +0,0 @@ -/** - * X11 keysym mapping shared by all provider adapters. - * - * Models emit human-friendly key names like `ENTER`, `Ctrl`, `META`, `cmd`, - * `PageUp`, etc. The Kernel computer API expects xdotool keysyms (`Return`, - * `Control_L`, `Super_L`, `Prior`, ...). This module is the single source of - * truth for that mapping. - */ - -export 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", -}; - -export const PRINTABLE_KEYSYM_MAP: Record = { - "!": "exclam", - '"': "quotedbl", - "#": "numbersign", - $: "dollar", - "%": "percent", - "&": "ampersand", - "'": "apostrophe", - "(": "parenleft", - ")": "parenright", - "*": "asterisk", - "+": "plus", - ",": "comma", - "-": "minus", - ".": "period", - "/": "slash", - ":": "colon", - ";": "semicolon", - "<": "less", - "=": "equal", - ">": "greater", - "?": "question", - "@": "at", - "[": "bracketleft", - "\\": "backslash", - "]": "bracketright", - "^": "asciicircum", - _: "underscore", - "`": "grave", - "{": "braceleft", - "|": "bar", - "}": "braceright", - "~": "asciitilde", -}; - -/** Translate human key names to xdotool keysyms. Pass-through if unknown. */ -export function translateKeys(keys: string[]): string[] { - return keys.map((k) => { - if (KEYSYM_MAP[k]) return KEYSYM_MAP[k]; - const upper = k.toUpperCase(); - if (KEYSYM_MAP[upper]) return KEYSYM_MAP[upper]; - if (PRINTABLE_KEYSYM_MAP[k]) return PRINTABLE_KEYSYM_MAP[k]; - // Single uppercase letters implicitly trigger Shift in xdotool. - // Use lowercase unless Shift is explicitly held. - if (k.length === 1 && k >= "A" && k <= "Z") return k.toLowerCase(); - return k; - }); -} - -export const MODIFIER_KEYS: ReadonlySet = new Set([ - "Control_L", - "Control_R", - "Ctrl", - "Alt_L", - "Alt_R", - "Alt", - "Shift_L", - "Shift_R", - "Shift", - "Super_L", - "Super_R", - "Meta", -]); - -export function isModifierKey(key: string): boolean { - return MODIFIER_KEYS.has(key); -} - -/** - * Take a flat array of keys and split it into (modifiers held during, primary - * tapped) for the Kernel `pressKey` API. The "primary" key is the - * right-most non-modifier; everything else becomes a hold key. - */ -export function splitKeypress(keys: string[]): { holdKeys: string[]; primaryKeys: string[] } { - const translated = translateKeys(keys); - if (translated.length === 0) return { holdKeys: [], primaryKeys: [] }; - if (translated.length === 1) return { holdKeys: [], primaryKeys: translated }; - - let lastNonModifier = -1; - for (let i = translated.length - 1; i >= 0; i--) { - if (!isModifierKey(translated[i]!)) { - lastNonModifier = i; - break; - } - } - - if (lastNonModifier === -1) { - return { - holdKeys: translated.slice(0, -1), - primaryKeys: translated.slice(-1), - }; - } - - const hold: string[] = []; - for (let i = 0; i < translated.length; i++) { - if (i !== lastNonModifier) hold.push(translated[i]!); - } - return { holdKeys: hold, primaryKeys: [translated[lastNonModifier]!] }; -} diff --git a/packages/cua-translator/src/scroll.ts b/packages/cua-translator/src/scroll.ts deleted file mode 100644 index a15e1643..00000000 --- a/packages/cua-translator/src/scroll.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Scroll-delta math. - * - * Models that emit pixel-style scroll deltas (OpenAI computer-use, where one - * mouse wheel "tick" is conventionally 120 pixels) call - * {@link modelScrollDeltaToWheelTicks} to convert their pixel value into - * the wheel-notch count Kernel's `browsers.computer.scroll` API wants. - * - * Models that emit a scroll-amount (Anthropic, Gemini) can call - * {@link wheelTicksFromAmount} to feed the same end-point in canonical - * units. Direction is the caller's responsibility; this helper only sizes. - */ - -const PIXELS_PER_TICK = 120; - -/** - * Convert a model-emitted pixel delta into wheel-notch count for the Kernel - * scroll endpoint. Sign is preserved. A non-zero magnitude always rounds to - * at least 1 tick so a small pixel value still scrolls. - */ -export function modelScrollDeltaToWheelTicks(delta: number): number { - if (!Number.isFinite(delta) || delta === 0) return 0; - const sign = delta < 0 ? -1 : 1; - const magnitude = Math.abs(delta); - const ticks = Math.max(1, Math.round(magnitude / PIXELS_PER_TICK)); - return sign * ticks; -} - -/** - * Convert a click/notch count (positive integer) into Kernel wheel-notch - * count. Useful for providers (Anthropic, Gemini) whose scroll actions - * specify N "clicks" rather than pixels. - */ -export function wheelTicksFromAmount(amount: number): number { - if (!Number.isFinite(amount) || amount <= 0) return 0; - return Math.max(1, Math.trunc(amount)); -} diff --git a/packages/cua-translator/src/translator.ts b/packages/cua-translator/src/translator.ts deleted file mode 100644 index 44ec3b20..00000000 --- a/packages/cua-translator/src/translator.ts +++ /dev/null @@ -1,556 +0,0 @@ -import type Kernel from "@onkernel/sdk"; -import { - backBatchActions, - currentUrlCopyActions, - forwardBatchActions, - gotoBatchActions, -} from "./cua-extras"; -import { splitKeypress, translateKeys } from "./keysym"; -import { modelScrollDeltaToWheelTicks } from "./scroll"; -import { - type ActionValidationScope, - ActionValidationError, - ALLOWED_MODEL_ACTION_TYPES, - type BatchAction, - type BatchExecutionResult, - type ModelAction, -} from "./types"; - -// ─── Numeric helpers ─────────────────────────────────────────────────────── - -function toInt(v: unknown): number { - if (typeof v === "number" && Number.isFinite(v)) return Math.trunc(v); - if (typeof v === "string" && v.trim() !== "") { - const parsed = Number(v); - if (Number.isFinite(parsed)) return Math.trunc(parsed); - } - return 0; -} - -function stringOr(v: unknown, fallback: string): string { - if (typeof v === "string" && v.length > 0) return v; - return fallback; -} - -function toStringSlice(v: unknown): string[] { - if (!Array.isArray(v)) return []; - return v.map((x) => (typeof x === "string" ? x : "")); -} - -function readHoldKeys(v: unknown): string[] | undefined { - if (!Array.isArray(v) || v.length === 0) return undefined; - const raw = v.filter((k): k is string => typeof k === "string" && k.length > 0); - if (raw.length === 0) return undefined; - return translateKeys(raw); -} - -function toIntPath(v: unknown): number[][] { - if (!Array.isArray(v)) return []; - return v.map((p) => { - if (Array.isArray(p) && p.length >= 2) { - return [toInt(p[0]), toInt(p[1])]; - } - if (p && typeof p === "object") { - const pt = p as Record; - return [toInt(pt.x), toInt(pt.y)]; - } - return [0, 0]; - }); -} - -function hasPoint(action: ModelAction): boolean { - return isFiniteNumberLike(action.x) && isFiniteNumberLike(action.y); -} - -function isFiniteNumberLike(value: unknown): boolean { - if (typeof value === "number") return Number.isFinite(value); - if (typeof value === "string" && value.trim() !== "") return Number.isFinite(Number(value)); - return false; -} - -function validateDragPath(path: number[][], idx: number, scope: ActionValidationScope): void { - if (path.length >= 2) return; - const reason = `drag action requires path with at least two points; got ${path.length} (${formatPath(path)})`; - throw new ActionValidationError({ - scope, - actionType: "drag", - batchIndex: scope === "batch" ? idx : -1, - allowed: [...ALLOWED_MODEL_ACTION_TYPES], - reason, - }); -} - -function formatPath(path: number[][]): string { - if (path.length === 0) return "[]"; - const parts: string[] = []; - for (let i = 0; i < path.length; i++) { - if (i >= 4) { - parts.push("..."); - break; - } - const pt = path[i]!; - if (pt.length < 2) { - parts.push(""); - continue; - } - parts.push(`(${pt[0]},${pt[1]})`); - } - return `[${parts.join(" -> ")}]`; -} - -function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -const CURRENT_URL_MAX_ATTEMPTS = 3; -const CURRENT_URL_RETRY_DELAY_MS = 120; - -// ─── ModelAction → BatchAction ──────────────────────────────────────────── - -export function translateToBatchAction(actionType: string, action: ModelAction, idx: number): BatchAction { - switch (actionType) { - case "click": { - const holdKeys = readHoldKeys(action.hold_keys); - return { - type: "click_mouse", - clickMouse: { - x: toInt(action.x), - y: toInt(action.y), - button: stringOr(action.button, "left"), - ...(holdKeys ? { holdKeys } : {}), - }, - }; - } - case "mouse_down": - case "mouse_up": { - const holdKeys = readHoldKeys(action.hold_keys); - return { - type: "click_mouse", - clickMouse: { - x: toInt(action.x), - y: toInt(action.y), - button: stringOr(action.button, "left"), - clickType: actionType === "mouse_down" ? "down" : "up", - ...(holdKeys ? { holdKeys } : {}), - }, - }; - } - case "double_click": { - const holdKeys = readHoldKeys(action.hold_keys); - return { - type: "click_mouse", - clickMouse: { - x: toInt(action.x), - y: toInt(action.y), - numClicks: 2, - ...(holdKeys ? { holdKeys } : {}), - }, - }; - } - case "type": - return { - type: "type_text", - typeText: { text: typeof action.text === "string" ? action.text : "" }, - }; - case "keypress": { - const { holdKeys, primaryKeys } = splitKeypress(toStringSlice(action.keys)); - const durationMs = typeof action.duration_ms === "number" ? Math.max(0, Math.trunc(action.duration_ms)) : undefined; - return { - type: "press_key", - pressKey: { - keys: primaryKeys, - holdKeys, - ...(durationMs !== undefined ? { durationMs } : {}), - }, - }; - } - case "scroll": { - const holdKeys = readHoldKeys(action.hold_keys); - return { - type: "scroll", - scroll: { - x: toInt(action.x), - y: toInt(action.y), - deltaX: modelScrollDeltaToWheelTicks(toInt(action.scroll_x)), - deltaY: modelScrollDeltaToWheelTicks(toInt(action.scroll_y)), - ...(holdKeys ? { holdKeys } : {}), - }, - }; - } - case "move": - return { type: "move_mouse", moveMouse: { x: toInt(action.x), y: toInt(action.y) } }; - case "drag": { - const path = toIntPath(action.path); - validateDragPath(path, idx, "batch"); - const holdKeys = readHoldKeys(action.hold_keys); - return { - type: "drag_mouse", - dragMouse: { - path, - ...(typeof action.button === "string" ? { button: action.button } : {}), - ...(holdKeys ? { holdKeys } : {}), - }, - }; - } - case "wait": { - const ms = typeof action.ms === "number" ? Math.trunc(action.ms) : 1000; - return { type: "sleep", sleep: { durationMs: ms } }; - } - default: - throw new ActionValidationError({ - scope: "batch", - actionType, - batchIndex: idx, - allowed: [...ALLOWED_MODEL_ACTION_TYPES], - }); - } -} - -// ─── SDK conversion ──────────────────────────────────────────────────────── - -type SdkBatchAction = import("@onkernel/sdk/resources/browsers/computer").ComputerBatchParams.Action; - -export function toSdkAction(action: BatchAction): SdkBatchAction { - switch (action.type) { - case "click_mouse": { - const op = action.clickMouse!; - const sdk: SdkBatchAction = { - type: "click_mouse", - click_mouse: { - x: op.x, - y: op.y, - ...(op.button ? { button: op.button as "left" | "right" | "middle" | "back" | "forward" } : {}), - ...(op.clickType ? { click_type: op.clickType } : {}), - ...(op.numClicks && op.numClicks > 1 ? { num_clicks: op.numClicks } : {}), - ...(op.holdKeys && op.holdKeys.length ? { hold_keys: op.holdKeys } : {}), - }, - }; - return sdk; - } - case "move_mouse": - return { - type: "move_mouse", - move_mouse: { - x: action.moveMouse!.x, - y: action.moveMouse!.y, - ...(action.moveMouse!.holdKeys && action.moveMouse!.holdKeys.length ? { hold_keys: action.moveMouse!.holdKeys } : {}), - }, - }; - case "type_text": - return { - type: "type_text", - type_text: { text: action.typeText!.text }, - }; - case "press_key": { - const op = action.pressKey!; - return { - type: "press_key", - press_key: { - keys: op.keys, - ...(op.holdKeys && op.holdKeys.length ? { hold_keys: op.holdKeys } : {}), - ...(op.durationMs !== undefined ? { duration: op.durationMs } : {}), - }, - }; - } - case "scroll": { - const op = action.scroll!; - return { - type: "scroll", - scroll: { - x: op.x, - y: op.y, - ...(op.deltaX !== undefined ? { delta_x: op.deltaX } : {}), - ...(op.deltaY !== undefined ? { delta_y: op.deltaY } : {}), - ...(op.holdKeys && op.holdKeys.length ? { hold_keys: op.holdKeys } : {}), - }, - }; - } - case "drag_mouse": - return { - type: "drag_mouse", - drag_mouse: { - path: action.dragMouse!.path, - ...(action.dragMouse!.button ? { button: action.dragMouse!.button as "left" | "middle" | "right" } : {}), - ...(action.dragMouse!.holdKeys && action.dragMouse!.holdKeys.length ? { hold_keys: action.dragMouse!.holdKeys } : {}), - }, - }; - case "sleep": - return { - type: "sleep", - sleep: { duration_ms: action.sleep!.durationMs }, - }; - } -} - -// ─── Translator ──────────────────────────────────────────────────────────── - -export interface ComputerLogger { - (label: string): () => void; -} - -export interface ComputerTranslatorOptions { - client: Kernel; - sessionId: string; - logger?: ComputerLogger; -} - -/** - * Translates `ModelAction[]` (the canonical OpenAI-style action shape) into - * Kernel SDK batch calls, with read coalescing for `url` and `screenshot` - * steps. Provider adapter packages normalize their own action shape to - * `ModelAction` before calling `executeBatch`. - */ -export class ComputerTranslator { - private readonly client: Kernel; - private readonly sessionId: string; - private readonly logger: ComputerLogger; - - constructor(opts: ComputerTranslatorOptions) { - this.client = opts.client; - this.sessionId = opts.sessionId; - this.logger = opts.logger ?? (() => () => {}); - } - - /** Capture a screenshot, returning the raw PNG bytes. */ - async screenshotRaw(): Promise { - const done = this.logger("screenshot()"); - try { - const response = await this.client.browsers.computer.captureScreenshot(this.sessionId, {}); - const ab = await response.arrayBuffer(); - return Buffer.from(ab); - } finally { - done(); - } - } - - /** Capture a screenshot, returning base64-encoded PNG bytes. */ - async screenshotBase64(): Promise { - const buf = await this.screenshotRaw(); - return buf.toString("base64"); - } - - /** Read the current URL via Ctrl+L → Ctrl+C → readClipboard. */ - async currentUrl(): Promise { - const done = this.logger("url()"); - try { - for (let attempt = 0; attempt < CURRENT_URL_MAX_ATTEMPTS; attempt++) { - await this.runKernelBatch(currentUrlCopyActions()); - if (attempt > 0) { - await delay(CURRENT_URL_RETRY_DELAY_MS); - } - const resp = await this.client.browsers.computer.readClipboard(this.sessionId); - const url = (resp.text ?? "").trim(); - if (url) return url; - if (attempt + 1 < CURRENT_URL_MAX_ATTEMPTS) { - await delay(CURRENT_URL_RETRY_DELAY_MS); - } - } - throw new Error("clipboard URL was empty"); - } finally { - done(); - } - } - - /** Read the current mouse cursor position. */ - async currentMousePosition(): Promise<{ x: number; y: number }> { - const done = this.logger("cursor_position()"); - try { - const pos = await this.client.browsers.computer.getMousePosition(this.sessionId); - return { x: toInt(pos.x), y: toInt(pos.y) }; - } finally { - done(); - } - } - - /** - * Execute a batch of model-level actions against the Kernel browser. - * - * Coalesces consecutive write actions into a single Kernel batch HTTP - * call. Read-style actions (`url`, `screenshot`) flush the pending writes - * first, then perform the read. The cua extensions (`goto`, `back`, - * `forward`) expand to their canonical batch sequences inline. - */ - async executeBatch(actions: ModelAction[]): Promise { - const result: BatchExecutionResult = { readResults: [] }; - let pending: BatchAction[] = []; - - const flush = async (): Promise => { - if (pending.length === 0) return; - await this.runKernelBatch(pending); - pending = []; - }; - - for (let idx = 0; idx < actions.length; idx++) { - const action = actions[idx]!; - const actionType = typeof action.type === "string" ? action.type : ""; - - switch (actionType) { - case "goto": - pending.push(...gotoBatchActions(stringOr(action.url, ""))); - continue; - case "back": - pending.push(...backBatchActions()); - continue; - case "forward": - pending.push(...forwardBatchActions()); - continue; - case "screenshot": { - await flush(); - const png = await this.screenshotRaw(); - result.readResults.push({ type: "screenshot", pngBytes: png }); - continue; - } - case "url": { - await flush(); - const url = await this.currentUrl(); - result.readResults.push({ type: "url", url }); - continue; - } - case "cursor_position": { - await flush(); - const pos = await this.currentMousePosition(); - result.readResults.push({ type: "cursor_position", x: pos.x, y: pos.y }); - continue; - } - } - - pending.push(translateToBatchAction(actionType, await this.resolveCurrentPosition(actionType, action), idx)); - } - - await flush(); - return result; - } - - private async runKernelBatch(batch: BatchAction[]): Promise { - if (batch.length === 0) return; - const done = this.logger(describeBatch(batch)); - try { - await this.client.browsers.computer.batch(this.sessionId, { - actions: batch.map(toSdkAction), - }); - } finally { - done(); - } - } - - private async resolveCurrentPosition(actionType: string, action: ModelAction): Promise { - if (needsCurrentPoint(actionType, action)) { - const pos = await this.currentMousePosition(); - return { ...action, x: pos.x, y: pos.y }; - } - if (actionType === "drag" && Array.isArray(action.path)) { - let changed = false; - const nextPath: unknown[] = []; - for (const point of action.path) { - if (isCurrentPointMarker(point)) { - const pos = await this.currentMousePosition(); - nextPath.push({ x: pos.x, y: pos.y }); - changed = true; - } else { - nextPath.push(point); - } - } - if (changed) return { ...action, path: nextPath }; - } - return action; - } -} - -function needsCurrentPoint(actionType: string, action: ModelAction): boolean { - if (hasPoint(action)) return false; - return actionType === "click" || actionType === "double_click" || actionType === "mouse_down" || actionType === "mouse_up" || actionType === "scroll"; -} - -function isCurrentPointMarker(value: unknown): boolean { - return Boolean(value && typeof value === "object" && (value as { current?: unknown }).current === true); -} - -// ─── Describe (for logging) ──────────────────────────────────────────────── - -export function describeBatch(actions: BatchAction[]): string { - const parts = actions.map((a) => { - switch (a.type) { - case "click_mouse": { - const op = a.clickMouse!; - if (op.clickType === "down") return `mouse_down(${op.x},${op.y})`; - if (op.clickType === "up") return `mouse_up(${op.x},${op.y})`; - if ((op.numClicks ?? 0) > 1) return `double_click(${op.x},${op.y})`; - return `click(${op.x},${op.y})`; - } - case "type_text": { - const text = a.typeText!.text; - const t = text.length > 30 ? `${text.slice(0, 27)}...` : text; - return `type(${JSON.stringify(t)})`; - } - case "press_key": { - const op = a.pressKey!; - if (op.holdKeys && op.holdKeys.length > 0) { - return `key(hold=${JSON.stringify(op.holdKeys)}, keys=${JSON.stringify(op.keys)})`; - } - return `key(${JSON.stringify(op.keys)})`; - } - case "scroll": { - const op = a.scroll!; - return `scroll(${op.x}, ${op.y}, wheel_dx=${op.deltaX ?? 0}, wheel_dy=${op.deltaY ?? 0})`; - } - case "move_mouse": - return "move"; - case "drag_mouse": - return `drag(points=${a.dragMouse!.path.length}, path=${formatPath(a.dragMouse!.path)})`; - case "sleep": - return `sleep(${a.sleep!.durationMs}ms)`; - } - }); - return `batch[${parts.join(" → ")}]`; -} - -export function describeSingleAction(actionType: string, a: ModelAction): string { - switch (actionType) { - case "click": { - const x = toInt(a.x); - const y = toInt(a.y); - const btn = stringOr(a.button, "left"); - return btn === "left" ? `click(${x}, ${y})` : `click(${x}, ${y}, ${btn})`; - } - case "double_click": - return `double_click(${toInt(a.x)}, ${toInt(a.y)})`; - case "mouse_down": - return `mouse_down(${toInt(a.x)}, ${toInt(a.y)})`; - case "mouse_up": - return `mouse_up(${toInt(a.x)}, ${toInt(a.y)})`; - case "type": { - const text = typeof a.text === "string" ? a.text : ""; - const t = text.length > 60 ? `${text.slice(0, 57)}...` : text; - return `type(${JSON.stringify(t)})`; - } - case "keypress": - return `keypress(${JSON.stringify(toStringSlice(a.keys))})`; - case "scroll": - return `scroll(${toInt(a.x)}, ${toInt(a.y)}, dx=${toInt(a.scroll_x)}, dy=${toInt(a.scroll_y)})`; - case "move": - return `move(${toInt(a.x)}, ${toInt(a.y)})`; - case "drag": - return `drag(points=${(toIntPath(a.path) ?? []).length})`; - case "wait": - return "wait"; - case "goto": - return `goto(${JSON.stringify(stringOr(a.url, ""))})`; - case "back": - return "back()"; - case "forward": - return "forward()"; - case "url": - return "url()"; - case "cursor_position": - return "cursor_position()"; - case "screenshot": - return "screenshot()"; - default: - return actionType; - } -} - -export function describeBatchModel(actions: ModelAction[]): string { - const parts = actions.map((a) => describeSingleAction(typeof a.type === "string" ? a.type : "", a)); - return `batch[${parts.join(" → ")}]`; -} diff --git a/packages/cua-translator/src/types.ts b/packages/cua-translator/src/types.ts deleted file mode 100644 index 094d95c6..00000000 --- a/packages/cua-translator/src/types.ts +++ /dev/null @@ -1,160 +0,0 @@ -/** - * Canonical action types for the @onkernel/cua-translator package. - * - * `ModelAction` is the high-level shape any provider adapter normalizes to - * before handing it to the translator. It happens to mirror the shape that - * OpenAI's `computer` tool emits today (`{type:"click", x, y, ...}`) - * because that schema has the broadest action vocabulary, but it is in no - * way OpenAI-specific — provider packages map their own action shape to it. - * - * `BatchAction` is the low-level shape we send to `@onkernel/sdk`'s - * `browsers.computer.batch` endpoint. The translator handles the conversion. - */ - -export type ModelAction = Record; - -export type BatchActionType = - | "click_mouse" - | "move_mouse" - | "type_text" - | "press_key" - | "scroll" - | "drag_mouse" - | "sleep"; - -export interface ClickMouseOp { - x: number; - y: number; - button?: string; - clickType?: "down" | "up" | "click"; - numClicks?: number; - holdKeys?: string[]; -} - -export interface MoveMouseOp { - x: number; - y: number; - holdKeys?: string[]; -} - -export interface TypeTextOp { - text: string; -} - -export interface PressKeyOp { - keys: string[]; - holdKeys?: string[]; - durationMs?: number; -} - -export interface ScrollOp { - x: number; - y: number; - deltaX?: number; - deltaY?: number; - holdKeys?: string[]; -} - -export interface DragMouseOp { - path: number[][]; - button?: string; - holdKeys?: string[]; -} - -export interface SleepOp { - durationMs: number; -} - -export interface BatchAction { - type: BatchActionType; - clickMouse?: ClickMouseOp; - moveMouse?: MoveMouseOp; - typeText?: TypeTextOp; - pressKey?: PressKeyOp; - scroll?: ScrollOp; - dragMouse?: DragMouseOp; - sleep?: SleepOp; -} - -export type BatchReadType = "screenshot" | "url" | "cursor_position"; - -export interface ScreenshotReadResult { - type: "screenshot"; - pngBytes: Buffer; -} - -export interface UrlReadResult { - type: "url"; - url: string; -} - -export interface CursorPositionReadResult { - type: "cursor_position"; - x: number; - y: number; -} - -export type BatchReadResult = ScreenshotReadResult | UrlReadResult | CursorPositionReadResult; - -export interface BatchExecutionResult { - readResults: BatchReadResult[]; -} - -export type ActionValidationScope = "single" | "batch"; - -export class ActionValidationError extends Error { - scope: ActionValidationScope; - actionType: string; - batchIndex: number; - allowed: string[]; - reason?: string; - - constructor(args: { - scope: ActionValidationScope; - actionType: string; - batchIndex: number; - allowed: string[]; - reason?: string; - }) { - super(args.reason || defaultMessage(args.scope, args.actionType)); - this.name = "ActionValidationError"; - this.scope = args.scope; - this.actionType = args.actionType; - this.batchIndex = args.batchIndex; - this.allowed = args.allowed; - this.reason = args.reason; - } -} - -/** - * The full canonical set of model action types `ComputerTranslator.executeBatch` - * understands. Includes both the provider-official primitives (`click`, - * `double_click`, `type`, `keypress`, `scroll`, `move`, `drag`, `wait`, - * `screenshot`) and the cua-added extensions (`goto`, `back`, `forward`, - * `url`, `cursor_position`). - */ -export const ALLOWED_MODEL_ACTION_TYPES = [ - "click", - "double_click", - "mouse_down", - "mouse_up", - "type", - "keypress", - "scroll", - "move", - "drag", - "wait", - "screenshot", - "goto", - "back", - "forward", - "url", - "cursor_position", -] as const; - -export type AllowedModelActionType = (typeof ALLOWED_MODEL_ACTION_TYPES)[number]; - -function defaultMessage(scope: ActionValidationScope, actionType: string): string { - if (scope === "batch") return `unknown action type for batch: ${actionType}`; - return `unknown action type: ${actionType}`; -} diff --git a/packages/cua-translator/tsconfig.json b/packages/cua-translator/tsconfig.json deleted file mode 100644 index 8f24167a..00000000 --- a/packages/cua-translator/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./dist", - "rootDir": "./src" - }, - "include": ["src/**/*"] -} diff --git a/packages/cua-tzafon/README.md b/packages/cua-tzafon/README.md deleted file mode 100644 index 05fd80be..00000000 --- a/packages/cua-tzafon/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# `@onkernel/cua-tzafon` - -Provider-neutral Tzafon Northstar computer-use helpers backed by -[`@onkernel/cua-translator`](../cua-translator). - -## Entry Points - -- `@onkernel/cua-tzafon` - standalone `tzafon(modelId)` model factory, - Tzafon function declarations, execution helpers, coordinate helpers, and - prompt builders. -- `@onkernel/cua-tzafon/pi` - `pi-agent-core` bindings: - `createTzafonComputerTools()` and `registerTzafonProvider()`. - -## Quick Start - -```typescript -import { browserSession, runComputerUse } from "@onkernel/cua-translator"; -import { tzafon } from "@onkernel/cua-tzafon"; - -const browser = await browserSession.open({ apiKey: process.env.KERNEL_API_KEY! }); - -const result = await runComputerUse({ - model: tzafon("tzafon.northstar-cua-fast"), - browser, - prompt: "Open https://example.com and tell me the heading.", -}); - -console.log(result.text); -``` - -## Action Reference - -Tzafon Northstar emits explicit function calls. All coordinates are normalized -to the 0-999 grid and are converted to browser pixels before execution. - -| Action | Args | Maps to canonical | -| ------ | ---- | ----------------- | -| `click` | `{x, y, button?}` | Single click. | -| `double_click` | `{x, y}` | Double click. | -| `point_and_type` | `{x, y, text, press_enter?}` | Click, type text, optional Return. | -| `key` | `{keys}` | Press a key or key combo like `ctrl+l`. | -| `scroll` | `{x, y, dy}` | Scroll by notches at a point. | -| `drag` | `{x1, y1, x2, y2}` | Drag from start to end. | -| `done` | `{result}` | Report task completion. | diff --git a/packages/cua-tzafon/package.json b/packages/cua-tzafon/package.json deleted file mode 100644 index 1a1b22db..00000000 --- a/packages/cua-tzafon/package.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "@onkernel/cua-tzafon", - "version": "0.1.0", - "description": "Provider-neutral Tzafon computer-use helpers with explicit /pi bindings", - "type": "module", - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "import": "./dist/index.js" - }, - "./pi": { - "types": "./dist/pi/index.d.ts", - "import": "./dist/pi/index.js" - } - }, - "files": [ - "dist", - "README.md" - ], - "scripts": { - "build": "tsc -b", - "clean": "tsc -b --clean" - }, - "dependencies": { - "@onkernel/cua-translator": "0.1.0", - "@sinclair/typebox": "0.34.49", - "@tzafon/lightcone": "^0.7.0" - }, - "peerDependencies": { - "@mariozechner/pi-agent-core": "0.67.6", - "@mariozechner/pi-ai": "0.67.6" - }, - "peerDependenciesMeta": { - "@mariozechner/pi-agent-core": { - "optional": true - }, - "@mariozechner/pi-ai": { - "optional": true - } - } -} diff --git a/packages/cua-tzafon/src/computer.ts b/packages/cua-tzafon/src/computer.ts deleted file mode 100644 index ff2b993e..00000000 --- a/packages/cua-tzafon/src/computer.ts +++ /dev/null @@ -1,391 +0,0 @@ -import type { - ComputerTranslator, - ComputerUseToolResult, - ModelAction, -} from "@onkernel/cua-translator"; -import { type Static, Type } from "@sinclair/typebox"; -import { denormalizeX, denormalizeY } from "./coords"; -import { - DEFAULT_TZAFON_SCREEN_SIZE, - TzafonAction, - type TzafonScreenSize, -} from "./official"; - -const SCREENSHOT_DELAY_MS = 500; -const SCROLL_WHEEL_TICKS_PER_NOTCH = 120; - -function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -export interface TzafonComputerToolsOptions { - screenSize?: TzafonScreenSize; - attachScreenshot?: boolean; -} - -export interface TzafonToolDetails { - action: string; - statusText: string; - result?: string; - error?: string; -} - -interface RunContext { - translator: ComputerTranslator; - screen: TzafonScreenSize; - attachScreenshot: boolean; -} - -type ToolSchema = ReturnType; - -interface TzafonDefinition { - name: TzafonAction; - description: string; - parameters: S; - usesCoordinates?: boolean; - exec: (params: Static, ctx: RunContext) => Promise<{ actions: ModelAction[]; result?: string; done?: boolean }>; -} - -const GridPoint = { - x: Type.Union([Type.Integer({ description: "X in 0-999 grid." }), Type.String({ description: "X in 0-999 grid." })]), - y: Type.Union([Type.Integer({ description: "Y in 0-999 grid." }), Type.String({ description: "Y in 0-999 grid." })]), -} as const; - -const ClickSchema = Type.Object( - { - ...GridPoint, - button: Type.Optional(Type.String({ enum: ["left", "right"] })), - }, - { additionalProperties: false }, -); -const DoubleClickSchema = Type.Object({ ...GridPoint }, { additionalProperties: false }); -const PointAndTypeSchema = Type.Object( - { - ...GridPoint, - text: Type.String(), - press_enter: Type.Optional(Type.Boolean({ description: "Press Enter after typing." })), - }, - { additionalProperties: false }, -); -const KeySchema = Type.Object( - { - keys: Type.String({ description: "Key or key combo, for example Enter, ctrl+a, or Tab." }), - }, - { additionalProperties: false }, -); -const ScrollSchema = Type.Object( - { - ...GridPoint, - dy: Type.Integer({ description: "Scroll notches. Positive scrolls down, negative scrolls up." }), - }, - { additionalProperties: false }, -); -const DragSchema = Type.Object( - { - x1: Type.Union([Type.Integer({ description: "Start X in 0-999 grid." }), Type.String()]), - y1: Type.Union([Type.Integer({ description: "Start Y in 0-999 grid." }), Type.String()]), - x2: Type.Union([Type.Integer({ description: "End X in 0-999 grid." }), Type.String()]), - y2: Type.Union([Type.Integer({ description: "End Y in 0-999 grid." }), Type.String()]), - }, - { additionalProperties: false }, -); -const DoneSchema = Type.Object( - { - result: Type.String({ description: "Summary of what was found or accomplished." }), - }, - { additionalProperties: false }, -); - -const TZAFON_DEFINITIONS: TzafonDefinition[] = [ - { - name: TzafonAction.CLICK, - description: "Single click at (x, y) in 0-999 grid.", - parameters: ClickSchema, - usesCoordinates: true, - async exec(params, ctx) { - return { - actions: [ - { - type: "click", - x: denormalizeX(params.x, ctx.screen), - y: denormalizeY(params.y, ctx.screen), - button: params.button ?? "left", - }, - ], - }; - }, - }, - { - name: TzafonAction.DOUBLE_CLICK, - description: "Double click at (x, y) in 0-999 grid.", - parameters: DoubleClickSchema, - usesCoordinates: true, - async exec(params, ctx) { - return { - actions: [ - { - type: "double_click", - x: denormalizeX(params.x, ctx.screen), - y: denormalizeY(params.y, ctx.screen), - }, - ], - }; - }, - }, - { - name: TzafonAction.POINT_AND_TYPE, - description: "Click at position then type text. For input fields, search bars, address bars.", - parameters: PointAndTypeSchema, - usesCoordinates: true, - async exec(params, ctx) { - const x = denormalizeX(params.x, ctx.screen); - const y = denormalizeY(params.y, ctx.screen); - const actions: ModelAction[] = [ - { type: "click", x, y, button: "left" }, - { type: "wait", ms: 300 }, - { type: "type", text: params.text }, - ]; - if (params.press_enter) { - actions.push({ type: "wait", ms: 100 }, { type: "keypress", keys: ["Return"] }); - } - return { actions }; - }, - }, - { - name: TzafonAction.KEY, - description: "Press key combo (e.g. 'Enter', 'ctrl+a', 'Tab').", - parameters: KeySchema, - async exec(params) { - return { - actions: [{ type: "keypress", keys: splitKeyCombo(String(params.keys ?? "")) }], - }; - }, - }, - { - name: TzafonAction.SCROLL, - description: "Scroll at (x, y) in 0-999 grid. Positive dy = down, negative = up.", - parameters: ScrollSchema, - usesCoordinates: true, - async exec(params, ctx) { - const rawDy = typeof params.dy === "number" ? params.dy : Number(params.dy ?? 0); - const dy = Math.max(-10, Math.min(10, Number.isFinite(rawDy) ? rawDy : 0)); - return { - actions: [ - { - type: "scroll", - x: denormalizeX(params.x, ctx.screen), - y: denormalizeY(params.y, ctx.screen), - scroll_x: 0, - scroll_y: dy * SCROLL_WHEEL_TICKS_PER_NOTCH, - }, - ], - }; - }, - }, - { - name: TzafonAction.DRAG, - description: "Drag from (x1, y1) to (x2, y2) in 0-999 grid.", - parameters: DragSchema, - usesCoordinates: true, - async exec(params, ctx) { - return { - actions: [ - { - type: "drag", - path: [ - { x: denormalizeX(params.x1, ctx.screen), y: denormalizeY(params.y1, ctx.screen) }, - { x: denormalizeX(params.x2, ctx.screen), y: denormalizeY(params.y2, ctx.screen) }, - ], - }, - ], - }; - }, - }, - { - name: TzafonAction.DONE, - description: "Task complete. Report findings.", - parameters: DoneSchema, - async exec(params) { - return { actions: [], result: String(params.result ?? ""), done: true }; - }, - }, -]; - -export const TZAFON_FUNCTION_TOOLS = TZAFON_DEFINITIONS.map((definition) => ({ - type: "function" as const, - name: definition.name, - description: definition.description, - parameters: definition.parameters, -})); - -export async function executeTzafonFunctionCall(args: { - translator: ComputerTranslator; - name: string; - input: Record; - options?: TzafonComputerToolsOptions; -}): Promise> { - const definition = TZAFON_DEFINITIONS.find((entry) => entry.name === args.name); - if (!definition) { - return { - content: [{ type: "text", text: `failed: unknown Tzafon function "${args.name}"` }], - details: { - action: args.name, - statusText: `failed: unknown Tzafon function "${args.name}"`, - error: `unknown Tzafon function "${args.name}"`, - }, - isError: true, - }; - } - const ctx: RunContext = { - translator: args.translator, - screen: args.options?.screenSize ?? await currentScreenSize(args.translator, definition.usesCoordinates === true), - attachScreenshot: args.options?.attachScreenshot !== false, - }; - return executeDefinition(definition, args.input, ctx); -} - -export function getTzafonDefinition(name: string): TzafonDefinition | undefined { - return TZAFON_DEFINITIONS.find((entry) => entry.name === name); -} - -export function splitKeyCombo(keys: string): string[] { - return keys - .split("+") - .map((part) => mapKey(part.trim())) - .filter(Boolean); -} - -async function executeDefinition( - definition: TzafonDefinition, - params: Record, - ctx: RunContext, -): Promise> { - const content: ComputerUseToolResult["content"] = []; - let statusText = "ok"; - let resultText: string | undefined; - let execErr: Error | undefined; - let skipScreenshot = false; - - try { - const { actions, result, done } = await definition.exec(params as never, ctx); - resultText = result; - if (done) { - skipScreenshot = true; - statusText = result ? `done: ${result}` : "done"; - } else if (actions.length === 0) { - skipScreenshot = true; - } else { - const result = await ctx.translator.executeBatch(actions); - for (const r of result.readResults) { - if (r.type === "screenshot") { - content.push({ type: "text", text: "screenshot:" }); - content.push({ - type: "image", - data: r.pngBytes.toString("base64"), - mimeType: "image/png", - }); - skipScreenshot = true; - } else if (r.type === "url") { - content.push({ type: "text", text: `url: ${r.url}` }); - } - } - } - } catch (err) { - execErr = err instanceof Error ? err : new Error(String(err)); - statusText = `failed: ${execErr.message}`; - } - - content.unshift({ type: "text", text: statusText }); - - if (!execErr && !skipScreenshot && ctx.attachScreenshot) { - await delay(SCREENSHOT_DELAY_MS); - try { - const png = await ctx.translator.screenshotRaw(); - content.push({ - type: "image", - data: png.toString("base64"), - mimeType: "image/png", - }); - } catch (shotErr) { - content[0] = { - type: "text", - text: `${statusText} (screenshot unavailable: ${(shotErr as Error).message})`, - }; - } - } - - const details: TzafonToolDetails = { - action: definition.name, - statusText, - ...(resultText ? { result: resultText } : {}), - ...(execErr ? { error: execErr.message } : {}), - }; - - return { - content, - details, - ...(execErr ? { isError: true } : {}), - }; -} - -const KEY_MAP: Record = { - return: "Return", - enter: "Return", - space: "space", - tab: "Tab", - backspace: "BackSpace", - delete: "Delete", - escape: "Escape", - esc: "Escape", - insert: "Insert", - up: "Up", - down: "Down", - left: "Left", - right: "Right", - home: "Home", - end: "End", - pageup: "Page_Up", - page_up: "Page_Up", - pagedown: "Page_Down", - page_down: "Page_Down", -}; - -const MODIFIER_MAP: Record = { - ctrl: "ctrl", - control: "ctrl", - alt: "alt", - shift: "shift", - meta: "super", - cmd: "super", - command: "super", - win: "super", -}; - -for (let i = 1; i <= 12; i++) { - KEY_MAP[`f${i}`] = `F${i}`; -} - -function mapKey(key: string): string { - const normalized = key.toLowerCase(); - return MODIFIER_MAP[normalized] ?? KEY_MAP[normalized] ?? key; -} - -async function currentScreenSize(translator: ComputerTranslator, needed: boolean): Promise { - if (!needed) return DEFAULT_TZAFON_SCREEN_SIZE; - try { - const png = await translator.screenshotRaw(); - return readPngSize(png) ?? DEFAULT_TZAFON_SCREEN_SIZE; - } catch { - return DEFAULT_TZAFON_SCREEN_SIZE; - } -} - -function readPngSize(buf: Buffer): TzafonScreenSize | undefined { - if (buf.length < 24) return undefined; - const signature = "89504e470d0a1a0a"; - if (buf.subarray(0, 8).toString("hex") !== signature) return undefined; - const width = buf.readUInt32BE(16); - const height = buf.readUInt32BE(20); - if (width <= 0 || height <= 0) return undefined; - return { width, height }; -} diff --git a/packages/cua-tzafon/src/coords.ts b/packages/cua-tzafon/src/coords.ts deleted file mode 100644 index 638d2dea..00000000 --- a/packages/cua-tzafon/src/coords.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { - DEFAULT_TZAFON_SCREEN_SIZE, - TZAFON_COORDINATE_SCALE, - type TzafonScreenSize, -} from "./official"; - -export function parseTzafonCoord(value: unknown): number { - if (value == null) return 0; - let text = String(value); - if (text.includes(",")) text = text.split(",")[0]!.trim(); - const parsed = Number(text); - if (!Number.isFinite(parsed)) return 0; - return Math.trunc(parsed); -} - -export function denormalizeX(value: unknown, screen: TzafonScreenSize = DEFAULT_TZAFON_SCREEN_SIZE): number { - return denormalizeCoord(value, screen.width); -} - -export function denormalizeY(value: unknown, screen: TzafonScreenSize = DEFAULT_TZAFON_SCREEN_SIZE): number { - return denormalizeCoord(value, screen.height); -} - -function denormalizeCoord(value: unknown, size: number): number { - const max = Math.max(0, Math.trunc(size) - 1); - const coord = parseTzafonCoord(value); - return Math.max(0, Math.min(Math.trunc((coord * max) / TZAFON_COORDINATE_SCALE), max)); -} diff --git a/packages/cua-tzafon/src/index.ts b/packages/cua-tzafon/src/index.ts deleted file mode 100644 index 0c157afc..00000000 --- a/packages/cua-tzafon/src/index.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @onkernel/cua-tzafon - * - * Provider-neutral Tzafon computer-use helpers backed by - * `@onkernel/cua-translator`. - * - * `pi-agent-core` bindings live under `@onkernel/cua-tzafon/pi`. - */ - -export { - denormalizeX, - denormalizeY, - parseTzafonCoord, -} from "./coords"; -export { - executeTzafonFunctionCall, - getTzafonDefinition, - splitKeyCombo, - TZAFON_FUNCTION_TOOLS, -} from "./computer"; -export type { - TzafonComputerToolsOptions, - TzafonToolDetails, -} from "./computer"; -export { - TzafonAction, - DEFAULT_TZAFON_SCREEN_SIZE, - TZAFON_ACTIONS, - TZAFON_COORDINATE_SCALE, - TZAFON_DEFAULT_MODEL, -} from "./official"; -export type { - TzafonActionName, - TzafonScreenSize, -} from "./official"; -export { tzafon } from "./model"; -export type { - TzafonModelOptions, - TzafonModelRunDetails, -} from "./model"; -export { - buildTzafonSystemPrompt, - TZAFON_INSTRUCTIONS_RAW, -} from "./system-prompt"; -export type { TzafonSystemPromptOptions } from "./system-prompt"; diff --git a/packages/cua-tzafon/src/model.ts b/packages/cua-tzafon/src/model.ts deleted file mode 100644 index 60706d2b..00000000 --- a/packages/cua-tzafon/src/model.ts +++ /dev/null @@ -1,230 +0,0 @@ -import type { - ComputerTranslator, - ComputerUseModel, - ComputerUseRunResult, - ComputerUseToolResult, -} from "@onkernel/cua-translator"; -import Lightcone from "@tzafon/lightcone"; -import { - executeTzafonFunctionCall, - TZAFON_FUNCTION_TOOLS, - type TzafonComputerToolsOptions, - type TzafonToolDetails, -} from "./computer"; -import { TZAFON_DEFAULT_MODEL } from "./official"; -import { buildTzafonSystemPrompt } from "./system-prompt"; - -const DEFAULT_MAX_OUTPUT_TOKENS = 4096; -const MAX_HISTORY_ITEMS = 30; -const KEEP_RECENT_ITEMS = 22; - -export interface TzafonModelOptions extends TzafonComputerToolsOptions { - apiKey?: string; - instructions?: string; - maxOutputTokens?: number; - temperature?: number; -} - -export interface TzafonModelRunDetails { - model?: string; -} - -interface TzafonFunctionCall { - callId: string; - name: string; - args: Record; - rawArguments: unknown; -} - -type LightconeItem = Record; - -export function tzafon(modelId: string = TZAFON_DEFAULT_MODEL, opts: TzafonModelOptions = {}): ComputerUseModel { - return { - provider: "tzafon", - modelId, - async run({ prompt, translator, maxTurns = 50 }): Promise> { - const apiKey = opts.apiKey || process.env.TZAFON_API_KEY; - if (!apiKey) { - throw new Error("missing Tzafon API key"); - } - - const client = new Lightcone({ apiKey }); - const instructions = buildTzafonSystemPrompt({ suffix: opts.instructions }); - const items: LightconeItem[] = [ - imageMessage( - `data:image/png;base64,${await translator.screenshotBase64()}`, - `${prompt}\n\nCurrent screenshot:`, - ), - ]; - let response: unknown; - - for (let turn = 0; turn < maxTurns; turn++) { - pruneHistory(items); - response = await client.responses.create({ - model: modelId, - input: items, - tools: TZAFON_FUNCTION_TOOLS, - instructions, - temperature: opts.temperature ?? 0, - max_output_tokens: opts.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS, - } as never); - - const calls = collectResponseItems(response, items); - if (calls.length === 0) { - return { - text: extractMessages(response).join("\n").trim() || "(no response)", - provider: "tzafon", - modelId, - turns: turn + 1, - details: { model: modelId }, - }; - } - - for (const call of calls) { - if (call.name === "done") { - const result = typeof call.args.result === "string" ? call.args.result : ""; - items.push({ type: "function_call_output", call_id: call.callId, output: "ok" }); - return { - text: result, - provider: "tzafon", - modelId, - turns: turn + 1, - details: { model: modelId }, - }; - } - - const result = await executeTzafonFunctionCall({ - translator, - name: call.name, - input: call.args, - options: opts, - }); - items.push(toFunctionOutput(call.callId, result)); - addScreenshotMessage(items, result); - } - } - - return { - text: extractMessages(response).join("\n").trim() || "(max turns reached)", - provider: "tzafon", - modelId, - turns: maxTurns, - details: { model: modelId }, - }; - }, - }; -} - -function collectResponseItems(response: unknown, items: LightconeItem[]): TzafonFunctionCall[] { - const calls: TzafonFunctionCall[] = []; - for (const item of getArray(response, "output")) { - const itemType = getString(item, "type"); - if (itemType === "message") { - const text = extractMessageText(item); - if (text) items.push({ role: "assistant", content: text }); - continue; - } - if (itemType === "function_call") { - const callId = getString(item, "call_id"); - const name = getString(item, "name"); - const rawArguments = getValue(item, "arguments") ?? "{}"; - const args = parseArguments(rawArguments); - calls.push({ callId, name, args, rawArguments }); - items.push({ - type: "function_call", - call_id: callId, - name, - arguments: typeof rawArguments === "string" ? rawArguments : JSON.stringify(rawArguments), - }); - } - } - return calls; -} - -function toFunctionOutput(callId: string, result: ComputerUseToolResult): LightconeItem { - const text = result.content - .filter((part): part is { type: "text"; text: string } => part.type === "text") - .map((part) => part.text) - .join("\n") - .trim(); - return { - type: "function_call_output", - call_id: callId, - output: result.isError ? `Error: ${text || "tool execution failed"}` : text || "ok", - }; -} - -function addScreenshotMessage(items: LightconeItem[], result: ComputerUseToolResult): void { - const image = [...result.content].reverse().find((part) => part.type === "image"); - if (!image || image.type !== "image") return; - removeOldImages(items); - items.push(imageMessage(`data:${image.mimeType};base64,${image.data}`)); -} - -function imageMessage(imageUrl: string, text = "screenshot"): LightconeItem { - return { - role: "user", - content: [ - { type: "input_text", text }, - { type: "input_image", image_url: imageUrl, detail: "auto" }, - ], - }; -} - -function pruneHistory(items: LightconeItem[]): void { - if (items.length <= MAX_HISTORY_ITEMS) return; - items.splice(2, items.length - KEEP_RECENT_ITEMS); -} - -function removeOldImages(items: LightconeItem[]): void { - for (const item of items) { - const content = item.content; - if (!Array.isArray(content)) continue; - const filtered = content.filter((part) => !(part && typeof part === "object" && "type" in part && part.type === "input_image")); - if (filtered.length === content.length) continue; - item.content = filtered.length > 0 ? filtered : "(old screenshot)"; - } -} - -function extractMessages(response: unknown): string[] { - return getArray(response, "output") - .filter((item) => getString(item, "type") === "message") - .map(extractMessageText) - .filter(Boolean); -} - -function extractMessageText(item: unknown): string { - return getArray(item, "content") - .map((block) => getString(block, "text")) - .filter(Boolean) - .join("\n") - .trim(); -} - -function parseArguments(value: unknown): Record { - if (typeof value === "string" && value.trim()) { - try { - const parsed = JSON.parse(value); - return parsed && typeof parsed === "object" ? parsed as Record : {}; - } catch { - return {}; - } - } - if (value && typeof value === "object") return value as Record; - return {}; -} - -function getArray(obj: unknown, key: string): unknown[] { - const value = getValue(obj, key); - return Array.isArray(value) ? value : []; -} - -function getString(obj: unknown, key: string): string { - const value = getValue(obj, key); - return typeof value === "string" ? value : ""; -} - -function getValue(obj: unknown, key: string): unknown { - if (!obj || typeof obj !== "object") return undefined; - return (obj as Record)[key]; -} diff --git a/packages/cua-tzafon/src/official.ts b/packages/cua-tzafon/src/official.ts deleted file mode 100644 index b4d73e5f..00000000 --- a/packages/cua-tzafon/src/official.ts +++ /dev/null @@ -1,35 +0,0 @@ -export const TZAFON_DEFAULT_MODEL = "tzafon.northstar-cua-fast"; - -export const TZAFON_COORDINATE_SCALE = 999; - -export interface TzafonScreenSize { - width: number; - height: number; -} - -export const DEFAULT_TZAFON_SCREEN_SIZE: TzafonScreenSize = { - width: 1920, - height: 1080, -}; - -export enum TzafonAction { - CLICK = "click", - DOUBLE_CLICK = "double_click", - POINT_AND_TYPE = "point_and_type", - KEY = "key", - SCROLL = "scroll", - DRAG = "drag", - DONE = "done", -} - -export const TZAFON_ACTIONS = [ - TzafonAction.CLICK, - TzafonAction.DOUBLE_CLICK, - TzafonAction.POINT_AND_TYPE, - TzafonAction.KEY, - TzafonAction.SCROLL, - TzafonAction.DRAG, - TzafonAction.DONE, -] as const; - -export type TzafonActionName = (typeof TZAFON_ACTIONS)[number]; diff --git a/packages/cua-tzafon/src/pi/index.ts b/packages/cua-tzafon/src/pi/index.ts deleted file mode 100644 index 67569bc3..00000000 --- a/packages/cua-tzafon/src/pi/index.ts +++ /dev/null @@ -1,296 +0,0 @@ -import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core"; -import { - createAssistantMessageEventStream, - registerApiProvider, - type Api, - type AssistantMessage, - type Context, - type ImageContent, - type Model, - type SimpleStreamOptions, - type StreamFunction, - type StreamOptions, - type TextContent, - type Tool, - type ToolCall, -} from "@mariozechner/pi-ai"; -import type { ComputerTranslator } from "@onkernel/cua-translator"; -import Lightcone from "@tzafon/lightcone"; -import { - executeTzafonFunctionCall, - TZAFON_FUNCTION_TOOLS, - type TzafonComputerToolsOptions, - type TzafonToolDetails, -} from "../computer"; - -export const TZAFON_RESPONSES_API = "tzafon-responses"; - -export interface TzafonResponsesOptions extends StreamOptions { - maxOutputTokens?: number; -} - -export interface TzafonComputerToolsPiOptions extends TzafonComputerToolsOptions {} - -export function createTzafonComputerTools( - translator: ComputerTranslator, - opts: TzafonComputerToolsPiOptions = {}, -): AgentTool[] { - return TZAFON_FUNCTION_TOOLS.map((tool) => ({ - name: tool.name, - label: tool.name, - description: tool.description, - parameters: tool.parameters, - async execute(_id, params): Promise> { - const result = await executeTzafonFunctionCall({ - translator, - name: tool.name, - input: params as Record, - options: opts, - }); - if (result.isError) { - const message = result.content - .filter((part): part is TextContent => part.type === "text") - .map((part) => part.text) - .join("\n") - .trim() || "Tzafon tool execution failed"; - throw Object.assign(new Error(message), { - details: result.details, - content: result.content, - }); - } - return { - content: result.content, - details: result.details, - }; - }, - })); -} - -export function registerTzafonProvider(): void { - registerApiProvider({ - api: TZAFON_RESPONSES_API, - stream: streamTzafonResponses, - streamSimple: streamSimpleTzafonResponses, - }); -} - -export const streamSimpleTzafonResponses: StreamFunction = (model, context, options) => { - return streamTzafonResponses(model, context, options); -}; - -export const streamTzafonResponses: StreamFunction = (model, context, options) => { - const stream = createAssistantMessageEventStream(); - const output = initialAssistantMessage(model); - - void (async () => { - try { - const apiKey = options?.apiKey || process.env.TZAFON_API_KEY; - if (!apiKey) throw new Error(`No API key for provider: ${model.provider}`); - const client = new Lightcone({ apiKey }); - const payload = { - model: model.id, - input: convertContextMessages(context), - tools: convertTools(context.tools ?? []), - instructions: context.systemPrompt, - temperature: options?.temperature ?? 0, - max_output_tokens: options?.maxOutputTokens ?? options?.maxTokens ?? model.maxTokens, - }; - const nextPayload = await options?.onPayload?.(payload, model as Model); - if (options?.signal?.aborted) throw new Error("Request was aborted"); - const response = await client.responses.create((nextPayload ?? payload) as never, { - signal: options?.signal, - }); - if (options?.signal?.aborted) throw new Error("Request was aborted"); - - stream.push({ type: "start", partial: output }); - for (const item of getArray(response, "output")) { - const type = getString(item, "type"); - if (type === "message") { - const text = extractMessageText(item); - if (text) emitText(stream, output, text); - continue; - } - if (type === "function_call") { - emitToolCall(stream, output, { - type: "toolCall", - id: getString(item, "call_id"), - name: getString(item, "name"), - arguments: parseArguments(getValue(item, "arguments")), - }); - } - } - - output.stopReason = output.content.some((part) => part.type === "toolCall") ? "toolUse" : "stop"; - stream.push({ type: "done", reason: output.stopReason, message: output }); - stream.end(); - } catch (err) { - output.stopReason = options?.signal?.aborted ? "aborted" : "error"; - output.errorMessage = err instanceof Error ? err.message : String(err); - stream.push({ type: "error", reason: output.stopReason, error: output }); - stream.end(); - } - })(); - - return stream; -}; - -function initialAssistantMessage(model: Model): AssistantMessage { - return { - role: "assistant", - content: [], - api: model.api, - provider: model.provider, - model: model.id, - usage: zeroUsage(), - stopReason: "stop", - timestamp: Date.now(), - }; -} - -function zeroUsage(): AssistantMessage["usage"] { - return { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - totalTokens: 0, - cost: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - total: 0, - }, - }; -} - -function emitText( - stream: ReturnType, - output: AssistantMessage, - text: string, -): void { - const contentIndex = output.content.length; - const content: TextContent = { type: "text", text }; - output.content.push(content); - stream.push({ type: "text_start", contentIndex, partial: output }); - stream.push({ type: "text_delta", contentIndex, delta: text, partial: output }); - stream.push({ type: "text_end", contentIndex, content: text, partial: output }); -} - -function emitToolCall( - stream: ReturnType, - output: AssistantMessage, - toolCall: ToolCall, -): void { - const contentIndex = output.content.length; - output.content.push(toolCall); - stream.push({ type: "toolcall_start", contentIndex, partial: output }); - stream.push({ type: "toolcall_end", contentIndex, toolCall, partial: output }); -} - -function convertTools(tools: Tool[]): Array> { - return tools.map((tool) => ({ - type: "function", - name: tool.name, - description: tool.description, - parameters: tool.parameters, - })); -} - -function convertContextMessages(context: Context): Array> { - const items: Array> = []; - for (const message of context.messages) { - if (message.role === "user") { - items.push({ - role: "user", - content: convertUserContent(message.content), - }); - continue; - } - if (message.role === "assistant") { - const text = message.content - .filter((part): part is TextContent => part.type === "text") - .map((part) => part.text) - .join("\n") - .trim(); - if (text) items.push({ role: "assistant", content: text }); - for (const part of message.content) { - if (part.type !== "toolCall") continue; - items.push({ - type: "function_call", - call_id: part.id, - name: part.name, - arguments: JSON.stringify(part.arguments ?? {}), - }); - } - continue; - } - if (message.role === "toolResult") { - const text = message.content - .filter((part): part is TextContent => part.type === "text") - .map((part) => part.text) - .join("\n") - .trim(); - items.push({ - type: "function_call_output", - call_id: message.toolCallId, - output: message.isError ? `Error: ${text || "tool execution failed"}` : text || "ok", - }); - const image = [...message.content].reverse().find((part): part is ImageContent => part.type === "image"); - if (image) { - items.push({ - role: "user", - content: [ - { type: "input_text", text: "screenshot" }, - { type: "input_image", image_url: `data:${image.mimeType};base64,${image.data}`, detail: "auto" }, - ], - }); - } - } - } - return items; -} - -function convertUserContent(content: string | (TextContent | ImageContent)[]): unknown { - if (typeof content === "string") return [{ type: "input_text", text: content }]; - return content.map((part: TextContent | ImageContent) => { - if (part.type === "text") return { type: "input_text", text: part.text }; - return { type: "input_image", image_url: `data:${part.mimeType};base64,${part.data}`, detail: "auto" }; - }); -} - -function extractMessageText(item: unknown): string { - return getArray(item, "content") - .map((block) => getString(block, "text")) - .filter(Boolean) - .join("\n") - .trim(); -} - -function parseArguments(value: unknown): Record { - if (typeof value === "string" && value.trim()) { - try { - const parsed = JSON.parse(value); - return parsed && typeof parsed === "object" ? parsed as Record : {}; - } catch { - return {}; - } - } - if (value && typeof value === "object") return value as Record; - return {}; -} - -function getArray(obj: unknown, key: string): unknown[] { - const value = getValue(obj, key); - return Array.isArray(value) ? value : []; -} - -function getString(obj: unknown, key: string): string { - const value = getValue(obj, key); - return typeof value === "string" ? value : ""; -} - -function getValue(obj: unknown, key: string): unknown { - if (!obj || typeof obj !== "object") return undefined; - return (obj as Record)[key]; -} diff --git a/packages/cua-tzafon/src/system-prompt.ts b/packages/cua-tzafon/src/system-prompt.ts deleted file mode 100644 index 70ef1a5d..00000000 --- a/packages/cua-tzafon/src/system-prompt.ts +++ /dev/null @@ -1,25 +0,0 @@ -const TZAFON_COMPUTER_INSTRUCTIONS = `Use a mouse and keyboard to interact with a Chromium browser and take screenshots. -* Chromium is already open on a Kernel cloud browser. If a startup wizard appears, ignore it. -* The screen's coordinate space is a 0-999 grid. -* To navigate to a URL, use point_and_type on the address bar, or key("ctrl+l") to focus it first. -* Some pages may take time to load. Wait and take successive screenshots to confirm the result. -* Whenever you click on an element, consult the screenshot to determine coordinates first. -* Click buttons, links, and icons in the center of the element, not on edges. -* If a click did not work, try adjusting the coordinates slightly. -* For full-page scrolling, prefer key("PageDown") / key("PageUp") over the scroll tool. -* After each action, evaluate the screenshot to confirm it succeeded before moving on. -* When the task is complete, call done() with a summary of what you found or accomplished.`; - -export interface TzafonSystemPromptOptions { - suffix?: string; -} - -export function buildTzafonSystemPrompt(opts: TzafonSystemPromptOptions = {}): string { - const suffix = (opts.suffix ?? "").trim(); - if (!suffix) return TZAFON_COMPUTER_INSTRUCTIONS; - return `${TZAFON_COMPUTER_INSTRUCTIONS}\n\n${suffix}`; -} - -export const TZAFON_INSTRUCTIONS_RAW = { - computer: TZAFON_COMPUTER_INSTRUCTIONS, -}; diff --git a/packages/cua-tzafon/tsconfig.json b/packages/cua-tzafon/tsconfig.json deleted file mode 100644 index c2e66df0..00000000 --- a/packages/cua-tzafon/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./dist", - "rootDir": "./src" - }, - "include": ["src/**/*"], - "references": [{ "path": "../cua-translator" }] -} diff --git a/packages/cua-yutori/README.md b/packages/cua-yutori/README.md deleted file mode 100644 index 0f82812a..00000000 --- a/packages/cua-yutori/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# `@onkernel/cua-yutori` - -Yutori Navigator computer-use helpers for CUA. - -The package exposes Yutori's native browser action names and `pi-agent-core` -bindings backed by `@onkernel/cua-translator`. Runtime calls use Yutori's -OpenAI-compatible `chat.completions` API at `https://api.yutori.com/v1`. -Coordinates are denormalized from Yutori's 0-1000 space to Kernel's default -1920x1080 cloud-browser viewport. - -`pi-agent-core` bindings live under `@onkernel/cua-yutori/pi`. diff --git a/packages/cua-yutori/package.json b/packages/cua-yutori/package.json deleted file mode 100644 index d78f557b..00000000 --- a/packages/cua-yutori/package.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "@onkernel/cua-yutori", - "version": "0.1.0", - "description": "Provider-neutral Yutori Navigator computer-use helpers with explicit /pi bindings", - "type": "module", - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "import": "./dist/index.js" - }, - "./pi": { - "types": "./dist/pi/index.d.ts", - "import": "./dist/pi/index.js" - } - }, - "files": [ - "dist", - "README.md" - ], - "scripts": { - "build": "tsc -b", - "clean": "tsc -b --clean" - }, - "dependencies": { - "@onkernel/cua-translator": "0.1.0", - "@sinclair/typebox": "0.34.49", - "openai": "^6.26.0" - }, - "peerDependencies": { - "@mariozechner/pi-agent-core": "0.67.6", - "@mariozechner/pi-ai": "0.67.6" - }, - "peerDependenciesMeta": { - "@mariozechner/pi-agent-core": { - "optional": true - }, - "@mariozechner/pi-ai": { - "optional": true - } - } -} diff --git a/packages/cua-yutori/src/computer-tool.ts b/packages/cua-yutori/src/computer-tool.ts deleted file mode 100644 index fc8e64c2..00000000 --- a/packages/cua-yutori/src/computer-tool.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core"; -import type { ImageContent, TextContent } from "@mariozechner/pi-ai"; -import type { ComputerTranslator } from "@onkernel/cua-translator"; -import { type Static } from "@sinclair/typebox"; -import { - YUTORI_DEFINITIONS, - type YutoriComputerToolsOptions, - type YutoriToolDetails, - executeYutoriFunctionCall, -} from "./computer"; - -export function createYutoriPerActionTools( - translator: ComputerTranslator, - opts: YutoriComputerToolsOptions = {}, -): AgentTool[] { - return YUTORI_DEFINITIONS.map((definition) => ({ - name: definition.name, - label: definition.name, - description: definition.description, - parameters: definition.parameters, - async execute(_id, params: Static): Promise> { - const result = await executeYutoriFunctionCall({ - translator, - name: definition.name, - input: params, - options: opts, - }); - const content = result.content as (TextContent | ImageContent)[]; - const details = result.details; - if (result.isError) { - const message = details.error ?? details.statusText; - throw Object.assign(new Error(message), { details, content }); - } - return { content, details }; - }, - })); -} diff --git a/packages/cua-yutori/src/computer.ts b/packages/cua-yutori/src/computer.ts deleted file mode 100644 index 96d8cfb7..00000000 --- a/packages/cua-yutori/src/computer.ts +++ /dev/null @@ -1,340 +0,0 @@ -import { - type ComputerTranslator, - type ComputerUseToolResult, - type ModelAction, - backModelAction, -} from "@onkernel/cua-translator"; -import { type TObject, Type } from "@sinclair/typebox"; -import { denormalizeX, denormalizeY } from "./coords"; -import { - DEFAULT_YUTORI_SCREEN_SIZE, - YutoriAction, - type YutoriScreenSize, - type YutoriScrollDirection, -} from "./official"; - -const SCREENSHOT_DELAY_MS = 300; -const WAIT_MS = 2000; -const SCROLL_UNIT_SCREEN_FRACTION = 0.1; - -export interface YutoriComputerToolsOptions { - screenSize?: YutoriScreenSize; - attachScreenshot?: boolean; -} - -export interface YutoriToolDetails { - action: string; - statusText: string; - error?: string; -} - -interface RunContext { - translator: ComputerTranslator; - screen: YutoriScreenSize; - attachScreenshot: boolean; -} - -interface YutoriDefinition { - name: YutoriAction; - description: string; - parameters: S; - exec: (params: any, ctx: RunContext) => Promise; -} - -const NormalizedPoint = Type.Tuple([ - Type.Number({ description: "X in 0-1000 normalized coordinates." }), - Type.Number({ description: "Y in 0-1000 normalized coordinates." }), -]); - -const PointSchema = Type.Object( - { - coordinates: NormalizedPoint, - }, - { additionalProperties: false }, -); - -const ScrollSchema = Type.Object( - { - coordinates: NormalizedPoint, - direction: Type.String({ enum: ["up", "down", "left", "right"] }), - amount: Type.Integer({ minimum: 1, description: "Scroll units; 1 is roughly 10% of screen height." }), - }, - { additionalProperties: false }, -); - -const TypeSchema = Type.Object( - { - text: Type.String(), - press_enter_after: Type.Optional(Type.Boolean()), - clear_before_typing: Type.Optional(Type.Boolean()), - }, - { additionalProperties: false }, -); - -const KeyPressSchema = Type.Object( - { - key_comb: Type.Optional(Type.String({ description: "Playwright-compatible key or key combination, e.g. Control+c." })), - key: Type.Optional(Type.String({ description: "n1.5 key alias for key_comb." })), - }, - { additionalProperties: false }, -); - -const DragSchema = Type.Object( - { - start_coordinates: NormalizedPoint, - coordinates: NormalizedPoint, - }, - { additionalProperties: false }, -); - -const EmptySchema = Type.Object({}, { additionalProperties: false }); - -const GotoUrlSchema = Type.Object( - { - url: Type.String({ description: "Fully-qualified URL to navigate to." }), - }, - { additionalProperties: false }, -); - -export const YUTORI_DEFINITIONS: YutoriDefinition[] = [ - { - name: YutoriAction.LEFT_CLICK, - description: "Left mouse click at a specific point on the page.", - parameters: PointSchema, - async exec({ coordinates }, ctx) { - const [x, y] = point(coordinates, ctx.screen); - return [{ type: "click", x, y, button: "left" }]; - }, - }, - { - name: YutoriAction.DOUBLE_CLICK, - description: "Double left mouse click at a specific point on the page.", - parameters: PointSchema, - async exec({ coordinates }, ctx) { - const [x, y] = point(coordinates, ctx.screen); - return [{ type: "double_click", x, y }]; - }, - }, - { - name: YutoriAction.TRIPLE_CLICK, - description: "Triple left mouse click at a specific point on the page.", - parameters: PointSchema, - async exec({ coordinates }, ctx) { - const [x, y] = point(coordinates, ctx.screen); - return [ - { type: "double_click", x, y }, - { type: "click", x, y, button: "left" }, - ]; - }, - }, - { - name: YutoriAction.RIGHT_CLICK, - description: "Right mouse click at a specific point on the page.", - parameters: PointSchema, - async exec({ coordinates }, ctx) { - const [x, y] = point(coordinates, ctx.screen); - return [{ type: "click", x, y, button: "right" }]; - }, - }, - { - name: YutoriAction.SCROLL, - description: "Scrolls the page in a given direction from a point.", - parameters: ScrollSchema, - async exec({ coordinates, direction, amount }, ctx) { - const [x, y] = point(coordinates, ctx.screen); - const { scroll_x, scroll_y } = scrollDelta(direction, amount, ctx.screen); - return [{ type: "scroll", x, y, scroll_x, scroll_y }]; - }, - }, - { - name: YutoriAction.TYPE, - description: "Types text into the focused input.", - parameters: TypeSchema, - async exec(params) { - const actions: ModelAction[] = []; - if (params.clear_before_typing) { - actions.push({ type: "keypress", keys: ["Control", "a"] }); - actions.push({ type: "keypress", keys: ["Backspace"] }); - } - actions.push({ type: "type", text: params.text }); - if (params.press_enter_after) actions.push({ type: "keypress", keys: ["Enter"] }); - return actions; - }, - }, - { - name: YutoriAction.KEY_PRESS, - description: "Sends a Playwright-compatible keyboard input.", - parameters: KeyPressSchema, - async exec({ key_comb, key }) { - return [{ type: "keypress", keys: splitKeyCombination(key_comb ?? key) }]; - }, - }, - { - name: YutoriAction.HOVER, - description: "Hovers over a specific point on the page.", - parameters: PointSchema, - async exec({ coordinates }, ctx) { - const [x, y] = point(coordinates, ctx.screen); - return [{ type: "move", x, y }]; - }, - }, - { - name: YutoriAction.DRAG, - description: "Drags from a start point to a target point.", - parameters: DragSchema, - async exec({ start_coordinates, coordinates }, ctx) { - const [sx, sy] = point(start_coordinates, ctx.screen); - const [x, y] = point(coordinates, ctx.screen); - return [{ type: "drag", path: [{ x: sx, y: sy }, { x, y }], button: "left" }]; - }, - }, - { - name: YutoriAction.WAIT, - description: "Pauses execution.", - parameters: EmptySchema, - async exec() { - return [{ type: "wait", ms: WAIT_MS }]; - }, - }, - { - name: YutoriAction.REFRESH, - description: "Reloads the current page.", - parameters: EmptySchema, - async exec() { - return [{ type: "keypress", keys: ["F5"] }, { type: "wait", ms: WAIT_MS }]; - }, - }, - { - name: YutoriAction.GO_BACK, - description: "Navigates back in browser history.", - parameters: EmptySchema, - async exec() { - return [backModelAction(), { type: "wait", ms: 1500 }]; - }, - }, - { - name: YutoriAction.GOTO_URL, - description: "Navigates to a URL.", - parameters: GotoUrlSchema, - async exec({ url }) { - return [{ type: "goto", url }, { type: "wait", ms: 2000 }]; - }, - }, -]; - -export const YUTORI_FUNCTION_DECLARATIONS = YUTORI_DEFINITIONS.map((definition) => ({ - name: definition.name, - description: definition.description, - parameters: definition.parameters, -})); - -export async function executeYutoriFunctionCall(args: { - translator: ComputerTranslator; - name: string; - input: Record; - options?: YutoriComputerToolsOptions; -}): Promise> { - const definition = YUTORI_DEFINITIONS.find((entry) => entry.name === args.name); - if (!definition) { - const statusText = `failed: unknown Yutori action "${args.name}"`; - return { - content: [{ type: "text", text: statusText }], - details: { action: args.name, statusText, error: statusText }, - isError: true, - }; - } - const ctx: RunContext = { - translator: args.translator, - screen: args.options?.screenSize ?? DEFAULT_YUTORI_SCREEN_SIZE, - attachScreenshot: args.options?.attachScreenshot !== false, - }; - return executeDefinition(definition, args.input, ctx); -} - -async function executeDefinition( - definition: YutoriDefinition, - params: Record, - ctx: RunContext, -): Promise> { - const content: ComputerUseToolResult["content"] = []; - let statusText = "ok"; - let execErr: Error | undefined; - - try { - const actions = await definition.exec(params, ctx); - await ctx.translator.executeBatch(actions); - } catch (err) { - execErr = err instanceof Error ? err : new Error(String(err)); - statusText = `failed: ${execErr.message}`; - } - - content.push({ type: "text", text: statusText }); - - if (!execErr && ctx.attachScreenshot) { - await delay(SCREENSHOT_DELAY_MS); - try { - const png = await ctx.translator.screenshotRaw(); - content.push({ - type: "image", - data: png.toString("base64"), - mimeType: "image/png", - }); - } catch (shotErr) { - content[0] = { - type: "text", - text: `${statusText} (screenshot unavailable: ${(shotErr as Error).message})`, - }; - } - } - - const details: YutoriToolDetails = { - action: definition.name, - statusText, - ...(execErr ? { error: execErr.message } : {}), - }; - - return { - content, - details, - ...(execErr ? { isError: true } : {}), - }; -} - -function point(value: unknown, screen: YutoriScreenSize): [number, number] { - if (!Array.isArray(value) || value.length < 2) { - return [Math.round(screen.width / 2), Math.round(screen.height / 2)]; - } - return [denormalizeX(Number(value[0]) || 0, screen), denormalizeY(Number(value[1]) || 0, screen)]; -} - -function scrollDelta( - direction: YutoriScrollDirection, - amount: number | undefined, - screen: YutoriScreenSize, -): { scroll_x: number; scroll_y: number } { - const px = Math.max(1, Math.trunc(amount ?? 3)) * Math.round(screen.height * SCROLL_UNIT_SCREEN_FRACTION); - switch (direction) { - case "up": - return { scroll_x: 0, scroll_y: -px }; - case "down": - return { scroll_x: 0, scroll_y: px }; - case "left": - return { scroll_x: -px, scroll_y: 0 }; - case "right": - return { scroll_x: px, scroll_y: 0 }; - default: - throw new Error(`unknown scroll direction: ${direction}`); - } -} - -function splitKeyCombination(value: string | undefined): string[] { - if (!value) throw new Error("key_comb or key is required for key_press"); - return value - .split("+") - .map((part) => part.trim()) - .filter(Boolean); -} - -function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} diff --git a/packages/cua-yutori/src/coords.ts b/packages/cua-yutori/src/coords.ts deleted file mode 100644 index 6dab57ea..00000000 --- a/packages/cua-yutori/src/coords.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { YUTORI_COORDINATE_SCALE, type YutoriScreenSize } from "./official"; - -export function denormalizeX(x: number, screen: YutoriScreenSize): number { - return Math.round((x / YUTORI_COORDINATE_SCALE) * screen.width); -} - -export function denormalizeY(y: number, screen: YutoriScreenSize): number { - return Math.round((y / YUTORI_COORDINATE_SCALE) * screen.height); -} diff --git a/packages/cua-yutori/src/index.ts b/packages/cua-yutori/src/index.ts deleted file mode 100644 index 380cefa2..00000000 --- a/packages/cua-yutori/src/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @onkernel/cua-yutori - * - * Provider-neutral Yutori Navigator computer-use helpers backed by - * `@onkernel/cua-translator`. - * - * `pi-agent-core` bindings live under `@onkernel/cua-yutori/pi`. - */ - -export { - executeYutoriFunctionCall, - YUTORI_DEFINITIONS, - YUTORI_FUNCTION_DECLARATIONS, -} from "./computer"; -export type { - YutoriComputerToolsOptions, - YutoriToolDetails, -} from "./computer"; -export { - DEFAULT_YUTORI_SCREEN_SIZE, - YUTORI_ACTION_TYPES, - YUTORI_COORDINATE_SCALE, - YUTORI_MODEL_IDS, - YutoriAction, -} from "./official"; -export type { - YutoriActionType, - YutoriModelId, - YutoriScreenSize, - YutoriScrollDirection, -} from "./official"; -export { denormalizeX, denormalizeY } from "./coords"; -export { yutori } from "./model"; -export type { YutoriModelOptions, YutoriModelRunDetails } from "./model"; -export { buildYutoriSystemPrompt } from "./system-prompt"; -export type { YutoriSystemPromptOptions } from "./system-prompt"; diff --git a/packages/cua-yutori/src/model.ts b/packages/cua-yutori/src/model.ts deleted file mode 100644 index 6245aef1..00000000 --- a/packages/cua-yutori/src/model.ts +++ /dev/null @@ -1,116 +0,0 @@ -import type { - ComputerUseModel, - ComputerUseRunResult, -} from "@onkernel/cua-translator"; -import OpenAI from "openai"; -import type { ChatCompletionMessageParam } from "openai/resources/chat/completions"; -import { executeYutoriFunctionCall, type YutoriComputerToolsOptions } from "./computer"; - -export interface YutoriModelOptions extends YutoriComputerToolsOptions { - apiKey?: string; - baseUrl?: string; - maxCompletionTokens?: number; - temperature?: number; -} - -export interface YutoriModelRunDetails { - finishReason?: string | null; -} - -export function yutori(modelId: string, opts: YutoriModelOptions = {}): ComputerUseModel { - return { - provider: "yutori", - modelId, - async run({ prompt, translator, maxTurns = 50 }): Promise> { - const apiKey = opts.apiKey || process.env.YUTORI_API_KEY; - if (!apiKey) { - throw new Error("missing Yutori API key"); - } - const client = new OpenAI({ - apiKey, - baseURL: opts.baseUrl ?? "https://api.yutori.com/v1", - }); - - const messages: ChatCompletionMessageParam[] = [ - { - role: "user", - content: [ - { type: "text", text: prompt }, - { - type: "image_url", - image_url: { - url: `data:image/png;base64,${await translator.screenshotBase64()}`, - }, - }, - ], - }, - ]; - - for (let turn = 0; turn < maxTurns; turn++) { - const response = await client.chat.completions.create({ - model: modelId, - messages, - max_completion_tokens: opts.maxCompletionTokens ?? 4096, - temperature: opts.temperature ?? 0.3, - }); - const choice = response.choices[0]; - const message = choice?.message; - if (!message) break; - messages.push(message); - - const toolCalls = message.tool_calls ?? []; - if (toolCalls.length === 0) { - return { - text: message.content ?? "(no response)", - provider: "yutori", - modelId, - turns: turn + 1, - details: { finishReason: choice?.finish_reason ?? null }, - }; - } - - for (const toolCall of toolCalls) { - const functionCall = (toolCall as { function?: { name?: string; arguments?: string } }).function; - if (!functionCall?.name) continue; - const result = await executeYutoriFunctionCall({ - translator, - name: functionCall.name, - input: parseArguments(functionCall.arguments ?? ""), - options: opts, - }); - messages.push({ - role: "tool", - tool_call_id: toolCall.id, - content: toYutoriToolContent(result.content), - } as ChatCompletionMessageParam); - } - } - - return { - text: "(max turns reached)", - provider: "yutori", - modelId, - turns: maxTurns, - }; - }, - }; -} - -function parseArguments(value: string): Record { - if (!value.trim()) return {}; - return JSON.parse(value) as Record; -} - -function toYutoriToolContent(content: Array<{ type: string; text?: string; data?: string; mimeType?: string }>): any { - return content.map((part) => - part.type === "image" - ? { - type: "image_url", - image_url: { url: `data:${part.mimeType};base64,${part.data}` }, - } - : { - type: "text", - text: part.text ?? "", - }, - ); -} diff --git a/packages/cua-yutori/src/official.ts b/packages/cua-yutori/src/official.ts deleted file mode 100644 index 8a095c6e..00000000 --- a/packages/cua-yutori/src/official.ts +++ /dev/null @@ -1,41 +0,0 @@ -export const YUTORI_COORDINATE_SCALE = 1000; - -export interface YutoriScreenSize { - width: number; - height: number; -} - -export const DEFAULT_YUTORI_SCREEN_SIZE: YutoriScreenSize = { - width: 1920, - height: 1080, -}; - -export enum YutoriAction { - LEFT_CLICK = "left_click", - DOUBLE_CLICK = "double_click", - TRIPLE_CLICK = "triple_click", - RIGHT_CLICK = "right_click", - SCROLL = "scroll", - TYPE = "type", - KEY_PRESS = "key_press", - HOVER = "hover", - DRAG = "drag", - WAIT = "wait", - REFRESH = "refresh", - GO_BACK = "go_back", - GOTO_URL = "goto_url", -} - -export const YUTORI_ACTION_TYPES = Object.values(YutoriAction); - -export type YutoriActionType = `${YutoriAction}`; -export type YutoriScrollDirection = "up" | "down" | "left" | "right"; - -export const YUTORI_MODEL_IDS = [ - "n1-latest", - "n1-20260203", - "n1.5-latest", - "n1.5-20260428", -] as const; - -export type YutoriModelId = (typeof YUTORI_MODEL_IDS)[number]; diff --git a/packages/cua-yutori/src/pi/index.ts b/packages/cua-yutori/src/pi/index.ts deleted file mode 100644 index 219933f4..00000000 --- a/packages/cua-yutori/src/pi/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { AgentTool } from "@mariozechner/pi-agent-core"; -import type { ComputerTranslator } from "@onkernel/cua-translator"; -import { createYutoriPerActionTools } from "../computer-tool"; -import type { YutoriComputerToolsOptions } from "../computer"; -import { YUTORI_ACTION_TYPES } from "../official"; -export { - YUTORI_CHAT_COMPLETIONS_API, - registerYutoriProvider, - streamSimpleYutori, - streamYutori, -} from "./provider"; -export type { YutoriOptions } from "./provider"; - -const YUTORI_BUILTIN_TOOL_NAMES = new Set(YUTORI_ACTION_TYPES); - -export function createYutoriComputerTools( - translator: ComputerTranslator, - opts: YutoriComputerToolsOptions = {}, -): AgentTool[] { - return createYutoriPerActionTools(translator, opts); -} - -/** - * Yutori provides Navigator browser actions as built-in tools. Keep the local - * AgentTool definitions so pi-agent-core can execute returned tool calls, but - * remove those duplicate function definitions from the outbound payload. - */ -export function yutoriBuiltinToolsOnPayload(payload: unknown): unknown | undefined { - if (!payload || typeof payload !== "object") return undefined; - const current = payload as { tools?: unknown }; - if (!Array.isArray(current.tools)) return undefined; - const tools = current.tools.filter((tool) => { - const name = readToolName(tool); - return !name || !YUTORI_BUILTIN_TOOL_NAMES.has(name); - }); - return { - ...(payload as Record), - ...(tools.length > 0 ? { tools } : { tools: undefined }), - }; -} - -function readToolName(tool: unknown): string | undefined { - if (!tool || typeof tool !== "object") return undefined; - const obj = tool as { function?: { name?: unknown }; name?: unknown }; - if (typeof obj.function?.name === "string") return obj.function.name; - if (typeof obj.name === "string") return obj.name; - return undefined; -} - -export { createYutoriPerActionTools } from "../computer-tool"; -export type { YutoriToolDetails, YutoriComputerToolsOptions } from "../computer"; diff --git a/packages/cua-yutori/src/pi/provider.ts b/packages/cua-yutori/src/pi/provider.ts deleted file mode 100644 index b4ebf0dd..00000000 --- a/packages/cua-yutori/src/pi/provider.ts +++ /dev/null @@ -1,243 +0,0 @@ -import OpenAI from "openai"; -import type { ChatCompletion, ChatCompletionMessageParam } from "openai/resources/chat/completions"; -import { - type AssistantMessage, - type Api, - type Context, - type ImageContent, - type Model, - type SimpleStreamOptions, - type StreamFunction, - type StreamOptions, - type TextContent, - type ToolCall, - createAssistantMessageEventStream, - registerApiProvider, -} from "@mariozechner/pi-ai"; -import { YUTORI_ACTION_TYPES } from "../official"; - -export const YUTORI_CHAT_COMPLETIONS_API = "yutori-chat-completions"; - -const YUTORI_BUILTIN_TOOL_NAMES = new Set(YUTORI_ACTION_TYPES); - -export interface YutoriOptions extends StreamOptions { - temperature?: number; -} - -export const streamYutori: StreamFunction = ( - model, - context, - options, -) => { - const stream = createAssistantMessageEventStream(); - void runYutoriStream(stream, model, context, options); - return stream; -}; - -export const streamSimpleYutori: StreamFunction = ( - model, - context, - options, -) => streamYutori(model, context, options); - -export function registerYutoriProvider(): void { - registerApiProvider({ - api: YUTORI_CHAT_COMPLETIONS_API, - stream: streamYutori, - streamSimple: streamSimpleYutori, - }); -} - -async function runYutoriStream( - stream: ReturnType, - model: Model, - context: Context, - options: YutoriOptions | undefined, -): Promise { - const output: AssistantMessage = { - role: "assistant" as const, - content: [] as AssistantMessage["content"], - api: model.api, - provider: model.provider, - model: model.id, - usage: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - totalTokens: 0, - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }, - }, - stopReason: "stop", - timestamp: Date.now(), - }; - - try { - const apiKey = options?.apiKey || process.env.YUTORI_API_KEY; - if (!apiKey) throw new Error("missing Yutori API key"); - const client = new OpenAI({ - apiKey, - baseURL: model.baseUrl || "https://api.yutori.com/v1", - defaultHeaders: model.headers, - }); - let payload: Record = { - model: model.id, - messages: convertMessages(context), - max_completion_tokens: options?.maxTokens ?? model.maxTokens, - temperature: options?.temperature ?? 0.3, - }; - const tools = convertTools(context); - if (tools.length > 0) payload.tools = tools; - const nextPayload = await options?.onPayload?.(payload, model); - if (nextPayload !== undefined) payload = nextPayload as Record; - - const { data: response, response: rawResponse } = await client.chat.completions - .create(payload as unknown as Parameters[0], { signal: options?.signal }) - .withResponse(); - const completion = response as ChatCompletion; - await options?.onResponse?.({ status: rawResponse.status, headers: headersToRecord(rawResponse.headers) }, model); - - stream.push({ type: "start", partial: output }); - const choice = completion.choices?.[0]; - const message = choice?.message; - output.responseId = completion.id; - output.usage = usageFromYutori(completion.usage); - if (choice?.finish_reason === "tool_calls") output.stopReason = "toolUse"; - else if (choice?.finish_reason === "length") output.stopReason = "length"; - - const text = typeof message?.content === "string" ? message.content : ""; - if (text) { - const contentIndex = output.content.length; - const block: TextContent = { type: "text", text }; - output.content.push(block); - stream.push({ type: "text_start", contentIndex, partial: output }); - stream.push({ type: "text_delta", contentIndex, delta: text, partial: output }); - stream.push({ type: "text_end", contentIndex, content: text, partial: output }); - } - - for (const call of message?.tool_calls ?? []) { - if (call.type !== "function") continue; - const contentIndex = output.content.length; - const toolCall: ToolCall = { - type: "toolCall", - id: call.id, - name: call.function.name, - arguments: parseArguments(call.function.arguments), - }; - output.content.push(toolCall); - stream.push({ type: "toolcall_start", contentIndex, partial: output }); - stream.push({ type: "toolcall_delta", contentIndex, delta: call.function.arguments ?? "", partial: output }); - stream.push({ type: "toolcall_end", contentIndex, toolCall, partial: output }); - } - - stream.push({ type: "done", reason: output.stopReason as "stop" | "length" | "toolUse", message: output }); - stream.end(); - } catch (err) { - output.stopReason = options?.signal?.aborted ? "aborted" : "error"; - output.errorMessage = err instanceof Error ? err.message : String(err); - stream.push({ type: "error", reason: output.stopReason, error: output }); - stream.end(); - } -} - -function convertMessages(context: Context): ChatCompletionMessageParam[] { - const messages: ChatCompletionMessageParam[] = []; - if (context.systemPrompt) { - messages.push({ role: "system", content: context.systemPrompt }); - } - for (const message of context.messages) { - if (message.role === "user") { - messages.push({ - role: "user", - content: typeof message.content === "string" ? message.content : message.content.map(toOpenAIContentPart), - } as ChatCompletionMessageParam); - } else if (message.role === "assistant") { - const text = message.content - .filter((part): part is TextContent => part.type === "text") - .map((part) => part.text) - .join(""); - const toolCalls = message.content - .filter((part): part is ToolCall => part.type === "toolCall") - .map((part) => ({ - id: part.id, - type: "function" as const, - function: { name: part.name, arguments: JSON.stringify(part.arguments ?? {}) }, - })); - messages.push({ - role: "assistant", - content: text || null, - ...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}), - }); - } else if (message.role === "toolResult") { - messages.push({ - role: "tool", - tool_call_id: message.toolCallId, - content: message.content.map(toOpenAIContentPart) as unknown as string, - }); - } - } - return messages; -} - -function toOpenAIContentPart(part: TextContent | ImageContent): Record { - if (part.type === "text") return { type: "text", text: part.text }; - return { - type: "image_url", - image_url: { url: `data:${part.mimeType};base64,${part.data}` }, - }; -} - -function convertTools(context: Context): Array> { - return (context.tools ?? []) - .filter((tool) => !YUTORI_BUILTIN_TOOL_NAMES.has(tool.name)) - .map((tool) => ({ - type: "function", - function: { - name: tool.name, - description: tool.description, - parameters: tool.parameters, - }, - })); -} - -function parseArguments(value: string | undefined): Record { - if (!value?.trim()) return {}; - return JSON.parse(value) as Record; -} - -function usageFromYutori(usage: unknown): typeof baseUsage { - const input = readNumber(usage, "prompt_tokens"); - const output = readNumber(usage, "completion_tokens"); - const totalTokens = readNumber(usage, "total_tokens") || input + output; - return { - input, - output, - cacheRead: 0, - cacheWrite: 0, - totalTokens, - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }, - }; -} - -const baseUsage = { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - totalTokens: 0, - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }, -}; - -function readNumber(value: unknown, key: string): number { - if (!value || typeof value !== "object") return 0; - const n = (value as Record)[key]; - return typeof n === "number" && Number.isFinite(n) ? n : 0; -} - -function headersToRecord(headers: Headers): Record { - const out: Record = {}; - headers.forEach((value, key) => { - out[key] = value; - }); - return out; -} diff --git a/packages/cua-yutori/src/system-prompt.ts b/packages/cua-yutori/src/system-prompt.ts deleted file mode 100644 index 0d1b971e..00000000 --- a/packages/cua-yutori/src/system-prompt.ts +++ /dev/null @@ -1,15 +0,0 @@ -export interface YutoriSystemPromptOptions { - toolPreamble?: boolean; - additionalSystemPrompt?: string; -} - -const YUTORI_BROWSER_NOTE = `Use Yutori Navigator's browser actions for web interaction. Coordinates are normalized by the model and executed by the runtime.`; -const TOOL_PREAMBLE_LINE = `Before every tool call, first output a single short sentence describing what you are about to do.`; - -export function buildYutoriSystemPrompt(opts: YutoriSystemPromptOptions = {}): string { - const sections = [YUTORI_BROWSER_NOTE]; - if (opts.toolPreamble !== false) sections.push(TOOL_PREAMBLE_LINE); - const extra = (opts.additionalSystemPrompt ?? "").trim(); - if (extra) sections.push(extra); - return sections.join("\n\n"); -} diff --git a/packages/cua-yutori/tsconfig.json b/packages/cua-yutori/tsconfig.json deleted file mode 100644 index c2e66df0..00000000 --- a/packages/cua-yutori/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./dist", - "rootDir": "./src" - }, - "include": ["src/**/*"], - "references": [{ "path": "../cua-translator" }] -} diff --git a/tsconfig.json b/tsconfig.json index 49377629..120571fb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,12 +3,6 @@ "references": [ { "path": "./packages/ai" }, { "path": "./packages/agent" }, - { "path": "./packages/cua-translator" }, - { "path": "./packages/cua-openai" }, - { "path": "./packages/cua-anthropic" }, - { "path": "./packages/cua-gemini" }, - { "path": "./packages/cua-tzafon" }, - { "path": "./packages/cua-yutori" }, { "path": "./packages/ptywright" }, { "path": "./packages/cua-cli" } ] From bdffee682958ecdb6e05e6dd073194ff6b433c5c Mon Sep 17 00:00:00 2001 From: rgarcia <72655+rgarcia@users.noreply.github.com> Date: Fri, 12 Jun 2026 06:23:23 +0000 Subject: [PATCH 2/2] PR 4 review fixes: prune lockfile, update docs - restore package-lock.json from main and prune only the deleted workspace entries, so dependency versions for cua-ai and cua-agent stay untouched - rewrite docs/DESIGN.md "Follow-up Direction" to describe the shipped surface instead of completed work - reword README CLI reference pointer; the cua-cli README is now env-var driven - add cli-harness.ts to the CLI runtime flow inventory in docs/architecture.md and .agents/skills/update-docs/SKILL.md --- .agents/skills/update-docs/SKILL.md | 2 +- README.md | 2 +- docs/DESIGN.md | 19 +- docs/architecture.md | 7 + package-lock.json | 2141 ++++++++++++--------------- 5 files changed, 995 insertions(+), 1176 deletions(-) diff --git a/.agents/skills/update-docs/SKILL.md b/.agents/skills/update-docs/SKILL.md index a5a6c6ff..d7102612 100644 --- a/.agents/skills/update-docs/SKILL.md +++ b/.agents/skills/update-docs/SKILL.md @@ -44,7 +44,7 @@ Start with these source-of-truth checks: - Design invariants: `@onkernel/cua-ai` owns provider-specific policy (catalog, tool schemas, payload transforms); `@onkernel/cua-agent` is provider-neutral runtime glue around `pi-agent-core` (no provider names in `packages/agent/src`); every provider difference reaches the agent as data through `CuaRuntimeSpec`; `@onkernel/cua-cli` composes both for orchestration. - Model layer: `packages/ai/src/index.ts`, `getCuaModel`/`listCuaModels`/`parseCuaModelRef`, `resolveCuaRuntimeSpec`, provider adapters, and `api-keys.ts`. - Execution layer: `packages/agent/src/index.ts`, `CuaAgent` and `CuaAgentHarness` wiring, and the canonical CUA tool executors against `@onkernel/sdk`. -- CLI runtime flow: `packages/cua-cli/src/cli.ts`, `harness.ts`, `harness-browser.ts`, `harness-models.ts`, `harness-sessions.ts`, `harness-named-sessions.ts`, `harness-skills.ts`, `print.ts`, `output/harness-jsonl.ts`, `action/`, and `tui/`. +- CLI runtime flow: `packages/cua-cli/src/cli.ts`, `cli-harness.ts`, `harness.ts`, `harness-browser.ts`, `harness-models.ts`, `harness-sessions.ts`, `harness-named-sessions.ts`, `harness-skills.ts`, `print.ts`, `output/harness-jsonl.ts`, `action/`, and `tui/`. - TUI test infrastructure: `packages/ptywright/package.json`, `src/index.ts`, `src/session.ts`, `src/terminal.ts`, and `README.md`. - External drift: provider computer-use docs, `@earendil-works/pi-*` versions, and `@onkernel/sdk` versions in package manifests. diff --git a/README.md b/README.md index 7eeeb782..0bf82c58 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ end-to-end flow. ## CLI reference See [`packages/cua-cli/README.md`](packages/cua-cli/README.md) for the -full CLI reference, configuration schema, and provider routing rules. +full CLI reference, env-var configuration, and model selection. Highlights: diff --git a/docs/DESIGN.md b/docs/DESIGN.md index 6634981c..9f722c12 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -62,13 +62,12 @@ CUA model refs should be provider-qualified, for example persisted config, and transcripts unambiguous. The SDK should not export a default CUA model. -## Follow-up Direction - -The current additive packages are intended to become the public SDK surface. -The expected follow-up work is: - -- migrate `@onkernel/cua-cli` to consume `@onkernel/cua-ai` and - `@onkernel/cua-agent` -- remove the old provider-specific packages -- remove the old translator package once the new internal translator fully - covers the needed behavior +## Current Surface + +`@onkernel/cua-ai`, `@onkernel/cua-agent`, and `@onkernel/cua-cli` are the +public SDK surface. `@onkernel/cua-cli` consumes both `@onkernel/cua-ai` (for +the CUA model catalog and API-key helpers) and `@onkernel/cua-agent` (for the +`CuaAgentHarness` and the re-exported pi-agent-core primitives). The legacy +provider-specific packages and the public translator package have been removed +from the workspace; provider quirks now live inside `@onkernel/cua-ai`'s +internal providers and `@onkernel/cua-agent`'s tool translator. diff --git a/docs/architecture.md b/docs/architecture.md index 53726355..d13c8385 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -145,6 +145,13 @@ env-var-based API keys, a `JsonlSessionRepo`, pi skills, and the pi coding tools, then renders the result to text, JSONL, or pi-tui. - `cli.ts` — argv parsing, mode dispatch. +- `cli-harness.ts` — shared dispatch layer behind `cli.ts`; exports + `runModelsSubcommand`, `runSessionSubcommand`, + `runPrintCommand`, `runActionCommand`, and `runInteractiveCommand`. + The harness-driven entry points share `setupHarnessRuntime`, which + resolves the model, browser, session, and skills before calling + `buildCuaHarness` and routing into `print.ts`, `action/`, or + `tui/main.ts`. - `harness.ts` — `buildCuaHarness(opts)`: one assembly function that produces the `CuaAgentHarness` shared by `--print`, action subcommands, and the interactive TUI. diff --git a/package-lock.json b/package-lock.json index f17dc641..69a46b84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,9 +23,9 @@ } }, "node_modules/@anthropic-ai/sdk": { - "version": "0.91.1", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", - "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", + "version": "0.90.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.90.0.tgz", + "integrity": "sha512-MzZtPabJF1b0FTDl6Z6H5ljphPwACLGP13lu8MTiB8jXaW/YXlpOp+Po2cVou3MPM5+f5toyLnul9whKCy7fBg==", "license": "MIT", "dependencies": { "json-schema-to-ts": "^3.1.1" @@ -198,19 +198,19 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.972.53", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.53.tgz", - "integrity": "sha512-ZfdhIOR41q8TcWEnUac+gCOb+O2LBWdHLmjedXpXz4IEFW2ppNuFcm6p0sMTavpM+zD5TYfpH5Gp7guRyqSgsQ==", + "version": "3.972.52", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.52.tgz", + "integrity": "sha512-szg1nnebqC+Svv6Vfsdf6P/QK8x5g/ghG2CKa/1WkHifRnq0BBmDELj2Qnqk9nPsUvEu/OEcYic97CPLpKqF9g==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.20", "@aws-sdk/credential-provider-env": "^3.972.46", "@aws-sdk/credential-provider-http": "^3.972.48", - "@aws-sdk/credential-provider-login": "^3.972.52", + "@aws-sdk/credential-provider-login": "^3.972.51", "@aws-sdk/credential-provider-process": "^3.972.46", - "@aws-sdk/credential-provider-sso": "^3.972.52", - "@aws-sdk/credential-provider-web-identity": "^3.972.52", - "@aws-sdk/nested-clients": "^3.997.20", + "@aws-sdk/credential-provider-sso": "^3.972.51", + "@aws-sdk/credential-provider-web-identity": "^3.972.51", + "@aws-sdk/nested-clients": "^3.997.19", "@aws-sdk/types": "^3.973.12", "@smithy/core": "^3.24.6", "@smithy/credential-provider-imds": "^4.3.7", @@ -222,13 +222,13 @@ } }, "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.52", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.52.tgz", - "integrity": "sha512-9hu2oR0qH7Fst5Tzdx+UWxm+w5zCXtErTLtOOW5hwwQc170CLwOeniRxyFY6s9mHfGEfC5zFukNBdKBwJR8mhQ==", + "version": "3.972.51", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.51.tgz", + "integrity": "sha512-csHFsH+/VjnI40oqm1l1OqMY4B4kza36DbfcbHcgcbobgjebasqUbTU34xvwUkvtoNGGizbfyMSlMzJWUPv3dQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.20", - "@aws-sdk/nested-clients": "^3.997.20", + "@aws-sdk/nested-clients": "^3.997.19", "@aws-sdk/types": "^3.973.12", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", @@ -239,17 +239,17 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.55", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.55.tgz", - "integrity": "sha512-zMGLa/dhESVqmCD7mmIFFKSwSFrJGScvCXcjvBZEVOOMauFS5JRQvLTMukFpMEFWiV6dTAlsen2ATDBulLPtbg==", + "version": "3.972.54", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.54.tgz", + "integrity": "sha512-vinTSQtziNHxi2nqXF+76jr2sO44q88Ind1qFFVaotNgBaC1rcWDjBug8yoE8n0ov33s21xks9WY5XDHH9SENw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.46", "@aws-sdk/credential-provider-http": "^3.972.48", - "@aws-sdk/credential-provider-ini": "^3.972.53", + "@aws-sdk/credential-provider-ini": "^3.972.52", "@aws-sdk/credential-provider-process": "^3.972.46", - "@aws-sdk/credential-provider-sso": "^3.972.52", - "@aws-sdk/credential-provider-web-identity": "^3.972.52", + "@aws-sdk/credential-provider-sso": "^3.972.51", + "@aws-sdk/credential-provider-web-identity": "^3.972.51", "@aws-sdk/types": "^3.973.12", "@smithy/core": "^3.24.6", "@smithy/credential-provider-imds": "^4.3.7", @@ -277,14 +277,14 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.972.52", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.52.tgz", - "integrity": "sha512-nb2/n4o/HQf+FVpVbZe9vCTFngmuDoIsltMgLAtjixaKzvzhB4J8WSDFyWgnErgLHk55ctWH+I4PU+LIHhyffg==", + "version": "3.972.51", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.51.tgz", + "integrity": "sha512-60qhpQcSDIKIr0AuBlmJezKX0b5nbJPCINiR49N9yJXrEI5tTRwsXVBr0IdSvvsNJyqgiINyoBd++Ed0yvggbw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.20", - "@aws-sdk/nested-clients": "^3.997.20", - "@aws-sdk/token-providers": "3.1066.0", + "@aws-sdk/nested-clients": "^3.997.19", + "@aws-sdk/token-providers": "3.1065.0", "@aws-sdk/types": "^3.973.12", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", @@ -295,13 +295,13 @@ } }, "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { - "version": "3.1066.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1066.0.tgz", - "integrity": "sha512-UqEUJq7dqa44hneLDUcX7UJy95cg8YqEWyakRpvIPnrNS3Mq+UlQHgCDGu5pvwAPtlIW4qcYbvW6reG6++FyvA==", + "version": "3.1065.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1065.0.tgz", + "integrity": "sha512-qdHQntq82gMqG6Tf8xrgmhJxacaYkxW4PEeDg/ISMVJ84EWe7iD6JyCTgbyox3uNDH6vqEJ8GUiTaXCq307zVw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.20", - "@aws-sdk/nested-clients": "^3.997.20", + "@aws-sdk/nested-clients": "^3.997.19", "@aws-sdk/types": "^3.973.12", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", @@ -312,13 +312,13 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.52", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.52.tgz", - "integrity": "sha512-lKj6aRSGbqLmpYmM24bY7a1Xmfcq2vkE3hv8CSPYfc1yCu0BPu/XEJ1L4Fm61MsU6ULLNSG8UGsffNoFUBjESA==", + "version": "3.972.51", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.51.tgz", + "integrity": "sha512-0X5eWsUIp8ItRJeJBBrhQAPzc9AQelDetRTVTsycCAISCCzM17R4hs/vFAPeQ0o0B35sciLiqe/Pwmml909cZA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.20", - "@aws-sdk/nested-clients": "^3.997.20", + "@aws-sdk/nested-clients": "^3.997.19", "@aws-sdk/types": "^3.973.12", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", @@ -377,15 +377,15 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.20", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.20.tgz", - "integrity": "sha512-IYJuLpXp2DEILVQpQOy0PMpkftv0AHEOCn52o0atyOaumA0CdWQ3klPyXdViGYLbNpESsVFMVybvHUeZAuiGxA==", + "version": "3.997.19", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.19.tgz", + "integrity": "sha512-P2Otgf15GBJMKzG6j5Ddf7w+Kz6z2jvesMy874TD3jlMfDWNK7clJeUd7hgigdeVOotjoUP4emcTWVdS9sfZDw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.20", - "@aws-sdk/signature-v4-multi-region": "^3.996.34", + "@aws-sdk/signature-v4-multi-region": "^3.996.33", "@aws-sdk/types": "^3.973.12", "@smithy/core": "^3.24.6", "@smithy/fetch-http-handler": "^5.4.6", @@ -412,9 +412,9 @@ } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.34", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.34.tgz", - "integrity": "sha512-mx1L5qlumSOt/nKM3BFaHE2HVkWwz0i4Bw0pyYO42FfX/FeLlo8YI6csC0gSPprEk6fTIqI+CZN9RwUwKd5krQ==", + "version": "3.996.33", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.33.tgz", + "integrity": "sha512-Hn0RThJEbyOZWV2PV9Z4YD3nitGPxybmyU17dSe9b61WOBcKnqS0WTtM3c1zyZq9WnGiyrfi/i+UBPUk7cM8Ug==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.12", @@ -546,9 +546,7 @@ } }, "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "version": "7.29.2", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -607,27 +605,37 @@ "node": ">=22.19.0" } }, - "node_modules/@earendil-works/pi-ai/node_modules/openai": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-6.26.0.tgz", - "integrity": "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==", - "license": "Apache-2.0", + "node_modules/@earendil-works/pi-ai/node_modules/@anthropic-ai/sdk": { + "version": "0.91.1", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", + "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, "bin": { - "openai": "bin/cli" + "anthropic-ai-sdk": "bin/cli" }, "peerDependencies": { - "ws": "^8.18.0", - "zod": "^3.25 || ^4.0" + "zod": "^3.25.0 || ^4.0.0" }, "peerDependenciesMeta": { - "ws": { - "optional": true - }, "zod": { "optional": true } } }, + "node_modules/@earendil-works/pi-ai/node_modules/@mistralai/mistralai": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-2.2.1.tgz", + "integrity": "sha512-uKU8CZmL2RzYKmplsU01hii4p3pe4HqJefpWNRWXm1Tcm0Sm4xXfwSLIy4k7ZCPlbETCGcp69E7hZs+WOJ5itQ==", + "license": "Apache-2.0", + "dependencies": { + "ws": "^8.18.0", + "zod": "^3.25.0 || ^4.0.0", + "zod-to-json-schema": "^3.25.0" + } + }, "node_modules/@earendil-works/pi-coding-agent": { "version": "0.79.1", "resolved": "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.79.1.tgz", @@ -2426,21 +2434,21 @@ } }, "node_modules/@emnapi/core": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.0.tgz", - "integrity": "sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.2", + "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.0.tgz", - "integrity": "sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "license": "MIT", "optional": true, "dependencies": { @@ -2448,9 +2456,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", "optional": true, @@ -2459,9 +2467,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", - "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", "cpu": [ "ppc64" ], @@ -2476,9 +2484,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", - "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", "cpu": [ "arm" ], @@ -2493,9 +2501,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", - "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", "cpu": [ "arm64" ], @@ -2510,9 +2518,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", - "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", "cpu": [ "x64" ], @@ -2527,9 +2535,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", - "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", "cpu": [ "arm64" ], @@ -2544,9 +2552,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", - "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", "cpu": [ "x64" ], @@ -2561,9 +2569,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", - "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", "cpu": [ "arm64" ], @@ -2578,9 +2586,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", - "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", "cpu": [ "x64" ], @@ -2595,9 +2603,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", - "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", "cpu": [ "arm" ], @@ -2612,9 +2620,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", - "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", "cpu": [ "arm64" ], @@ -2629,9 +2637,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", - "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", "cpu": [ "ia32" ], @@ -2646,9 +2654,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", - "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", "cpu": [ "loong64" ], @@ -2663,9 +2671,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", - "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", "cpu": [ "mips64el" ], @@ -2680,9 +2688,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", - "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", "cpu": [ "ppc64" ], @@ -2697,9 +2705,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", - "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", "cpu": [ "riscv64" ], @@ -2714,9 +2722,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", - "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", "cpu": [ "s390x" ], @@ -2731,9 +2739,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", - "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", "cpu": [ "x64" ], @@ -2748,9 +2756,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", - "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", "cpu": [ "arm64" ], @@ -2765,9 +2773,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", - "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", "cpu": [ "x64" ], @@ -2782,9 +2790,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", - "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", "cpu": [ "arm64" ], @@ -2799,9 +2807,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", - "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", "cpu": [ "x64" ], @@ -2816,9 +2824,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", - "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", "cpu": [ "arm64" ], @@ -2833,9 +2841,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", - "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", "cpu": [ "x64" ], @@ -2850,9 +2858,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", - "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", "cpu": [ "arm64" ], @@ -2867,9 +2875,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", - "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", "cpu": [ "ia32" ], @@ -2884,9 +2892,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", - "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", "cpu": [ "x64" ], @@ -3428,15 +3436,53 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mariozechner/pi-agent-core": { + "version": "0.67.6", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@mariozechner/pi-ai": "^0.67.6" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@mariozechner/pi-ai": { + "version": "0.67.6", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@anthropic-ai/sdk": "^0.90.0", + "@aws-sdk/client-bedrock-runtime": "^3.1030.0", + "@google/genai": "^1.40.0", + "@mistralai/mistralai": "1.14.1", + "@sinclair/typebox": "^0.34.41", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "chalk": "^5.6.2", + "openai": "6.26.0", + "partial-json": "^0.1.7", + "proxy-agent": "^6.5.0", + "undici": "^7.19.1", + "zod-to-json-schema": "^3.24.6" + }, + "bin": { + "pi-ai": "dist/cli.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/@mistralai/mistralai": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-2.2.1.tgz", - "integrity": "sha512-uKU8CZmL2RzYKmplsU01hii4p3pe4HqJefpWNRWXm1Tcm0Sm4xXfwSLIy4k7ZCPlbETCGcp69E7hZs+WOJ5itQ==", - "license": "Apache-2.0", + "version": "1.14.1", + "optional": true, + "peer": true, "dependencies": { "ws": "^8.18.0", "zod": "^3.25.0 || ^4.0.0", - "zod-to-json-schema": "^3.25.0" + "zod-to-json-schema": "^3.24.1" } }, "node_modules/@napi-rs/wasm-runtime": { @@ -3459,9 +3505,9 @@ } }, "node_modules/@nodable/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.1.tgz", + "integrity": "sha512-Pig3HxDIoMgjdEH8OCf/dkcTmLFjJRjWuq8jSnklu284/TKOPibSRERmOykiwmyXTtv61mP+44f3GMx0tLAyjg==", "funding": [ { "type": "github", @@ -3488,14 +3534,12 @@ }, "node_modules/@onkernel/sdk": { "version": "0.49.0", - "resolved": "https://registry.npmjs.org/@onkernel/sdk/-/sdk-0.49.0.tgz", - "integrity": "sha512-nsq5OfkaNKxRTCdXQF8BSTj/Wl0iBIqyWoI/ATgQt15pV+59E22MsZ+IHPiVwwb33tXLtnOqUe5ffOxm7l3GHg==", "license": "Apache-2.0" }, "node_modules/@oxc-project/types": { - "version": "0.135.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.135.0.tgz", - "integrity": "sha512-wR+xRdFkUBMvcAjBJ2q2kcZM6d+DKu2NgoOyxZgYwZdLhmiv6+rnO8PZ/P68kMiZtIKm+pW7zyEJ4kSOs0vo+Q==", + "version": "0.134.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.134.0.tgz", + "integrity": "sha512-T0xuRRKrQFmocH8y+jGfpmSkGcheaJExY9lEihmR1Gm2aH+75B8CzgU2rABRQSzzDxLjZ15Sc0bRVLj5lVeNXQ==", "dev": true, "license": "MIT", "funding": { @@ -3504,65 +3548,46 @@ }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/codegen": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", - "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "version": "2.0.4", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/eventemitter": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", - "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "version": "1.1.0", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/fetch": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", - "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "version": "1.1.0", "license": "BSD-3-Clause", "dependencies": { - "@protobufjs/aspromise": "^1.1.1" + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" } }, "node_modules/@protobufjs/float": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/inquire": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.2.tgz", - "integrity": "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==", + "version": "1.1.0", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/path": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/pool": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/utf8": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", - "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", + "version": "1.1.0", "license": "BSD-3-Clause" }, "node_modules/@quansync/fs": { @@ -3579,9 +3604,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.1.tgz", - "integrity": "sha512-BLf9Wak/gfwVb7NQTQW4wBgL3oAfPy7ArEkhwV543OVw/uY6B47z5xYsqPSZ9PDOorvURPinws6ThaFuNgGLgA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.0.tgz", + "integrity": "sha512-gCYzGOSkYY6Z034suzd20euvds7lPzMEEla62DJGE/ZAlR4OMBnNbvnBSsIGUCAr52gaWMsloGxP4tVGtN5aCA==", "cpu": [ "arm64" ], @@ -3596,9 +3621,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.1.tgz", - "integrity": "sha512-rRZRPy/Ynb+Mxu0O6tfPldHeDgAn0sRij+IOUy6sFdUlv3hArGW/DloE3GfAxtqpOJuRNgF74Nr5gM4xBeU2jQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.0.tgz", + "integrity": "sha512-JQBD77MNgu+4Z6RAyg69acugdrhhVoWesr3l47zohYZ2YV2fwkWMArkN/2p4l6Ei+Sno7W5q+UsKdVWq5Ens0w==", "cpu": [ "arm64" ], @@ -3613,9 +3638,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.1.tgz", - "integrity": "sha512-/MtefPxhKPyWWFM8L45OWiEqRf+eSU2Qv9ZAyTaoZOoGcoPKxbbhjTJO2/U2IThv0uDZ4NWHc3/oTsR6IEOtww==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.0.tgz", + "integrity": "sha512-p/8cXUTK4Sob604e+xxPhVSbDFf29E6J0l/xESM9rdCfn3aDai3nEs6TnMHUsdD5aNlFz0+gDbiGlozLKGa2YA==", "cpu": [ "x64" ], @@ -3630,9 +3655,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.1.tgz", - "integrity": "sha512-202K+cpIi1kx/Zn7AtxBi4LTXSY67Aszb2K9rNsuW7FeBeh0nqoNmYLOSZidV0p88VPBzMmTZcHAdPNo3kRYzQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.0.tgz", + "integrity": "sha512-KbtOSlVv6fElujiZWMcC3aQYhEwLVVf073RcwlSmpGQvIsKZFUqc0ef4sjUuurRwfbiI6JJXji9DQn+86hawmQ==", "cpu": [ "x64" ], @@ -3647,9 +3672,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.1.tgz", - "integrity": "sha512-wl9NfeXNUwrXtUc063tddmZFUI6qiNs1CNOwni0OL4vC7MqVSYugra3ZgtDmtVy8e0DluJTENmzIv2BwqLzT4Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.0.tgz", + "integrity": "sha512-9fZ9i0o0/MQaw7om6Z6TsT7tfCk0jtbEFtC+aPqZL5RNsGWNcHvn6EHgL3dAprjq+AZzPTAQjg2JtpJaMt+6pg==", "cpu": [ "arm" ], @@ -3664,9 +3689,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.1.tgz", - "integrity": "sha512-at2EO4o7D/PJLC4Xik16bU4CcjQE2tSv1LfqMA0TRYQYQihRm3gZeDB8xaX28A9SFedibcAk5DeMCKt4REKG0A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.0.tgz", + "integrity": "sha512-+tog7T66i+yFyIuuAnjL6xmW182W/qTBOUt6BtQ6lBIM1Eikh/fSMz4HGgvuCp5uU0zuIVWng7kDYthjCMOHcg==", "cpu": [ "arm64" ], @@ -3681,9 +3706,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.1.tgz", - "integrity": "sha512-5PUjZx366h9tkJTPJF5eibxOlK3sGoeRiBJLLjjEB5/kLDuhr6qB3LkhqLz1smXNgsX+pBhnbcJBrPE30HznAA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.0.tgz", + "integrity": "sha512-4b7yruLIIj/oZ3GpcLOvxcLCLDMraohn3IhQfN2hBP4w9UekG0DTIajWguJosRGfySf/+h/NwRUiMKoCpxCrqQ==", "cpu": [ "arm64" ], @@ -3698,9 +3723,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.1.tgz", - "integrity": "sha512-1WK84XPeio3tjP1sM/TMXiC0G1i1iq1qGZ71KfNQjEFLU1kwD+Cv5T8nGySg/JUFwLbaScu6ve9DmeXlmqpkFA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.0.tgz", + "integrity": "sha512-QRDOVZd0bhQ5jLsUsCC3dUxDWdTSVY9WMznowZgCGOrZfLLgctWpelhUASEiBwsXfat/JwYnVd1EaxMhqyT+UQ==", "cpu": [ "ppc64" ], @@ -3715,9 +3740,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.1.tgz", - "integrity": "sha512-1nS1X5z1uMJ369RU25hTpKCFvUwXZp12dIzlzk4S+UxCTcSVGsAE6tzkOSufv/7jnmAtK0ZlrsJxh2fGmsnVSw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.0.tgz", + "integrity": "sha512-ypxT+Hq76NFG7woFbNbySnGEajFuYuIXeKz/jfCU+lXUoxfi3zLE6OG/ZQNeK3RpZSYJlAe2bokpsQ046CaieQ==", "cpu": [ "s390x" ], @@ -3732,9 +3757,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.1.tgz", - "integrity": "sha512-NwX/wspnq4vYyMFsqbYvzums3ki/Tk8FZbMzMAovPDp3OfLeYKby/D+9osokadXuYEV3OvpeHlwnr/bG8QMixA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.0.tgz", + "integrity": "sha512-IdovCmfROFmpTLahdecTDFL74aLERVYN68F/mLZjfVh6LfoplPfI6deyHNMTcVujbokDV5k05XrFO22zfv+qjg==", "cpu": [ "x64" ], @@ -3749,9 +3774,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.1.tgz", - "integrity": "sha512-+n46LhDrJFQM+229y4oXtVpj1G50U/+XuHMlpnisFTEXhrg9f/YIjp/HymX+PVJjBEr7XHRs3CFLelV464pqwA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.0.tgz", + "integrity": "sha512-pcA8xlFp2tyk9T2R6Fi/rPe3bQ1MA+sSMDNUU5Ogu80GHOatkE4P8YCreGAvZErm5Ho2YRXnyvNrWiRncfVysQ==", "cpu": [ "x64" ], @@ -3766,9 +3791,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.1.tgz", - "integrity": "sha512-qGwEu47zOWYo7LdRHhCWTNhzwGtxXpdY6CERs8QEOqC0PXGGics/e3vHnyEUKt8xK6YkbZXFUCeklrpB6js8ag==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.0.tgz", + "integrity": "sha512-4+fexHayrLCWpriPh4c6dNvL4an34DEZCG7zOM/FD5QNF6h8DT+bDXzyB/kfC8lDJbaFb7jKShtnjDQFXVQEjg==", "cpu": [ "arm64" ], @@ -3783,9 +3808,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.1.tgz", - "integrity": "sha512-qczfgEH8u0wHGGOXtA7UMAybNKuQjjEXairyQaw4WzjiMztfbgatG1h4OKays/smhtwbWltpKCRGtVhU6h40Sg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.0.tgz", + "integrity": "sha512-SbL++MNmOw6QamrwIGDMSSfM4ceTzFr+RjbOExJSLLBinScU4WI5OdA413h1qwPw2yH7lVF1+H4svQ+6mSXKTQ==", "cpu": [ "wasm32" ], @@ -3793,18 +3818,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "1.11.0", - "@emnapi/runtime": "1.11.0", - "@napi-rs/wasm-runtime": "^1.1.5" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.1.tgz", - "integrity": "sha512-4psXSh63mSbwJF+mB8/9yfUUEzBiHYcUjxa32EO9ZwKy0Ypwjcg4F10D8SvVXgd+isy2UUUjF9HJJnDu1T/4Gg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.0.tgz", + "integrity": "sha512-+xTE6XC7wBgk0VKRXGG+QAnyW5S9b8vfsFpiMjf0waQTmSQSU8onsH/beyZ8X4aXVveJnotiy7VDjLOaW8bTrg==", "cpu": [ "arm64" ], @@ -3819,9 +3844,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.1.tgz", - "integrity": "sha512-MUvC/HLXVjzkQkWiExdVTEEWf0py+GfWm8WKSZsekG3ih6a21iy0BHPF07X3JIf3ifoklZXTIaHTLPBgH1C3dw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.0.tgz", + "integrity": "sha512-Ogji1TQNqH3ACLnYr+1Ns1nyrJ0CO2P585u9Hsh02pXvtFiFpgtgT2b3P4PnCOU86VVCvqtAeCN4OftMT8KU4w==", "cpu": [ "x64" ], @@ -3843,9 +3868,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.61.1.tgz", - "integrity": "sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz", + "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==", "cpu": [ "arm" ], @@ -3857,9 +3882,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.61.1.tgz", - "integrity": "sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz", + "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==", "cpu": [ "arm64" ], @@ -3871,9 +3896,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.61.1.tgz", - "integrity": "sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz", + "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==", "cpu": [ "arm64" ], @@ -3885,9 +3910,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.61.1.tgz", - "integrity": "sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz", + "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==", "cpu": [ "x64" ], @@ -3899,9 +3924,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.61.1.tgz", - "integrity": "sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz", + "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==", "cpu": [ "arm64" ], @@ -3913,9 +3938,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.61.1.tgz", - "integrity": "sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz", + "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==", "cpu": [ "x64" ], @@ -3927,9 +3952,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.61.1.tgz", - "integrity": "sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz", + "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==", "cpu": [ "arm" ], @@ -3941,9 +3966,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.61.1.tgz", - "integrity": "sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz", + "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==", "cpu": [ "arm" ], @@ -3955,9 +3980,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.61.1.tgz", - "integrity": "sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz", + "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==", "cpu": [ "arm64" ], @@ -3969,9 +3994,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.61.1.tgz", - "integrity": "sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz", + "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==", "cpu": [ "arm64" ], @@ -3983,9 +4008,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.61.1.tgz", - "integrity": "sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz", + "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==", "cpu": [ "loong64" ], @@ -3997,9 +4022,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.61.1.tgz", - "integrity": "sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz", + "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==", "cpu": [ "loong64" ], @@ -4011,9 +4036,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.61.1.tgz", - "integrity": "sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz", + "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==", "cpu": [ "ppc64" ], @@ -4025,9 +4050,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.61.1.tgz", - "integrity": "sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz", + "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==", "cpu": [ "ppc64" ], @@ -4039,9 +4064,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.61.1.tgz", - "integrity": "sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz", + "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==", "cpu": [ "riscv64" ], @@ -4053,9 +4078,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.61.1.tgz", - "integrity": "sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz", + "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==", "cpu": [ "riscv64" ], @@ -4067,9 +4092,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.61.1.tgz", - "integrity": "sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz", + "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==", "cpu": [ "s390x" ], @@ -4081,9 +4106,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.1.tgz", - "integrity": "sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", + "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", "cpu": [ "x64" ], @@ -4095,9 +4120,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.61.1.tgz", - "integrity": "sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz", + "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==", "cpu": [ "x64" ], @@ -4109,9 +4134,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.61.1.tgz", - "integrity": "sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz", + "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==", "cpu": [ "x64" ], @@ -4123,9 +4148,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.61.1.tgz", - "integrity": "sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz", + "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==", "cpu": [ "arm64" ], @@ -4137,9 +4162,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.61.1.tgz", - "integrity": "sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz", + "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==", "cpu": [ "arm64" ], @@ -4151,9 +4176,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.61.1.tgz", - "integrity": "sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz", + "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==", "cpu": [ "ia32" ], @@ -4165,9 +4190,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.61.1.tgz", - "integrity": "sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz", + "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==", "cpu": [ "x64" ], @@ -4179,9 +4204,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.1.tgz", - "integrity": "sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz", + "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==", "cpu": [ "x64" ], @@ -4192,6 +4217,10 @@ "win32" ] }, + "node_modules/@sinclair/typebox": { + "version": "0.34.49", + "license": "MIT" + }, "node_modules/@smithy/core": { "version": "3.24.6", "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.24.6.tgz", @@ -4312,6 +4341,12 @@ "node": ">=14.0.0" } }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/@tybys/wasm-util": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", @@ -4342,9 +4377,9 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, @@ -4357,8 +4392,6 @@ }, "node_modules/@types/node": { "version": "22.18.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.4.tgz", - "integrity": "sha512-UJdblFqXymSBhmZf96BnbisoFIr8ooiiBRMolQgg77Ea+VM37jXw76C2LQr9n8wm9+i/OvlUlW6xSvqwzwqznw==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -4366,8 +4399,6 @@ }, "node_modules/@types/retry": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "license": "MIT" }, "node_modules/@tzafon/lightcone": { @@ -4377,15 +4408,15 @@ "license": "Apache-2.0" }, "node_modules/@vitest/expect": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.6.tgz", - "integrity": "sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", "dev": true, "license": "MIT", "dependencies": { "@types/chai": "^5.2.2", - "@vitest/spy": "3.2.6", - "@vitest/utils": "3.2.6", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" }, @@ -4394,13 +4425,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.6.tgz", - "integrity": "sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.2.6", + "@vitest/spy": "3.2.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, @@ -4421,9 +4452,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.6.tgz", - "integrity": "sha512-lb7XXXzmm2h2ASzFnRvQpDo6onT1NmMJA3tkGTWiBFtRJ9lxGY3d3mm/Apt36gej2bkkOVLL/yTOtufDaFa/jA==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", "dev": true, "license": "MIT", "dependencies": { @@ -4434,13 +4465,13 @@ } }, "node_modules/@vitest/runner": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.6.tgz", - "integrity": "sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.2.6", + "@vitest/utils": "3.2.4", "pathe": "^2.0.3", "strip-literal": "^3.0.0" }, @@ -4449,13 +4480,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.6.tgz", - "integrity": "sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.6", + "@vitest/pretty-format": "3.2.4", "magic-string": "^0.30.17", "pathe": "^2.0.3" }, @@ -4464,9 +4495,9 @@ } }, "node_modules/@vitest/spy": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.6.tgz", - "integrity": "sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", "dev": true, "license": "MIT", "dependencies": { @@ -4477,13 +4508,13 @@ } }, "node_modules/@vitest/utils": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.6.tgz", - "integrity": "sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg==", + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.6", + "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" }, @@ -4493,13 +4524,44 @@ }, "node_modules/agent-base": { "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "license": "MIT", "engines": { "node": ">= 14" } }, + "node_modules/ajv": { + "version": "8.18.0", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ansis": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.3.1.tgz", @@ -4550,10 +4612,20 @@ "url": "https://github.com/sponsors/sxzz" } }, + "node_modules/ast-types": { + "version": "0.13.4", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "funding": [ { "type": "github", @@ -4570,10 +4642,17 @@ ], "license": "MIT" }, + "node_modules/basic-ftp": { + "version": "5.3.0", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/bignumber.js": { "version": "9.3.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", - "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", "license": "MIT", "engines": { "node": "*" @@ -4597,18 +4676,16 @@ }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", "license": "BSD-3-Clause" }, "node_modules/cac": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cac/-/cac-7.0.0.tgz", - "integrity": "sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==", + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=20.19.0" + "node": ">=8" } }, "node_modules/chai": { @@ -4628,6 +4705,18 @@ "node": ">=18" } }, + "node_modules/chalk": { + "version": "5.6.2", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/check-error": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", @@ -4640,8 +4729,6 @@ }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", "license": "MIT", "engines": { "node": ">= 12" @@ -4649,8 +4736,6 @@ }, "node_modules/debug": { "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4681,6 +4766,20 @@ "dev": true, "license": "MIT" }, + "node_modules/degenerator": { + "version": "5.0.1", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -4713,8 +4812,6 @@ }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" @@ -4738,9 +4835,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", - "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4751,32 +4848,75 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.1", - "@esbuild/android-arm": "0.28.1", - "@esbuild/android-arm64": "0.28.1", - "@esbuild/android-x64": "0.28.1", - "@esbuild/darwin-arm64": "0.28.1", - "@esbuild/darwin-x64": "0.28.1", - "@esbuild/freebsd-arm64": "0.28.1", - "@esbuild/freebsd-x64": "0.28.1", - "@esbuild/linux-arm": "0.28.1", - "@esbuild/linux-arm64": "0.28.1", - "@esbuild/linux-ia32": "0.28.1", - "@esbuild/linux-loong64": "0.28.1", - "@esbuild/linux-mips64el": "0.28.1", - "@esbuild/linux-ppc64": "0.28.1", - "@esbuild/linux-riscv64": "0.28.1", - "@esbuild/linux-s390x": "0.28.1", - "@esbuild/linux-x64": "0.28.1", - "@esbuild/netbsd-arm64": "0.28.1", - "@esbuild/netbsd-x64": "0.28.1", - "@esbuild/openbsd-arm64": "0.28.1", - "@esbuild/openbsd-x64": "0.28.1", - "@esbuild/openharmony-arm64": "0.28.1", - "@esbuild/sunos-x64": "0.28.1", - "@esbuild/win32-arm64": "0.28.1", - "@esbuild/win32-ia32": "0.28.1", - "@esbuild/win32-x64": "0.28.1" + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "engines": { + "node": ">=4.0" } }, "node_modules/estree-walker": { @@ -4789,6 +4929,15 @@ "@types/estree": "^1.0.0" } }, + "node_modules/esutils": { + "version": "2.0.3", + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/expect-type": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", @@ -4801,10 +4950,30 @@ }, "node_modules/extend": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause", + "optional": true, + "peer": true + }, "node_modules/fast-xml-builder": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", @@ -4862,8 +5031,6 @@ }, "node_modules/fetch-blob": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", "funding": [ { "type": "github", @@ -4885,8 +5052,6 @@ }, "node_modules/formdata-polyfill": { "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", "license": "MIT", "dependencies": { "fetch-blob": "^3.1.2" @@ -4911,9 +5076,7 @@ } }, "node_modules/gaxios": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.5.tgz", - "integrity": "sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg==", + "version": "7.1.4", "license": "Apache-2.0", "dependencies": { "extend": "^3.0.2", @@ -4926,8 +5089,6 @@ }, "node_modules/gcp-metadata": { "version": "8.1.2", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", - "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", "license": "Apache-2.0", "dependencies": { "gaxios": "^7.0.0", @@ -4951,25 +5112,43 @@ } }, "node_modules/get-tsconfig": { - "version": "5.0.0-beta.5", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.5.tgz", - "integrity": "sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", "dev": true, "license": "MIT", "dependencies": { "resolve-pkg-maps": "^1.0.0" }, - "engines": { - "node": ">=20.20.0" - }, "funding": { "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/get-uri": { + "version": "6.0.5", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/get-uri/node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 14" + } + }, "node_modules/google-auth-library": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.7.0.tgz", - "integrity": "sha512-QpTAbNJ36TliZLx3TTtahR8HG0hN9RllL1e3FymOvQSIKK8JmgV58H924ub2wa2DsS3ANjjP1Aw1N+Ramc8hqQ==", + "version": "10.6.2", "license": "Apache-2.0", "dependencies": { "base64-js": "^1.3.0", @@ -4985,8 +5164,6 @@ }, "node_modules/google-logging-utils": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", - "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", "license": "Apache-2.0", "engines": { "node": ">=14" @@ -5001,8 +5178,6 @@ }, "node_modules/http-proxy-agent": { "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "license": "MIT", "dependencies": { "agent-base": "^7.1.0", @@ -5014,8 +5189,6 @@ }, "node_modules/https-proxy-agent": { "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -5027,8 +5200,6 @@ }, "node_modules/ignore": { "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "license": "MIT", "engines": { "node": ">= 4" @@ -5047,6 +5218,15 @@ "url": "https://github.com/sponsors/sxzz" } }, + "node_modules/ip-address": { + "version": "10.1.0", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 12" + } + }, "node_modules/js-tokens": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", @@ -5069,8 +5249,6 @@ }, "node_modules/json-bigint": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", "license": "MIT", "dependencies": { "bignumber.js": "^9.0.0" @@ -5078,8 +5256,6 @@ }, "node_modules/json-schema-to-ts": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", - "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", @@ -5089,10 +5265,14 @@ "node": ">=16" } }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/jwa": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", "dependencies": { "buffer-equal-constant-time": "^1.0.1", @@ -5102,8 +5282,6 @@ }, "node_modules/jws": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", - "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { "jwa": "^2.0.1", @@ -5112,8 +5290,6 @@ }, "node_modules/long": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", - "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", "license": "Apache-2.0" }, "node_modules/loupe": { @@ -5123,6 +5299,15 @@ "dev": true, "license": "MIT" }, + "node_modules/lru-cache": { + "version": "7.18.3", + "license": "ISC", + "optional": true, + "peer": true, + "engines": { + "node": ">=12" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -5135,8 +5320,6 @@ }, "node_modules/marked": { "version": "15.0.12", - "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", - "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -5147,8 +5330,6 @@ }, "node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/nanoid": { @@ -5170,10 +5351,19 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/netmask": { + "version": "2.1.1", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/node-addon-api": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.8.0.tgz", - "integrity": "sha512-c5Ko1fZJIJmzhFIkhRN76WTq+fC6tWnGy9CXA0fA+XygsWZmEwG8vmbkNqxMyoaa0Tin4djul49NzdVcJJcjeA==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", "license": "MIT", "engines": { "node": "^18 || ^20 || >= 21" @@ -5181,9 +5371,6 @@ }, "node_modules/node-domexception": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", "funding": [ { "type": "github", @@ -5201,8 +5388,6 @@ }, "node_modules/node-fetch": { "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "license": "MIT", "dependencies": { "data-uri-to-buffer": "^4.0.0", @@ -5248,10 +5433,11 @@ } }, "node_modules/openai": { - "version": "6.42.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-6.42.0.tgz", - "integrity": "sha512-1WFEt/uXMXOLhYRNkgJWo08Y2YNvNwpVU72K7ibrWgWpNOXd4VojXLbe6SQ4bLiUQ3Y8jz4IiyVkylJCL1DtZg==", + "version": "6.26.0", "license": "Apache-2.0", + "bin": { + "openai": "bin/cli" + }, "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" @@ -5267,8 +5453,6 @@ }, "node_modules/p-retry": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "license": "MIT", "dependencies": { "@types/retry": "0.12.0", @@ -5278,10 +5462,40 @@ "node": ">=8" } }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/partial-json": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", - "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", "license": "MIT" }, "node_modules/path-expression-matcher": { @@ -5337,9 +5551,9 @@ } }, "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.13.tgz", + "integrity": "sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==", "dev": true, "funding": [ { @@ -5357,7 +5571,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.12", + "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -5366,29 +5580,52 @@ } }, "node_modules/protobufjs": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.3.tgz", - "integrity": "sha512-+k0vdJKNdW+Vu+dYe8tZA/VvQb6XKNWexC6URwBFXxNnjLJz9nQJCemGyNgRAWD+B7+nGNc9qMPGwcD7s4nzUw==", + "version": "7.5.5", "hasInstallScript": true, "license": "BSD-3-Clause", "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/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.2", + "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.1", + "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", - "long": "^5.3.2" + "long": "^5.0.0" }, "engines": { "node": ">=12.0.0" } }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/quansync": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/quansync/-/quansync-1.0.0.tgz", @@ -5406,6 +5643,15 @@ ], "license": "MIT" }, + "node_modules/require-from-string": { + "version": "2.0.2", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -5418,21 +5664,19 @@ }, "node_modules/retry": { "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/rolldown": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.1.tgz", - "integrity": "sha512-IN750c0p+s3jqJIsFLRZrQazmbAB1kkQDTtQjSt/gbS2ywLhlv4R5Shazer0FZKmuo/BsO3/w2UoYnUjuOZqHg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.0.tgz", + "integrity": "sha512-zpMvlJhs5PkXRTtKc0CaLBVI9AR/VDiJFpM+kx//hgToEca7FgMlGjaRIisXBcb19T76LswgmKECSQ96hjWr5A==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.135.0", + "@oxc-project/types": "=0.134.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -5442,21 +5686,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.1.1", - "@rolldown/binding-darwin-arm64": "1.1.1", - "@rolldown/binding-darwin-x64": "1.1.1", - "@rolldown/binding-freebsd-x64": "1.1.1", - "@rolldown/binding-linux-arm-gnueabihf": "1.1.1", - "@rolldown/binding-linux-arm64-gnu": "1.1.1", - "@rolldown/binding-linux-arm64-musl": "1.1.1", - "@rolldown/binding-linux-ppc64-gnu": "1.1.1", - "@rolldown/binding-linux-s390x-gnu": "1.1.1", - "@rolldown/binding-linux-x64-gnu": "1.1.1", - "@rolldown/binding-linux-x64-musl": "1.1.1", - "@rolldown/binding-openharmony-arm64": "1.1.1", - "@rolldown/binding-wasm32-wasi": "1.1.1", - "@rolldown/binding-win32-arm64-msvc": "1.1.1", - "@rolldown/binding-win32-x64-msvc": "1.1.1" + "@rolldown/binding-android-arm64": "1.1.0", + "@rolldown/binding-darwin-arm64": "1.1.0", + "@rolldown/binding-darwin-x64": "1.1.0", + "@rolldown/binding-freebsd-x64": "1.1.0", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.0", + "@rolldown/binding-linux-arm64-gnu": "1.1.0", + "@rolldown/binding-linux-arm64-musl": "1.1.0", + "@rolldown/binding-linux-ppc64-gnu": "1.1.0", + "@rolldown/binding-linux-s390x-gnu": "1.1.0", + "@rolldown/binding-linux-x64-gnu": "1.1.0", + "@rolldown/binding-linux-x64-musl": "1.1.0", + "@rolldown/binding-openharmony-arm64": "1.1.0", + "@rolldown/binding-wasm32-wasi": "1.1.0", + "@rolldown/binding-win32-arm64-msvc": "1.1.0", + "@rolldown/binding-win32-x64-msvc": "1.1.0" } }, "node_modules/rolldown-plugin-dts": { @@ -5503,14 +5747,30 @@ } } }, + "node_modules/rolldown-plugin-dts/node_modules/get-tsconfig": { + "version": "5.0.0-beta.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.5.tgz", + "integrity": "sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "engines": { + "node": ">=20.20.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/rollup": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.61.1.tgz", - "integrity": "sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz", + "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.9" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -5520,38 +5780,36 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.61.1", - "@rollup/rollup-android-arm64": "4.61.1", - "@rollup/rollup-darwin-arm64": "4.61.1", - "@rollup/rollup-darwin-x64": "4.61.1", - "@rollup/rollup-freebsd-arm64": "4.61.1", - "@rollup/rollup-freebsd-x64": "4.61.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.61.1", - "@rollup/rollup-linux-arm-musleabihf": "4.61.1", - "@rollup/rollup-linux-arm64-gnu": "4.61.1", - "@rollup/rollup-linux-arm64-musl": "4.61.1", - "@rollup/rollup-linux-loong64-gnu": "4.61.1", - "@rollup/rollup-linux-loong64-musl": "4.61.1", - "@rollup/rollup-linux-ppc64-gnu": "4.61.1", - "@rollup/rollup-linux-ppc64-musl": "4.61.1", - "@rollup/rollup-linux-riscv64-gnu": "4.61.1", - "@rollup/rollup-linux-riscv64-musl": "4.61.1", - "@rollup/rollup-linux-s390x-gnu": "4.61.1", - "@rollup/rollup-linux-x64-gnu": "4.61.1", - "@rollup/rollup-linux-x64-musl": "4.61.1", - "@rollup/rollup-openbsd-x64": "4.61.1", - "@rollup/rollup-openharmony-arm64": "4.61.1", - "@rollup/rollup-win32-arm64-msvc": "4.61.1", - "@rollup/rollup-win32-ia32-msvc": "4.61.1", - "@rollup/rollup-win32-x64-gnu": "4.61.1", - "@rollup/rollup-win32-x64-msvc": "4.61.1", + "@rollup/rollup-android-arm-eabi": "4.60.2", + "@rollup/rollup-android-arm64": "4.60.2", + "@rollup/rollup-darwin-arm64": "4.60.2", + "@rollup/rollup-darwin-x64": "4.60.2", + "@rollup/rollup-freebsd-arm64": "4.60.2", + "@rollup/rollup-freebsd-x64": "4.60.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", + "@rollup/rollup-linux-arm-musleabihf": "4.60.2", + "@rollup/rollup-linux-arm64-gnu": "4.60.2", + "@rollup/rollup-linux-arm64-musl": "4.60.2", + "@rollup/rollup-linux-loong64-gnu": "4.60.2", + "@rollup/rollup-linux-loong64-musl": "4.60.2", + "@rollup/rollup-linux-ppc64-gnu": "4.60.2", + "@rollup/rollup-linux-ppc64-musl": "4.60.2", + "@rollup/rollup-linux-riscv64-gnu": "4.60.2", + "@rollup/rollup-linux-riscv64-musl": "4.60.2", + "@rollup/rollup-linux-s390x-gnu": "4.60.2", + "@rollup/rollup-linux-x64-gnu": "4.60.2", + "@rollup/rollup-linux-x64-musl": "4.60.2", + "@rollup/rollup-openbsd-x64": "4.60.2", + "@rollup/rollup-openharmony-arm64": "4.60.2", + "@rollup/rollup-win32-arm64-msvc": "4.60.2", + "@rollup/rollup-win32-ia32-msvc": "4.60.2", + "@rollup/rollup-win32-x64-gnu": "4.60.2", + "@rollup/rollup-win32-x64-msvc": "4.60.2", "fsevents": "~2.3.2" } }, "node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "funding": [ { "type": "github", @@ -5631,6 +5889,53 @@ "dev": true, "license": "ISC" }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.7", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "license": "BSD-3-Clause", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -5650,8 +5955,6 @@ }, "node_modules/std-env": { "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", "dev": true, "license": "MIT" }, @@ -5691,14 +5994,11 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", - "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } + "license": "MIT" }, "node_modules/tinyglobby": { "version": "0.2.17", @@ -5759,8 +6059,6 @@ }, "node_modules/ts-algebra": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", - "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", "license": "MIT" }, "node_modules/tsdown": { @@ -5836,20 +6134,39 @@ } } }, + "node_modules/tsdown/node_modules/cac": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cac/-/cac-7.0.0.tgz", + "integrity": "sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/tsdown/node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/tsx": { - "version": "4.22.4", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz", - "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "~0.28.0" + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" }, "bin": { "tsx": "dist/cli.mjs" @@ -5869,8 +6186,6 @@ }, "node_modules/typescript": { "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5895,16 +6210,23 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/undici": { + "version": "7.25.0", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/undici-types": { "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "license": "MIT" }, "node_modules/vite": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.5.tgz", - "integrity": "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", + "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", "dev": true, "license": "MIT", "dependencies": { @@ -5999,670 +6321,161 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/vite-node/node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "node_modules/vitest": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, "engines": { - "node": ">=8" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } } }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", - "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", - "cpu": [ - "ppc64" - ], - "dev": true, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", "license": "MIT", - "optional": true, - "os": [ - "aix" - ], "engines": { - "node": ">=18" + "node": ">= 8" } }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", - "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", - "cpu": [ - "arm" - ], + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", - "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/ws": { + "version": "8.20.0", "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", - "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", - "cpu": [ - "x64" + "node_modules/xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } ], - "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": ">=16.0.0" } }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", - "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, "engines": { - "node": ">=18" + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", - "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/zod": { + "version": "4.3.6", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", - "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", - "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", - "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", - "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", - "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", - "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", - "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", - "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", - "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", - "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", - "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", - "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", - "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", - "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", - "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", - "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", - "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", - "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", - "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", - "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", - "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.7", - "@esbuild/android-arm": "0.27.7", - "@esbuild/android-arm64": "0.27.7", - "@esbuild/android-x64": "0.27.7", - "@esbuild/darwin-arm64": "0.27.7", - "@esbuild/darwin-x64": "0.27.7", - "@esbuild/freebsd-arm64": "0.27.7", - "@esbuild/freebsd-x64": "0.27.7", - "@esbuild/linux-arm": "0.27.7", - "@esbuild/linux-arm64": "0.27.7", - "@esbuild/linux-ia32": "0.27.7", - "@esbuild/linux-loong64": "0.27.7", - "@esbuild/linux-mips64el": "0.27.7", - "@esbuild/linux-ppc64": "0.27.7", - "@esbuild/linux-riscv64": "0.27.7", - "@esbuild/linux-s390x": "0.27.7", - "@esbuild/linux-x64": "0.27.7", - "@esbuild/netbsd-arm64": "0.27.7", - "@esbuild/netbsd-x64": "0.27.7", - "@esbuild/openbsd-arm64": "0.27.7", - "@esbuild/openbsd-x64": "0.27.7", - "@esbuild/openharmony-arm64": "0.27.7", - "@esbuild/sunos-x64": "0.27.7", - "@esbuild/win32-arm64": "0.27.7", - "@esbuild/win32-ia32": "0.27.7", - "@esbuild/win32-x64": "0.27.7" - } - }, - "node_modules/vitest": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.6.tgz", - "integrity": "sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/expect": "3.2.6", - "@vitest/mocker": "3.2.6", - "@vitest/pretty-format": "^3.2.6", - "@vitest/runner": "3.2.6", - "@vitest/snapshot": "3.2.6", - "@vitest/spy": "3.2.6", - "@vitest/utils": "3.2.6", - "chai": "^5.2.0", - "debug": "^4.4.1", - "expect-type": "^1.2.1", - "magic-string": "^0.30.17", - "pathe": "^2.0.3", - "picomatch": "^4.0.2", - "std-env": "^3.9.0", - "tinybench": "^2.9.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.14", - "tinypool": "^1.1.1", - "tinyrainbow": "^2.0.0", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", - "vite-node": "3.2.4", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/debug": "^4.1.12", - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.2.6", - "@vitest/ui": "3.2.6", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/debug": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ws": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", - "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", - "license": "MIT", - "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 - } - } - }, - "node_modules/xml-naming": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", - "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT", - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "funding": { + "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/zod-to-json-schema": { "version": "3.25.2", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", - "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", "license": "ISC", "peerDependencies": { "zod": "^3.25.28 || ^4"