From 7b1ecf317dfef2c6e3189d857a5705dc45dbd144 Mon Sep 17 00:00:00 2001 From: rgarcia <72655+rgarcia@users.noreply.github.com> Date: Wed, 19 Aug 2026 17:25:48 +0000 Subject: [PATCH 1/2] Rename the package to Browser Loop --- .agents/skills/release/SKILL.md | 52 +++++------ .agents/skills/update-docs/SKILL.md | 10 +-- .github/workflows/ci.yml | 16 ++-- ...ease-loop.yml => release-browser-loop.yml} | 28 +++--- README.md | 42 ++++----- docs/architecture.md | 46 +++++----- docs/npm-releases.md | 85 ++++++++++-------- package-lock.json | 18 ++-- package.json | 6 +- packages/{loop => browser-loop}/CHANGELOG.md | 6 +- packages/{loop => browser-loop}/README.md | 62 ++++++------- .../docs/supported-models.md | 10 +-- .../{loop => browser-loop}/examples/agent.ts | 0 .../examples/anthropic-native-smoke.ts | 0 .../examples/harness.ts | 0 .../examples/quickstart.ts | 0 .../examples/screenshot.png | Bin .../examples/shared/logging.ts | 0 .../examples/shared/options.ts | 0 .../examples/shared/scenarios.ts | 0 .../examples/shared/tools.ts | 0 packages/{loop => browser-loop}/package.json | 10 +-- .../scripts/native-action-probe.ts | 8 +- .../src/core/actions/browser.ts | 0 .../src/core/actions/computer.ts | 0 .../src/core/actions/index.ts | 0 .../src/core/anthropic-native.ts | 0 .../src/core/browser-result-format.ts | 0 .../{loop => browser-loop}/src/core/menu.ts | 0 .../src/core/model-info.ts | 0 .../src/core/resources.ts | 0 .../src/core/tool-catalog.ts | 2 +- .../{loop => browser-loop}/src/core/tools.ts | 0 .../src/core/translator/browser-act.ts | 0 .../browser-document-reconciliation.ts | 0 .../translator/browser-frame-collection.ts | 0 .../core/translator/browser-observation.ts | 0 .../core/translator/browser-ref-lifecycle.ts | 0 .../src/core/translator/browser-wait.ts | 0 .../src/core/translator/browser.ts | 0 .../src/core/translator/cdp.ts | 0 .../src/core/translator/keys.ts | 0 .../src/core/translator/translator.ts | 0 .../src/core/translator/types.ts | 0 .../{loop => browser-loop}/src/core/url.ts | 0 packages/{loop => browser-loop}/src/index.ts | 0 .../src/pi-extension/browser-runtime.ts | 2 +- .../src/pi-extension/index.ts | 4 +- .../src/pi-extension/render.ts | 0 .../src/pi-extension/selection.ts | 2 +- .../src/pi-extension/state.ts | 0 .../{loop => browser-loop}/src/pi/api-keys.ts | 0 .../{loop => browser-loop}/src/pi/attach.ts | 0 .../{loop => browser-loop}/src/pi/catalog.ts | 0 .../{loop => browser-loop}/src/pi/index.ts | 0 .../{loop => browser-loop}/src/pi/loop.ts | 0 .../{loop => browser-loop}/src/pi/models.ts | 0 .../src/pi/provider-retry.ts | 0 .../src/pi/providers.ts | 0 .../providers/anthropic/adaptive-thinking.ts | 0 .../providers/anthropic/browser-fallback.ts | 0 .../pi/providers/anthropic/capabilities.ts | 0 .../src/pi/providers/common.ts | 0 .../src/pi/providers/google/provider.ts | 0 .../src/pi/providers/openai/provider.ts | 0 .../src/pi/tool-manager.ts | 0 .../test/anthropic-browser-fallback.test.ts | 0 .../test/anthropic-native.integration.test.ts | 0 .../test/anthropic-payload.test.ts | 0 .../test/api-keys.test.ts | 0 .../test/attach-session.test.ts | 0 .../test/attach.test.ts | 0 .../test/browser-act-fail-fast.test.ts | 0 .../test/browser-cross-process.live.test.ts | 0 .../test/browser-frame-collection.test.ts | 0 .../test/browser-ref-lifecycle.test.ts | 0 .../test/browser-runtime.test.ts | 2 +- .../test/browser-wait.test.ts | 0 .../{loop => browser-loop}/test/cdp.test.ts | 0 .../test/core-boundary.test.ts | 8 +- .../test/e2e.live.test.ts | 0 .../test/example-tool-policy.test.ts | 0 .../test/extension.test.ts | 0 .../test/google-provider.test.ts | 0 .../test/harness-context.test.ts | 0 .../{loop => browser-loop}/test/keys.test.ts | 0 .../{loop => browser-loop}/test/menu.test.ts | 0 .../test/models.test.ts | 0 .../test/openai-adapter-routing.test.ts | 0 .../test/openai-native-provider.test.ts | 0 .../test/pi-export-surface.test.ts | 0 .../test/pi-modes.test.ts | 0 .../test/provider-retry.test.ts | 0 .../test/provider-stream.test.ts | 4 +- .../test/providers.test.ts | 0 .../test/published-declarations.test.ts | 8 +- .../test/published-package.test.ts | 0 .../test/resources.test.ts | 0 .../test/selection.test.ts | 0 .../test/tool-catalog.test.ts | 0 .../test/tool-manager.test.ts | 0 .../test/translator-browser.test.ts | 0 .../test/translator.test.ts | 0 .../tsconfig.build.json | 4 +- packages/{loop => browser-loop}/tsconfig.json | 0 .../{loop => browser-loop}/tsdown.config.ts | 0 .../{loop => browser-loop}/vitest.config.ts | 4 +- .../vitest.integration.config.ts | 4 +- tsconfig.json | 2 +- 109 files changed, 228 insertions(+), 217 deletions(-) rename .github/workflows/{release-loop.yml => release-browser-loop.yml} (73%) rename packages/{loop => browser-loop}/CHANGELOG.md (99%) rename packages/{loop => browser-loop}/README.md (89%) rename packages/{loop => browser-loop}/docs/supported-models.md (92%) rename packages/{loop => browser-loop}/examples/agent.ts (100%) rename packages/{loop => browser-loop}/examples/anthropic-native-smoke.ts (100%) rename packages/{loop => browser-loop}/examples/harness.ts (100%) rename packages/{loop => browser-loop}/examples/quickstart.ts (100%) rename packages/{loop => browser-loop}/examples/screenshot.png (100%) rename packages/{loop => browser-loop}/examples/shared/logging.ts (100%) rename packages/{loop => browser-loop}/examples/shared/options.ts (100%) rename packages/{loop => browser-loop}/examples/shared/scenarios.ts (100%) rename packages/{loop => browser-loop}/examples/shared/tools.ts (100%) rename packages/{loop => browser-loop}/package.json (87%) rename packages/{loop => browser-loop}/scripts/native-action-probe.ts (96%) rename packages/{loop => browser-loop}/src/core/actions/browser.ts (100%) rename packages/{loop => browser-loop}/src/core/actions/computer.ts (100%) rename packages/{loop => browser-loop}/src/core/actions/index.ts (100%) rename packages/{loop => browser-loop}/src/core/anthropic-native.ts (100%) rename packages/{loop => browser-loop}/src/core/browser-result-format.ts (100%) rename packages/{loop => browser-loop}/src/core/menu.ts (100%) rename packages/{loop => browser-loop}/src/core/model-info.ts (100%) rename packages/{loop => browser-loop}/src/core/resources.ts (100%) rename packages/{loop => browser-loop}/src/core/tool-catalog.ts (99%) rename packages/{loop => browser-loop}/src/core/tools.ts (100%) rename packages/{loop => browser-loop}/src/core/translator/browser-act.ts (100%) rename packages/{loop => browser-loop}/src/core/translator/browser-document-reconciliation.ts (100%) rename packages/{loop => browser-loop}/src/core/translator/browser-frame-collection.ts (100%) rename packages/{loop => browser-loop}/src/core/translator/browser-observation.ts (100%) rename packages/{loop => browser-loop}/src/core/translator/browser-ref-lifecycle.ts (100%) rename packages/{loop => browser-loop}/src/core/translator/browser-wait.ts (100%) rename packages/{loop => browser-loop}/src/core/translator/browser.ts (100%) rename packages/{loop => browser-loop}/src/core/translator/cdp.ts (100%) rename packages/{loop => browser-loop}/src/core/translator/keys.ts (100%) rename packages/{loop => browser-loop}/src/core/translator/translator.ts (100%) rename packages/{loop => browser-loop}/src/core/translator/types.ts (100%) rename packages/{loop => browser-loop}/src/core/url.ts (100%) rename packages/{loop => browser-loop}/src/index.ts (100%) rename packages/{loop => browser-loop}/src/pi-extension/browser-runtime.ts (98%) rename packages/{loop => browser-loop}/src/pi-extension/index.ts (99%) rename packages/{loop => browser-loop}/src/pi-extension/render.ts (100%) rename packages/{loop => browser-loop}/src/pi-extension/selection.ts (99%) rename packages/{loop => browser-loop}/src/pi-extension/state.ts (100%) rename packages/{loop => browser-loop}/src/pi/api-keys.ts (100%) rename packages/{loop => browser-loop}/src/pi/attach.ts (100%) rename packages/{loop => browser-loop}/src/pi/catalog.ts (100%) rename packages/{loop => browser-loop}/src/pi/index.ts (100%) rename packages/{loop => browser-loop}/src/pi/loop.ts (100%) rename packages/{loop => browser-loop}/src/pi/models.ts (100%) rename packages/{loop => browser-loop}/src/pi/provider-retry.ts (100%) rename packages/{loop => browser-loop}/src/pi/providers.ts (100%) rename packages/{loop => browser-loop}/src/pi/providers/anthropic/adaptive-thinking.ts (100%) rename packages/{loop => browser-loop}/src/pi/providers/anthropic/browser-fallback.ts (100%) rename packages/{loop => browser-loop}/src/pi/providers/anthropic/capabilities.ts (100%) rename packages/{loop => browser-loop}/src/pi/providers/common.ts (100%) rename packages/{loop => browser-loop}/src/pi/providers/google/provider.ts (100%) rename packages/{loop => browser-loop}/src/pi/providers/openai/provider.ts (100%) rename packages/{loop => browser-loop}/src/pi/tool-manager.ts (100%) rename packages/{loop => browser-loop}/test/anthropic-browser-fallback.test.ts (100%) rename packages/{loop => browser-loop}/test/anthropic-native.integration.test.ts (100%) rename packages/{loop => browser-loop}/test/anthropic-payload.test.ts (100%) rename packages/{loop => browser-loop}/test/api-keys.test.ts (100%) rename packages/{loop => browser-loop}/test/attach-session.test.ts (100%) rename packages/{loop => browser-loop}/test/attach.test.ts (100%) rename packages/{loop => browser-loop}/test/browser-act-fail-fast.test.ts (100%) rename packages/{loop => browser-loop}/test/browser-cross-process.live.test.ts (100%) rename packages/{loop => browser-loop}/test/browser-frame-collection.test.ts (100%) rename packages/{loop => browser-loop}/test/browser-ref-lifecycle.test.ts (100%) rename packages/{loop => browser-loop}/test/browser-runtime.test.ts (98%) rename packages/{loop => browser-loop}/test/browser-wait.test.ts (100%) rename packages/{loop => browser-loop}/test/cdp.test.ts (100%) rename packages/{loop => browser-loop}/test/core-boundary.test.ts (93%) rename packages/{loop => browser-loop}/test/e2e.live.test.ts (100%) rename packages/{loop => browser-loop}/test/example-tool-policy.test.ts (100%) rename packages/{loop => browser-loop}/test/extension.test.ts (100%) rename packages/{loop => browser-loop}/test/google-provider.test.ts (100%) rename packages/{loop => browser-loop}/test/harness-context.test.ts (100%) rename packages/{loop => browser-loop}/test/keys.test.ts (100%) rename packages/{loop => browser-loop}/test/menu.test.ts (100%) rename packages/{loop => browser-loop}/test/models.test.ts (100%) rename packages/{loop => browser-loop}/test/openai-adapter-routing.test.ts (100%) rename packages/{loop => browser-loop}/test/openai-native-provider.test.ts (100%) rename packages/{loop => browser-loop}/test/pi-export-surface.test.ts (100%) rename packages/{loop => browser-loop}/test/pi-modes.test.ts (100%) rename packages/{loop => browser-loop}/test/provider-retry.test.ts (100%) rename packages/{loop => browser-loop}/test/provider-stream.test.ts (96%) rename packages/{loop => browser-loop}/test/providers.test.ts (100%) rename packages/{loop => browser-loop}/test/published-declarations.test.ts (96%) rename packages/{loop => browser-loop}/test/published-package.test.ts (100%) rename packages/{loop => browser-loop}/test/resources.test.ts (100%) rename packages/{loop => browser-loop}/test/selection.test.ts (100%) rename packages/{loop => browser-loop}/test/tool-catalog.test.ts (100%) rename packages/{loop => browser-loop}/test/tool-manager.test.ts (100%) rename packages/{loop => browser-loop}/test/translator-browser.test.ts (100%) rename packages/{loop => browser-loop}/test/translator.test.ts (100%) rename packages/{loop => browser-loop}/tsconfig.build.json (83%) rename packages/{loop => browser-loop}/tsconfig.json (100%) rename packages/{loop => browser-loop}/tsdown.config.ts (100%) rename packages/{loop => browser-loop}/vitest.config.ts (86%) rename packages/{loop => browser-loop}/vitest.integration.config.ts (68%) diff --git a/.agents/skills/release/SKILL.md b/.agents/skills/release/SKILL.md index e729f080..95da7597 100644 --- a/.agents/skills/release/SKILL.md +++ b/.agents/skills/release/SKILL.md @@ -1,13 +1,13 @@ --- name: release -description: Prepare and publish the @onkernel/loop npm release from kernel/cua. Use when checking release readiness, choosing a package version, writing the package changelog, committing release metadata to main, pushing package-prefixed tags, or monitoring the release workflow. +description: Prepare and publish the @onkernel/browser-loop npm release from kernel/browser-loop. Use when checking release readiness, choosing a package version, writing the package changelog, committing release metadata to main, pushing package-prefixed tags, or monitoring the release workflow. --- # Release -Use this workflow to release `@onkernel/loop`. +Use this workflow to release `@onkernel/browser-loop`. -The first publish under the `@onkernel/loop` name is manual, because npm binds a +The first publish under the `@onkernel/browser-loop` name is manual, because npm binds a trusted publisher to a (repository, workflow filename) pair and a brand-new package name has none. See `docs/npm-releases.md`. @@ -20,7 +20,7 @@ error-prone. | package | directory | tag prefix | workflow | | --- | --- | --- | --- | -| `@onkernel/loop` | `packages/loop` | `loop/v` | `release-loop.yml` | +| `@onkernel/browser-loop` | `packages/browser-loop` | `browser-loop/v` | `release-browser-loop.yml` | | `@onkernel/ptywright` | `packages/ptywright` | — | not published | ## Quick Start @@ -37,14 +37,14 @@ git fetch --tags origin ```bash git status --short -npm view @onkernel/loop versions --json -test -f .github/workflows/release-loop.yml +npm view @onkernel/browser-loop versions --json +test -f .github/workflows/release-browser-loop.yml ``` 3. Find the previous release tag: ```bash -git tag --list "loop/v*" --sort=-v:refname | head -1 +git tag --list "browser-loop/v*" --sort=-v:refname | head -1 ``` If no tag exists, treat the next release as the current `package.json` version @@ -53,8 +53,8 @@ unless npm already has that version. 4. Inspect changes since the last tag: ```bash -git log --oneline ..HEAD -- packages/loop package.json package-lock.json tsconfig.base.json -git diff --name-status ..HEAD -- packages/loop package.json package-lock.json tsconfig.base.json +git log --oneline ..HEAD -- packages/browser-loop package.json package-lock.json tsconfig.base.json +git diff --name-status ..HEAD -- packages/browser-loop package.json package-lock.json tsconfig.base.json ``` ## Version Choice @@ -71,11 +71,11 @@ tag: minor bump for breaking changes unless it is intentionally moving to `1.0.0`. The candidate version must be greater than both the last tag and every version -returned by `npm view @onkernel/loop versions --json`. +returned by `npm view @onkernel/browser-loop versions --json`. ## Changelog -Changes land under a `## Unreleased` heading in `packages/loop/CHANGELOG.md` as +Changes land under a `## Unreleased` heading in `packages/browser-loop/CHANGELOG.md` as they merge, so the changelog has at most one unreleased section. Releasing renames that heading in place — do not add a second top entry: @@ -105,7 +105,7 @@ per-merge heading claims a release that never happened. Set the version explicitly: ```bash -npm pkg set version= --workspace @onkernel/loop +npm pkg set version= --workspace @onkernel/browser-loop ``` Refresh the lockfile: @@ -118,16 +118,16 @@ npm install --package-lock-only ```bash npm ci -npm run build --workspace @onkernel/loop +npm run build --workspace @onkernel/browser-loop npm run typecheck -npm test --workspace @onkernel/loop -npm pack --workspace @onkernel/loop --dry-run +npm test --workspace @onkernel/browser-loop +npm pack --workspace @onkernel/browser-loop --dry-run ``` Build before testing: the pi print/RPC test loads the extension the way pi does, through the package's own entry points. Run the full unit suite — do not pass individual test files. Integration tests run separately (`npm run -test:integration --workspace @onkernel/loop`), and live e2e tests skip unless +test:integration --workspace @onkernel/browser-loop`), and live e2e tests skip unless `LOOP_E2E_LIVE=1` is set. Confirm the packed tarball ships `dist` and the extension source pi loads @@ -142,8 +142,8 @@ limited to the package version, changelog, and `package-lock.json`. ```bash git status --short -git add package-lock.json packages/loop/package.json packages/loop/CHANGELOG.md -git commit -m "Release @onkernel/loop v" +git add package-lock.json packages/browser-loop/package.json packages/browser-loop/CHANGELOG.md +git commit -m "Release @onkernel/browser-loop v" git push origin main ``` @@ -152,8 +152,8 @@ git push origin main After the release commit is on `main`, create an annotated tag at that commit: ```bash -git tag -a loop/v -m "@onkernel/loop v" -git push origin loop/v +git tag -a browser-loop/v -m "@onkernel/browser-loop v" +git push origin browser-loop/v ``` ## Monitor @@ -161,15 +161,15 @@ git push origin loop/v Find and watch the workflow run triggered by the tag: ```bash -gh run list --workflow release-loop.yml --json databaseId,status,conclusion,headBranch,displayTitle,url --limit 10 +gh run list --workflow release-browser-loop.yml --json databaseId,status,conclusion,headBranch,displayTitle,url --limit 10 gh run watch --exit-status ``` After the workflow succeeds, verify npm: ```bash -npm view @onkernel/loop@ version -npm dist-tag ls @onkernel/loop +npm view @onkernel/browser-loop@ version +npm dist-tag ls @onkernel/browser-loop ``` Then verify the published artifact actually imports — `npm view` only proves @@ -178,9 +178,9 @@ the version exists, not that the tarball is loadable: ```bash cd "$(mktemp -d)" npm init -y -npm install @onkernel/loop@ -node --input-type=module -e "import('@onkernel/loop').then((m) => { if (typeof m.compileLoopToolCatalog !== 'function') process.exit(1); })" -node --input-type=module -e "import('@onkernel/loop/pi').then((m) => { if (typeof m.attach !== 'function') process.exit(1); })" +npm install @onkernel/browser-loop@ +node --input-type=module -e "import('@onkernel/browser-loop').then((m) => { if (typeof m.compileLoopToolCatalog !== 'function') process.exit(1); })" +node --input-type=module -e "import('@onkernel/browser-loop/pi').then((m) => { if (typeof m.attach !== 'function') process.exit(1); })" ``` If the workflow fails after a tag is pushed, do not reuse the same version diff --git a/.agents/skills/update-docs/SKILL.md b/.agents/skills/update-docs/SKILL.md index db193f19..a0277eb4 100644 --- a/.agents/skills/update-docs/SKILL.md +++ b/.agents/skills/update-docs/SKILL.md @@ -40,11 +40,11 @@ For every doc update: Start with these source-of-truth checks: -- Package topology: `package.json`, `tsconfig.json`, and `packages/*/package.json`. `@onkernel/loop` is one package with two entry points (`.` and `./pi`) and a `pi.extensions` field. -- Design invariants: `packages/loop/src/core` is the framework-neutral core (canonical actions, tool declarations, catalog compilation, tool menu, tool manager, Kernel-browser execution); `packages/loop/src/pi` owns provider-specific policy (model resolution, transport derivation, adapters, payload transforms, headers, retry); provider differences reach execution as compiled `LoopToolCatalog` data rather than provider conditionals in the translator. -- Neutral core: `packages/loop/src/index.ts`, `core/tools.ts`, `core/actions/`, `core/tool-catalog.ts`, `core/menu.ts`, `core/tool-manager.ts`, `core/resources.ts`, and `core/translator/`. -- pi binding: `packages/loop/src/pi/index.ts`, `pi/attach.ts`, `pi/models.ts` (`getLoopModel`/`listLoopModels`/`parseLoopModelRef`), `pi/providers/`, `pi/provider-retry.ts`, and `pi/api-keys.ts`. -- Extension runtime flow: `packages/loop/src/pi-extension/index.ts`, `selection.ts`, `browser-runtime.ts`, `state.ts`, and `render.ts`. +- Package topology: `package.json`, `tsconfig.json`, and `packages/*/package.json`. `@onkernel/browser-loop` is one package with two entry points (`.` and `./pi`) and a `pi.extensions` field. +- Design invariants: `packages/browser-loop/src/core` is the framework-neutral core (canonical actions, tool declarations, catalog compilation, tool menu, tool manager, Kernel-browser execution); `packages/browser-loop/src/pi` owns provider-specific policy (model resolution, transport derivation, adapters, payload transforms, headers, retry); provider differences reach execution as compiled `LoopToolCatalog` data rather than provider conditionals in the translator. +- Neutral core: `packages/browser-loop/src/index.ts`, `core/tools.ts`, `core/actions/`, `core/tool-catalog.ts`, `core/menu.ts`, `core/tool-manager.ts`, `core/resources.ts`, and `core/translator/`. +- pi binding: `packages/browser-loop/src/pi/index.ts`, `pi/attach.ts`, `pi/models.ts` (`getLoopModel`/`listLoopModels`/`parseLoopModelRef`), `pi/providers/`, `pi/provider-retry.ts`, and `pi/api-keys.ts`. +- Extension runtime flow: `packages/browser-loop/src/pi-extension/index.ts`, `selection.ts`, `browser-runtime.ts`, `state.ts`, and `render.ts`. - 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/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7de571c1..9337bc22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,19 +22,19 @@ jobs: - run: npm ci # The pi print/RPC test loads the extension the way pi does, through the # package's own entry points, so dist has to exist before the unit run. - - run: npm run build --workspace @onkernel/loop + - run: npm run build --workspace @onkernel/browser-loop - name: Unit tests - run: npm test --workspace @onkernel/loop + run: npm test --workspace @onkernel/browser-loop - name: Pack tarball - run: npm pack --workspace @onkernel/loop --pack-destination "$RUNNER_TEMP" + run: npm pack --workspace @onkernel/browser-loop --pack-destination "$RUNNER_TEMP" - name: ESM import smoke test run: | mkdir -p "$RUNNER_TEMP/esm-smoke" cd "$RUNNER_TEMP/esm-smoke" npm init -y - npm install "$RUNNER_TEMP"/onkernel-loop-*.tgz - node --input-type=module -e "import('@onkernel/loop').then((m) => { if (typeof m.compileLoopToolCatalog !== 'function') process.exit(1); })" - node --input-type=module -e "import('@onkernel/loop/pi').then((m) => { if (typeof m.attach !== 'function') process.exit(1); })" + npm install "$RUNNER_TEMP"/onkernel-browser-loop-*.tgz + node --input-type=module -e "import('@onkernel/browser-loop').then((m) => { if (typeof m.compileLoopToolCatalog !== 'function') process.exit(1); })" + node --input-type=module -e "import('@onkernel/browser-loop/pi').then((m) => { if (typeof m.attach !== 'function') process.exit(1); })" typecheck-and-ptywright: runs-on: ubuntu-latest @@ -100,7 +100,7 @@ jobs: GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} XAI_API_KEY: ${{ secrets.XAI_API_KEY }} MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }} - run: npm run test:integration --workspace @onkernel/loop + run: npm run test:integration --workspace @onkernel/browser-loop live-e2e: runs-on: ubuntu-latest @@ -124,4 +124,4 @@ jobs: GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} XAI_API_KEY: ${{ secrets.XAI_API_KEY }} MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }} - run: npm run test:integration --workspace @onkernel/loop -- test/e2e.live.test.ts + run: npm run test:integration --workspace @onkernel/browser-loop -- test/e2e.live.test.ts diff --git a/.github/workflows/release-loop.yml b/.github/workflows/release-browser-loop.yml similarity index 73% rename from .github/workflows/release-loop.yml rename to .github/workflows/release-browser-loop.yml index 50e4036e..22924b00 100644 --- a/.github/workflows/release-loop.yml +++ b/.github/workflows/release-browser-loop.yml @@ -1,16 +1,16 @@ -name: Release Loop +name: Release Browser Loop on: push: tags: - - "loop/v*" + - "browser-loop/v*" permissions: contents: read id-token: write concurrency: - group: release-loop-${{ github.ref_name }} + group: release-browser-loop-${{ github.ref_name }} cancel-in-progress: false jobs: @@ -43,13 +43,13 @@ jobs: import { readFileSync } from "node:fs"; const tag = process.env.GITHUB_REF_NAME; - const prefix = "loop/v"; + const prefix = "browser-loop/v"; if (!tag?.startsWith(prefix)) { throw new Error(`Expected tag to start with ${prefix}, got ${tag}`); } const tagVersion = tag.slice(prefix.length); - const pkg = JSON.parse(readFileSync("packages/loop/package.json", "utf8")); + const pkg = JSON.parse(readFileSync("packages/browser-loop/package.json", "utf8")); if (pkg.version !== tagVersion) { throw new Error(`Tag version ${tagVersion} does not match ${pkg.name} package.json version ${pkg.version}`); } @@ -57,24 +57,24 @@ jobs: console.log(`${pkg.name}@${pkg.version}`); NODE - - run: npm run build --workspace @onkernel/loop - - run: npm run typecheck --workspace @onkernel/loop + - run: npm run build --workspace @onkernel/browser-loop + - run: npm run typecheck --workspace @onkernel/browser-loop - name: Unit tests - run: npm test --workspace @onkernel/loop + run: npm test --workspace @onkernel/browser-loop - name: Pack tarball - run: npm pack --workspace @onkernel/loop --pack-destination "$RUNNER_TEMP" + run: npm pack --workspace @onkernel/browser-loop --pack-destination "$RUNNER_TEMP" - name: ESM import smoke test run: | SMOKE_DIR=$(mktemp -d) cd "$SMOKE_DIR" npm init -y > /dev/null - npm install "$RUNNER_TEMP"/onkernel-loop-*.tgz + npm install "$RUNNER_TEMP"/onkernel-browser-loop-*.tgz cat > smoke.mjs <<'NODE' - import { compileLoopToolCatalog, formatBrowserActResult, loop } from "@onkernel/loop"; - import * as loopPi from "@onkernel/loop/pi"; + import { compileLoopToolCatalog, formatBrowserActResult, loop } from "@onkernel/browser-loop"; + import * as loopPi from "@onkernel/browser-loop/pi"; const { attach, createLoopModels, getLoopModel } = loopPi; for (const [name, value] of Object.entries({ compileLoopToolCatalog, formatBrowserActResult, attach, createLoopModels, getLoopModel })) { @@ -86,11 +86,11 @@ jobs: throw new Error(`expected loop to be an object, got ${typeof loop}`); } if ("Agent" in loopPi || "NodeExecutionEnv" in loopPi) { - throw new Error("expected @onkernel/loop/pi not to re-export pi-agent-core"); + throw new Error("expected @onkernel/browser-loop/pi not to re-export pi-agent-core"); } console.log("ESM import smoke OK"); NODE node smoke.mjs - name: Publish to npm - run: npm publish --workspace @onkernel/loop --access public + run: npm publish --workspace @onkernel/browser-loop --access public diff --git a/README.md b/README.md index 393aba9c..a11a3278 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# loop +# browser loop Browser tools for your agent. The agent can be a [pi](https://github.com/earendil-works/pi) `Agent` or `AgentHarness` — or your coding harness through a plugin — with Eve and -AI SDK bindings anticipated next. Kernel Loop supplies the tools, the +AI SDK bindings anticipated next. Browser Loop supplies the tools, the [Kernel cloud browser](https://kernel.sh/) they run against, and the per-model compatibility knowledge. @@ -10,8 +10,8 @@ Point any model at a Kernel browser: pick the tools, get plain agent objects back, and run whatever loop you already have. ```ts -import { loop } from "@onkernel/loop"; -import { attach } from "@onkernel/loop/pi"; +import { loop } from "@onkernel/browser-loop"; +import { attach } from "@onkernel/browser-loop/pi"; const kb = attach({ client, browser }); const { model, agentTools, models } = kb.compile({ @@ -26,7 +26,7 @@ what you deploy into your production agent. Same catalog, same tool identities, same model knowledge on both sides, so the hand-off is lossless: ```bash -pi install npm:@onkernel/loop +pi install npm:@onkernel/browser-loop pi -p --browser-tools browser,browser-act "open example.com and report the heading" ``` @@ -46,7 +46,7 @@ All of them expect you to: it had the intended effect. 4. Know which of those protocols the model you picked actually accepts. -This repo does all of that and stops there. `@onkernel/loop` represents the +This repo does all of that and stops there. `@onkernel/browser-loop` represents the provider differences as an explicit, identity-keyed tool catalog; you choose the exact tools, and provider transforms compose only the declarations and request fields those identities require. It does not supply an agent class, a session @@ -60,21 +60,21 @@ transcripts and evals stay comparable wherever the same catalog runs. ``` packages/ -├── loop/ # @onkernel/loop - framework-neutral core, pi binding, pi extension +├── browser-loop/ # @onkernel/browser-loop - framework-neutral core, pi binding, pi extension └── ptywright/ # @onkernel/ptywright - development-only PTY/TUI test infrastructure ``` | Entry point | What it ships | | --- | --- | -| `@onkernel/loop` | The framework-neutral core: canonical actions, tool factories/toolsets, catalog compilation, the tool menu, and Kernel-browser execution. Imports nothing from pi — a unit test enforces the boundary. | -| `@onkernel/loop/pi` | The pi binding — the first of the framework bindings (`./eve` and `./ai-sdk` are the anticipated next). `attach()` binds a Kernel browser and compiles a (model, tools) pair into plain pi objects, plus model resolution and provider adapters. | +| `@onkernel/browser-loop` | The framework-neutral core: canonical actions, tool factories/toolsets, catalog compilation, the tool menu, and Kernel-browser execution. Imports nothing from pi — a unit test enforces the boundary. | +| `@onkernel/browser-loop/pi` | The pi binding — the first of the framework bindings (`./eve` and `./ai-sdk` are the anticipated next). `attach()` binds a Kernel browser and compiles a (model, tools) pair into plain pi objects, plus model resolution and provider adapters. | | `pi.extensions` | A pi extension contributing those tools to pi's own agent session. | | [`@onkernel/ptywright`](packages/ptywright) | Development-only PTY/TUI test infrastructure. | ```mermaid flowchart LR - core["@onkernel/loop"] - pibind["@onkernel/loop/pi"] + core["@onkernel/browser-loop"] + pibind["@onkernel/browser-loop/pi"] ext["pi extension"] pi["pi-agent-core / pi-ai / pi-coding-agent"] sdk["@onkernel/sdk"] @@ -92,13 +92,13 @@ flowchart LR ## Building an agent `attach()` binds the browser once; `compile()` turns a (model, tools) pair into -plain pi objects. Nothing here is a Loop type you have to learn: +plain pi objects. Nothing here is a Browser Loop-specific type you have to learn: ```ts import Kernel from "@onkernel/sdk"; import { Agent } from "@earendil-works/pi-agent-core"; -import { loop } from "@onkernel/loop"; -import { attach } from "@onkernel/loop/pi"; +import { loop } from "@onkernel/browser-loop"; +import { attach } from "@onkernel/browser-loop/pi"; const client = new Kernel({ apiKey: process.env.KERNEL_API_KEY! }); const browser = await client.browsers.create({ stealth: true }); @@ -125,7 +125,7 @@ try { The compiled `model` carries the transport its tools derive: selecting a provider-native browser or computer surface can change `model.api`, so the pair has to reach the agent together. See -[`packages/loop/README.md`](packages/loop/README.md) for the harness variant, +[`packages/browser-loop/README.md`](packages/browser-loop/README.md) for the harness variant, swapping tools on a running session, and tool contexts. ## Choosing tools for a model @@ -133,8 +133,8 @@ swapping tools on a running session, and tool contexts. Not every model accepts every tool. Ask, rather than guess: ```ts -import { loopToolMenu } from "@onkernel/loop"; -import { getLoopModel } from "@onkernel/loop/pi"; +import { loopToolMenu } from "@onkernel/browser-loop"; +import { getLoopModel } from "@onkernel/browser-loop/pi"; for (const entry of loopToolMenu(getLoopModel("openai:gpt-5.6-sol"))) { console.log(entry.label, entry.available ? "ok" : `unavailable: ${entry.unavailableReason}`); @@ -151,10 +151,10 @@ per-tool verdict. ## How it works -1. **Execution layer** — `@onkernel/loop` materializes the caller's exact +1. **Execution layer** — `@onkernel/browser-loop` materializes the caller's exact catalog over one shared resource pool and executes canonical actions through Kernel's computer API or a raw-CDP browser executor. -2. **Model layer** — `@onkernel/loop/pi` opens pi-ai's whole model catalog and +2. **Model layer** — `@onkernel/browser-loop/pi` opens pi-ai's whole model catalog and composes provider declarations, headers, and payload transforms around that core. Catalog compilation is declaration-only: it never sees an executor. 3. **Transport** — the compiled catalog derives `model.api` from the selected @@ -172,8 +172,8 @@ See [`docs/architecture.md`](docs/architecture.md) for the full end-to-end flow. ```bash npm ci npm run typecheck -npm run build --workspace @onkernel/loop -npm test --workspace @onkernel/loop +npm run build --workspace @onkernel/browser-loop +npm test --workspace @onkernel/browser-loop ``` Build before testing: the pi print/RPC test loads the extension the way pi does, diff --git a/docs/architecture.md b/docs/architecture.md index 34196268..5edc882f 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -12,7 +12,7 @@ both explicitly and may use pi's orchestration primitives directly. ## Module boundaries -`@onkernel/loop` is one package with two entry points and three source trees: +`@onkernel/browser-loop` is one package with two entry points and three source trees: - `.` (`src/core/`) is the framework-neutral core: canonical actions, the tool declarations namespace, the catalog compiler, the tool menu, and @@ -27,7 +27,7 @@ both explicitly and may use pi's orchestration primitives directly. core only orders and validates what it is given. `test/core-boundary.test.ts` fails the unit suite on any `src/core` import that is not core-relative or an allowlisted neutral dependency — including - pi packages and this package's own `@onkernel/loop/pi` subpath. + pi packages and this package's own `@onkernel/browser-loop/pi` subpath. - `./pi` (`src/pi/`) is the pi binding: `attach()`/`compile()`, the tool manager that joins compiled catalogs to executable pi `AgentTool`s, model resolution and availability facts (`compileLoopToolCatalog`/`loopToolMenu` @@ -44,8 +44,8 @@ both explicitly and may use pi's orchestration primitives directly. pieces that are not pi-shaped — the catalog compiler and `LoopExecutionResources` — and applies headers and payload transforms through pi's own `before_provider_headers` and `before_provider_request` hooks. It - imports the rest of the package by name (`@onkernel/loop`, - `@onkernel/loop/pi`) rather than by relative path, because pi loads the + imports the rest of the package by name (`@onkernel/browser-loop`, + `@onkernel/browser-loop/pi`) rather than by relative path, because pi loads the extension as TypeScript through jiti and jiti's pi-ai alias cannot follow the deep `@earendil-works/pi-ai/api/*` imports the provider adapters make. - `@onkernel/ptywright` is development-only PTY/TUI test infrastructure. It has @@ -58,8 +58,8 @@ not a conditional in the translator. ```mermaid flowchart LR - core["@onkernel/loop (src/core)"] - pibind["@onkernel/loop/pi (src/pi)"] + core["@onkernel/browser-loop (src/core)"] + pibind["@onkernel/browser-loop/pi (src/pi)"] ext["src/pi-extension"] pi["pi-agent-core / pi-ai / pi-coding-agent"] sdk["@onkernel/sdk"] @@ -77,7 +77,7 @@ flowchart LR The core exposes one frozen namespace: ```ts -import { loop } from "@onkernel/loop"; +import { loop } from "@onkernel/browser-loop"; const tools = [ loop.tools.browser.snapshot(), @@ -93,12 +93,12 @@ The main groups are: default. - `loop.tools.playwright()`: a Playwright code execution tool. - `loop.toolsets.browser()`, `computer()`, and `mixed()`: ordinary convenience - arrays of Loop-authored tools. + arrays of Browser Loop-authored tools. - `loop.providers.*`: only provider-native tools and predefined toolsets backed by linked first-party documentation. Each provider namespace exposes its `source` (or versioned `sources`), and every returned spec carries that URL. -Each Loop-owned tool has a stable identity independent of its caller-visible +Each Browser Loop-owned tool has a stable identity independent of its caller-visible name. Compilation preserves requested order and derives provider-safe names, schema fingerprints, coordinate contracts, loading eligibility, headers, payload transforms, and native input mappings. Duplicate identities, @@ -144,11 +144,11 @@ exactly once per spec object. ## Action planes and result feedback -Canonical actions live under `packages/loop/src/core/actions/`: +Canonical actions live under `packages/browser-loop/src/core/actions/`: - **Computer actions** use Kernel's `browsers.computer` API and OS screenshot coordinates. -- **Browser actions** use `packages/loop/src/core/translator/browser.ts` over the +- **Browser actions** use `packages/browser-loop/src/core/translator/browser.ts` over the browser's raw CDP websocket. Element refs are snapshot-scoped and stale refs fail with a request to snapshot again. @@ -181,13 +181,13 @@ catalog: - Anthropic native browser/computer declarations replace only their own placeholders and merge required beta headers with caller headers. - OpenAI streams through pi's builtin Responses transport and its automatic - prompt caching by default; a Loop-owned adapter handles OpenAI's native + prompt caching by default; a Browser Loop-owned adapter handles OpenAI's native computer tool and tool-search namespace round-trips. - Anthropic's native browser tool falls back to an equivalent function-tool declaration when the active credential cannot access `browser_20260701`; the selected tool identity, name, schema, and executor remain unchanged. - Google's current predefined browser toolset serializes one `computer_use` - declaration plus exact exclusions through the Loop-owned Interactions API + declaration plus exact exclusions through the Browser Loop-owned Interactions API adapter. Excluded calls fail with a named catalog error instead of reaching generic tool dispatch. - Meta, xAI, and Moonshot disable parallel tool calls when the selected catalog @@ -205,17 +205,17 @@ bindings require different transports fails to compile with a named catalog error. A model resolved with no such tool selected keeps its ordinary registry api. -This is why an OpenAI model selected with only Loop browser tools streams +This is why an OpenAI model selected with only Browser Loop tools streams through pi's builtin `openai-responses` transport, but the same model selected -with `loop.providers.openai.tools.computer()` compiles to the Loop-owned +with `loop.providers.openai.tools.computer()` compiles to the Browser Loop-owned `openai-computer-use` api — and symmetrically for Google's `google-interactions` Interactions API versus pi's builtin Google transport. ### The tool menu -`loopToolMenu(model, selected)` in `packages/loop/src/core/menu.ts` returns every tool -Loop can offer for a model, each marked available or not. It decides availability +`loopToolMenu(model, selected)` in `packages/browser-loop/src/core/menu.ts` returns every tool +Browser Loop can offer for a model, each marked available or not. It decides availability by compiling the candidate catalog rather than by restating the compiler's rules, so the menu cannot drift from what `compileLoopToolCatalog` accepts: an entry is available exactly when selecting it compiles. Compilation is pure and @@ -241,7 +241,7 @@ serialization, provider fields, then the caller's `onPayload` hook. ## Extension composition -`packages/loop/src/pi-extension/index.ts` is the composition root for pi sessions. pi +`packages/browser-loop/src/pi-extension/index.ts` is the composition root for pi sessions. pi owns the agent loop, session, UI, and model selection; the extension contributes only what Kernel owns: @@ -286,14 +286,14 @@ user prompt ## Validation and test ownership -- `packages/loop/test/tool-catalog.test.ts`: identities, collisions, provider +- `packages/browser-loop/test/tool-catalog.test.ts`: identities, collisions, provider composition, compatibility, declarations, and coordinate contracts. -- `packages/loop/test/resources.test.ts`: action feedback and batch boundaries. -- `packages/loop/test/attach.test.ts` and `attach-session.test.ts`: compiled +- `packages/browser-loop/test/resources.test.ts`: action feedback and batch boundaries. +- `packages/browser-loop/test/attach.test.ts` and `attach-session.test.ts`: compiled pairs, applying one to a running harness, and the behaviors `activate()` installs. -- `packages/loop/test/translator-browser.test.ts`: browser behavior and ref +- `packages/browser-loop/test/translator-browser.test.ts`: browser behavior and ref lifecycle. -- `packages/loop/test/`: selection and availability, provider stream +- `packages/browser-loop/test/`: selection and availability, provider stream ownership, browser lifecycle, and an end-to-end run against real `pi` in print and RPC modes. diff --git a/docs/npm-releases.md b/docs/npm-releases.md index 562761c1..14a89730 100644 --- a/docs/npm-releases.md +++ b/docs/npm-releases.md @@ -1,11 +1,11 @@ # npm releases -`@onkernel/loop` publishes from a package tag: +`@onkernel/browser-loop` publishes from a package tag: -- `loop/v0.11.0` runs `.github/workflows/release-loop.yml` +- `browser-loop/v0.11.0` runs `.github/workflows/release-browser-loop.yml` -The tag version must match `packages/loop/package.json`, and the tagged commit -must be contained in `main`. +The tag version must match `packages/browser-loop/package.json`, and the tagged +commit must be contained in `main`. ## Trusted publishing setup @@ -13,69 +13,76 @@ Configure the package on npm with a GitHub Actions trusted publisher: | package | organization | repository | workflow filename | environment | | --- | --- | --- | --- | --- | -| `@onkernel/loop` | `kernel` | `cua` | `release-loop.yml` | leave blank | +| `@onkernel/browser-loop` | `kernel` | `browser-loop` | `release-browser-loop.yml` | leave blank | The same configuration can be created from the npm CLI: ```sh npm install -g npm@^11.17.0 -npm trust github @onkernel/loop --repo kernel/cua --file release-loop.yml --allow-publish +npm trust github @onkernel/browser-loop \ + --repo kernel/browser-loop \ + --file release-browser-loop.yml \ + --allow-publish ``` npm requires packages to exist before a trusted publisher can be configured, so -`@onkernel/loop`'s first version is published manually — see below. +`@onkernel/browser-loop`'s first version is published manually — see below. ## Releasing from a tag +After the first manual publish, bump the version before creating the next tag: + ```sh git checkout main git pull --ff-only -git tag loop/v0.11.0 -git push origin loop/v0.11.0 +git tag browser-loop/v0.11.1 +git push origin browser-loop/v0.11.1 ``` -## First publish of a new package name - -npm requires a package to exist before a trusted publisher can be configured for -it, so the first release of any new name is a manual publish from a local -checkout. This applies to `@onkernel/loop`, whose predecessors published under -the retired `@onkernel/cua-ai` and `@onkernel/cua-agent` names. +Do not create `browser-loop/v0.11.0` after manually publishing 0.11.0: npm +versions are immutable, so the workflow would attempt to republish the same +version and fail. -Two related constraints, because a trusted publisher is bound to a -*(repository, workflow filename)* pair: +## First publish of the package -- Renaming the repository invalidates every existing entry. -- Renaming a release workflow file does the same. +npm requires a package to exist before a trusted publisher can be configured for +it. The first `@onkernel/browser-loop` release is therefore a manual publish +from a maintainer account in the `onkernel` npm organization. -So a repository rename and a first publish are cheapest done together: one -reconfiguration instead of two. +Rename the GitHub repository to `kernel/browser-loop` before publishing. Trusted +publishers bind to a *(repository, workflow filename)* pair, so doing the repo +rename, first publish, and trusted-publisher setup together avoids configuring +that pair twice. -Manual first-publish steps (from a maintainer machine with an npm account in the -`onkernel` org): +Publish the same tarball that passed the install smoke test: ```sh -git clone https://github.com/kernel/cua.git -cd cua && git checkout main && git pull --ff-only +git clone https://github.com/kernel/browser-loop.git +cd browser-loop +git checkout main +git pull --ff-only npm ci -npm run build -npm test --workspace @onkernel/ +npm run build --workspace @onkernel/browser-loop +npm run typecheck --workspace @onkernel/browser-loop +npm test --workspace @onkernel/browser-loop -# Pack, install into a throwaway project, and import it before publishing — -# published npm versions are immutable. PACK_DIR=$(mktemp -d) -npm pack --workspace @onkernel/ --pack-destination "$PACK_DIR" +npm pack --workspace @onkernel/browser-loop --pack-destination "$PACK_DIR" +TARBALL="$PACK_DIR/onkernel-browser-loop-0.11.0.tgz" + SMOKE_DIR=$(mktemp -d) -(cd "$SMOKE_DIR" && npm init -y > /dev/null && npm install "$PACK_DIR"/*.tgz) +( + cd "$SMOKE_DIR" + npm init -y > /dev/null + npm install "$TARBALL" + node --input-type=module -e \ + 'import("@onkernel/browser-loop").then(m => console.log(Object.keys(m)))' +) npm login -npm publish --workspace @onkernel/ --access public +npm publish "$TARBALL" --access public ``` -Then configure the trusted publisher, either on the package page in the npm web -UI (Settings → Publishing access → Add trusted publisher) or from the CLI: - -```sh -npm install -g npm@^11.17.0 -npm trust github @onkernel/ --repo kernel/ --file .yml --allow-publish -``` +Then configure the trusted publisher using the command above or the npm package +page (Settings → Publishing access → Add trusted publisher). diff --git a/package-lock.json b/package-lock.json index c72d1c6a..195e7b8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,14 @@ { - "name": "cua", + "name": "browser-loop", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "cua", + "name": "browser-loop", "version": "0.1.0", "workspaces": [ - "packages/loop", + "packages/browser-loop", "packages/ptywright" ], "devDependencies": { @@ -2242,8 +2242,8 @@ } } }, - "node_modules/@onkernel/loop": { - "resolved": "packages/loop", + "node_modules/@onkernel/browser-loop": { + "resolved": "packages/browser-loop", "link": true }, "node_modules/@onkernel/ptywright": { @@ -4012,8 +4012,8 @@ "zod": "^3.25.28 || ^4" } }, - "packages/loop": { - "name": "@onkernel/loop", + "packages/browser-loop": { + "name": "@onkernel/browser-loop", "version": "0.11.0", "license": "MIT", "dependencies": { @@ -4044,7 +4044,7 @@ } } }, - "packages/loop/node_modules/@anthropic-ai/sdk": { + "packages/browser-loop/node_modules/@anthropic-ai/sdk": { "version": "0.117.1", "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.117.1.tgz", "integrity": "sha512-Yn2QlXfyCiKJ5YGCOOay7ZE78ISvII2XY621WMCiflmG8IYgwx59IBwPExxki3Xk9jKUtnD/Sj6UvplWr0rZxg==", @@ -4066,7 +4066,7 @@ } } }, - "packages/loop/node_modules/@google/genai": { + "packages/browser-loop/node_modules/@google/genai": { "version": "2.17.1", "resolved": "https://registry.npmjs.org/@google/genai/-/genai-2.17.1.tgz", "integrity": "sha512-CdZ3M/titoH81hXXkvOikrOW26bC9IXh9iYT7u+r+5p7wi1LnMEnB0AbJfDeWAkjuneP4oJ299BtCt6twmORWg==", diff --git a/package.json b/package.json index ac86e26b..9d6aea79 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,15 @@ { - "name": "cua", + "name": "browser-loop", "version": "0.1.0", "description": "Browser tools for your agent: framework-neutral tool catalog, per-model compilation, Kernel-browser execution, and a pi binding", "type": "module", "private": true, "workspaces": [ - "packages/loop", + "packages/browser-loop", "packages/ptywright" ], "scripts": { - "build": "npm run build --workspace @onkernel/loop && tsc -b && npm run build:native --workspace @onkernel/ptywright --if-present", + "build": "npm run build --workspace @onkernel/browser-loop && tsc -b && npm run build:native --workspace @onkernel/ptywright --if-present", "dev": "tsc -b --watch", "typecheck": "tsc -b", "clean": "tsc -b --clean && npm run clean:native --workspace @onkernel/ptywright --if-present" diff --git a/packages/loop/CHANGELOG.md b/packages/browser-loop/CHANGELOG.md similarity index 99% rename from packages/loop/CHANGELOG.md rename to packages/browser-loop/CHANGELOG.md index 4d9f11ea..2ca3eb9b 100644 --- a/packages/loop/CHANGELOG.md +++ b/packages/browser-loop/CHANGELOG.md @@ -2,7 +2,11 @@ ## Unreleased -- The three packages are one: `@onkernel/loop` replaces `@onkernel/cua-ai`, +- Rename the product and unpublished package to Browser Loop: the repository is + prepared for `kernel/browser-loop`, the package is `@onkernel/browser-loop`, + and release tags use `browser-loop/v*`. The public `loop` namespace, `Loop*` + TypeScript names, and `kloop.*.v1` tool identities are unchanged. +- The three packages are one: `@onkernel/browser-loop` replaces `@onkernel/cua-ai`, `@onkernel/cua-agent`, and `@onkernel/cua-pi-extension`. `.` exports the framework-neutral core (canonical actions, tool declarations, catalog compiler, tool menu, tool manager, browser execution), `./pi` exports the pi diff --git a/packages/loop/README.md b/packages/browser-loop/README.md similarity index 89% rename from packages/loop/README.md rename to packages/browser-loop/README.md index b1048923..d063b39b 100644 --- a/packages/loop/README.md +++ b/packages/browser-loop/README.md @@ -1,4 +1,4 @@ -# `@onkernel/loop` +# `@onkernel/browser-loop` Browser tools for your agent: a framework-neutral core (tool declarations, per-model catalog compilation, Kernel-browser execution) plus a pi binding @@ -9,16 +9,16 @@ binding; Eve and AI SDK are anticipated next. | import | what it is | | --- | --- | -| `@onkernel/loop` | The framework-neutral core: canonical actions, the tool namespace, catalog compilation, the tool menu, and Kernel-browser execution. Core declarations (`LoopToolDeclaration`) and executables (`LoopExecutableTool`) import nothing from pi — schemas come from `typebox` directly — and a unit test enforces the boundary. | -| `@onkernel/loop/pi` | The pi binding: `attach()`, model resolution, transport derivation, provider adapters, and provider retry. | +| `@onkernel/browser-loop` | The framework-neutral core: canonical actions, the tool namespace, catalog compilation, the tool menu, and Kernel-browser execution. Core declarations (`LoopToolDeclaration`) and executables (`LoopExecutableTool`) import nothing from pi — schemas come from `typebox` directly — and a unit test enforces the boundary. | +| `@onkernel/browser-loop/pi` | The pi binding: `attach()`, model resolution, transport derivation, provider adapters, and provider retry. | -Installing the package into pi (`pi install npm:@onkernel/loop`) registers the +Installing the package into pi (`pi install npm:@onkernel/browser-loop`) registers the extension described under [pi extension](#pi-extension). ## Install ```bash -npm install @onkernel/loop @onkernel/sdk @earendil-works/pi-agent-core +npm install @onkernel/browser-loop @onkernel/sdk @earendil-works/pi-agent-core ``` Requires Node 22.19 or newer, `KERNEL_API_KEY` for browser execution, and the @@ -33,8 +33,8 @@ you construct whatever pi agent you want with them. There is no agent class here ```ts import Kernel from "@onkernel/sdk"; import { Agent } from "@earendil-works/pi-agent-core"; -import { loop } from "@onkernel/loop"; -import { attach } from "@onkernel/loop/pi"; +import { loop } from "@onkernel/browser-loop"; +import { attach } from "@onkernel/browser-loop/pi"; const client = new Kernel({ apiKey: process.env.KERNEL_API_KEY! }); const browser = await client.browsers.create({ stealth: true }); @@ -75,8 +75,8 @@ points the handle's `models` at this catalog: ```ts import { AgentHarness, InMemorySessionRepo } from "@earendil-works/pi-agent-core"; -import { loop } from "@onkernel/loop"; -import { attach } from "@onkernel/loop/pi"; +import { loop } from "@onkernel/browser-loop"; +import { attach } from "@onkernel/browser-loop/pi"; const session = await new InMemorySessionRepo().create(); const kb = attach({ client, browser }); @@ -108,7 +108,7 @@ the new one. Changing the model or the tool list compiles a new pair; nothing mutates in place, and one shared execution-resource pool survives every change, so browser refs, tabs, connections, and translator state are not reset. -`@onkernel/loop/pi` does not re-export pi: install `@earendil-works/pi-agent-core` +`@onkernel/browser-loop/pi` does not re-export pi: install `@earendil-works/pi-agent-core` and import its session, skill, prompt-template, compaction, and execution-environment primitives directly, as these examples do. @@ -122,8 +122,8 @@ to every tool call: ```ts import { AgentHarness, createBashTool, createReadTool, type ExecutionToolContext } from "@earendil-works/pi-agent-core"; import { NodeExecutionEnv } from "@earendil-works/pi-agent-core/node"; -import { loop } from "@onkernel/loop"; -import { attach } from "@onkernel/loop/pi"; +import { loop } from "@onkernel/browser-loop"; +import { attach } from "@onkernel/browser-loop/pi"; const compiled = kb.compile({ model: "openai:gpt-5.6-sol", @@ -142,7 +142,7 @@ compiled.activate(harness); ``` Compile for the same context the harness delivers, so a later swap stays -type-compatible. Loop specs and plain pi `AgentTool`s are accepted too — they +type-compatible. Browser Loop specs and plain pi `AgentTool`s are accepted too — they simply ignore the context. `compiled.agentTools` is the context-free view for the low-level `Agent`. @@ -203,7 +203,7 @@ import { getLoopModel, listLoopModels, parseLoopModelRef, -} from "@onkernel/loop/pi"; +} from "@onkernel/browser-loop/pi"; const model = getLoopModel("openai:gpt-5.6-sol"); console.log(parseLoopModelRef("anthropic:claude-opus-5")); @@ -216,10 +216,10 @@ for which models have provider-native tools and which have known request limits. ## Explicit tools -All Loop-owned tools are available from one frozen namespace: +All Browser Loop-owned tools are available from one frozen namespace: ```ts -import { loop } from "@onkernel/loop"; +import { loop } from "@onkernel/browser-loop"; const tools = [ loop.tools.browser.snapshot(), @@ -337,7 +337,7 @@ loop.providers.anthropic.tools.browser({ version: "20260701" }); loop.providers.google.source; loop.providers.google.toolsets.browser({ exclude: ["right_click"] }); -// Meta, xAI, and Moonshot use the ordinary Loop browser tools. +// Meta, xAI, and Moonshot use the ordinary Browser Loop tools. loop.toolsets.browser(); ``` @@ -358,7 +358,7 @@ which models carry which surface. Provider-native caller-visible names are fixed by protocol. Version/tool/model mismatches fail during catalog compilation. If an Anthropic credential cannot -access `browser_20260701`, Loop retries with an equivalent `browser` function +access `browser_20260701`, Browser Loop retries with an equivalent `browser` function tool and remembers that choice for the credential and process. Every `loop.providers.*` tool surface exposes its first-party `source` (or versioned `sources`), and every returned provider spec carries the applicable URL. @@ -372,7 +372,7 @@ themselves: ```ts const catalog = compileLoopToolCatalog({ model: "anthropic:claude-opus-5", - requestedTools: tools, // Loop specs and plain declarations ({ name, description, parameters }) + requestedTools: tools, // Browser Loop specs and plain declarations ({ name, description, parameters }) }); catalog.entries; // identities, fingerprints, declarations, coordinates @@ -388,7 +388,7 @@ executable tools or retains the requested input objects. Execution is a separate concern: `attach()` materializes specs against a Kernel browser and owns implementation identity. -A Loop-owned identity remains stable when its name is customized. Caller tools +A Browser Loop-owned identity remains stable when its name is customized. Caller tools receive `caller.` identities through the canonical `callerToolIdentity()` helper shared with every consumer. Compilation rejects: @@ -428,10 +428,10 @@ tool's provider binding may declare `requiresApi`, and `compileLoopToolCatalog` returns a `catalog.model` carrying that api. Selecting tools whose bindings require different transports fails to compile. -- **OpenAI**: a model selected with only ordinary/Loop browser tools streams +- **OpenAI**: a model selected with only ordinary Browser Loop tools streams through pi's builtin Responses transport and its automatic prompt caching. - Selecting `loop.providers.openai.tools.computer()` derives the Loop-owned - `openai-computer-use` api instead, which a Loop adapter handles; that same + Selecting `loop.providers.openai.tools.computer()` derives the Browser Loop-owned + `openai-computer-use` api instead, which a Browser Loop adapter handles; that same adapter also covers tool-search namespace round-trips regardless of api, since pi's builtin transport does not replay them. - **Anthropic**: exact native declarations, beta-header composition, and @@ -439,7 +439,7 @@ require different transports fails to compile. through pi's builtin transport. - **Google**: a model selected without Google's native browser toolset streams through pi's builtin transport. Selecting - `loop.providers.google.toolsets.browser()` derives the Loop-owned + `loop.providers.google.toolsets.browser()` derives the Browser Loop-owned `google-interactions` api, which serializes one `computer_use` declaration plus explicit exclusions through the Interactions API adapter. - **Meta/xAI/Moonshot**: ordinary function tools with serial tool calls when the @@ -452,7 +452,7 @@ import { loopApiKeyEnvVarsForProvider, getLoopEnvApiKeyForModel, requireLoopEnvApiKeyForModel, -} from "@onkernel/loop/pi"; +} from "@onkernel/browser-loop/pi"; ``` Conventional variables are `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, @@ -473,7 +473,7 @@ case, then deploy the same catalog — same identities, same names — through `attach()` in your production agent. ```sh -pi install npm:@onkernel/loop +pi install npm:@onkernel/browser-loop pi -p --provider openai --model gpt-5.6-sol \ --browser-tools browser,browser-act "Open example.com and report its heading" @@ -541,9 +541,9 @@ provision one. An owned browser is deleted on session shutdown. ## Development ```bash -npm run typecheck --workspace @onkernel/loop -npm run build --workspace @onkernel/loop -npm test --workspace @onkernel/loop +npm run typecheck --workspace @onkernel/browser-loop +npm run build --workspace @onkernel/browser-loop +npm test --workspace @onkernel/browser-loop ``` Build before testing: the pi print/RPC test loads the extension the way pi does, @@ -552,9 +552,9 @@ through this package's own entry points. The npm-wired agent and harness examples accept `--model` and `--scenario`: ```bash -npm run example:agent --workspace @onkernel/loop -- \ +npm run example:agent --workspace @onkernel/browser-loop -- \ --model anthropic:claude-opus-5 --scenario wikipedia-search -npm run example:harness --workspace @onkernel/loop -- \ +npm run example:harness --workspace @onkernel/browser-loop -- \ --model google:gemini-3.6-flash --scenario hn-url-and-screenshot ``` diff --git a/packages/loop/docs/supported-models.md b/packages/browser-loop/docs/supported-models.md similarity index 92% rename from packages/loop/docs/supported-models.md rename to packages/browser-loop/docs/supported-models.md index ac1f90c4..3bdbffc0 100644 --- a/packages/loop/docs/supported-models.md +++ b/packages/browser-loop/docs/supported-models.md @@ -1,11 +1,11 @@ # Models and native surfaces -`@onkernel/loop` accepts **any model pi-ai carries**, and any model id its +`@onkernel/browser-loop` accepts **any model pi-ai carries**, and any model id its registry has not caught up with yet. There is no allowlist: a model id you pass resolves, and the provider decides whether it exists. Run `listLoopModels(provider?)` for the live catalog. -Two small tables in [`src/pi/models.ts`](https://github.com/kernel/cua/blob/main/packages/loop/src/pi/models.ts) +Two small tables in [`src/pi/models.ts`](https://github.com/kernel/browser-loop/blob/main/packages/browser-loop/src/pi/models.ts) describe what is *different* about particular models. Neither decides whether a model may run. @@ -31,7 +31,7 @@ Anthropic's entries live in `src/pi/providers/anthropic/capabilities.ts`, which version-gated separately; `computerUseNativeSurfaces(model)` reads both sources. A model with no native surface is not restricted — it drives a Kernel browser -with Loop's own CDP tools, which is the default for every provider. +with Browser Loop's own CDP tools, which is the default for every provider. ## Quirks @@ -88,7 +88,7 @@ four such providers rather than carry them unused. a table edit. Probe what the model actually emits: ```bash -npx tsx packages/loop/scripts/native-action-probe.ts --provider openai --model gpt-5.5 --limit 3 +npx tsx packages/browser-loop/scripts/native-action-probe.ts --provider openai --model gpt-5.5 --limit 3 ``` Update that provider's adapter under `src/pi/providers/` to execute the actions the @@ -97,7 +97,7 @@ provider's documentation. Anthropic's computer tool version and its `computer-use-*` beta header are chosen by pi-ai per model, so a new dated version there usually means bumping pi-ai rather than editing this package. -**A model rejects a tool Loop sends.** Add a `LOOP_MODEL_QUIRKS` entry with the +**A model rejects a tool Browser Loop sends.** Add a `LOOP_MODEL_QUIRKS` entry with the observed error as its `reason`, scoped as narrowly as the evidence supports: a single model id over a family, a family over a whole provider. Remove a quirk when the provider lifts the limit — a stale quirk silently denies a model a tool diff --git a/packages/loop/examples/agent.ts b/packages/browser-loop/examples/agent.ts similarity index 100% rename from packages/loop/examples/agent.ts rename to packages/browser-loop/examples/agent.ts diff --git a/packages/loop/examples/anthropic-native-smoke.ts b/packages/browser-loop/examples/anthropic-native-smoke.ts similarity index 100% rename from packages/loop/examples/anthropic-native-smoke.ts rename to packages/browser-loop/examples/anthropic-native-smoke.ts diff --git a/packages/loop/examples/harness.ts b/packages/browser-loop/examples/harness.ts similarity index 100% rename from packages/loop/examples/harness.ts rename to packages/browser-loop/examples/harness.ts diff --git a/packages/loop/examples/quickstart.ts b/packages/browser-loop/examples/quickstart.ts similarity index 100% rename from packages/loop/examples/quickstart.ts rename to packages/browser-loop/examples/quickstart.ts diff --git a/packages/loop/examples/screenshot.png b/packages/browser-loop/examples/screenshot.png similarity index 100% rename from packages/loop/examples/screenshot.png rename to packages/browser-loop/examples/screenshot.png diff --git a/packages/loop/examples/shared/logging.ts b/packages/browser-loop/examples/shared/logging.ts similarity index 100% rename from packages/loop/examples/shared/logging.ts rename to packages/browser-loop/examples/shared/logging.ts diff --git a/packages/loop/examples/shared/options.ts b/packages/browser-loop/examples/shared/options.ts similarity index 100% rename from packages/loop/examples/shared/options.ts rename to packages/browser-loop/examples/shared/options.ts diff --git a/packages/loop/examples/shared/scenarios.ts b/packages/browser-loop/examples/shared/scenarios.ts similarity index 100% rename from packages/loop/examples/shared/scenarios.ts rename to packages/browser-loop/examples/shared/scenarios.ts diff --git a/packages/loop/examples/shared/tools.ts b/packages/browser-loop/examples/shared/tools.ts similarity index 100% rename from packages/loop/examples/shared/tools.ts rename to packages/browser-loop/examples/shared/tools.ts diff --git a/packages/loop/package.json b/packages/browser-loop/package.json similarity index 87% rename from packages/loop/package.json rename to packages/browser-loop/package.json index dfda2a16..e46f5d9d 100644 --- a/packages/loop/package.json +++ b/packages/browser-loop/package.json @@ -1,5 +1,5 @@ { - "name": "@onkernel/loop", + "name": "@onkernel/browser-loop", "version": "0.11.0", "description": "Browser tools for your agent: framework-neutral tool catalog, per-model compilation, Kernel-browser execution, and a pi binding + extension", "license": "MIT", @@ -8,13 +8,13 @@ "types": "./dist/index.d.ts", "repository": { "type": "git", - "url": "git+https://github.com/kernel/cua.git", - "directory": "packages/loop" + "url": "git+https://github.com/kernel/browser-loop.git", + "directory": "packages/browser-loop" }, "bugs": { - "url": "https://github.com/kernel/cua/issues" + "url": "https://github.com/kernel/browser-loop/issues" }, - "homepage": "https://github.com/kernel/cua/tree/main/packages/loop#readme", + "homepage": "https://github.com/kernel/browser-loop/tree/main/packages/browser-loop#readme", "keywords": [ "pi-package", "pi-extension", diff --git a/packages/loop/scripts/native-action-probe.ts b/packages/browser-loop/scripts/native-action-probe.ts similarity index 96% rename from packages/loop/scripts/native-action-probe.ts rename to packages/browser-loop/scripts/native-action-probe.ts index 7fdbe37f..4e63d772 100644 --- a/packages/loop/scripts/native-action-probe.ts +++ b/packages/browser-loop/scripts/native-action-probe.ts @@ -71,9 +71,9 @@ function parseArgs(argv: string[]): Args { function usage(): never { console.log(`Usage: - npx tsx packages/loop/scripts/native-action-probe.ts --provider openai --model gpt-5.5 --out /tmp/actions.json - npx tsx packages/loop/scripts/native-action-probe.ts --provider anthropic --model claude-opus-4-7 --limit 3 - npx tsx packages/loop/scripts/native-action-probe.ts --provider xai --model grok-4.5 --limit 3 + npx tsx packages/browser-loop/scripts/native-action-probe.ts --provider openai --model gpt-5.5 --out /tmp/actions.json + npx tsx packages/browser-loop/scripts/native-action-probe.ts --provider anthropic --model claude-opus-4-7 --limit 3 + npx tsx packages/browser-loop/scripts/native-action-probe.ts --provider xai --model grok-4.5 --limit 3 `); process.exit(0); } @@ -248,7 +248,7 @@ async function readFixtureScreenshot(): Promise { join(process.cwd(), "examples", "screenshot.png"), join(process.cwd(), "packages", "loop", "examples", "screenshot.png"), ].find(existsSync); - if (!path) throw new Error("could not find packages/loop/examples/screenshot.png"); + if (!path) throw new Error("could not find packages/browser-loop/examples/screenshot.png"); return readFile(path); } diff --git a/packages/loop/src/core/actions/browser.ts b/packages/browser-loop/src/core/actions/browser.ts similarity index 100% rename from packages/loop/src/core/actions/browser.ts rename to packages/browser-loop/src/core/actions/browser.ts diff --git a/packages/loop/src/core/actions/computer.ts b/packages/browser-loop/src/core/actions/computer.ts similarity index 100% rename from packages/loop/src/core/actions/computer.ts rename to packages/browser-loop/src/core/actions/computer.ts diff --git a/packages/loop/src/core/actions/index.ts b/packages/browser-loop/src/core/actions/index.ts similarity index 100% rename from packages/loop/src/core/actions/index.ts rename to packages/browser-loop/src/core/actions/index.ts diff --git a/packages/loop/src/core/anthropic-native.ts b/packages/browser-loop/src/core/anthropic-native.ts similarity index 100% rename from packages/loop/src/core/anthropic-native.ts rename to packages/browser-loop/src/core/anthropic-native.ts diff --git a/packages/loop/src/core/browser-result-format.ts b/packages/browser-loop/src/core/browser-result-format.ts similarity index 100% rename from packages/loop/src/core/browser-result-format.ts rename to packages/browser-loop/src/core/browser-result-format.ts diff --git a/packages/loop/src/core/menu.ts b/packages/browser-loop/src/core/menu.ts similarity index 100% rename from packages/loop/src/core/menu.ts rename to packages/browser-loop/src/core/menu.ts diff --git a/packages/loop/src/core/model-info.ts b/packages/browser-loop/src/core/model-info.ts similarity index 100% rename from packages/loop/src/core/model-info.ts rename to packages/browser-loop/src/core/model-info.ts diff --git a/packages/loop/src/core/resources.ts b/packages/browser-loop/src/core/resources.ts similarity index 100% rename from packages/loop/src/core/resources.ts rename to packages/browser-loop/src/core/resources.ts diff --git a/packages/loop/src/core/tool-catalog.ts b/packages/browser-loop/src/core/tool-catalog.ts similarity index 99% rename from packages/loop/src/core/tool-catalog.ts rename to packages/browser-loop/src/core/tool-catalog.ts index 595e767b..fdbd0d30 100644 --- a/packages/loop/src/core/tool-catalog.ts +++ b/packages/browser-loop/src/core/tool-catalog.ts @@ -8,7 +8,7 @@ import { type LoopModelFacts, } from "./model-info"; -export const LOOP_TOOL_SPEC_KIND = "@onkernel/loop-tool-spec/v1" as const; +export const LOOP_TOOL_SPEC_KIND = "@onkernel/browser-loop-tool-spec/v1" as const; /** Loop-owned api id for OpenAI's native computer tool, derived onto the model by {@link compileLoopToolCatalog} when that tool is selected. */ export const OPENAI_COMPUTER_USE_API = "openai-computer-use"; diff --git a/packages/loop/src/core/tools.ts b/packages/browser-loop/src/core/tools.ts similarity index 100% rename from packages/loop/src/core/tools.ts rename to packages/browser-loop/src/core/tools.ts diff --git a/packages/loop/src/core/translator/browser-act.ts b/packages/browser-loop/src/core/translator/browser-act.ts similarity index 100% rename from packages/loop/src/core/translator/browser-act.ts rename to packages/browser-loop/src/core/translator/browser-act.ts diff --git a/packages/loop/src/core/translator/browser-document-reconciliation.ts b/packages/browser-loop/src/core/translator/browser-document-reconciliation.ts similarity index 100% rename from packages/loop/src/core/translator/browser-document-reconciliation.ts rename to packages/browser-loop/src/core/translator/browser-document-reconciliation.ts diff --git a/packages/loop/src/core/translator/browser-frame-collection.ts b/packages/browser-loop/src/core/translator/browser-frame-collection.ts similarity index 100% rename from packages/loop/src/core/translator/browser-frame-collection.ts rename to packages/browser-loop/src/core/translator/browser-frame-collection.ts diff --git a/packages/loop/src/core/translator/browser-observation.ts b/packages/browser-loop/src/core/translator/browser-observation.ts similarity index 100% rename from packages/loop/src/core/translator/browser-observation.ts rename to packages/browser-loop/src/core/translator/browser-observation.ts diff --git a/packages/loop/src/core/translator/browser-ref-lifecycle.ts b/packages/browser-loop/src/core/translator/browser-ref-lifecycle.ts similarity index 100% rename from packages/loop/src/core/translator/browser-ref-lifecycle.ts rename to packages/browser-loop/src/core/translator/browser-ref-lifecycle.ts diff --git a/packages/loop/src/core/translator/browser-wait.ts b/packages/browser-loop/src/core/translator/browser-wait.ts similarity index 100% rename from packages/loop/src/core/translator/browser-wait.ts rename to packages/browser-loop/src/core/translator/browser-wait.ts diff --git a/packages/loop/src/core/translator/browser.ts b/packages/browser-loop/src/core/translator/browser.ts similarity index 100% rename from packages/loop/src/core/translator/browser.ts rename to packages/browser-loop/src/core/translator/browser.ts diff --git a/packages/loop/src/core/translator/cdp.ts b/packages/browser-loop/src/core/translator/cdp.ts similarity index 100% rename from packages/loop/src/core/translator/cdp.ts rename to packages/browser-loop/src/core/translator/cdp.ts diff --git a/packages/loop/src/core/translator/keys.ts b/packages/browser-loop/src/core/translator/keys.ts similarity index 100% rename from packages/loop/src/core/translator/keys.ts rename to packages/browser-loop/src/core/translator/keys.ts diff --git a/packages/loop/src/core/translator/translator.ts b/packages/browser-loop/src/core/translator/translator.ts similarity index 100% rename from packages/loop/src/core/translator/translator.ts rename to packages/browser-loop/src/core/translator/translator.ts diff --git a/packages/loop/src/core/translator/types.ts b/packages/browser-loop/src/core/translator/types.ts similarity index 100% rename from packages/loop/src/core/translator/types.ts rename to packages/browser-loop/src/core/translator/types.ts diff --git a/packages/loop/src/core/url.ts b/packages/browser-loop/src/core/url.ts similarity index 100% rename from packages/loop/src/core/url.ts rename to packages/browser-loop/src/core/url.ts diff --git a/packages/loop/src/index.ts b/packages/browser-loop/src/index.ts similarity index 100% rename from packages/loop/src/index.ts rename to packages/browser-loop/src/index.ts diff --git a/packages/loop/src/pi-extension/browser-runtime.ts b/packages/browser-loop/src/pi-extension/browser-runtime.ts similarity index 98% rename from packages/loop/src/pi-extension/browser-runtime.ts rename to packages/browser-loop/src/pi-extension/browser-runtime.ts index 503fa31d..ce06c56c 100644 --- a/packages/loop/src/pi-extension/browser-runtime.ts +++ b/packages/browser-loop/src/pi-extension/browser-runtime.ts @@ -1,5 +1,5 @@ import Kernel from "@onkernel/sdk"; -import { LoopExecutionResources } from "@onkernel/loop"; +import { LoopExecutionResources } from "@onkernel/browser-loop"; /** * Browser configuration, passed as one JSON object rather than a flag per field. diff --git a/packages/loop/src/pi-extension/index.ts b/packages/browser-loop/src/pi-extension/index.ts similarity index 99% rename from packages/loop/src/pi-extension/index.ts rename to packages/browser-loop/src/pi-extension/index.ts index 6a750833..b857e09f 100644 --- a/packages/loop/src/pi-extension/index.ts +++ b/packages/browser-loop/src/pi-extension/index.ts @@ -6,8 +6,8 @@ import type { Api, Model, SimpleStreamOptions, StreamOptions } from "@earendil-w // package root and cannot follow the deep `@earendil-works/pi-ai/api/*` imports // the provider adapters make. By name, those adapters are loaded from the built // package instead, the way any other consumer loads them. -import type { LoopIncomingToolPlan, LoopToolCatalog, LoopToolSpec } from "@onkernel/loop"; -import { createLoopModels } from "@onkernel/loop/pi"; +import type { LoopIncomingToolPlan, LoopToolCatalog, LoopToolSpec } from "@onkernel/browser-loop"; +import { createLoopModels } from "@onkernel/browser-loop/pi"; import { allSelectableSpecs, compileSpecs, diff --git a/packages/loop/src/pi-extension/render.ts b/packages/browser-loop/src/pi-extension/render.ts similarity index 100% rename from packages/loop/src/pi-extension/render.ts rename to packages/browser-loop/src/pi-extension/render.ts diff --git a/packages/loop/src/pi-extension/selection.ts b/packages/browser-loop/src/pi-extension/selection.ts similarity index 99% rename from packages/loop/src/pi-extension/selection.ts rename to packages/browser-loop/src/pi-extension/selection.ts index 03461596..66bcbf21 100644 --- a/packages/loop/src/pi-extension/selection.ts +++ b/packages/browser-loop/src/pi-extension/selection.ts @@ -1,5 +1,5 @@ import type { Api, Model } from "@earendil-works/pi-ai"; -import { compileLoopToolCatalog, loop, loopToolMenu, type LoopToolCatalog, type LoopToolSpec } from "@onkernel/loop"; +import { compileLoopToolCatalog, loop, loopToolMenu, type LoopToolCatalog, type LoopToolSpec } from "@onkernel/browser-loop"; type Coordinates = "pixels" | "normalized-1000"; type CoordinateSystem = ReturnType | ReturnType; diff --git a/packages/loop/src/pi-extension/state.ts b/packages/browser-loop/src/pi-extension/state.ts similarity index 100% rename from packages/loop/src/pi-extension/state.ts rename to packages/browser-loop/src/pi-extension/state.ts diff --git a/packages/loop/src/pi/api-keys.ts b/packages/browser-loop/src/pi/api-keys.ts similarity index 100% rename from packages/loop/src/pi/api-keys.ts rename to packages/browser-loop/src/pi/api-keys.ts diff --git a/packages/loop/src/pi/attach.ts b/packages/browser-loop/src/pi/attach.ts similarity index 100% rename from packages/loop/src/pi/attach.ts rename to packages/browser-loop/src/pi/attach.ts diff --git a/packages/loop/src/pi/catalog.ts b/packages/browser-loop/src/pi/catalog.ts similarity index 100% rename from packages/loop/src/pi/catalog.ts rename to packages/browser-loop/src/pi/catalog.ts diff --git a/packages/loop/src/pi/index.ts b/packages/browser-loop/src/pi/index.ts similarity index 100% rename from packages/loop/src/pi/index.ts rename to packages/browser-loop/src/pi/index.ts diff --git a/packages/loop/src/pi/loop.ts b/packages/browser-loop/src/pi/loop.ts similarity index 100% rename from packages/loop/src/pi/loop.ts rename to packages/browser-loop/src/pi/loop.ts diff --git a/packages/loop/src/pi/models.ts b/packages/browser-loop/src/pi/models.ts similarity index 100% rename from packages/loop/src/pi/models.ts rename to packages/browser-loop/src/pi/models.ts diff --git a/packages/loop/src/pi/provider-retry.ts b/packages/browser-loop/src/pi/provider-retry.ts similarity index 100% rename from packages/loop/src/pi/provider-retry.ts rename to packages/browser-loop/src/pi/provider-retry.ts diff --git a/packages/loop/src/pi/providers.ts b/packages/browser-loop/src/pi/providers.ts similarity index 100% rename from packages/loop/src/pi/providers.ts rename to packages/browser-loop/src/pi/providers.ts diff --git a/packages/loop/src/pi/providers/anthropic/adaptive-thinking.ts b/packages/browser-loop/src/pi/providers/anthropic/adaptive-thinking.ts similarity index 100% rename from packages/loop/src/pi/providers/anthropic/adaptive-thinking.ts rename to packages/browser-loop/src/pi/providers/anthropic/adaptive-thinking.ts diff --git a/packages/loop/src/pi/providers/anthropic/browser-fallback.ts b/packages/browser-loop/src/pi/providers/anthropic/browser-fallback.ts similarity index 100% rename from packages/loop/src/pi/providers/anthropic/browser-fallback.ts rename to packages/browser-loop/src/pi/providers/anthropic/browser-fallback.ts diff --git a/packages/loop/src/pi/providers/anthropic/capabilities.ts b/packages/browser-loop/src/pi/providers/anthropic/capabilities.ts similarity index 100% rename from packages/loop/src/pi/providers/anthropic/capabilities.ts rename to packages/browser-loop/src/pi/providers/anthropic/capabilities.ts diff --git a/packages/loop/src/pi/providers/common.ts b/packages/browser-loop/src/pi/providers/common.ts similarity index 100% rename from packages/loop/src/pi/providers/common.ts rename to packages/browser-loop/src/pi/providers/common.ts diff --git a/packages/loop/src/pi/providers/google/provider.ts b/packages/browser-loop/src/pi/providers/google/provider.ts similarity index 100% rename from packages/loop/src/pi/providers/google/provider.ts rename to packages/browser-loop/src/pi/providers/google/provider.ts diff --git a/packages/loop/src/pi/providers/openai/provider.ts b/packages/browser-loop/src/pi/providers/openai/provider.ts similarity index 100% rename from packages/loop/src/pi/providers/openai/provider.ts rename to packages/browser-loop/src/pi/providers/openai/provider.ts diff --git a/packages/loop/src/pi/tool-manager.ts b/packages/browser-loop/src/pi/tool-manager.ts similarity index 100% rename from packages/loop/src/pi/tool-manager.ts rename to packages/browser-loop/src/pi/tool-manager.ts diff --git a/packages/loop/test/anthropic-browser-fallback.test.ts b/packages/browser-loop/test/anthropic-browser-fallback.test.ts similarity index 100% rename from packages/loop/test/anthropic-browser-fallback.test.ts rename to packages/browser-loop/test/anthropic-browser-fallback.test.ts diff --git a/packages/loop/test/anthropic-native.integration.test.ts b/packages/browser-loop/test/anthropic-native.integration.test.ts similarity index 100% rename from packages/loop/test/anthropic-native.integration.test.ts rename to packages/browser-loop/test/anthropic-native.integration.test.ts diff --git a/packages/loop/test/anthropic-payload.test.ts b/packages/browser-loop/test/anthropic-payload.test.ts similarity index 100% rename from packages/loop/test/anthropic-payload.test.ts rename to packages/browser-loop/test/anthropic-payload.test.ts diff --git a/packages/loop/test/api-keys.test.ts b/packages/browser-loop/test/api-keys.test.ts similarity index 100% rename from packages/loop/test/api-keys.test.ts rename to packages/browser-loop/test/api-keys.test.ts diff --git a/packages/loop/test/attach-session.test.ts b/packages/browser-loop/test/attach-session.test.ts similarity index 100% rename from packages/loop/test/attach-session.test.ts rename to packages/browser-loop/test/attach-session.test.ts diff --git a/packages/loop/test/attach.test.ts b/packages/browser-loop/test/attach.test.ts similarity index 100% rename from packages/loop/test/attach.test.ts rename to packages/browser-loop/test/attach.test.ts diff --git a/packages/loop/test/browser-act-fail-fast.test.ts b/packages/browser-loop/test/browser-act-fail-fast.test.ts similarity index 100% rename from packages/loop/test/browser-act-fail-fast.test.ts rename to packages/browser-loop/test/browser-act-fail-fast.test.ts diff --git a/packages/loop/test/browser-cross-process.live.test.ts b/packages/browser-loop/test/browser-cross-process.live.test.ts similarity index 100% rename from packages/loop/test/browser-cross-process.live.test.ts rename to packages/browser-loop/test/browser-cross-process.live.test.ts diff --git a/packages/loop/test/browser-frame-collection.test.ts b/packages/browser-loop/test/browser-frame-collection.test.ts similarity index 100% rename from packages/loop/test/browser-frame-collection.test.ts rename to packages/browser-loop/test/browser-frame-collection.test.ts diff --git a/packages/loop/test/browser-ref-lifecycle.test.ts b/packages/browser-loop/test/browser-ref-lifecycle.test.ts similarity index 100% rename from packages/loop/test/browser-ref-lifecycle.test.ts rename to packages/browser-loop/test/browser-ref-lifecycle.test.ts diff --git a/packages/loop/test/browser-runtime.test.ts b/packages/browser-loop/test/browser-runtime.test.ts similarity index 98% rename from packages/loop/test/browser-runtime.test.ts rename to packages/browser-loop/test/browser-runtime.test.ts index 9c0cef91..56d40d02 100644 --- a/packages/loop/test/browser-runtime.test.ts +++ b/packages/browser-loop/test/browser-runtime.test.ts @@ -6,7 +6,7 @@ vi.mock("@onkernel/sdk", () => ({ browsers = { create: state.create, retrieve: state.retrieve, deleteByID: state.deleteByID }; }, })); -vi.mock("@onkernel/loop", () => ({ +vi.mock("@onkernel/browser-loop", () => ({ LoopExecutionResources: class { dispose = state.dispose; constructor(_options: unknown) {} diff --git a/packages/loop/test/browser-wait.test.ts b/packages/browser-loop/test/browser-wait.test.ts similarity index 100% rename from packages/loop/test/browser-wait.test.ts rename to packages/browser-loop/test/browser-wait.test.ts diff --git a/packages/loop/test/cdp.test.ts b/packages/browser-loop/test/cdp.test.ts similarity index 100% rename from packages/loop/test/cdp.test.ts rename to packages/browser-loop/test/cdp.test.ts diff --git a/packages/loop/test/core-boundary.test.ts b/packages/browser-loop/test/core-boundary.test.ts similarity index 93% rename from packages/loop/test/core-boundary.test.ts rename to packages/browser-loop/test/core-boundary.test.ts index af50b6f6..51f000c6 100644 --- a/packages/loop/test/core-boundary.test.ts +++ b/packages/browser-loop/test/core-boundary.test.ts @@ -7,7 +7,7 @@ const CORE_DIR = join(SRC_DIR, "core"); /** * Bare specifiers core may import. Everything else — pi packages, this - * package's own entry points (`@onkernel/loop`, `@onkernel/loop/pi`), any + * package's own entry points (`@onkernel/browser-loop`, `@onkernel/browser-loop/pi`), any * future alias — is rejected by default rather than by enumeration. */ const ALLOWED_BARE_IMPORTS = [/^node:/, /^typebox(\/|$)/, /^@onkernel\/sdk(\/|$)/, /^sharp(\/|$)/]; @@ -50,7 +50,7 @@ function isInsideCore(path: string): boolean { * The neutral boundary: src/core must be expressible without pi in the room. * Nothing under it may import a pi package — even type-only — or reach the pi * binding through any specifier: relative (`../pi`), the package's own public - * subpaths (`@onkernel/loop/pi`), or an unlisted bare import. + * subpaths (`@onkernel/browser-loop/pi`), or an unlisted bare import. */ describe("core boundary", () => { const files = coreFiles(CORE_DIR); @@ -76,8 +76,8 @@ describe("core boundary", () => { for (const forbidden of [ "@earendil-works/pi-ai", "@earendil-works/pi-agent-core", - "@onkernel/loop", - "@onkernel/loop/pi", + "@onkernel/browser-loop", + "@onkernel/browser-loop/pi", "../pi/models", "../pi-extension/selection", "..", diff --git a/packages/loop/test/e2e.live.test.ts b/packages/browser-loop/test/e2e.live.test.ts similarity index 100% rename from packages/loop/test/e2e.live.test.ts rename to packages/browser-loop/test/e2e.live.test.ts diff --git a/packages/loop/test/example-tool-policy.test.ts b/packages/browser-loop/test/example-tool-policy.test.ts similarity index 100% rename from packages/loop/test/example-tool-policy.test.ts rename to packages/browser-loop/test/example-tool-policy.test.ts diff --git a/packages/loop/test/extension.test.ts b/packages/browser-loop/test/extension.test.ts similarity index 100% rename from packages/loop/test/extension.test.ts rename to packages/browser-loop/test/extension.test.ts diff --git a/packages/loop/test/google-provider.test.ts b/packages/browser-loop/test/google-provider.test.ts similarity index 100% rename from packages/loop/test/google-provider.test.ts rename to packages/browser-loop/test/google-provider.test.ts diff --git a/packages/loop/test/harness-context.test.ts b/packages/browser-loop/test/harness-context.test.ts similarity index 100% rename from packages/loop/test/harness-context.test.ts rename to packages/browser-loop/test/harness-context.test.ts diff --git a/packages/loop/test/keys.test.ts b/packages/browser-loop/test/keys.test.ts similarity index 100% rename from packages/loop/test/keys.test.ts rename to packages/browser-loop/test/keys.test.ts diff --git a/packages/loop/test/menu.test.ts b/packages/browser-loop/test/menu.test.ts similarity index 100% rename from packages/loop/test/menu.test.ts rename to packages/browser-loop/test/menu.test.ts diff --git a/packages/loop/test/models.test.ts b/packages/browser-loop/test/models.test.ts similarity index 100% rename from packages/loop/test/models.test.ts rename to packages/browser-loop/test/models.test.ts diff --git a/packages/loop/test/openai-adapter-routing.test.ts b/packages/browser-loop/test/openai-adapter-routing.test.ts similarity index 100% rename from packages/loop/test/openai-adapter-routing.test.ts rename to packages/browser-loop/test/openai-adapter-routing.test.ts diff --git a/packages/loop/test/openai-native-provider.test.ts b/packages/browser-loop/test/openai-native-provider.test.ts similarity index 100% rename from packages/loop/test/openai-native-provider.test.ts rename to packages/browser-loop/test/openai-native-provider.test.ts diff --git a/packages/loop/test/pi-export-surface.test.ts b/packages/browser-loop/test/pi-export-surface.test.ts similarity index 100% rename from packages/loop/test/pi-export-surface.test.ts rename to packages/browser-loop/test/pi-export-surface.test.ts diff --git a/packages/loop/test/pi-modes.test.ts b/packages/browser-loop/test/pi-modes.test.ts similarity index 100% rename from packages/loop/test/pi-modes.test.ts rename to packages/browser-loop/test/pi-modes.test.ts diff --git a/packages/loop/test/provider-retry.test.ts b/packages/browser-loop/test/provider-retry.test.ts similarity index 100% rename from packages/loop/test/provider-retry.test.ts rename to packages/browser-loop/test/provider-retry.test.ts diff --git a/packages/loop/test/provider-stream.test.ts b/packages/browser-loop/test/provider-stream.test.ts similarity index 96% rename from packages/loop/test/provider-stream.test.ts rename to packages/browser-loop/test/provider-stream.test.ts index 75de0a0f..8c11876e 100644 --- a/packages/loop/test/provider-stream.test.ts +++ b/packages/browser-loop/test/provider-stream.test.ts @@ -7,8 +7,8 @@ import { describe, expect, it, vi } from "vitest"; // extension forwarded, so the test observes the model and options that would go // on the wire without a network call. Everything else in the package stays real, and // this mock is scoped to this file so it cannot weaken assertions elsewhere. -vi.mock("@onkernel/loop/pi", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("@onkernel/browser-loop/pi", async (importOriginal) => { + const actual = await importOriginal(); const echo = (id: string) => ({ id, name: `echo-${id}`, diff --git a/packages/loop/test/providers.test.ts b/packages/browser-loop/test/providers.test.ts similarity index 100% rename from packages/loop/test/providers.test.ts rename to packages/browser-loop/test/providers.test.ts diff --git a/packages/loop/test/published-declarations.test.ts b/packages/browser-loop/test/published-declarations.test.ts similarity index 96% rename from packages/loop/test/published-declarations.test.ts rename to packages/browser-loop/test/published-declarations.test.ts index 8f94c537..cdab620c 100644 --- a/packages/loop/test/published-declarations.test.ts +++ b/packages/browser-loop/test/published-declarations.test.ts @@ -20,7 +20,7 @@ import { type LoopAgentTool, type LoopHarnessTool, type KernelBrowser, -} from "@onkernel/loop"; +} from "@onkernel/browser-loop"; import { Agent, AgentHarness, @@ -33,7 +33,7 @@ import { type ExecutionToolContext, } from "@earendil-works/pi-agent-core"; import { NodeExecutionEnv } from "@earendil-works/pi-agent-core/node"; -import { attach, getLoopModel } from "@onkernel/loop/pi"; +import { attach, getLoopModel } from "@onkernel/browser-loop/pi"; import type Kernel from "@onkernel/sdk"; declare const browser: KernelBrowser; @@ -156,8 +156,8 @@ describe("published declarations", () => { noEmit: true, baseUrl: repoRoot, paths: { - "@onkernel/loop": [join(out, "index.d.ts")], - "@onkernel/loop/pi": [join(out, "pi", "index.d.ts")], + "@onkernel/browser-loop": [join(out, "index.d.ts")], + "@onkernel/browser-loop/pi": [join(out, "pi", "index.d.ts")], // The "*" fallback resolves a package root through its package.json, // but not subpath exports; map this one explicitly. "@earendil-works/pi-agent-core/node": [join(repoRoot, "node_modules", "@earendil-works", "pi-agent-core", "dist", "node.d.ts")], diff --git a/packages/loop/test/published-package.test.ts b/packages/browser-loop/test/published-package.test.ts similarity index 100% rename from packages/loop/test/published-package.test.ts rename to packages/browser-loop/test/published-package.test.ts diff --git a/packages/loop/test/resources.test.ts b/packages/browser-loop/test/resources.test.ts similarity index 100% rename from packages/loop/test/resources.test.ts rename to packages/browser-loop/test/resources.test.ts diff --git a/packages/loop/test/selection.test.ts b/packages/browser-loop/test/selection.test.ts similarity index 100% rename from packages/loop/test/selection.test.ts rename to packages/browser-loop/test/selection.test.ts diff --git a/packages/loop/test/tool-catalog.test.ts b/packages/browser-loop/test/tool-catalog.test.ts similarity index 100% rename from packages/loop/test/tool-catalog.test.ts rename to packages/browser-loop/test/tool-catalog.test.ts diff --git a/packages/loop/test/tool-manager.test.ts b/packages/browser-loop/test/tool-manager.test.ts similarity index 100% rename from packages/loop/test/tool-manager.test.ts rename to packages/browser-loop/test/tool-manager.test.ts diff --git a/packages/loop/test/translator-browser.test.ts b/packages/browser-loop/test/translator-browser.test.ts similarity index 100% rename from packages/loop/test/translator-browser.test.ts rename to packages/browser-loop/test/translator-browser.test.ts diff --git a/packages/loop/test/translator.test.ts b/packages/browser-loop/test/translator.test.ts similarity index 100% rename from packages/loop/test/translator.test.ts rename to packages/browser-loop/test/translator.test.ts diff --git a/packages/loop/tsconfig.build.json b/packages/browser-loop/tsconfig.build.json similarity index 83% rename from packages/loop/tsconfig.build.json rename to packages/browser-loop/tsconfig.build.json index da5abfed..0b0cc7c9 100644 --- a/packages/loop/tsconfig.build.json +++ b/packages/browser-loop/tsconfig.build.json @@ -11,8 +11,8 @@ // path; see the note in src/pi-extension/index.ts. Point those specifiers // at source so a typecheck does not require a build first. "paths": { - "@onkernel/loop": ["./src/index.ts"], - "@onkernel/loop/pi": ["./src/pi/index.ts"] + "@onkernel/browser-loop": ["./src/index.ts"], + "@onkernel/browser-loop/pi": ["./src/pi/index.ts"] } }, "include": ["src/**/*.ts"], diff --git a/packages/loop/tsconfig.json b/packages/browser-loop/tsconfig.json similarity index 100% rename from packages/loop/tsconfig.json rename to packages/browser-loop/tsconfig.json diff --git a/packages/loop/tsdown.config.ts b/packages/browser-loop/tsdown.config.ts similarity index 100% rename from packages/loop/tsdown.config.ts rename to packages/browser-loop/tsdown.config.ts diff --git a/packages/loop/vitest.config.ts b/packages/browser-loop/vitest.config.ts similarity index 86% rename from packages/loop/vitest.config.ts rename to packages/browser-loop/vitest.config.ts index 736a603f..82f79f18 100644 --- a/packages/loop/vitest.config.ts +++ b/packages/browser-loop/vitest.config.ts @@ -11,8 +11,8 @@ export default defineConfig({ // `@earendil-works/pi-ai/api/*` imports the provider adapters make. Unit // tests point that name back at source so they do not need a build. alias: { - "@onkernel/loop/pi": fileURLToPath(new URL("./src/pi/index.ts", import.meta.url)), - "@onkernel/loop": fileURLToPath(new URL("./src/index.ts", import.meta.url)), + "@onkernel/browser-loop/pi": fileURLToPath(new URL("./src/pi/index.ts", import.meta.url)), + "@onkernel/browser-loop": fileURLToPath(new URL("./src/index.ts", import.meta.url)), }, }, test: { diff --git a/packages/loop/vitest.integration.config.ts b/packages/browser-loop/vitest.integration.config.ts similarity index 68% rename from packages/loop/vitest.integration.config.ts rename to packages/browser-loop/vitest.integration.config.ts index 861d004c..489101ac 100644 --- a/packages/loop/vitest.integration.config.ts +++ b/packages/browser-loop/vitest.integration.config.ts @@ -8,8 +8,8 @@ export default defineConfig({ resolve: { // Same source alias the unit config sets; see the note there. alias: { - "@onkernel/loop/pi": fileURLToPath(new URL("./src/pi/index.ts", import.meta.url)), - "@onkernel/loop": fileURLToPath(new URL("./src/index.ts", import.meta.url)), + "@onkernel/browser-loop/pi": fileURLToPath(new URL("./src/pi/index.ts", import.meta.url)), + "@onkernel/browser-loop": fileURLToPath(new URL("./src/index.ts", import.meta.url)), }, }, test: { diff --git a/tsconfig.json b/tsconfig.json index 34b327be..5c29957f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "files": [], "references": [ - { "path": "./packages/loop" }, + { "path": "./packages/browser-loop" }, { "path": "./packages/ptywright" } ] } From f72a0f2689d0337d0fb2089a88d037938a8d4b8f Mon Sep 17 00:00:00 2001 From: rgarcia <72655+rgarcia@users.noreply.github.com> Date: Wed, 19 Aug 2026 17:31:55 +0000 Subject: [PATCH 2/2] Fix the renamed probe fixture path --- packages/browser-loop/scripts/native-action-probe.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/browser-loop/scripts/native-action-probe.ts b/packages/browser-loop/scripts/native-action-probe.ts index 4e63d772..1cdba3f0 100644 --- a/packages/browser-loop/scripts/native-action-probe.ts +++ b/packages/browser-loop/scripts/native-action-probe.ts @@ -246,7 +246,7 @@ async function probeXai(model: string, prompt: ProbePrompt): Promise { const path = [ join(process.cwd(), "examples", "screenshot.png"), - join(process.cwd(), "packages", "loop", "examples", "screenshot.png"), + join(process.cwd(), "packages", "browser-loop", "examples", "screenshot.png"), ].find(existsSync); if (!path) throw new Error("could not find packages/browser-loop/examples/screenshot.png"); return readFile(path);