pi-agent-browser-native 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +16 -7
- package/dist/extensions/agent-browser/index.js +430 -157
- package/dist/extensions/agent-browser/lib/browser-journal.js +418 -0
- package/dist/extensions/agent-browser/lib/browser-session-conversion.js +381 -0
- package/dist/extensions/agent-browser/lib/browser-transcript.js +119 -19
- package/dist/extensions/agent-browser/lib/input-modes/job.js +49 -2
- package/dist/extensions/agent-browser/lib/input-modes/params.js +32 -35
- package/dist/extensions/agent-browser/lib/managed-session-policy-lock.js +25 -5
- package/dist/extensions/agent-browser/lib/managed-session-restore.js +20 -5
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-policy.js +97 -78
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +23 -2
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +52 -17
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +1 -1
- package/dist/extensions/agent-browser/lib/orchestration/script-mode.js +13 -8
- package/dist/extensions/agent-browser/lib/playbook.js +9 -2
- package/dist/extensions/agent-browser/lib/prompt-policy.js +0 -14
- package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +2 -1
- package/dist/extensions/agent-browser/lib/session-page-state.js +95 -157
- package/dist/extensions/agent-browser/lib/temp.js +14 -6
- package/dist/extensions/agent-browser/lib/tool-surface.js +12 -23
- package/dist/extensions/agent-browser/lib/web-search.js +0 -8
- package/docs/ARCHITECTURE.md +13 -11
- package/docs/COMMAND_REFERENCE.md +9 -7
- package/docs/RELEASE.md +3 -3
- package/docs/REQUIREMENTS.md +1 -1
- package/docs/SESSION_STORAGE.md +60 -0
- package/docs/SUPPORT_MATRIX.md +8 -5
- package/docs/TOOL_CONTRACT.md +17 -14
- package/package.json +9 -5
- package/scripts/build.mjs +4 -3
- package/scripts/convert-browser-session.mjs +22 -0
package/docs/TOOL_CONTRACT.md
CHANGED
|
@@ -12,7 +12,9 @@ Related docs:
|
|
|
12
12
|
|
|
13
13
|
Entry tools are `agent_browser` (native argv), `agent_browser_code` (fresh JavaScript over a persistent browser), and `agent_browser_tools` (advanced capability discovery/activation). Optional credential-backed `agent_browser_web_search` remains independent of browser state and joins the entry surface only when registered.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
The extension synchronously registers a `browser` instruction group through the public `pi:instruction-groups` event bus. One full instruction function supplies project/config guidance, shared browser rules, and all specialized tool guidance. When the collector's dynamic `isManaged()` is true, Pi owns delivery through `discover_tools` and compaction repair; the extension does not inject a duplicate eager section. Otherwise `before_agent_start` supplies the identical full instructions eagerly, including on generic prompts and stock Pi. There is no legacy discovery metadata or prompt-keyword gate.
|
|
16
|
+
|
|
17
|
+
Group enablement reveals selected declarations and instructions, not callable permissions. `agent_browser_tools` remains the separate advanced-tool activation path. Existing host selections, exclusions, namespaces, and restored tool history are unchanged.
|
|
16
18
|
|
|
17
19
|
Pi 0.87.0 or newer is required; official and fork qualification is independent. Five specialized tools are registered but initially inactive: `agent_browser_action`, `agent_browser_qa`, `agent_browser_electron`, `agent_browser_source`, and `agent_browser_network_source`. Explicit CLI allowlists, filtered SDK catalogs, and restored Pi tool history are respected. Omit CLI `--tools` for lazy activation, or include every desired advanced tool in its allowlist; the loader reports excluded tools as unavailable rather than bypassing host selection. Pi 0.87 does not distinguish an SDK explicitly selecting the complete browser catalog from its default catalog; SDK hosts choosing activation for that complete catalog can call `session.setActiveToolsByName(...)` after `bindExtensions()`.
|
|
18
20
|
|
|
@@ -29,7 +31,7 @@ It also keeps the main UX where it belongs: the agent invokes the tool directly
|
|
|
29
31
|
|
|
30
32
|
The tool guidance should be written for task discovery first, not wrapper implementation first. That means the description should emphasize browser use cases like reading live pages, clicking, filling, screenshots, extraction, and authenticated/profile-based workflows. Live/current external facts belong on `agent_browser_web_search` when that companion tool is registered. Low-level wrapper details like `stdin` and exact CLI args belong in the schema and guidelines, not the lead description.
|
|
31
33
|
|
|
32
|
-
The tool also needs an operating playbook, not just a capability list. The model
|
|
34
|
+
The tool also needs an operating playbook, not just a capability list. The model receives the full operating guidance before browser use. The canonical agent-facing playbook lives in `extensions/agent-browser/lib/playbook.ts`; it provides the shared full instruction source plus absolute installed-package paths to `README.md`, `docs/COMMAND_REFERENCE.md`, and this contract so agents with file tools can read targeted guidance on demand instead of receiving the full docs in prompt context. Generated Markdown fragments are updated by `npm run docs -- playbook write`, and `npm run docs -- playbook check` fails when checked-in documentation drifts.
|
|
33
35
|
|
|
34
36
|
The native command reference in `docs/COMMAND_REFERENCE.md` is driven by the same pattern: `scripts/agent-browser-target.mjs` owns the runtime version and `scripts/agent-browser-capability-baseline.mjs` imports it alongside help/doc inventory; selected regions are generated into the Markdown by `npm run docs -- command-reference write`, and `npm run docs` plus `npm run verify -- command-reference` catch drift (the latter also samples the installed `agent-browser` on `PATH`). Maintainer workflow details live in `AGENTS.md` under upstream capability baseline.
|
|
35
37
|
|
|
@@ -323,9 +325,9 @@ Source runs in a fresh permissioned Node child with an empty child environment,
|
|
|
323
325
|
|
|
324
326
|
`codeRun` reports `callCount`, `emitCount`, `failedCallCount`, `rejectedCallCount`, and timeout/abort flags. `codeSteps` retains bounded audit rows. Handled browser failures may coexist with successful source completion, but remain model-visible in `failures` with exact recovery evidence and in the failure count. A successful code result therefore does not assert that every inner command succeeded. Invalid inner input shapes make the outer result fail even if source handles their observations. Uncaught source exceptions use `script-error`; deadline and cancellation use `timeout` and `aborted`; output/bridge validation retains its specific failure.
|
|
325
327
|
|
|
326
|
-
|
|
328
|
+
Direct browser use in a disabled/no-file Pi session (`--no-session`) records current in-memory state without claiming persistence. Code requires an actually published journal, and a named but not-yet-published persistent conversation refuses browser dispatch. Sessionless local inspections and browser-independent reads remain available without journal publication, including complete redacted private spills and selected output files; observation-only artifact receipts are optional until publication. Direct, code and Electron host operations use one canonical journal event/reducer. Begin/finish records correlate operation ID, outer tool-call ID and inner command index, preserving native effects before presentation/export. Complete snapshots are defined once; ordinary finishes explicitly reuse, replace, invalidate or keep refs unknown. An unfinished begin requires inspection and a new capture, without repeating the mutation. Failed finish publication reports `browserStatePersistence: "finish-unconfirmed"` and stops dependent code calls; failed begin reports `"begin-unconfirmed"` and prevents dispatch. These acknowledgments do not promise power-loss-atomic browser actions. See [session storage and conversion](SESSION_STORAGE.md).
|
|
327
329
|
|
|
328
|
-
Abort, timeout, branch change, reload, and shutdown stop/reap the child
|
|
330
|
+
Abort, timeout, branch change, reload, and shutdown stop/reap the child, settle the active inner call and join outer observation finalization before releasing lifecycle coordination. A result from a prior branch retains its complete caller observation in a process-private spill without changing the newly selected branch's artifact state. They do not roll back browser actions or automatically close the selected browser. Existing ownership still controls later shutdown cleanup. The offline converter normalizes exact pre-0.7 isolated-session cleanup leases into owner-qualified canonical events; runtime only reads those canonical cleanup facts, without old public script execution.
|
|
329
331
|
|
|
330
332
|
### `agent_browser_action`
|
|
331
333
|
|
|
@@ -357,7 +359,7 @@ Locator click/check/fill compiles to native `find`; direct targets compile to th
|
|
|
357
359
|
Enable `qa`. Flat input is either `{ url, ...checks }` or `{ attached: true, ...checks }`; these forms are exclusive. Checks are optional `expectedText` (string or string array), `expectedSelector`, `screenshotPath`, `checkNetwork`, `checkConsole`, `checkErrors`, and `loadState` (`domcontentloaded` default, `load`, or `networkidle`). `outputPath`, `timeoutMs`, and `sessionMode` are supported; attached QA only accepts `sessionMode: "auto"`.
|
|
358
360
|
|
|
359
361
|
```json
|
|
360
|
-
{ "url": "https://example.com", "expectedText": "
|
|
362
|
+
{ "url": "https://example.com", "expectedText": "Learn more", "screenshotPath": "/tmp/qa.png" }
|
|
361
363
|
{ "attached": true, "expectedText": "Explorer", "checkErrors": true }
|
|
362
364
|
```
|
|
363
365
|
|
|
@@ -365,7 +367,7 @@ QA compiles a fixed `batch --bail` diagnostic plan. URL QA clears enabled networ
|
|
|
365
367
|
|
|
366
368
|
Attached QA checks the current browser without navigation or buffer clears. It first requires a live nonempty URL, including file/custom app URLs. Failed target verification returns exact tab/URL recovery instead of running the batch. Diagnostic reads default off because preserved buffers may predate this check; URL diagnostics default on. Explicit `checkErrors: false` skips the error-baseline check.
|
|
367
369
|
|
|
368
|
-
The verdict is `qaPreset: { passed, failedChecks, warnings, summary }`. Console errors, definitely new page errors, ambiguous matching post-clear residue, actionable failed requests, failed batch steps, or failed visible assertions cause `qa-failure`. Matching a nonempty error baseline is an **unverified check**, not proof of a new application error. A clean final buffer can pass. Benign low-impact icon misses may be warnings when the failed row and resource metadata satisfy `classifyNetworkRequestFailure`; ordinary document/script/API failures remain actionable. Native diagnostic-read success alone never constitutes a QA pass.
|
|
370
|
+
The verdict is `qaPreset: { passed, failedChecks, notRunChecks, warnings, summary }`. When a reported fail-fast step stops the batch, `notRunChecks` lists later readiness, text/selector, diagnostic, and screenshot checks rather than falsely marking them failed; reset and settle rows are omitted. Incomplete receipts without a reported failure remain unverified, not inferred as unexecuted. Failed QA leads with the redacted causal error when available, then failed/not-run checks and reported execution coverage; a timeout without step receipts shows an unknown executed count, not zero. Console errors, definitely new page errors, ambiguous matching post-clear residue, actionable failed requests, failed batch steps, or failed visible assertions cause `qa-failure`. Matching a nonempty error baseline is an **unverified check**, not proof of a new application error. A clean final buffer can pass. Benign low-impact icon misses may be warnings when the failed row and resource metadata satisfy `classifyNetworkRequestFailure`; ordinary document/script/API failures remain actionable. Native diagnostic-read success alone never constitutes a QA pass.
|
|
369
371
|
|
|
370
372
|
`details.compiledQaPreset` retains the generated plan and checks, including `diagnosticsResetAtStart`; `compiledJob` is internal QA batch-plan metadata, not a public job DSL. Use native batch/code for custom checks.
|
|
371
373
|
|
|
@@ -701,7 +703,7 @@ Additional structured fields can appear when relevant:
|
|
|
701
703
|
- `compiledSourceLookup` when the call used `agent_browser_source`: `{ args: ["batch"], stdin, steps, query }` with the generated local-evidence plan and original query fields (`selector?`, `reactFiberId?`, `componentName?`, `includeDomHints?`, `maxWorkspaceFiles?`).
|
|
702
704
|
- `sourceLookup` when the call used `agent_browser_source`: `{ status, candidates, limitations, summary, workspaceRoot?, electronContext? }`; wrapper-tracked packaged Electron no-candidate diagnostics may carry `workspaceRoot` plus `electronContext` and live Electron nextActions without marking the successful batch as a tool failure.
|
|
703
705
|
- `compiledNetworkSourceLookup` / `networkSourceLookup` when the call used `agent_browser_network_source`: the generated batch plan plus bounded failed-request/candidate evidence as described above.
|
|
704
|
-
- `qaPreset` when the call used `agent_browser_qa`: `{ passed, failedChecks, warnings, summary }`. `failedChecks` includes “page-error check could not be verified” when final errors match a nonempty post-clear baseline; this sets `passed: false` without claiming those matched rows are new application errors. Definitely new rows are counted separately as page errors. Network rows inside the `network requests` batch step use `summarizeNetworkFailures` / `classifyNetworkRequestFailure` in `network.ts`: actionable failures appear in `failedChecks` (and fail the tool when the upstream batch still succeeded); benign icon-classified failures appear only in `warnings` and in `summary` as `QA preset passed with warnings: …` when nothing else failed.
|
|
706
|
+
- `qaPreset` when the call used `agent_browser_qa`: `{ passed, failedChecks, notRunChecks, warnings, summary }`. `notRunChecks` is empty on a complete result or an unknown timeout; after a reported fail-fast failure it lists only significant checks whose later compiled steps have no result. `failedChecks` includes “page-error check could not be verified” when final errors match a nonempty post-clear baseline; this sets `passed: false` without claiming those matched rows are new application errors. Definitely new rows are counted separately as page errors. Network rows inside the `network requests` batch step use `summarizeNetworkFailures` / `classifyNetworkRequestFailure` in `network.ts`: actionable failures appear in `failedChecks` (and fail the tool when the upstream batch still succeeded); benign icon-classified failures appear only in `warnings` and in `summary` as `QA preset passed with warnings: …` when nothing else failed.
|
|
705
707
|
- `networkRouteDiagnostics` after successful `network requests` when the wrapper has observed active `network route` patterns for that session and a matching request row is pending/no-status or carries CORS/preflight-looking error text. Each row includes `reason` (`"pending-routed-request"` or `"cors-likely-routed-request"`), `routePattern`, `mode`, optional `requestId`, optional `requestUrl`, and `summary`; visible text starts with `Network route diagnostics`, and `details.nextActions` prepends executable route-mock inspection/HAR follow-ups before generic request follow-ups.
|
|
706
708
|
- `compiledElectron` when the call used `agent_browser_electron`: redacted action plan for `list`, `launch`, `status`, `cleanup`, or `probe`.
|
|
707
709
|
- `electron` when the call used `agent_browser_electron`: action-specific lifecycle, discovery, probe, and cleanup data; see the `agent_browser_electron` contract above.
|
|
@@ -712,6 +714,7 @@ Additional structured fields can appear when relevant:
|
|
|
712
714
|
- `promptGuard` when the requested-artifact-before-close guard blocks browser close before required prompt artifact paths are verified; implementation lives in `extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.ts`
|
|
713
715
|
- `overlayBlockers` for conservative overlay/banner/dialog blocker candidates when a successful snapshot itself contains strong modal evidence, or after a qualifying top-level `@e…` / `ref=` click stays on the same URL, no `clickDispatch` diagnostic fired, and a fresh snapshot provides evidence (`candidates`, `summary`, and `snapshot` per `OverlayBlockerDiagnostic` in `extensions/agent-browser/index.ts`). CSS selector clicks do not run this overlay probe.
|
|
714
716
|
- `visibleRefFallback` after a raw `find` or compiled `agent_browser_action` fails with `selector-not-found` and a fresh snapshot finds exact role/name `@ref` matches. Shape follows `VisibleRefFallbackDiagnostic` in `extensions/agent-browser/lib/results/selector-recovery.ts`: `{ candidates, snapshot, summary, target }`, where each candidate has `ref`, `role`, `name`, optional direct ref `args`, and `reason`; visible text appends `Current snapshot ref fallback`. Non-fill candidates with direct args add `try-current-visible-ref` or numbered `try-current-visible-ref-N` actions. Fill candidates omit direct args and target text so recovery details do not repeat potentially sensitive fill text.
|
|
717
|
+
- `browserEventVersion: 1` marks current tool observations; replay authority is the canonical custom journal event, not presentation details. Ordinary commands omit unchanged `refSnapshot`; dedicated snapshot captures retain full membership, accessible metadata, target, snapshot ID and verified native generation when available. A changed or unverifiable generation requires a new complete capture even at the same URL.
|
|
715
718
|
- `refSnapshotInvalidation` after a confirmed cold managed-session shutdown (`reason: "page-transition"`, including when reopening fails), a session `snapshot` fails with `No active page`, any upstream-executed `record start` attempt or URL-bearing `record restart` conservatively invalidates refs (including failures, for older-native protection rather than proof of a page change), a direct or reached batch `window new` / `diff url` attempt changes the page, or a failed non-batch transition command (`eval`, `back`, `forward`, `reload`, `connect`, `state load`, `tab` selection) whose live URL re-verification probe observed the page (a failed transition can still have mutated the document, so the verified URL is kept but the prior refs are not). Shape follows `SessionRefSnapshotInvalidation` in `extensions/agent-browser/lib/session-page-state.ts`: `{ reason: "no-active-page" | "page-transition", summary }`; replay preserves the persisted summary. The wrapper deletes prior refs for that session, persists the invalidation for resume, and blocks mutation-prone `@e…` preflight with `failureCategory: "stale-ref"` until a successful fresh `snapshot -i` records refs again.
|
|
716
719
|
- `snapshotFilter` after wrapper-side `snapshot -i --search <text>` or `snapshot -i --filter role=<role>`. Shape: `{ cleanArgs, search?, role?, matchedRefs, totalRefs, visibleLines, totalLines, renderedTextMatches?, renderedTextTotalMatches?, renderedTextTruncated? }`. Search runs one bounded read-only rendered-DOM probe across the full document; each visible match carries bounded `text`, `tagName`, `kind` (`text` or prioritized `validation`), `offscreen`, optional `role`/accessible `name`, and a unique mapped `ref` when the full snapshot supports it. Hidden elements are excluded. The filtered accessibility snapshot remains separate, while `details.refSnapshot` still records the full upstream ref map for later stale-ref checks.
|
|
717
720
|
- `snapshotViewport` after wrapper-side `snapshot --viewport` (with or without `-i`, `--search`, or `--filter`). Shape matches the scroll-position probe: viewport scroll offsets, inner/document dimensions, sampled scrollable-container count, and bounded container offsets. The wrapper strips `--viewport` before upstream spawn and gathers this with a read-only `eval --stdin` call.
|
|
@@ -737,10 +740,10 @@ Additional structured fields can appear when relevant:
|
|
|
737
740
|
|
|
738
741
|
Recording destinations are reserved within one Pi process, not across processes. Use unique paths for concurrent Pi processes: different explicit sessions can overwrite one file even when both `record stop` results are verified. Upstream’s same-session `record start` guard does not reserve the filename across other sessions.
|
|
739
742
|
- `savedFilePath` / `savedFile` for direct `download`, `pdf`, and `wait --download` / `wait -d` saved-file workflows when a host file path is reported or wrapper-verified. Batch results preserve the same fields on the relevant `batchSteps` entry. These fields are metadata only until `artifactVerification` verifies the file. Native `download <selector> <path>` always owns the click and download, including loopback links, generated Blob exports, and redirects; the wrapper does not substitute a fetch of an anchor's `href`.
|
|
740
|
-
- `batchSteps[].artifacts` for per-step artifacts in `batch` output; top-level `artifacts` and `artifactManifest` coalesce an earlier pending recording into the later saved, missing, or stale terminal result for the same namespace/session identity. `record restart` includes both the previous recording it finalized (or an explicit missing/stale failure) and the new pending recording; missing/stale terminal rows retire the prior pending manifest row. A successful later `close` / `quit` / `exit` retires an earlier unfinalized pending recording as `subcommand: "close-abandoned"`, clears its stop action, and leaves its file unverified. Batch presentation checks the path: only a confirmed absent file becomes `status: "missing"`; a present or inaccessible file stays unverified. It updates aggregate verification/manifest state consistently; a later successful `record stop` replaces that intermediate abandoned row with its saved artifact. Close also resets ref/page/network-route state produced by earlier rows; later lifecycle-proven browser launches, including `record stop`, can rebuild that state without triggering stale pre-close `about:blank` recovery, explicitly non-launching diagnostics cannot, and unknown later rows stay conservatively active. Per-step history remains unchanged. When any later call on the same namespace/session fails while a recording remains pending, `nextActions` combines its normal recovery with exact `stop-pending-recording` args and visible cleanup guidance; the same applies at top level when a later batch step fails. After reload in a non-Git checkout or with managed restore disabled, a live daemon without current-instance provenance cannot accept a stop. A tracked Electron attachment can rebuild that proof through the live debug-endpoint check described above;
|
|
743
|
+
- `batchSteps[].artifacts` for per-step artifacts in `batch` output; top-level `artifacts` and `artifactManifest` coalesce an earlier pending recording into the later saved, missing, or stale terminal result for the same namespace/session identity. `record restart` includes both the previous recording it finalized (or an explicit missing/stale failure) and the new pending recording; missing/stale terminal rows retire the prior pending manifest row. A successful later `close` / `quit` / `exit` retires an earlier unfinalized pending recording as `subcommand: "close-abandoned"`, clears its stop action, and leaves its file unverified. Batch presentation checks the path: only a confirmed absent file becomes `status: "missing"`; a present or inaccessible file stays unverified. It updates aggregate verification/manifest state consistently; a later successful `record stop` replaces that intermediate abandoned row with its saved artifact. Close also resets ref/page/network-route state produced by earlier rows; later lifecycle-proven browser launches, including `record stop`, can rebuild that state without triggering stale pre-close `about:blank` recovery, explicitly non-launching diagnostics cannot, and unknown later rows stay conservatively active. Per-step history remains unchanged. When any later call on the same namespace/session fails while a recording remains pending, `nextActions` combines its normal recovery with exact `stop-pending-recording` args and visible cleanup guidance; the same applies at top level when a later batch step fails. After reload in a non-Git checkout or with managed restore disabled, a live daemon without current-instance provenance or a matching same-owner native daemon receipt cannot accept a stop. A tracked Electron attachment can rebuild that proof through the live debug-endpoint check described above; unproven restore-disabled sessions cannot rebuild provenance from a name or URL. That policy refusal includes `managedSessionCleanupOnlyReason: "restore-disabled-daemon-without-provenance"` plus the exact `sessionName`/`namespace`, including on implicit calls. It replaces the impossible stop with `close-pending-recording`, an exact close without `sessionMode: "fresh"`. Close retires the recording as `close-abandoned`; any file it leaves is unverified. Same-instance recordings and supported durable-Git reloads still use stop and normal WebM verification.
|
|
741
744
|
- `artifactVerification` for a normalized verification summary on the unified result and on each successful `batchSteps[]` row and on failed recording rows whose receipt identifies an artifact. Top-level `batch` verification rolls up all step file artifacts; each step’s summary reflects that step’s nested tool presentation (including its spill paths and manifest slice). It reports `verified`, `verifiedCount`, `missingCount`, `pendingCount`, `unverifiedCount`, and `artifacts[]` entries with `path`, optional `absolutePath`, optional `requestedPath`, `kind` (a normal file artifact kind or `"spill"` for manifest-backed rows), optional `mediaType`, optional `exists`, optional `sizeBytes`, optional `updatedAtMs`, optional `status`, optional `retentionState` / `storageScope` on manifest-derived rows, `state` (`verified`, `missing`, `pending`, or `unverified`), and optional `limitation` (human-readable lifecycle or retention context, for example pending `record start` / `record restart`, missing, stale, or otherwise unverified files, ephemeral spill files, or evicted persisted spills). The summary `verified` boolean is true only when every entry is `verified`. `record start` / `record restart` are `pending` until `record stop`; `state load` may mention a path in command output but is not a saved artifact row.
|
|
742
745
|
- `fullOutputPath` / `fullOutputPaths` when parse-valid large snapshot output or other oversized tool output is compacted and spilled to a private file; persisted sessions keep that path under a private session-scoped artifact directory for reload/resume, with a per-session byte budget by default; `PI_AGENT_BROWSER_SESSION_ARTIFACT_MAX_BYTES=0` disables automatic eviction. Malformed oversized upstream output is discarded after parsing, is omitted from `details.stdout`, and reports `fullOutputUnavailable` instead of creating a parse-failure spill.
|
|
743
|
-
- `artifactManifest` for
|
|
746
|
+
- `artifactManifest` for changed or referenced metadata-only receipts in this invocation, without unchanged session history. Entries include path metadata, optional recording receipt/start-window metadata, canonical `namespace` plus `session` lifecycle identity, artifact `kind`, source `command`/`subcommand` when safe, `storageScope` (`persistent-session`, `process-temp`, or `explicit-path`), and `retentionState` (`live`, `ephemeral`, `missing`, or `evicted`). The default recent window is 100 entries and can be configured with `PI_AGENT_BROWSER_SESSION_ARTIFACT_MANIFEST_MAX_ENTRIES`. A successful session close retires only that exact namespace/session identity's pending recording rows; the separate active reservation index remains authoritative even if this bounded display inventory evicts them. Only the newest pending recording row per namespace/session identity remains live in the manifest. The manifest must not store command args, output contents, headers, DOM snapshots, or downloaded file contents.
|
|
744
747
|
- `artifactRetentionSummary` with a concise count of live, evicted, ephemeral, and missing artifacts from the current manifest; results append this summary to model-facing text only when retention state affects recovery, such as spill files, ephemeral files, or evictions. Routine explicit saved files keep the summary in details to avoid noisy browsing transcripts.
|
|
745
748
|
- `artifactCleanup` after a successful close command (`close`, `quit`, or `exit`) only when `artifactManifest` contains at least one existing explicit artifact path. Fields: `owner: "host-file-tools"`, `summary` (same retention summary string as `artifactRetentionSummary` for that manifest), `note` explaining that browser close commands do not delete explicit screenshots/downloads/PDFs/traces/HAR/recordings, and `explicitArtifactPaths`: up to ten **distinct existing** paths taken from manifest rows with `storageScope: "explicit-path"` in encounter order (de-duplicated after checking the filesystem); deleted/stale explicit paths are skipped. When the recent window has only spill/ephemeral inventory or explicit paths already deleted, the field and visible cleanup guidance are omitted. The visible close text stays compact and points operators to `details.artifactCleanup.explicitArtifactPaths` instead of listing paths inline. The native browser tool intentionally does not expose a delete operation for arbitrary user-chosen artifact paths; agents should inspect `artifactVerification` / manifest metadata, then remove files with normal host file tools when cleanup is required.
|
|
746
749
|
- compact **snapshot** metadata on successful presentation when `details.data.compacted` is true (oversized trees): `previewMode` (`"structured"` vs outline `"outline"`), `structuredPreviewUsed`, `previewRefIds`, `previewSections` (per-section `linesShown` / `omittedLines` / root `role` / `title`), `additionalSectionsOmitted`, counts such as `refCount`, `snapshotLineCount`, and `roleCounts`, optional `highValueControlRefIds` aligned with the visible bounded `Omitted high-value controls` lines, and optional `spillError` when the wrapper could not write the redacted spill file; the model text still ends with `Full redacted snapshot path:` or an explicit unavailable reason plus `details.fullOutputPath` when a path exists
|
|
@@ -754,7 +757,7 @@ When the tool echoes `args` or `effectiveArgs` back into Pi, sensitive values su
|
|
|
754
757
|
|
|
755
758
|
URL redaction covers `code`, SAMLRequest, SAMLResponse, RelayState, and `authorization_session_id` (including common separator/case variants); `state` and `nonce` are redacted only when the same URL token has an auth/login/OAuth/OIDC/SAML/SSO context or another known sensitive query name, so ordinary application state URLs remain useful. URLs needing no redaction keep their original spelling. Exact internal page-target URLs stay unredacted for browser correctness; model-facing content, structured details, persisted spills, and explicit `outputPath` exports receive the same redacted copies.
|
|
756
759
|
|
|
757
|
-
For parse-valid oversized snapshots and other oversized tool outputs, details should switch to a compact metadata object and include `fullOutputPath` pointing at a private spill file with the full redacted upstream payload. When the caller supplied `outputPath`, only matching live wrapper-manifest spills may provide pre-compaction payloads; direct compacted data, compacted result rows, and command-redacted whole-batch data are rehydrated in place, while any unavailable required spill fails without writing compact metadata. Malformed oversized output is not safe to redact structurally, so its temporary subprocess spill is deleted and no durable `fullOutputPath` is returned. The model-facing tool text should print the actual spill-file path when one exists instead of only saying to inspect a details key. Oversized batch/QA failures include bounded failed-step context inline before the preview so agents can see the failed assertion/error and failure category without opening the spill file. Persisted sessions should keep that spill file under a private session-scoped artifact directory so the path remains usable after reload/restart. The oldest persisted spill files are evicted as needed to stay within `PI_AGENT_BROWSER_SESSION_ARTIFACT_MAX_BYTES` (default 32 MiB), and
|
|
760
|
+
For parse-valid oversized snapshots and other oversized tool outputs, details should switch to a compact metadata object and include `fullOutputPath` pointing at a private spill file with the full redacted upstream payload. When the caller supplied `outputPath`, only matching live wrapper-manifest spills may provide pre-compaction payloads; direct compacted data, compacted result rows, and command-redacted whole-batch data are rehydrated in place, while any unavailable required spill fails without writing compact metadata. Malformed oversized output is not safe to redact structurally, so its temporary subprocess spill is deleted and no durable `fullOutputPath` is returned. The model-facing tool text should print the actual spill-file path when one exists instead of only saying to inspect a details key. Oversized batch/QA failures include bounded failed-step context inline before the preview so agents can see the failed assertion/error and failure category without opening the spill file. Persisted sessions should keep that spill file under a private session-scoped artifact directory so the path remains usable after reload/restart. The oldest persisted spill files are evicted as needed to stay within `PI_AGENT_BROWSER_SESSION_ARTIFACT_MAX_BYTES` (default 32 MiB), and changed eviction receipts use `artifactManifest.entries[].retentionState: "evicted"` while the internal recent view is rebuilt from journal-row changes. Set `PI_AGENT_BROWSER_SESSION_ARTIFACT_MAX_BYTES=0` to retain existing and new persistent spill files without automatic byte-budget eviction; unset or invalid values use the default, and positive integer limits retain oldest-first eviction. This does not recover previously evicted files or change temporary subprocess spill cleanup. This persisted-spill byte budget is separate from the recent metadata window controlled by `PI_AGENT_BROWSER_SESSION_ARTIFACT_MANIFEST_MAX_ENTRIES`.
|
|
758
761
|
|
|
759
762
|
## Recording receipts and recovery
|
|
760
763
|
|
|
@@ -791,7 +794,7 @@ The TUI renderer is user-facing only. It may compact or colorize what the human
|
|
|
791
794
|
|
|
792
795
|
Worth doing in v1:
|
|
793
796
|
- screenshots → saved-path summary, visible artifact metadata, `details.artifacts` metadata, and inline image attachment when safe; screenshot paths that upstream would treat ambiguously, such as `.dogfood/run/foo.png`, are normalized to absolute paths before launch and repaired from upstream temp output when possible
|
|
794
|
-
- file artifacts such as PDFs, downloads, `wait --download` / `wait -d` files, `state save` state files, diff screenshot output images, traces, CPU profiles, completed video recordings, and path-bearing HAR captures → concise saved-path summaries plus metadata in `details.artifacts` and
|
|
797
|
+
- file artifacts such as PDFs, downloads, `wait --download` / `wait -d` files, `state save` state files, diff screenshot output images, traces, CPU profiles, completed video recordings, and path-bearing HAR captures → concise saved-path summaries plus metadata in `details.artifacts` and changed/referenced invocation receipts in `details.artifactManifest`; `record start` / `record restart` report recording lifecycle state and the future output path without adding a missing manifest entry, and `record restart` can also report the previous wrapper-known recording that was finalized by the restart; native 0.37 checks `ffmpeg` before starting video capture, while older supported natives may defer failure; successful start/restart calls without ffmpeg expose `details.recordingDependencyWarning` and leave output unverified until checked after stop; direct saved-file workflows also expose `details.savedFilePath` / `details.savedFile`; large or binary artifacts are not inlined into model context; the recent manifest cap can age out explicit-file metadata but does not remove explicit saved files from disk
|
|
795
798
|
- `diff screenshot` → same file-artifact pattern as above for the **diff** image path only (summary text uses “Saved diff image” only when the diff output exists; missing output says “Diff image reported; file not verified” and fails as `artifact-missing`); baseline paths and other fields stay in the structured payload but are not echoed as separate saved artifacts in the visible artifact block, and there is no Pi inline image attachment for the diff output
|
|
796
799
|
- `state load` → completion text may mention the loaded path, but the wrapper does **not** treat that path as a new saved artifact (`artifacts` / `artifactManifest` stay unset) the way `state save` does
|
|
797
800
|
- auth, cookies, storage, clipboard, dialog, frame, state, network, debug, diff, stream, dashboard, chat, and other structured results → concise summaries that avoid expanding secret-bearing payloads; `state show` exposes metadata only in visible text and redacts every cookie/localStorage/sessionStorage `value` in structured details; credential-like keys, values, URLs, body snippets, bearer/basic credentials, clipboard write text, cookie values, and likely secret storage values are redacted before model-facing output and `details.data`, while benign primitive storage values may remain visible for local QA
|
|
@@ -825,8 +828,8 @@ If `agent-browser` is not on `PATH`, fail with a message that:
|
|
|
825
828
|
- close the active extension-managed session when the originating `pi` process quits, while leaving explicit caller-provided sessions alone
|
|
826
829
|
- set one idle timeout on extension-managed sessions as a backstop for abnormal exits or cleanup failures, and pass that same `AGENT_BROWSER_IDLE_TIMEOUT_MS` to top-level commands plus every helper targeting that owned session; caller-owned sessions retain native idle policy so upstream does not restart the background browser, reset the active tab, or discard current refs between a snapshot and action
|
|
827
830
|
- clean up process-private temp spill artifacts on shutdown, while keeping persisted-session snapshot spill files in a private session-scoped artifact directory so `details.fullOutputPath` survives reload/restart and the oldest spill files are evicted if the per-session artifact budget is exceeded
|
|
828
|
-
- reconstruct the current branch-visible extension-managed session, every transcript-proven still-active wrapper-owned identity, latest page-scoped refs,
|
|
829
|
-
- keep runtime cleanup ownership separate from branch-visible state: `session_tree` restore and wrapper-owned browser commands are serialized with managed-session work; caller-owned explicit-session commands use local queues plus a cooperating-process execution lock keyed by actual socket context and effective canonical namespace/session (explicit namespace argv wins over inherited `AGENT_BROWSER_NAMESPACE`, including an explicit empty default), so the live URL probe, preparation helpers, semantic snapshot, main command, and state commit for one identity cannot interleave while different identities remain concurrent. Namespace-scoped `close --all` is the exception: it drains and exclusively barriers managed plus matching caller-owned work before clearing global namespace state. Namespace and session identity components are additionally Unicode-normalized and case-folded on macOS and Windows to match their case-insensitive daemon paths. Only the outer tool execution acquires that key; nested helpers run under it without re-entry. Policy, route, and artifact deltas survive unrelated managed-state commits, while a separate branch-restore generation guard prevents stale completions from overwriting a newer branch. Concurrent artifact-producing
|
|
831
|
+
- reconstruct the current branch-visible extension-managed session, every transcript-proven still-active wrapper-owned identity, latest page-scoped refs, journal-ordered artifact-row changes, and wrapper-tracked Electron launch records from the active transcript branch on `session_start` and Pi `session_tree` so later default and explicit off-current calls keep following owned managed browsers and can continue reporting artifact retention state; successful explicit wrapper-owned close rows and `electron.cleanup` managed-session steps are restore-visible close events
|
|
832
|
+
- keep runtime cleanup ownership separate from branch-visible state: `session_tree` restore and wrapper-owned browser commands are serialized with managed-session work; caller-owned explicit-session commands use local queues plus a cooperating-process execution lock keyed by actual socket context and effective canonical namespace/session (explicit namespace argv wins over inherited `AGENT_BROWSER_NAMESPACE`, including an explicit empty default), so the live URL probe, preparation helpers, semantic snapshot, main command, and state commit for one identity cannot interleave while different identities remain concurrent. Namespace-scoped `close --all` is the exception: it drains and exclusively barriers managed plus matching caller-owned work before clearing global namespace state. Namespace and session identity components are additionally Unicode-normalized and case-folded on macOS and Windows to match their case-insensitive daemon paths. Only the outer tool execution acquires that key; nested helpers run under it without re-entry. Policy, route, and artifact deltas survive unrelated managed-state commits, while a separate branch-restore generation guard prevents stale completions from overwriting a newer branch. Concurrent artifact-producing operations merge under the existing artifact queue and persist ordered row changes; replay derives the same bounded recent view from journal order. Extension-managed sessions and wrapper-launched Electron records owned by the current process remain eligible for quit/cleanup, and fresh-session allocation stays monotonic across branch restores, including auto rows and close rows that reference wrapper-generated fresh names
|
|
830
833
|
- when a close command or `electron.cleanup` successfully closes the current wrapper-managed session, clear live page/ref state, reserve the next generated fresh-session ordinal, and rotate the next default auto call to a fresh wrapper-generated session name rather than reusing the closed name
|
|
831
834
|
- when `/reload` shuts down an extension instance, close off-branch owned managed sessions and off-branch owned Electron launches before clearing process-local ownership; retain attached-browser context for those still-owned off-branch resources so cleanup cannot resend local-launch defaults. Preserve only the current branch-visible active managed session and active Electron launch plus its isolated `userDataDir` for reload continuity, and also persistently protect `userDataDir` paths when partial cleanup intentionally skips or fails profile removal so later temp cleanup, process exit, and stale temp-root pruning after restart do not violate Electron cleanup's safety decision; rebuild active branch state from the active branch on the next `session_start`
|
|
832
835
|
- when an unnamed `sessionMode: "fresh"` launch succeeds, make it the new extension-managed session so later default calls keep using it
|
|
@@ -892,7 +895,7 @@ For exact delayed-input behavior, build native rows instead of relying on unveri
|
|
|
892
895
|
{ "args": ["batch", "--bail"], "stdin": "[[\"focus\",\"#prompt\"],[\"keyboard\",\"type\",\"h\"],[\"wait\",\"20\"],[\"keyboard\",\"type\",\"i\"]]" }
|
|
893
896
|
```
|
|
894
897
|
|
|
895
|
-
Fixed waits are elapsed time, not postconditions. Preserve explicit URL/text waits, same-snapshot fill ordering, fresh refs after mutations, and partial-progress inspection. There is no legacy public script/job runtime. Exact isolated-script cleanup leases are
|
|
898
|
+
Fixed waits are elapsed time, not postconditions. Preserve explicit URL/text waits, same-snapshot fill ordering, fresh refs after mutations, and partial-progress inspection. There is no legacy public script/job runtime. Exact isolated-script cleanup leases are normalized only by offline conversion so canonical replay can retire their recorded pre-upgrade resources. Saved auth and original Pi transcripts are not rewritten or deleted; [rollback](RELEASE.md#07-upgrade-and-rollback) changes the package version, not browser side effects.
|
|
896
899
|
|
|
897
900
|
## Non-goals
|
|
898
901
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-agent-browser-native",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "pi extension that exposes agent-browser as a native tool for browser automation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Mitch Fultz (https://github.com/fitchmultz)",
|
|
@@ -28,12 +28,14 @@
|
|
|
28
28
|
},
|
|
29
29
|
"bin": {
|
|
30
30
|
"pi-agent-browser-config": "scripts/config.mjs",
|
|
31
|
+
"pi-agent-browser-convert": "scripts/convert-browser-session.mjs",
|
|
31
32
|
"pi-agent-browser-doctor": "scripts/doctor.mjs"
|
|
32
33
|
},
|
|
33
34
|
"files": [
|
|
34
35
|
"dist",
|
|
35
36
|
"platform-smoke.config.mjs",
|
|
36
37
|
"scripts/config.mjs",
|
|
38
|
+
"scripts/convert-browser-session.mjs",
|
|
37
39
|
"scripts/doctor.mjs",
|
|
38
40
|
"scripts/prepare.mjs",
|
|
39
41
|
"scripts/build.mjs",
|
|
@@ -48,6 +50,7 @@
|
|
|
48
50
|
"docs/COMMAND_REFERENCE.md",
|
|
49
51
|
"docs/ELECTRON.md",
|
|
50
52
|
"docs/RELEASE.md",
|
|
53
|
+
"docs/SESSION_STORAGE.md",
|
|
51
54
|
"docs/platform-smoke.md",
|
|
52
55
|
"docs/REQUIREMENTS.md",
|
|
53
56
|
"docs/SUPPORT_MATRIX.md",
|
|
@@ -65,14 +68,14 @@
|
|
|
65
68
|
"typebox": "*"
|
|
66
69
|
},
|
|
67
70
|
"devDependencies": {
|
|
68
|
-
"@earendil-works/pi-ai": "0.
|
|
69
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
70
|
-
"@earendil-works/pi-tui": "0.
|
|
71
|
+
"@earendil-works/pi-ai": "0.99.2",
|
|
72
|
+
"@earendil-works/pi-coding-agent": "0.99.2",
|
|
73
|
+
"@earendil-works/pi-tui": "0.99.2",
|
|
71
74
|
"@types/cross-spawn": "6.0.6",
|
|
72
75
|
"@types/node": "24.19.0",
|
|
73
76
|
"@types/which": "2.0.2",
|
|
74
77
|
"tsx": "4.23.15",
|
|
75
|
-
"typebox": "1.3.
|
|
78
|
+
"typebox": "1.3.27",
|
|
76
79
|
"typescript": "7.0.2"
|
|
77
80
|
},
|
|
78
81
|
"scripts": {
|
|
@@ -113,6 +116,7 @@
|
|
|
113
116
|
"dependencies": {
|
|
114
117
|
"cross-spawn": "7.0.6",
|
|
115
118
|
"path-key": "3.1.1",
|
|
119
|
+
"stream-json": "3.7.0",
|
|
116
120
|
"which": "2.0.2"
|
|
117
121
|
}
|
|
118
122
|
}
|
package/scripts/build.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* Purpose: Produce the compiled runtime files that the published Pi package loads.
|
|
4
|
-
* Responsibilities: Remove stale dist output, run TypeScript emit
|
|
4
|
+
* Responsibilities: Remove stale dist output, run TypeScript emit, and fail with clear build output.
|
|
5
5
|
* Scope: Maintainer/package build only; runtime behavior remains in extensions/agent-browser TypeScript sources.
|
|
6
6
|
* Usage: `npm run build` before package verification, lifecycle validation, and npm pack/publish.
|
|
7
|
-
* Invariants/Assumptions: `node_modules`
|
|
7
|
+
* Invariants/Assumptions: `node_modules` provides `typescript`; Termux supplies Android-native `tsgo` on PATH. `dist/` is generated output.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { execFile as execFileCallback } from "node:child_process";
|
|
@@ -15,7 +15,8 @@ import { promisify } from "node:util";
|
|
|
15
15
|
|
|
16
16
|
const execFile = promisify(execFileCallback);
|
|
17
17
|
const binSuffix = process.platform === "win32" ? ".cmd" : "";
|
|
18
|
-
|
|
18
|
+
// TypeScript's npm binaries do not support Android; Termux supplies native tsgo.
|
|
19
|
+
const tscPath = process.platform === "android" ? "tsgo" : join(process.cwd(), "node_modules", ".bin", `tsc${binSuffix}`);
|
|
19
20
|
|
|
20
21
|
async function main() {
|
|
21
22
|
await rm(join(process.cwd(), "dist"), { force: true, maxRetries: 5, recursive: true, retryDelay: 100 });
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { writeFile } from "node:fs/promises";
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
|
|
5
|
+
const { values } = parseArgs({ options: {
|
|
6
|
+
source: { type: "string" }, output: { type: "string" }, receipt: { type: "string" },
|
|
7
|
+
"confirm-stopped": { type: "boolean" }, help: { type: "boolean", short: "h" },
|
|
8
|
+
} });
|
|
9
|
+
if (values.help) {
|
|
10
|
+
console.log("Usage: pi-agent-browser-convert --source <retained.jsonl> --output <private-archive/copy.jsonl> --confirm-stopped [--receipt <new.json>]\nStop/quiesce the exact writer first. This offline command never starts Pi, a provider or a browser, never edits the source, and publishes only a separate private copy. Keep the destination outside automatic session discovery until explicitly selected. The receipt and each converted record identify the retained source checksum/byte range.");
|
|
11
|
+
} else {
|
|
12
|
+
try {
|
|
13
|
+
if (!values.source || !values.output) throw new Error("--source and --output are required; use --help for the stopped-writer workflow.");
|
|
14
|
+
const { convertBrowserSession } = await import("../dist/extensions/agent-browser/lib/browser-session-conversion.js");
|
|
15
|
+
const receipt = await convertBrowserSession({ source: values.source, destination: values.output, confirmedStopped: values["confirm-stopped"] === true });
|
|
16
|
+
console.log(JSON.stringify(receipt, null, 2));
|
|
17
|
+
if (values.receipt) await writeFile(values.receipt, `${JSON.stringify(receipt, null, 2)}\n`, { flag: "wx", mode: 0o600 });
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
20
|
+
process.exitCode = 1;
|
|
21
|
+
}
|
|
22
|
+
}
|