pi-agent-browser-native 0.8.3 → 0.9.0
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 +13 -1
- package/README.md +11 -11
- package/dist/extensions/agent-browser/index.js +93 -213
- package/dist/extensions/agent-browser/lib/browser-journal.js +33 -12
- package/dist/extensions/agent-browser/lib/execution-cwd.js +0 -16
- package/dist/extensions/agent-browser/lib/native-output.js +46 -0
- package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +30 -16
- package/dist/extensions/agent-browser/lib/prompt-policy.js +16 -12
- package/dist/extensions/agent-browser/lib/results/presentation/content.js +4 -0
- package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +15 -8
- package/dist/extensions/agent-browser/lib/tool-surface.js +39 -11
- package/dist/extensions/agent-browser/lib/web-search.js +85 -64
- package/docs/ARCHITECTURE.md +13 -15
- package/docs/COMMAND_REFERENCE.md +4 -2
- package/docs/RELEASE.md +25 -19
- package/docs/REQUIREMENTS.md +5 -5
- package/docs/SESSION_STORAGE.md +4 -4
- package/docs/SUPPORT_MATRIX.md +12 -10
- package/docs/TOOL_CONTRACT.md +9 -5
- package/package.json +4 -4
- package/scripts/doctor.mjs +2 -2
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { JsonSchema } from "./json-schema.js";
|
|
2
|
+
import { isRecord } from "./parsing.js";
|
|
3
|
+
import { AGENT_BROWSER_NAMESPACE, AGENT_BROWSER_OUTPUT_SCHEMA, finalizeAgentBrowserNativeResult } from "./native-output.js";
|
|
4
|
+
import { redactSensitiveText } from "./runtime.js";
|
|
2
5
|
import { StringEnum as localStringEnum } from "./string-enum-schema.js";
|
|
3
6
|
import { DEFAULT_WEB_SEARCH_PROVIDER, EXA_SEARCH_TYPES, WEB_SEARCH_PROVIDERS, resolvePreferredWebSearchCredential, } from "./config.js";
|
|
4
7
|
export const AGENT_BROWSER_WEB_SEARCH_TOOL_NAME = "agent_browser_web_search";
|
|
@@ -311,10 +314,10 @@ function getStartPublishedDate(freshness, now) {
|
|
|
311
314
|
export function buildExaSearchRequestBody(params, now = () => new Date()) {
|
|
312
315
|
const searchType = params.searchType ?? "auto";
|
|
313
316
|
if (params.additionalQueries?.length && !searchType.startsWith("deep")) {
|
|
314
|
-
throw new
|
|
317
|
+
throw new WebSearchLocalError(`additionalQueries requires deep-lite, deep, or deep-reasoning; received ${searchType}.`);
|
|
315
318
|
}
|
|
316
319
|
if ((params.category === "company" || params.category === "people") && (params.freshness || params.excludeDomains?.length)) {
|
|
317
|
-
throw new
|
|
320
|
+
throw new WebSearchLocalError(`category ${params.category} cannot be combined with freshness or excludeDomains.`);
|
|
318
321
|
}
|
|
319
322
|
const body = {
|
|
320
323
|
query: params.query,
|
|
@@ -558,79 +561,97 @@ function buildMissingCredentialError(provider) {
|
|
|
558
561
|
return "agent_browser_web_search provider exa was requested but no EXA_API_KEY/config credential resolved.";
|
|
559
562
|
return "No Exa or Brave web search credential resolved. Configure webSearch.exaApiKey or webSearch.braveApiKey, or load EXA_API_KEY/BRAVE_API_KEY in the runtime environment.";
|
|
560
563
|
}
|
|
564
|
+
/** Local validation/config failures, not provider outages; reported as `validation-error`. */
|
|
565
|
+
class WebSearchLocalError extends Error {
|
|
566
|
+
}
|
|
561
567
|
export function createAgentBrowserWebSearchTool(configState, options = {}) {
|
|
562
568
|
const requestGate = new WebSearchRequestGate();
|
|
563
569
|
return {
|
|
564
570
|
name: AGENT_BROWSER_WEB_SEARCH_TOOL_NAME,
|
|
571
|
+
namespace: AGENT_BROWSER_NAMESPACE,
|
|
572
|
+
outputSchema: AGENT_BROWSER_OUTPUT_SCHEMA,
|
|
565
573
|
label: "Agent Browser Web Search",
|
|
566
574
|
description: `Search the live web with Exa or Brave for current or external information. For Exa research tasks, use searchType deep-lite or deeper. Returns up to ${MAX_SEARCH_RESULT_COUNT} concise web results.`,
|
|
567
575
|
promptSnippet: "Search the live web with Exa or Brave for current or external information.",
|
|
568
576
|
parameters: AgentBrowserWebSearchParams,
|
|
569
577
|
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
if (!runtimeConfigState.webSearchEnabled) {
|
|
575
|
-
throw new Error("agent_browser_web_search is disabled by pi-agent-browser-native config.");
|
|
576
|
-
}
|
|
577
|
-
const requestedProvider = params.provider ?? "auto";
|
|
578
|
-
const resolved = await resolvePreferredWebSearchCredential(runtimeConfigState, { provider: requestedProvider, signal });
|
|
579
|
-
if (!resolved)
|
|
580
|
-
throw new Error(buildMissingCredentialError(requestedProvider));
|
|
581
|
-
if (resolved.provider === "brave") {
|
|
582
|
-
const exaOnlyFields = [
|
|
583
|
-
params.includeDomains ? "includeDomains" : undefined,
|
|
584
|
-
params.excludeDomains ? "excludeDomains" : undefined,
|
|
585
|
-
params.category ? "category" : undefined,
|
|
586
|
-
params.additionalQueries ? "additionalQueries" : undefined,
|
|
587
|
-
params.highlightsDynamic ? "highlightsDynamic" : undefined,
|
|
588
|
-
].filter((field) => Boolean(field));
|
|
589
|
-
if (exaOnlyFields.length > 0) {
|
|
590
|
-
throw new Error(`${exaOnlyFields.join(", ")} ${exaOnlyFields.length === 1 ? "requires" : "require"} provider exa; resolved provider was brave.`);
|
|
578
|
+
try {
|
|
579
|
+
const runtimeConfigState = ctx ? options.loadConfigState?.(ctx) ?? configState : configState;
|
|
580
|
+
if (runtimeConfigState.errors.length > 0) {
|
|
581
|
+
throw new WebSearchLocalError(`agent_browser_web_search config is invalid: ${runtimeConfigState.errors.join("; ")}`);
|
|
591
582
|
}
|
|
583
|
+
if (!runtimeConfigState.webSearchEnabled) {
|
|
584
|
+
throw new WebSearchLocalError("agent_browser_web_search is disabled by pi-agent-browser-native config.");
|
|
585
|
+
}
|
|
586
|
+
const requestedProvider = params.provider ?? "auto";
|
|
587
|
+
const resolved = await resolvePreferredWebSearchCredential(runtimeConfigState, { provider: requestedProvider, signal });
|
|
588
|
+
if (!resolved)
|
|
589
|
+
throw new WebSearchLocalError(buildMissingCredentialError(requestedProvider));
|
|
590
|
+
if (resolved.provider === "brave") {
|
|
591
|
+
const exaOnlyFields = [
|
|
592
|
+
params.includeDomains ? "includeDomains" : undefined,
|
|
593
|
+
params.excludeDomains ? "excludeDomains" : undefined,
|
|
594
|
+
params.category ? "category" : undefined,
|
|
595
|
+
params.additionalQueries ? "additionalQueries" : undefined,
|
|
596
|
+
params.highlightsDynamic ? "highlightsDynamic" : undefined,
|
|
597
|
+
].filter((field) => Boolean(field));
|
|
598
|
+
if (exaOnlyFields.length > 0) {
|
|
599
|
+
throw new WebSearchLocalError(`${exaOnlyFields.join(", ")} ${exaOnlyFields.length === 1 ? "requires" : "require"} provider exa; resolved provider was brave.`);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
const query = params.query.trim();
|
|
603
|
+
if (!query)
|
|
604
|
+
throw new WebSearchLocalError("query must not be blank");
|
|
605
|
+
const count = Math.min(Math.max(params.count ?? DEFAULT_SEARCH_RESULT_COUNT, 1), MAX_SEARCH_RESULT_COUNT);
|
|
606
|
+
const offset = Math.max(params.offset ?? 0, 0);
|
|
607
|
+
const adapter = getWebSearchProviderAdapter(resolved.provider);
|
|
608
|
+
const executionParams = {
|
|
609
|
+
additionalQueries: params.additionalQueries,
|
|
610
|
+
category: params.category,
|
|
611
|
+
country: params.country,
|
|
612
|
+
count,
|
|
613
|
+
excludeDomains: params.excludeDomains,
|
|
614
|
+
freshness: params.freshness,
|
|
615
|
+
highlightsDynamic: params.highlightsDynamic,
|
|
616
|
+
includeDomains: params.includeDomains,
|
|
617
|
+
offset,
|
|
618
|
+
query,
|
|
619
|
+
safesearch: params.safesearch,
|
|
620
|
+
searchLang: params.searchLang,
|
|
621
|
+
searchType: params.searchType ?? runtimeConfigState.config.webSearch?.defaultSearchType ?? "auto",
|
|
622
|
+
};
|
|
623
|
+
const request = adapter.buildRequest(executionParams);
|
|
624
|
+
const data = await requestGate.run(signal, () => adapter.fetchJson(request, resolved.credential.value, signal));
|
|
625
|
+
const normalized = adapter.normalizeResponse(data, executionParams);
|
|
626
|
+
const results = dedupeSearchResults(normalized.results);
|
|
627
|
+
const duplicatesRemoved = normalized.results.length - results.length;
|
|
628
|
+
const details = {
|
|
629
|
+
provider: adapter.provider,
|
|
630
|
+
query,
|
|
631
|
+
returnedQuery: normalized.returnedQuery,
|
|
632
|
+
count,
|
|
633
|
+
offset,
|
|
634
|
+
...normalized.extraDetails,
|
|
635
|
+
fetchedAt: new Date().toISOString(),
|
|
636
|
+
results,
|
|
637
|
+
duplicatesRemoved: duplicatesRemoved || undefined,
|
|
638
|
+
};
|
|
639
|
+
const result = await finalizeAgentBrowserNativeResult({
|
|
640
|
+
content: [{ type: "text", text: `${formatSearchResults(adapter.provider, normalized.returnedQuery, results)}${duplicatesRemoved ? `\n\nDuplicate URLs removed: ${duplicatesRemoved}.` : ""}` }],
|
|
641
|
+
details: { data: details },
|
|
642
|
+
}, params);
|
|
643
|
+
// Keep the finalized spill's invocation artifact receipt while flattening the documented search details shape.
|
|
644
|
+
const finalizedManifest = isRecord(result.details) ? result.details.artifactManifest : undefined;
|
|
645
|
+
return finalizedManifest === undefined ? { ...result, details } : { ...result, details: { ...details, artifactManifest: finalizedManifest } };
|
|
646
|
+
}
|
|
647
|
+
catch (error) {
|
|
648
|
+
const message = redactSensitiveText(error instanceof Error ? error.message : String(error)).slice(0, 1_000);
|
|
649
|
+
return finalizeAgentBrowserNativeResult({
|
|
650
|
+
content: [{ type: "text", text: message }],
|
|
651
|
+
details: { error: message, resultCategory: "failure", failureCategory: signal?.aborted ? "aborted" : error instanceof WebSearchLocalError ? "validation-error" : "upstream-error" },
|
|
652
|
+
isError: true,
|
|
653
|
+
}, params);
|
|
592
654
|
}
|
|
593
|
-
const query = params.query.trim();
|
|
594
|
-
if (!query)
|
|
595
|
-
throw new Error("query must not be blank");
|
|
596
|
-
const count = Math.min(Math.max(params.count ?? DEFAULT_SEARCH_RESULT_COUNT, 1), MAX_SEARCH_RESULT_COUNT);
|
|
597
|
-
const offset = Math.max(params.offset ?? 0, 0);
|
|
598
|
-
const adapter = getWebSearchProviderAdapter(resolved.provider);
|
|
599
|
-
const executionParams = {
|
|
600
|
-
additionalQueries: params.additionalQueries,
|
|
601
|
-
category: params.category,
|
|
602
|
-
country: params.country,
|
|
603
|
-
count,
|
|
604
|
-
excludeDomains: params.excludeDomains,
|
|
605
|
-
freshness: params.freshness,
|
|
606
|
-
highlightsDynamic: params.highlightsDynamic,
|
|
607
|
-
includeDomains: params.includeDomains,
|
|
608
|
-
offset,
|
|
609
|
-
query,
|
|
610
|
-
safesearch: params.safesearch,
|
|
611
|
-
searchLang: params.searchLang,
|
|
612
|
-
searchType: params.searchType ?? runtimeConfigState.config.webSearch?.defaultSearchType ?? "auto",
|
|
613
|
-
};
|
|
614
|
-
const request = adapter.buildRequest(executionParams);
|
|
615
|
-
const data = await requestGate.run(signal, () => adapter.fetchJson(request, resolved.credential.value, signal));
|
|
616
|
-
const normalized = adapter.normalizeResponse(data, executionParams);
|
|
617
|
-
const results = dedupeSearchResults(normalized.results);
|
|
618
|
-
const duplicatesRemoved = normalized.results.length - results.length;
|
|
619
|
-
const details = {
|
|
620
|
-
provider: adapter.provider,
|
|
621
|
-
query,
|
|
622
|
-
returnedQuery: normalized.returnedQuery,
|
|
623
|
-
count,
|
|
624
|
-
offset,
|
|
625
|
-
...normalized.extraDetails,
|
|
626
|
-
fetchedAt: new Date().toISOString(),
|
|
627
|
-
results,
|
|
628
|
-
duplicatesRemoved: duplicatesRemoved || undefined,
|
|
629
|
-
};
|
|
630
|
-
return {
|
|
631
|
-
content: [{ type: "text", text: `${formatSearchResults(adapter.provider, normalized.returnedQuery, results)}${duplicatesRemoved ? `\n\nDuplicate URLs removed: ${duplicatesRemoved}.` : ""}` }],
|
|
632
|
-
details,
|
|
633
|
-
};
|
|
634
655
|
},
|
|
635
656
|
};
|
|
636
657
|
}
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -19,7 +19,7 @@ The package install path is the primary product path. Local checkout development
|
|
|
19
19
|
|
|
20
20
|
`agent_browser` accepts native argv/stdin, result output path, timeout, and session mode. `agent_browser_code` accepts strict JSON source plus optional parent-selected session/namespace, timeout, and output path. Both use one ordinary CLI executor. Use direct calls for one action, native batch for fixed sequences, and code for branches, loops, or aggregation; return to the model at judgment boundaries.
|
|
21
21
|
|
|
22
|
-
`agent_browser_tools` inventories/enables five flat specialized tools: action, QA, Electron, UI source, and network source. `lib/tool-surface.ts` registers them once and adds them through Pi's native active-tool API, preserving unrelated tools, explicit host selections, and native selected-tool history. It owns no parallel activation journal. QA verdicts, unique accessible select, host Electron lifecycle, and bounded source scans remain specialized capabilities rather than being reduced to raw-command approximations. The former public job DSL and isolated script route are removed.
|
|
22
|
+
`agent_browser_tools` inventories/enables five flat specialized tools: action, QA, Electron, UI source, and network source. `lib/tool-surface.ts` registers them once and adds them through Pi's native active-tool API, preserving unrelated tools, explicit host selections, and native selected-tool history. The five advanced direct tools use native `defaultActive: false`, not deferred registration. A narrow additive fallback restores transcript-enabled advanced tools on official Pi 1.0 initial resume, whose SDK bypasses native restoration by supplying initial tool names. It does not deactivate explicit/defaultTools selections or widen filtered catalogs/CLI allowlists; loader, tree and reload retain native selection semantics. It owns no parallel activation journal. QA verdicts, unique accessible select, host Electron lifecycle, and bounded source scans remain specialized capabilities rather than being reduced to raw-command approximations. The former public job DSL and isolated script route are removed.
|
|
23
23
|
|
|
24
24
|
Optional `agent_browser_web_search` remains separately credential/config gated and independent of browser state.
|
|
25
25
|
|
|
@@ -56,12 +56,14 @@ All participating Pi processes must restart with the updated package. The lock i
|
|
|
56
56
|
|
|
57
57
|
`lib/browser-transcript.ts` defines one canonical `data.event` format and optional once-stored `data.snapshot`. Direct, advanced, code and Electron host operations record begin/finish receipts before dispatch and after observed effects, using outer tool-call ID plus inner index and a unique operation ID. The shared page reducer retains an inaccessible candidate during unresolved work and requires explicit reuse/replace/invalidate/unknown disposition. Ordinary results omit unchanged maps and unrelated artifact receipts; journal events carry redacted artifact-row changes in commit order. Final rendering queues actual spill writes and manifest publication, allowing unrelated small observations to finish while another namespace holds its artifact/lifecycle operation. Native lifecycle evidence is retained before presentation/export. Failed begin blocks dispatch; failed finish stops dependent work and requires inspection without mutation replay. A named persistent journal requires actual publication even before Pi's first conversation. Disabled/no-file sessions use the native current in-memory ancestry for direct browser work without claiming durability; code still requires a published intent journal. Observation-only artifact receipts are optional without a published journal, so sessionless local results retain complete redacted private spills and selected files. Code lifecycle joins include outer finalization, and the shared generation guard keeps prior-branch observation spills process-private and prevents their artifact publication onto the new branch. JavaScript variables are never persisted.
|
|
58
58
|
|
|
59
|
-
`lib/browser-journal.ts` token-projects published envelopes and ancestry through public Pi file/header/leaf APIs, loading only winning snapshot definitions. It captures the selected leaf before asynchronous reads and validates that same branch through
|
|
59
|
+
`lib/browser-journal.ts` token-projects published envelopes and ancestry through public Pi file/header/leaf APIs, loading only winning snapshot definitions. It captures the selected leaf before asynchronous reads and validates that same branch through public `getEntry()` ancestry on both hosts. Capture-local admission reuses a validated append-only prefix while checking endpoint identity/parent and new suffixes; publication/durability checks remain independent. Startup/tree restoration uses one queued captured replay for branch state and cleanup leases, with one per-session launch-configuration fold. Stock official 1.0.0 still eagerly loads native history before extension startup. Legacy adapters live only in `lib/browser-session-conversion.ts`, which publishes a validated stopped separate copy while retaining the source. Native generation checks use PID/start and socket identity, never saved URL or delta revision alone. Filtered/helper captures share this check. Small owner-qualified launch receipts retain observed restore-key provenance; restart verifies the current native generation and key before treating that provenance as live. Full storage, migration and consumer-memory boundaries are documented in [`SESSION_STORAGE.md`](SESSION_STORAGE.md).
|
|
60
60
|
|
|
61
61
|
### Canonical observations and image geometry
|
|
62
62
|
|
|
63
63
|
`results/presentation/content.ts` projects decision-relevant fields once; `large-output.ts` renders model-visible JSON/prose after recovery, diagnostics, and requested output-file writes are assembled. Failed file exports retain partial code data/images and report a failed observation. `details` remains audit/replay metadata. Final text has a 16,000-character bound; a complete redacted observation spill retains data and exact recovery payloads that cannot fit inline. Native help/version stays text. Inner `modelVisible: false` calls keep data without full prose/spill/image encoding; selected JSON and images are emitted at the outer boundary. Handled failures remain visible with counts and recovery, even if source finishes successfully.
|
|
64
64
|
|
|
65
|
+
Native tool declarations share Browser namespace metadata and `outputSchema`; `structuredContent` reuses the bounded redacted observation or its existing compact/spill object. Loader inventory and normalized provider search keep their existing shapes. Internal ownership/replay details are not exported wholesale. This interoperates with host-selected native codemode without auto-enabling it or replacing the Browser VM. A path/handle is not native image data; verified content image blocks remain separate. Final results return native `isError` and retain prose failure notices while explicit JSON stays parseable and unchanged. Per-row TUI memoization skips unchanged formatting/Text updates without caching browser state or observations across calls.
|
|
66
|
+
|
|
65
67
|
`orchestration/browser-run/screenshot-observation.ts` brackets standalone screenshots with CSS viewport/document/scroll/DPR/frame samples. Existing Pi image-dimension primitives measure saved pixels. Matching samples and dimensions can establish a crop mapping; changed, unmeasured batch, scrolled/ambiguous element, zoom, or frame-uncertain captures remain unknown. These samples are not an atomic capture guarantee. Native mouse input uses current viewport CSS pixels, not image pixels; full-page/element origin and any Pi resize must be accounted for separately. Unchanged conditional screenshots attach nothing. See [image observations](TOOL_CONTRACT.md#image-observations).
|
|
66
68
|
|
|
67
69
|
### Agent-first UX
|
|
@@ -83,7 +85,7 @@ Pi docs use `settings.json` for package/resource loading and filtering, not arbi
|
|
|
83
85
|
- project-local: `.pi/config/pi-agent-browser-native/config.json`
|
|
84
86
|
- explicit override: `PI_AGENT_BROWSER_CONFIG=/path/to/config.json`
|
|
85
87
|
|
|
86
|
-
Config layers merge in that order: global, project, override. The shared policy module (`extensions/agent-browser/lib/config-policy.js`) owns provider descriptors, environment variable names, config keys, credential source parsing, developer-trusted project layer inclusion, layer validation/merge, redacted status projection, and credential summaries for both runtime config loading and the package config helper.
|
|
88
|
+
Config layers merge in that order: global, project, override. The shared policy module (`extensions/agent-browser/lib/config-policy.js`) owns provider descriptors, environment variable names, config keys, credential source parsing, developer-trusted project layer inclusion, layer validation/merge, redacted status projection, and credential summaries for both runtime config loading and the package config helper. Globally installed or CLI-loaded copies read `.pi/config/pi-agent-browser-native/config.json` when Pi's required native `isProjectTrusted()` decision permits it, and skip that project layer when the project is untrusted or Pi is launched with `--no-approve`. Global config and explicit `PI_AGENT_BROWSER_CONFIG` overrides remain available either way. The config reader accepts v1 fields for `webSearch.enabled`, `webSearch.preferredProvider`, `webSearch.defaultSearchType`, `webSearch.exaApiKey`, `webSearch.braveApiKey`, and conservative browser defaults such as `browser.defaultProfile` and `browser.executablePath`. Web-search key fields follow Pi model/provider-style value resolution from any loaded layer: literal values, `$ENV_VAR` / `${ENV_VAR}` interpolation, escapes (`$$`, `$!`), and leading `!command` resolved at request time. `EXA_API_KEY` and `BRAVE_API_KEY` remain environment fallbacks when no config credential source exists for that provider. Browser default values keep their source scope; prompt guidance is emitted from the highest-priority loaded layer, including project config when Pi trust/loading allows it.
|
|
87
89
|
|
|
88
90
|
`agent_browser_web_search` availability is conditional. Startup registration uses global, override, and environment fallback config without reading project-local config before Pi trust context exists; trusted project config can register the companion tool on `session_start`, and every execution reloads the final session config so `webSearch.enabled: false` still prevents a request even if a startup credential made the tool visible. A global disable is the normal user default and can still be overridden by project config or `PI_AGENT_BROWSER_CONFIG`; a project disable applies to one repo; an explicit `PI_AGENT_BROWSER_CONFIG` file with `webSearch.enabled: false` is the highest-priority hard disable for that run. Literal and env-backed sources must resolve before they make the tool available; command-backed sources are considered configured without running the command until tool execution, so secret managers do not slow startup or prompt unexpectedly. The tool resolves the selected key lazily, chooses Exa or Brave from available credentials (preferring Exa by default unless `webSearch.preferredProvider` says otherwise), then follows one provider-agnostic execution path through provider adapters for request building, HTTP JSON fetch, response normalization, and provider-specific detail fields. Exa search-type precedence is per-call value, merged config default, then `auto`; bounded Exa filters stay on the Exa adapter and explicit Exa-only options fail before a Brave request. The tool calls Exa `/search` with highlights plus a fixed primary-source/version/date/distinct-result system prompt, or Brave Search, then removes later exact normalized-URL duplicates while retaining provider order. It does not guess across distinct paths/query URLs or overfetch replacements; provider page dates remain clues rather than claimed crawl/version evidence. Compact result details report any `duplicatesRemoved` without exposing keys.
|
|
89
91
|
|
|
@@ -91,7 +93,7 @@ Global/override package profile names with `policy: "always"` and executable def
|
|
|
91
93
|
|
|
92
94
|
### Prompt guidance budget
|
|
93
95
|
|
|
94
|
-
Use Pi-native `promptGuidelines`, tool declarations, and named `systemPromptOptions.sections` contributions. Do not return a replacement full system prompt from `before_agent_start`: it breaks additive declaration anchoring. Official Pi 0
|
|
96
|
+
Use Pi-native `promptGuidelines`, tool declarations, and named `systemPromptOptions.sections` contributions. Do not return a replacement full system prompt from `before_agent_start`: it breaks additive declaration anchoring. Official Pi 1.0 and the fork use this same composition; hosted programmatic tool calling, async provider lifecycle, image-detail overrides, or model-specific payload edits are not package dependencies. Prefix stability is not proof of a cache hit.
|
|
95
97
|
|
|
96
98
|
Browser instructions come from one full source assembled from `lib/playbook.ts` and current trusted config. Shared rules and all advanced tool guidelines are delivered together, rather than maintaining a short eager summary beside a hidden manual. Managed hosts defer this full group; stock hosts receive it eagerly. Tool registrations retain concise descriptions and schemas without duplicate `promptGuidelines`.
|
|
97
99
|
|
|
@@ -112,7 +114,7 @@ The published package should load from the `pi` manifest in `package.json`.
|
|
|
112
114
|
Local checkout validation has two intentional modes:
|
|
113
115
|
|
|
114
116
|
- **Checkout-only extension mode:** use explicit CLI loading such as `pi --approve --no-extensions -e .` from the intentionally trusted repository root. This disables automatic extension loading and avoids duplicate `agent_browser` registrations, but settings, configured package resolution, and other resource types remain active. Temporary `HOME` and `PI_CODING_AGENT_DIR` directories isolate test settings; `PI_OFFLINE=1` disables automatic startup network/update operations. Omit `--approve` only when testing Project Trust.
|
|
115
|
-
- **Configured-source lifecycle mode:** configure exactly one active checkout or package source in Pi settings and launch plain `pi` for manual validation, or run the automated harness that launches with `--approve`. This is the right mode for validating `/reload` and exact-session relaunch because those lifecycle checks exercise discovered/configured resources. Focused extension harness tests validate branch-backed `session_tree` rehydration and cleanup ownership. Before shipping, maintainers also run `npm run verify -- lifecycle` (same semantics under automation, using Pi 0.
|
|
117
|
+
- **Configured-source lifecycle mode:** configure exactly one active checkout or package source in Pi settings and launch plain `pi` for manual validation, or run the automated harness that launches with `--approve`. This is the right mode for validating `/reload` and exact-session relaunch because those lifecycle checks exercise discovered/configured resources. Focused extension harness tests validate branch-backed `session_tree` rehydration and cleanup ownership. Before shipping, maintainers also run `npm run verify -- lifecycle` (same semantics under automation, using Pi 1.0.0+ `--approve --session-id` to reopen the exact JSONL session) plus the live-site checks in [`RELEASE.md`](RELEASE.md#pre-release-checks); `npm publish` enforces `npm run verify -- release` via `prepublishOnly` unless scripts are skipped.
|
|
116
118
|
|
|
117
119
|
The repo should not add a repo-local `.pi/extensions/` autoload shim as the documented checkout path.
|
|
118
120
|
|
|
@@ -173,7 +175,7 @@ Ownership rule:
|
|
|
173
175
|
- extension-managed sessions should be reusable during an active `pi` session and across `/reload`, exact-session relaunch, `/resume`, and Pi branch-tree transitions, while still being cleaned up predictably
|
|
174
176
|
|
|
175
177
|
Practical policy:
|
|
176
|
-
- preserve the current branch-visible extension-managed session across `/reload`, exact-session relaunch, `/resume`, and Pi 0.
|
|
178
|
+
- preserve the current branch-visible extension-managed session across `/reload`, exact-session relaunch, `/resume`, and Pi 1.0.0+ `session_tree` branch transitions so persisted sessions can keep following the live browser after lifecycle changes
|
|
177
179
|
- close the active extension-managed session when the originating `pi` process quits, while leaving explicit caller-provided sessions alone
|
|
178
180
|
- after branch restore, use the existing locked daemon inspection to distinguish a confirmed inactive wrapper-owned daemon from a live, unknown, or unavailable one. For compatible automatic managed restore only, keep the pending reopen in ordered session page state and persist it as `sessionTabReopenPending`. Non-page calls such as `tab list` can start a daemon without fulfilling it; explicit HTTP reads leave the managed browser and pending reopen untouched, including across branch/reload replay. Before the first current-page operation (`get url`, history commands and relative `pushstate` included), reopen the complete recorded URL with native `open`, invalidate old refs with the existing `page-transition` state, and verify the actual tab. Explicit URL reads and all-read batches skip managed ownership changes and browser helpers entirely; native owns their HTTP fetch and validation. Native `open` resets frame scope. Consume the obligation on that attempt or an executed explicit context/navigation/close command, not an unreached batch row; a failed open does not permit repeated navigation of a now-live browser. After the reopen CLI starts, cancellation returns a structured `aborted` result through the ordinary result path with the exact namespace/session, consumed marker and ref invalidation; it does not throw away replay state or run later browser helpers. Cancellation before the CLI starts does not consume the pending reopen. Internal URLs retain their fragments while tab/ref comparisons remain fragment-insensitive and presentation keeps normal redaction. Older transcripts cannot recover a fragment they did not record. Caller-owned/attached browsers and restore-disabled sessions do not take this path; live wrong-tab recovery still only selects an existing target. Reopening reloads the URL, not unsaved forms, JavaScript memory, or history. There is no second restore store or lifecycle lock.
|
|
179
181
|
- set an idle timeout on extension-managed sessions as a backstop for abnormal exits or cleanup failures, and apply that same `AGENT_BROWSER_IDLE_TIMEOUT_MS` value to every subprocess targeting that owned session (including wrapper helper snapshots, tab lists, and navigation-summary reads); caller-owned sessions instead retain native config/environment idle policy because changing the launch environment between calls can make upstream restart the background browser, discard the active tab, and invalidate fresh refs
|
|
@@ -198,7 +200,7 @@ Practical policy:
|
|
|
198
200
|
- native 0.37 owns first-document setup inheritance for new tabs; the wrapper does not copy headers, user agents or other browser setup itself. The page-summary formatter displays native positive WebMCP availability while retaining raw details; it adds no discovery probe
|
|
199
201
|
- when a direct or batched WebMCP call returns `status: "pending"`, or `result` / `cancel` fails while that target is unknown, keep its tab target unknown and discard same-call snapshot evidence instead of treating an immediate post-dispatch URL probe as stable; `webmcp result` / `cancel`, `get url`, and explicit navigation remain available while unknown; replace the generic blocked snapshot action with `verify-page-target-after-pending-webmcp` (`get url`), and let a completed `batch --bail` use that verification before `snapshot -i` to re-establish both target and refs
|
|
200
202
|
- for top-level non-Electron direct `click` commands with an eligible target, install a bounded in-page target-specific event probe before upstream runs; if upstream reports success but no trusted pointer/mouse/click event reached the resolved target, fail the tool and report `details.clickDispatch` with explicit retry/inspect next actions (the wrapper does not replay clicks in-page). The probe covers `xpath=` targets and current `@e…` / `ref=` refs whose latest stored `refSnapshot.refs` role is `button`, `checkbox`, `menuitem`, `radio`, `switch`, or `tab`; it requires a unique role/name in the saved snapshot and the live candidates instead of taking a fresh pre-click snapshot that could recycle upstream refs. Ref and XPath candidates must additionally prove identity through a per-probe temporary DOM attribute read back by native `get attr <original-selector> <marker>`. Missing or mismatched identity, including XPath/frame scope mismatches, cleans up the probe and lets native click run without dispatch verification; candidate naming heuristics alone are never proof. Duplicate-name refs pass through without a probe: their old ordinal is not target identity. The probe is intentionally skipped for CSS selector clicks, unresolved `find … click` locators, and `batch`/`qa` click steps
|
|
201
|
-
-
|
|
203
|
+
- skip unrelated tools and harmless Bash inspections before building prompt policy. Seed the latest raw user message on start/tree, update it on user `message_end`, and re-read its current content before parsing policy so native content replacement cannot leave stale intent. Capture that policy at queued admission without a whole-branch scan on every event. Derive narrow prompt guards only for concrete evidence invariants: explicitly requested screenshot/recording output paths block browser close until the artifact manifest verifies those paths, while bare inbound attachment paths remain inputs. The wrapper intentionally does not infer broad business/user intent from prompt text such as order/payment/post boundaries; agents must follow those instructions themselves. The artifact guard is bounded preflight policy (`details.promptGuard`, `failureCategory: "policy-blocked"`), not a reusable browser recipe layer
|
|
202
204
|
- keep the existing page/selector scroll API; explicit CSS-container movement uses `Element.scrollBy` with `behavior: "instant"` before measuring offsets so smooth-scroll CSS cannot cause a premature no-movement failure
|
|
203
205
|
- reject direct and effective batch `scrollintoview text=...` / `scrollinto text=...` before dispatch because current upstream can falsely report success without movement, while leaving help forms untouched; return only native recovery (`find text ... hover` or fresh snapshot/ref), leaving CSS, XPath, and current-ref behavior upstream-owned
|
|
204
206
|
- after successful `get text` on a qualifying non-ref CSS selector, optionally issue one read-only `eval --stdin` probe per selector when multiple DOM matches or a hidden first match with visible peers could misread tabbed or off-screen content; simple id selectors and sensitive-looking literals skip this probe. Merge `details.selectorTextVisibility` / `selectorTextVisibilityAll`, visible warning lines, and `inspect-visible-text-candidates*` next actions as documented in [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details) and `RQ-0074` in [`SUPPORT_MATRIX.md`](SUPPORT_MATRIX.md)
|
|
@@ -207,15 +209,11 @@ Practical policy:
|
|
|
207
209
|
|
|
208
210
|
This is primarily about ownership clarity and avoiding surprise, not adding a heavy safety wrapper. If the extension invented the session, the extension should own its lifecycle without breaking reload, resume, or branch-tree semantics. If the caller explicitly chose the upstream session model, the extension should stay out of the way.
|
|
209
211
|
|
|
210
|
-
###
|
|
211
|
-
|
|
212
|
-
The additive native `session_checkpoint` hook qualifies only the no-active-resource path. Pi already awaits tools, commands and lifecycle callbacks, including their returned execution queues. The hook checks the active code controllers/completion promises, recording reservations and dirty retry state, cleanup leases, Electron records/children, attachments, trace owners and routes. It adds no work queue or state journal, and never invokes shutdown, stops recording, or closes a browser during capture.
|
|
213
|
-
|
|
214
|
-
Known native identities come from existing ownership and all native tool-result entries, including off-branch caller-owned/root sessions and the unnamed native default (launch flags can open it even for an explicit URL read). Read-only `session info` must prove each daemon inactive; active, missing-binary and unknown results remain blockers. These probes reuse the existing owned-session context for runtime-owned identities and transcript-proven wrapper-created identities, including off-branch browsers after an abnormal restart, so an ambient `AGENT_BROWSER_SOCKET_DIR` cannot redirect their inspection. Historical routing uses the existing managed-resource events and namespace/session identity, not a name pattern alone, and does not acquire cleanup ownership. For owned or historically owned targets, inspection also checks native ambient routing: the same namespace/name can identify different daemons in different socket roots. A later transcript close does not suppress the historical route's read-only probe, since it may have closed only the ambient caller. Explicit caller choices (even the exact historical name with `sessionMode: "fresh"`), unrelated namespaces and root identities retain native ambient routing. An unused extension needs no browser executable or profile scan. Independent hosts/group members must still coordinate their own writers and resources; a Pi receipt is not a cross-process browser lock.
|
|
212
|
+
### Lifecycle boundary
|
|
215
213
|
|
|
216
|
-
|
|
214
|
+
Native Pi lifecycle callbacks and existing queues retain ownership-aware shutdown/reload behavior. Shared root and caller-owned browsers are not closed on Pi quit; wrapper-owned managed/fresh and Electron resources keep UUID/branch-qualified cleanup. An ordinary session fork does not inherit its parent's cleanup rights. Close or clean up owned resources before disabling/removing the extension: native reload after removal has no browser handover guarantee. Forced concurrent SDK reload and recovery after failed off-branch cleanup are not fully qualified lifecycle guarantees.
|
|
217
215
|
|
|
218
|
-
|
|
216
|
+
Native close/save and explicit URL reopen remain the persistence path, not a live browser snapshot. Page JavaScript, unsaved forms, history, IndexedDB and live recordings are not serialized by this extension. Neither supported Pi 1.0 target uses Browser checkpoint or fork metadata/revision hooks; retained legacy journal decoding remains confined to stopped-copy conversion.
|
|
219
217
|
|
|
220
218
|
### Launch flags
|
|
221
219
|
|
|
@@ -269,7 +267,7 @@ Upstream restore-state persistence remains upstream-owned. The wrapper passes an
|
|
|
269
267
|
- clear missing-binary errors
|
|
270
268
|
- filtered `network requests --current-page` / `--current-origin` / `--current-url` preparation results use the same `redactPresentationData` credential redactor as ordinary diagnostics before populating `details.data` or writing `outputPath`
|
|
271
269
|
- compact result summaries, including presentation-time redaction: stateful browser-context commands (`auth`, `cookies`, `storage`, `dialog`, `frame`, `state`) use field-aware value redaction and compact formatters, while other structured upstream JSON (for example `network`, `diff`, `trace` / `profiler` / `record`, `console` / `errors` / `highlight` / `inspect` / `clipboard`, `stream`, `dashboard`, and `chat`) is passed through `redactPresentationData` in `extensions/agent-browser/lib/results/presentation.ts` so model-facing `details.data` and batch roll-ups stay compact and do not echo bearer tokens, proxy passwords, or similar fields verbatim; `redactInvocationArgs` in `extensions/agent-browser/lib/runtime.ts` masks trailing values for sensitive global flags such as `--body`, `--headers`, `--password`, and `--proxy`, preserves positional rules for `cookies set` and `storage local|session set`, and nested `batch` steps use the same argv and error-body scrubbing before echoing commands or errors. Shared URL redaction covers SAMLRequest/SAMLResponse/RelayState and auth-context-only state/nonce at model/persisted-artifact boundaries while retaining exact internal page-target URLs; snapshot spills are redacted before disk writes
|
|
272
|
-
- bounded machine-readable outcome metadata on tool `details` (`resultCategory`, `successCategory`, `failureCategory`, optional `nextActions`, optional `pageChangeSummary` with observed-vs-dispatched evidence and per-step summaries on `batch`, optional `artifactVerification` with the same shape on each successful `batchSteps[]` row) so agents can branch without parsing prose; enums, classifier precedence, and generic follow-up payloads are implemented under `extensions/agent-browser/lib/results/` in focused modules (`contracts.ts` for shared types, `categories.ts` for `classifyAgentBrowserSuccessCategory` / `classifyAgentBrowserFailureCategory` / `buildAgentBrowserResultCategoryDetails`, `action-recommendations.ts` for `buildAgentBrowserNextActions`, `next-actions.ts` for the `AgentBrowserNextAction` shape and merge helpers, `recovery-actions.ts` for recovery id registries and `buildRecoveryNextActions`, `network.ts` for `classifyNetworkRequestFailure` / `summarizeNetworkFailures`, and related helpers). Per-session tab target, `refSnapshot` alignment, invalidation, and tab pinning observations flow through `extensions/agent-browser/lib/session-page-state.ts` from `extensions/agent-browser/index.ts`. Compact page-change summaries and artifact verification rollups are built in `extensions/agent-browser/lib/results/presentation.ts` (`buildPageChangeSummary`, `buildArtifactVerificationSummary`), and the human contract lives in [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details).
|
|
270
|
+
- bounded machine-readable outcome metadata on tool `details` (`resultCategory`, `successCategory`, `failureCategory`, optional `nextActions`, optional `pageChangeSummary` with observed-vs-dispatched evidence and per-step summaries on `batch`, optional `artifactVerification` with the same shape on each successful `batchSteps[]` row) so agents can branch without parsing prose; enums, classifier precedence, and generic follow-up payloads are implemented under `extensions/agent-browser/lib/results/` in focused modules (`contracts.ts` for shared types, `categories.ts` for `classifyAgentBrowserSuccessCategory` / `classifyAgentBrowserFailureCategory` / `buildAgentBrowserResultCategoryDetails`, `action-recommendations.ts` for `buildAgentBrowserNextActions`, `next-actions.ts` for the `AgentBrowserNextAction` shape and merge helpers, `recovery-actions.ts` for recovery id registries and `buildRecoveryNextActions`, `network.ts` for `classifyNetworkRequestFailure` / `summarizeNetworkFailures`, and related helpers). Per-session tab target, `refSnapshot` alignment, invalidation, and tab pinning observations flow through `extensions/agent-browser/lib/session-page-state.ts` from `extensions/agent-browser/index.ts`. Compact page-change summaries and artifact verification rollups are built in `extensions/agent-browser/lib/results/presentation.ts` (`buildPageChangeSummary`, `buildArtifactVerificationSummary`), and the human contract lives in [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details). Final public results return native `isError` after all wrapper reclassifications, without a `tool_result` repair hook. Prose retains the visible category notice; explicit parseable JSON stays unchanged. `lib/native-output.ts` and `finalizeAgentBrowserFailure` in `lib/pi-tool-rendering.ts` keep structured observations, transcript status and TUI affordances aligned (transcript semantics in the same contract doc)
|
|
273
271
|
- inline screenshots/images for the plain `screenshot` command; other image-like saves (for example `diff screenshot`) still appear in `details.artifacts` and summaries but are not auto-inlined as Pi image attachments (see [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details))
|
|
274
272
|
- lightweight session convenience
|
|
275
273
|
- docs, including a repo-readable command reference that mirrors the blocked direct-binary help path closely enough for normal agent work
|
|
@@ -10,7 +10,7 @@ Related docs:
|
|
|
10
10
|
|
|
11
11
|
## Purpose
|
|
12
12
|
|
|
13
|
-
Requires Pi 0.
|
|
13
|
+
Requires Pi 1.0.0 or newer; official and fork hosts are qualified independently.
|
|
14
14
|
|
|
15
15
|
Provide a local, repo-readable command reference for the native `agent_browser` tool.
|
|
16
16
|
|
|
@@ -18,6 +18,8 @@ This project intentionally blocks normal `agent-browser` bash usage in most agen
|
|
|
18
18
|
|
|
19
19
|
After updating `pi-agent-browser-native`, fully quit and restart Pi before using the updated tools. `/reload` can retain previously loaded compiled JavaScript even after `dist/` is rebuilt, so it is not a reliable way to pick up package updates.
|
|
20
20
|
|
|
21
|
+
Tool declarations use the native `browser` namespace and output schemas. Native `structuredContent` carries the same bounded redacted observation as direct/code output; loader inventory and optional search retain their existing data shapes. It does not expose internal replay details or turn image paths/handles into native `image()` input. The five advanced direct tools default inactive; enable them through `agent_browser_tools` unless already selected by the host. See [canonical observations](TOOL_CONTRACT.md#canonical-observation).
|
|
22
|
+
|
|
21
23
|
SDK hosts can supply an awaited [`beforeExecute` callback](TOOL_CONTRACT.md#host-execution-hook) to save host state before ordinary or code-inner browser dispatch. This is a factory option, not a tool argument; normal installations do not need it.
|
|
22
24
|
|
|
23
25
|
## Upstream baseline
|
|
@@ -910,7 +912,7 @@ When these commands are invoked through the native `agent_browser` tool, structu
|
|
|
910
912
|
- project-local: `.pi/config/pi-agent-browser-native/config.json`
|
|
911
913
|
- explicit override: `PI_AGENT_BROWSER_CONFIG=/path/to/config.json`
|
|
912
914
|
|
|
913
|
-
Get an Exa API key from the [Exa dashboard](https://dashboard.exa.ai/api-keys) or a Brave Search API key from the [Brave Search API dashboard](https://api-dashboard.search.brave.com/). If both keys are available, `agent_browser_web_search` prefers Exa by default because its `/search` endpoint returns token-efficient highlights and agent-oriented search modes; set `webSearch.preferredProvider` to `"brave"` when Brave Search is preferred. You can also disable this package's search tool with `webSearch.enabled: false` when another search tool should win. Config merges global → project → `PI_AGENT_BROWSER_CONFIG` override, so `enabled` is read from the final loaded config: a global disable can be re-enabled by project or override config, while an override file with `enabled: false` is the highest-priority hard disable for that run.
|
|
915
|
+
Get an Exa API key from the [Exa dashboard](https://dashboard.exa.ai/api-keys) or a Brave Search API key from the [Brave Search API dashboard](https://api-dashboard.search.brave.com/). If both keys are available, `agent_browser_web_search` prefers Exa by default because its `/search` endpoint returns token-efficient highlights and agent-oriented search modes; set `webSearch.preferredProvider` to `"brave"` when Brave Search is preferred. You can also disable this package's search tool with `webSearch.enabled: false` when another search tool should win. Config merges global → project → `PI_AGENT_BROWSER_CONFIG` override, so `enabled` is read from the final loaded config: a global disable can be re-enabled by project or override config, while an override file with `enabled: false` is the highest-priority hard disable for that run. Globally installed or CLI-loaded copies read project-local config under `.pi/config/...` when Pi's native trust decision permits it, and skip that layer when the project is untrusted or Pi is launched with `--no-approve`.
|
|
914
916
|
|
|
915
917
|
`pi install npm:pi-agent-browser-native` loads the extension, but it does **not** usually put the package helper on your shell `PATH`. The clearest setup is to write the config file directly and keep actual keys in the environment that launches `pi`:
|
|
916
918
|
|
package/docs/RELEASE.md
CHANGED
|
@@ -21,10 +21,16 @@ Provide one concrete maintainer workflow for validating repo state, package cont
|
|
|
21
21
|
|
|
22
22
|
The owner's 2026-09-21 **“waive windows”** instruction makes Windows qualification nonblocking for this rollout, even with available runners, and supersedes older mandatory-Windows/no-waiver wording below and in platform guidance. Preserve failed diagnostics; do not claim a Windows full-suite pass or continue Windows repair experiments. Known policy-lock/restored Electron failures and bounded repeat results are tracked in [#191](https://github.com/fitchmultz/pi-agent-browser-native/issues/191) and the [current support matrix](SUPPORT_MATRIX.md#current-0616-rollout).
|
|
23
23
|
|
|
24
|
-
Linux/macOS, declared Node floors, official/fork host and consumer-artifact checks, and Native
|
|
24
|
+
Linux/macOS, declared Node floors, official/fork host and consumer-artifact checks, and Native lifecycle Linux remain required. All three final reviewers (reviewer-gpt, reviewer-ponytail, reviewer-claude) must approve before merge, release or activation. This waiver changes neither runtime nor the composed `release`/`prepublishOnly` scripts: record individually satisfied gates and the explicit Windows waiver, never label the full composition passed.
|
|
25
25
|
|
|
26
26
|
Docs/workflow-only changes may reuse prior live/platform evidence when the complete compiled runtime, runtime dependencies and relevant tests are unchanged. Changed published files require a new retained tarball checked by `verify-package.mjs --smoke-pi`, including runtime-only SDK and actual CLI loading. Publish those exact checked bytes without repacking.
|
|
27
27
|
|
|
28
|
+
## Pi 1.0 upgrade and qualification
|
|
29
|
+
|
|
30
|
+
This contract requires Pi 1.0.0. Do not install or activate it in running pre-1.0 sessions; coordinate the runtime cutover and restart participating agents first. Keep runtime activation separate from isolated checkout/SDK qualification. Preserve auth/profile/state files, explicit artifacts and Pi journals when updating or rolling back; browser mutations are not reversible through a package rollback.
|
|
31
|
+
|
|
32
|
+
Qualify the exact official and fork host graphs independently, including SDK and actual CLI loading, explicit/defaultTools/loader/initial-resume/tree/reload selections, structured success/failure/redaction and unchanged JSON. Inspect regular and fullscreen native TUI results, including failures and images. Keep the existing 250 ms import/factory and 1,000 ms lock budgets; synthetic research timings are not final-source release evidence or universal performance guarantees. Apply normal release gates and the Windows waiver. Host identity and actual supported APIs, not a version label alone, determine qualification.
|
|
33
|
+
|
|
28
34
|
## 0.7 upgrade and rollback
|
|
29
35
|
|
|
30
36
|
The 0.7 tool contract is breaking: direct argv stays compact, `script` moves to `agent_browser_code.code` with a persistent browser, the job DSL is replaced by native batch/code, and five advanced tools use flat schemas after native activation. Publish with the [migration map](TOOL_CONTRACT.md#07-migration), not a parallel legacy public route. Preserve saved auth, explicit files, and Pi journals. Existing strict pre-0.7 isolated-script leases are only read for cleanup.
|
|
@@ -35,9 +41,9 @@ Rollback is package-level: select the exact previously installed 0.6 release wit
|
|
|
35
41
|
|
|
36
42
|
### Changed-path qualification
|
|
37
43
|
|
|
38
|
-
The minimum Pi runtime is 0.
|
|
44
|
+
The minimum Pi runtime is 1.0.0, matching the native APIs used by the new tool contract. Wildcard peers remain host-owned dependency declarations, not support for older runtimes.
|
|
39
45
|
|
|
40
|
-
Qualify official Pi 0
|
|
46
|
+
Qualify official Pi 1.0 and the fork independently with the existing host/package/lifecycle infrastructure. Required evidence for the redesign includes compact schema and additive activation/history, native prompt sections, shared direct/code auth continuity, fresh JavaScript globals, selected real images and conservative geometry, visible handled failures/exact recovery, real cross-process helper/action and whole-cell ordering, cancellation/reaping, and ordered transition replay after interruption/branch changes. Retain native batch and advanced action/QA/Electron/source outcome coverage. Small synthetic timing comparisons are not universal performance claims or sandbox certification.
|
|
41
47
|
|
|
42
48
|
Existing owner waivers remain authoritative. Windows qualification is waived; report diagnostic failures without claiming a pass or restarting waived repair work. Routine GitHub Actions now runs on PRs to `main` and manual dispatch, with no Windows CI job. These focused checks complement, rather than replace, the local release and publication gates.
|
|
43
49
|
|
|
@@ -67,7 +73,7 @@ npm run verify -- pre-pr
|
|
|
67
73
|
`npm run verify -- release` runs:
|
|
68
74
|
|
|
69
75
|
1. `npm run verify` for generated playbook drift, TypeScript, unit/fake coverage, command-reference generated-block drift, and live command-reference verification against the targeted upstream on `PATH`
|
|
70
|
-
2. `npm run verify -- lifecycle`, which launches the configured-source lifecycle harness for `/reload`, exact `--session-id` relaunch, managed-session continuity, persisted spill reachability, and
|
|
76
|
+
2. `npm run verify -- lifecycle`, which launches the configured-source lifecycle harness for `/reload`, exact `--session-id` relaunch, managed-session continuity, persisted spill reachability, and native returned-failure behavior
|
|
71
77
|
3. `npm run verify -- package-pi`, which first validates package contents via `npm pack --json --dry-run` and then smoke-loads the packed package in Pi isolation
|
|
72
78
|
4. `npm run smoke:platform:doctor` and the full Crabbox matrix from [`platform-smoke.md`](platform-smoke.md): macOS SSH, Ubuntu local-container, and native Windows Parallels targets running fast target-local `platform-build` plus `browser-dogfood-smoke`
|
|
73
79
|
|
|
@@ -105,9 +111,9 @@ The deterministic dogfood mode clean-builds the compiled package, uses the exten
|
|
|
105
111
|
|
|
106
112
|
Every release also requires interactive `tmux`-driven Pi dogfood with the native `agent_browser` tool against real sites. For extension-focused release smokes, use `pi --approve --no-extensions --no-skills -e .` from the trusted checkout before publish so auto-loaded dogfood/QA skills cannot replace the bounded smoke workflow; omit `--approve` only when the smoke is explicitly testing Pi's Project Trust prompt. Run separate skill-enabled dogfood only when validating skill routing or report-generation behavior. Drive prompts with `tmux send-keys`, exercise at least one simple static site and one real documentation/product site, include advanced QA, code, or native batch when those surfaces changed, close every opened browser session, remove screenshots/temp artifacts, and record the outcome in the release notes or support-matrix evidence. Do not paste raw multi-line prompts into a tmux Pi pane: plain newlines submit separate queued user messages. For scripted smoke driving, collapse prompt files to one line before sending (`PROMPT=$(tr '\n' ' ' < /tmp/smoke-prompt.md); tmux send-keys -t "$SESSION":0.0 -l "$PROMPT"; tmux send-keys -t "$SESSION":0.0 Enter`). For manual multi-line editing, use Pi's external editor shortcut (`Ctrl+G`) or configure tmux extended keys so Pi can receive `Shift+Enter` for newlines; see the installed Pi `docs/tmux.md` guidance. Automated localhost, fake-upstream, and deterministic dogfood gates do not replace this human-readable live-site transcript evidence. When code changes, add a persisted-session `agent_browser_code` pass that aggregates at least two real pages, exercises a conditional branch, compares selected output with an ordinary-call baseline, verifies selected screenshot bytes reach the model, and checks browser/auth continuity on a later direct/code call with fresh JS globals. Review ordered custom transition entries and interrupted/replayed state, not only the outer result. Exercise handled failures, timeout/cancellation, whole-cell ordering, and child reaping; close only test-owned browsers afterward and retain Pi transcripts. Never use `--no-session` for code dogfood. When `agent_browser_web_search` or package config changed, add one key-free smoke proving the optional tool is absent without config, one fake/unit-backed smoke in the default suite, and one opt-in live Exa or Brave Search check with a real key while confirming the key does not appear in transcripts, stdout/stderr, config status, PR text, or artifacts. When `electron.*` surfaces, attached-session diagnostics, or `qa.attached` changed, add a local Electron pass: `electron.list` → `electron.launch` (expect isolated profile behavior) → `snapshot -i` or `electron.probe` / `qa.attached` → `electron.cleanup` with the returned `launchId`, verifying status/mismatch guidance if you simulate a dead renderer or stale refs. For dense-dashboard stress coverage, use the [public Grafana stress checklist](#public-grafana-stress-checklist) below; it is a maintainer workflow, not bundled product skill or recipe runtime.
|
|
107
113
|
|
|
108
|
-
When reviewing saved session JSONL after a failed smoke or QA reclassification, expect browser tool rows to carry `isError: true` whenever `details.resultCategory` is `failure`. The model-visible observation must also report failure. Canonical JSON stays parseable
|
|
114
|
+
When reviewing saved session JSONL after a failed smoke or QA reclassification, expect browser tool rows to carry `isError: true` whenever `details.resultCategory` is `failure`. The model-visible observation must also report failure. Canonical JSON stays parseable and unchanged. Final public results return `isError` directly, with a prose failure notice outside explicit JSON, so Pi's transcript matches the wrapper contract ([`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details)). Preserve a normal Pi session directory for those checks; avoiding `--no-session` keeps this evidence intact ([`AGENTS.md`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/AGENTS.md) preferred validation workflow).
|
|
109
115
|
|
|
110
|
-
The configured-source lifecycle regression harness is required before release because it launches an interactive Pi 0.
|
|
116
|
+
The configured-source lifecycle regression harness is required before release because it launches an interactive Pi 1.0.0+ process under `tmux` with `--approve` and validates `/reload`, full relaunch with the same exact `--session-id`, managed-session continuity, persisted artifacts, compiled-entrypoint pickup after process restart, and native returned-failure behavior. Branch-backed `session_tree` rehydration and cleanup ownership are validated by focused extension harness tests:
|
|
111
117
|
|
|
112
118
|
```bash
|
|
113
119
|
npm run verify -- lifecycle
|
|
@@ -233,7 +239,7 @@ Before publishing, validate both local-checkout modes without mixing their assum
|
|
|
233
239
|
|
|
234
240
|
For expanded-surface validation, the smoke prompt should cover native tool invocation rather than shelling out to `agent-browser`: `--version`, `--help`, `skills list`, `skills get core --full`, `open` with `sessionMode: "fresh"`, `snapshot -i`, `click`, flat `agent_browser_action` after enabling `action` (including unique accessible select and explicit session routing), `eval --stdin`, `batch` via stdin, `agent_browser_code`, advanced QA, and experimental source/network tools after loader activation, `screenshot <path>`, explicit `--session … open` plus `--session … close`, `network requests`, `console` / `errors`, `diff snapshot`, `stream status` plus `stream disable`, `dashboard start` plus `dashboard stop`, and `chat <message>` (credential failure is acceptable evidence of wrapper pass-through when `AI_GATEWAY_API_KEY` is intentionally unset). Clean up any opened browser session with `close`, remove temporary files, and kill the tmux session before ending validation.
|
|
235
241
|
|
|
236
|
-
This checklist assumes a real `agent-browser` on `PATH`. It complements, but does not overlap, `npm run verify -- lifecycle`: that harness swaps in a fake upstream binary and focuses on `/reload`, exact `--session-id` relaunch, managed-session continuity, spill-path persistence, and
|
|
242
|
+
This checklist assumes a real `agent-browser` on `PATH`. It complements, but does not overlap, `npm run verify -- lifecycle`: that harness swaps in a fake upstream binary and focuses on `/reload`, exact `--session-id` relaunch, managed-session continuity, spill-path persistence, and native returned `isError` and JSON-preservation semantics (`scripts/verify-lifecycle.mjs`), not the full command matrix above.
|
|
237
243
|
|
|
238
244
|
When a smoke or dogfood run fails after `sessionMode: "fresh"` (missing binary, timeout, upstream error, or **`qa`** preset reclassification), read `details.managedSessionOutcome` before assuming which managed session the next default `sessionMode: "auto"` call will follow; the same struct can appear without the extra `Managed session outcome: …` prose line on `"auto"` failures. Field-level semantics and append ordering relative to other diagnostic tails are documented in [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details) and the session-mode notes in [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md).
|
|
239
245
|
|
|
@@ -245,7 +251,7 @@ Run the automated harness for deterministic configured-source lifecycle regressi
|
|
|
245
251
|
npm run verify -- lifecycle
|
|
246
252
|
```
|
|
247
253
|
|
|
248
|
-
The harness creates an isolated `PI_CODING_AGENT_DIR`, writes settings with exactly one temporary configured package source, runs `pi` in `tmux` with `--approve`, default model **`zai/glm-5.2`**, and a deterministic `--session-id`, puts a deterministic fake `agent-browser` first on `PATH`, starts an explicit `sessionMode: "fresh"` managed browser, drives `/reload`, closes Pi, and relaunches with the same exact session id instead of typing `/resume`. It also asserts the JSONL session header id, same-page managed-session continuity, compiled JS code pickup after full process relaunch, persisted spill reachability, and
|
|
254
|
+
The harness creates an isolated `PI_CODING_AGENT_DIR`, writes settings with exactly one temporary configured package source, runs `pi` in `tmux` with `--approve`, default model **`zai/glm-5.2`**, and a deterministic `--session-id`, puts a deterministic fake `agent-browser` first on `PATH`, starts an explicit `sessionMode: "fresh"` managed browser, drives `/reload`, closes Pi, and relaunches with the same exact session id instead of typing `/resume`. It also asserts the JSONL session header id, same-page managed-session continuity, compiled JS code pickup after full process relaunch, persisted spill reachability, and native returned `isError` and JSON-preservation semantics for a QA reclassification. Per-step tmux waits default to **180000 ms** (three minutes) in [`scripts/verify-lifecycle.mjs`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/scripts/verify-lifecycle.mjs) (`DEFAULT_TIMEOUT_MS`); override with `--timeout-ms <ms>` when slower models or cold starts need more headroom. Override the model when needed:
|
|
249
255
|
|
|
250
256
|
```bash
|
|
251
257
|
npm run verify -- lifecycle --model openai-codex/gpt-5.5:minimal
|
|
@@ -306,29 +312,29 @@ This suite requires the installed stable `agent-browser --version` to meet the m
|
|
|
306
312
|
|
|
307
313
|
The default unit suite also runs `agentBrowserExtension passes through core command coverage fallback matrix` in [`test/agent-browser.extension-passthrough-validation.test.ts`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/test/agent-browser.extension-passthrough-validation.test.ts): a fake upstream records argv so explicit `--session connector connect 9222`, plus `download` with a selector and path, `get url`, `snapshot --compact`, and `tab new` / `tab t1` / `tab close` on implicit managed sessions, still prove `--json` and session ordering without a browser. A second fake-upstream matrix in that file (`agentBrowserExtension passes through non-core network debug diff stream dashboard and chat families`) pins representative `network`, `diff`, `trace` / `profiler` / `record`, `console` / `errors` / `highlight` / `inspect` / `clipboard`, `stream`, `dashboard`, and `chat` JSON shapes plus redacted `details.data` and argv echoes without a browser. A third matrix (`agentBrowserExtension passes through provider and specialized skill workflows`) asserts provider `open` argv shapes still receive `--json` plus implicit `--session` while read-only `skills get …` stays stateless (no managed session fields) and provider credential env vars are forwarded into the fake upstream log. Extend those matrices when adding passthrough coverage that should stay out of the slow real-upstream loop.
|
|
308
314
|
|
|
309
|
-
### Native
|
|
315
|
+
### Native lifecycle qualification
|
|
310
316
|
|
|
311
|
-
`test/agent-browser.
|
|
317
|
+
[`test/agent-browser.native-lifecycle.test.mjs`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/test/agent-browser.native-lifecycle.test.mjs) is the model-free portable SDK lifecycle gate. It loads the compiled extension through real native resource discovery and executes browser tools against loopback fixtures. Qualify official and fork Pi 1.0 graphs independently: no removed fork-only APIs are required. It covers branch/reload continuity, detached and queued code cancellation/ordering, managed cleanup, caller-owned attachment and off-branch routing, failed journal-begin refusal during recording, and root save/reopen across fresh checkout/state-directory inodes. This is lifecycle evidence, not serialization of live page JavaScript, forms or recordings.
|
|
312
318
|
|
|
313
|
-
Run
|
|
319
|
+
Run non-root with an isolated HOME/socket root and stock `agent-browser`, Chrome for Testing and ffmpeg, without personal profiles or inherited credentials/configuration. The browser directory must contain binaries, never a personal profile.
|
|
314
320
|
|
|
315
321
|
```bash
|
|
316
322
|
npm run build
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
node --test test/agent-browser.
|
|
323
|
+
PI_NATIVE_LIFECYCLE_REQUIRED=1 \
|
|
324
|
+
PI_NATIVE_LIFECYCLE_SDK='/path/to/pi-coding-agent/dist/index.js' \
|
|
325
|
+
PI_NATIVE_LIFECYCLE_BROWSER_DIR='/path/to/browsers/chrome-<version>' \
|
|
326
|
+
node --test test/agent-browser.native-lifecycle.test.mjs
|
|
321
327
|
```
|
|
322
328
|
|
|
323
|
-
`
|
|
329
|
+
`PI_NATIVE_LIFECYCLE_EXTENSION` selects a separate compiled checkout; `PI_NATIVE_LIFECYCLE_ARTIFACT_DIR` selects retained transcript evidence. These are test selectors, not runtime package config. Retain exact host/source identity, native tool receipts and cleanup proof. Local SDK qualification complements, rather than replaces, the configured-source tmux harness, live-site smoke and platform gates.
|
|
324
330
|
|
|
325
331
|
#### Routine GitHub PR checks
|
|
326
332
|
|
|
327
|
-
[`.github/workflows/pi-compatibility.yml`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/.github/workflows/pi-compatibility.yml) runs on PRs to `main` and manual dispatch. Independent Ubuntu jobs qualify the locked official Pi graph and the maintained fork's current `main` as a complete installed graph on Node 24.21.0. Each runs `check:compat` once: host identity, typecheck, the full offline suite, and packed SDK/CLI loading. A parallel macOS Node 24.21.0 job checks the packed Pi load without repeating the full suite. When the candidate official version differs from the supported Pi floor, that macOS job also selects the actual floor graph for a focused type/package smoke. The host selector uses the pinned `fitchmultz/.github` automation scripts without changing them. There are no cross-job host artifacts or persistent caches.
|
|
333
|
+
[`.github/workflows/pi-compatibility.yml`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/.github/workflows/pi-compatibility.yml) runs on PRs to `main` and manual dispatch. Independent Ubuntu jobs qualify the locked official Pi graph and the maintained fork's current `main` as a complete installed graph on Node 24.21.0. Each runs `check:compat` once: host identity, typecheck, the full offline suite, and packed SDK/CLI loading. A parallel macOS Node 24.21.0 job checks the packed Pi load without repeating the full suite. When the candidate official version differs from the supported Pi floor, that macOS job also selects the actual floor graph for a focused type/package smoke. The host selector uses the pinned `fitchmultz/.github` automation scripts without changing them. There are no cross-job host artifacts or persistent caches. The official lane always qualifies the locked official graph; the fork lane first compares the fork's `main` Pi version against the supported Pi floor, and while the fork is below that floor it skips the fork build/qualification and emits a truthful unattempted-below-floor receipt in the job summary instead of failing or resurrecting dropped fork APIs. The full supported-fork qualification path runs unchanged once the fork reaches the floor.
|
|
328
334
|
|
|
329
|
-
[`.github/workflows/native-
|
|
335
|
+
[`.github/workflows/native-lifecycle.yml`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/.github/workflows/native-lifecycle.yml) runs the separate **Native lifecycle Linux** gate through [`scripts/ci-native-lifecycle.sh`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/scripts/ci-native-lifecycle.sh). It independently checks out the PR head, builds the compiled extension on Node **24.21.0**, and runs portable native SDK lifecycle checks against isolated loopback browser fixtures. It replaces the fork-only checkpoint gate and requires passing checks with no unexpected failure, cancellation or skip. It does not repeat the official full suite. Sources use a private `/tmp` root, sanitized environment, non-root execution, and a loopback-only network namespace. No personal profile, credentials, or model calls are involved.
|
|
330
336
|
|
|
331
|
-
|
|
337
|
+
The fork compatibility workflow resolves `main` once at checkout and uses that exact commit for its build and provenance checks; the native lifecycle gate instead uses the locked official Pi graph installed by `npm ci`. CI writes setup, provenance, command-reference, and native TAP results to the job log instead of uploading artifacts. The checks cover their exact source, host, and synthetic browser paths; they do not replace release/manual-publication gates, real-site authentication, or full personal-workspace restore qualification.
|
|
332
338
|
|
|
333
339
|
### Native Linux socket-root regression
|
|
334
340
|
|
package/docs/REQUIREMENTS.md
CHANGED
|
@@ -47,7 +47,7 @@ Define the product requirements and constraints for `pi-agent-browser-native`.
|
|
|
47
47
|
### Install priority
|
|
48
48
|
|
|
49
49
|
- Prioritize the package install path first.
|
|
50
|
-
- User-facing install docs should lead with `pi install npm:pi-agent-browser-native`; ephemeral package trials and validation should use `pi --no-extensions -e npm:pi-agent-browser-native[@<version>]` so configured checkout or global sources cannot duplicate `agent_browser`, adding `--approve` in
|
|
50
|
+
- User-facing install docs should lead with `pi install npm:pi-agent-browser-native`; ephemeral package trials and validation should use `pi --no-extensions -e npm:pi-agent-browser-native[@<version>]` so configured checkout or global sources cannot duplicate `agent_browser`, adding `--approve` in automation when the current project is intentionally trusted.
|
|
51
51
|
- User-facing install docs should also include the GitHub source path `pi install https://github.com/fitchmultz/pi-agent-browser-native`.
|
|
52
52
|
- Provide a read-only package-level doctor command that checks upstream `agent-browser` PATH/version and duplicate Pi package/checkout sources before first use. It must not mutate Pi settings and must remain distinct from upstream `agent-browser doctor`.
|
|
53
53
|
- Keep the current local-checkout path documented as the practical pre-release and development flow.
|
|
@@ -66,12 +66,12 @@ Define the product requirements and constraints for `pi-agent-browser-native`.
|
|
|
66
66
|
|
|
67
67
|
- Keep the always-on interface compact: `agent_browser { args, stdin?, outputPath?, timeoutMs?, sessionMode? }`, strict-JSON `agent_browser_code { code, session?, namespace?, timeoutMs?, outputPath? }`, and `agent_browser_tools { enable? }`.
|
|
68
68
|
- Preserve the complete native command surface through one CLI executor. Native batch handles fixed sequences; code handles branches/loops/aggregation. Remove the redundant public job DSL and old isolated-script execution instead of carrying parallel legacy runtimes.
|
|
69
|
-
- Register advanced action, QA, Electron, UI-source, and network-source tools once
|
|
69
|
+
- Register advanced action, QA, Electron, UI-source, and network-source tools once with native `defaultActive: false`. Enable additively through Pi's native tool selection/history without removing unrelated tools. Preserve explicit/defaultTools selections, loader activation, initial resume, tree navigation and reload; retain only the additive fallback needed for official Pi 1.0 initial resume. Use flat schemas and return executable next actions naming the actual tool.
|
|
70
70
|
- Preserve unique visible accessible dropdown selection, semantic/ref recovery, truthful QA verdicts (including ambiguous error-buffer residue), attached diagnostic preservation/defaults, Electron process/profile ownership, and bounded source scans. Raw diagnostic-read success is not a QA verdict, and source hints remain candidates rather than authoritative blame.
|
|
71
71
|
- Code runs in a fresh permissioned Node child with no host APIs/imports, null-prototype task globals, JSON-only bounded IPC, serial native calls, and explicit JSON/image output. Keep current source/output/call/deadline limits. Browser/authentication persists under existing native ownership and configuration; JavaScript variables do not. Allow ordinary native commands including batch/auth/profile/state/connect/close, but prevent changes to the fixed parent-selected identity and namespace-wide close within a cell.
|
|
72
72
|
- Hold a cooperating-process execution lock keyed by actual socket context, canonical namespace, and session across direct helper/action work or the entire code cell. Use ordered multi-identity acquisition for replacement/cleanup and a namespace barrier for direct close-all. This does not coordinate humans, third-party clients, or older versions, guarantee atomic browser actions, or provide rollback.
|
|
73
73
|
- Persist one canonical begin/finish event format for direct/code/host work through native Pi custom entries and a shared reducer. Define full captures once, preserve exact targets/native identity, and persist artifact-row changes rather than unchanged views. Interrupted outcomes remain unknown until inspection; failed begin blocks dispatch and failed finish stops dependent work without mutation retry. Require actual journal publication before browser dispatch. Legacy browser/lease decoders belong only to validated offline stopped-copy conversion; preserve original bytes, all ancestry and owner UUIDs. A fork must never acquire its parent's cleanup rights. Bound extension replay with token projection and winning definitions on both hosts, while disclosing stock official Pi's eager native loader and individual-value memory ceilings; see [`SESSION_STORAGE.md`](SESSION_STORAGE.md).
|
|
74
|
-
- Use one canonical model-visible observation for JSON/prose/code with success/data/error, exact recovery, artifact receipts, and image observations. Details is audit/replay metadata, not the sole source of actionable failures. Inner calls avoid full model rendering/spills/image encoding. Bound outer output and name a complete redacted observation spill rather than truncating executable payloads.
|
|
74
|
+
- Use one canonical model-visible observation for JSON/prose/code with success/data/error, exact recovery, artifact receipts, and image observations. Native `outputSchema`/`structuredContent` under the Browser tool namespace expose that same bounded redacted projection, not raw internal details. Loader inventory and normalized search data keep their existing shapes. Details is audit/replay metadata, not the sole source of actionable failures. Return canonical native `isError` without a result-repair hook; preserve prose notices and explicit JSON. Inner calls avoid full model rendering/spills/image encoding. Bound outer output and name a complete redacted observation spill rather than truncating executable payloads.
|
|
75
75
|
- Attach only verified real images; code selects current-cell image handles explicitly. Report pixel dimensions and CSS viewport/DPR/crop/scroll/frame evidence conservatively. Unknown geometry remains unknown; neither full-page nor element captures are assumed viewport coordinates. Do not inject model-specific image-detail/provider payload changes.
|
|
76
76
|
- Direct upstream capability remains available: explicit sessions, state/restore paths, profiles, config, file access, launch arguments, environment, local pages, output paths, and close arguments pass through under ordinary native semantics. Keep all session/state rows visible. Wrapper validation concerns input shape, lifecycle integrity, and truthful evidence, not authorization of resources.
|
|
77
77
|
- Native download owns clicking and saving, including loopback, Blob exports, and redirects. Create artifact directories before dispatch and verify saved files; output-data writes must not alias browser artifacts. Pending recording is not saved video.
|
|
@@ -94,7 +94,7 @@ Define the product requirements and constraints for `pi-agent-browser-native`.
|
|
|
94
94
|
- The primary confidence path is a real `pi` session driven in `tmux`.
|
|
95
95
|
- For quick local checkout smoke validation, launch `pi --approve --no-extensions -e .` from the repository root so only the checkout copy loads; do not rely on Pi settings or `/reload` semantics in this isolated mode.
|
|
96
96
|
- For hot-reload validation, configure exactly one active source for this extension in Pi settings and launch plain `pi`; validate `/reload` there because it exercises auto-discovered/configured resources.
|
|
97
|
-
- Maintain a tmux-driven configured-source lifecycle harness (`npm run verify -- lifecycle`; required before release per `docs/RELEASE.md`) that isolates Pi settings, uses exactly one configured source, exercises `/reload`, full restart plus exact `--session-id` relaunch, and asserts managed-session continuity, persisted artifact survival, and
|
|
97
|
+
- Maintain a tmux-driven configured-source lifecycle harness (`npm run verify -- lifecycle`; required before release per `docs/RELEASE.md`) that isolates Pi settings, uses exactly one configured source, exercises `/reload`, full restart plus exact `--session-id` relaunch, and asserts managed-session continuity, persisted artifact survival, and native returned `isError`, visible prose failure notices and unchanged parseable JSON. It remains outside the default `npm run verify` sequence, but it is embedded in `npm run verify -- release` so `prepublishOnly` enforces it before publish unless scripts are intentionally skipped. The harness defaults Pi to model `zai/glm-5.2` (`scripts/verify-lifecycle.mjs`); pass `--model <id>` after `lifecycle` when a different model is required. Keep `docs/RELEASE.md` accurate about the harness behavior, cleanup, transcript retention, and limitations.
|
|
98
98
|
- Validate a full `pi` restart with exact `--session-id` relaunch or `/resume` when changes touch managed-session continuity, reload behavior, or persisted artifact paths. Validate branch-backed state changes with the focused `session_tree` harness tests.
|
|
99
99
|
- Prefer full `pi` restart over `/reload` when validating extension changes beyond a quick reload smoke check.
|
|
100
100
|
- Use `/resume` or an explicit session id/path when needed after restart.
|
|
@@ -119,7 +119,7 @@ The design should comfortably support workflows such as:
|
|
|
119
119
|
## Implications for the implementation
|
|
120
120
|
|
|
121
121
|
- Package-manifest behavior matters more than repo-local development wiring.
|
|
122
|
-
- The extension uses native Pi tool registration/activation and named prompt sections rather than replacing the full system prompt.
|
|
122
|
+
- The extension uses native Pi tool registration/activation and named prompt sections rather than replacing the full system prompt. Require Pi 1.0.0 and qualify official and fork hosts independently. Retain the instruction-group collector when supported and identical full native prompt-section fallback otherwise; hosted provider orchestration is not required.
|
|
123
123
|
- The wrapper should stay thin, with upstream `agent-browser` remaining the source of truth for command semantics.
|
|
124
124
|
- Successful and failed tool outcomes should surface bounded machine-readable fields on Pi-facing `details` (`resultCategory`, `successCategory`, `failureCategory`, optional structured `nextActions`, optional `pageChangeSummary` with explicit observed-vs-dispatched evidence and per-step summaries on `batch`, optional `artifactVerification` with the same shape on successful `batchSteps[]` rows, optional `outputFile`, optional `timeoutPartialProgress`) so agents can branch without parsing prose; browser-bearing `nextActions` must preserve a known session identity so recovery cannot inspect an unrelated implicit session; stateful commands (`auth`, `cookies`, `storage`, `dialog`, `frame`, `state`) plus other structured diagnostics (for example `network`, `diff`, `trace`, `stream`, `dashboard`, `chat`) and `batch` should redact secret-bearing payloads in model-facing `details.data`, including the compact per-step `batch` roll-up on the parent result (full per-step payloads live on `batchSteps[]`). Dialog/prompt-related timeouts should be bounded with recovery `nextActions`; non-dialog timeouts should prefer best-effort per-step progress and retry payloads when a plan is available; no-op scrolls should expose no-movement state instead of only an upstream success boolean; explicit page/container scroll helpers should expose before/after movement evidence. The contract lives in [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details), enums and classifier precedence live in `extensions/agent-browser/lib/results/categories.ts` and `contracts.ts`, and presentation-time summaries, redaction, network request follow-ups, and artifact verification rollups are assembled in `extensions/agent-browser/lib/results/presentation.ts` (`buildPageChangeSummary`, command taxonomy predicates from `command-taxonomy.ts`, `redactPresentationData`, `buildArtifactVerificationSummary`, `buildBatchPresentation`).
|
|
125
125
|
- User-facing docs belong in `README.md` and the canonical published files under `docs/`.
|