pi-agent-browser-native 0.2.1 → 0.2.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.
@@ -10,6 +10,7 @@ import { readFile, stat } from "node:fs/promises";
10
10
  import { resolve } from "node:path";
11
11
 
12
12
  import { parseCommandInfo, type CommandInfo } from "../runtime.js";
13
+ import { type PersistentSessionArtifactStore } from "../temp.js";
13
14
  import { buildSnapshotPresentation, formatRawSnapshotText, formatSnapshotSummary } from "./snapshot.js";
14
15
  import {
15
16
  type AgentBrowserBatchResult,
@@ -106,6 +107,63 @@ function getScreenshotSummary(data: Record<string, unknown>): string | undefined
106
107
  return typeof data.path === "string" ? `Saved image: ${data.path}` : undefined;
107
108
  }
108
109
 
110
+ function getScalarExtractionResult(data: Record<string, unknown>): string | undefined {
111
+ const { result } = data;
112
+ if (typeof result === "string") {
113
+ return result.trim().length > 0 ? result : undefined;
114
+ }
115
+ if (typeof result === "number" || typeof result === "boolean") {
116
+ return String(result);
117
+ }
118
+ return undefined;
119
+ }
120
+
121
+ function getExtractionOrigin(data: Record<string, unknown>): string | undefined {
122
+ if (typeof data.origin === "string" && data.origin.trim().length > 0) {
123
+ return data.origin.trim();
124
+ }
125
+ if (typeof data.url === "string" && data.url.trim().length > 0) {
126
+ return data.url.trim();
127
+ }
128
+ return undefined;
129
+ }
130
+
131
+ function formatGetSummaryLabel(subcommand: string | undefined): string {
132
+ if (!subcommand) {
133
+ return "Get result";
134
+ }
135
+ if (subcommand.toLowerCase() === "url") {
136
+ return "URL";
137
+ }
138
+ return `${subcommand.slice(0, 1).toUpperCase()}${subcommand.slice(1)}`;
139
+ }
140
+
141
+ function formatExtractionSummary(commandInfo: CommandInfo, data: Record<string, unknown>): string | undefined {
142
+ const scalarResult = getScalarExtractionResult(data);
143
+ if (!scalarResult) {
144
+ return undefined;
145
+ }
146
+ if (commandInfo.command === "get") {
147
+ return `${formatGetSummaryLabel(commandInfo.subcommand)}: ${scalarResult.split("\n", 1)[0] ?? scalarResult}`;
148
+ }
149
+ if (commandInfo.command === "eval") {
150
+ return `Eval result: ${scalarResult.split("\n", 1)[0] ?? scalarResult}`;
151
+ }
152
+ return undefined;
153
+ }
154
+
155
+ function formatExtractionText(commandInfo: CommandInfo, data: Record<string, unknown>): string | undefined {
156
+ if (commandInfo.command !== "get" && commandInfo.command !== "eval") {
157
+ return undefined;
158
+ }
159
+ const scalarResult = getScalarExtractionResult(data);
160
+ if (!scalarResult) {
161
+ return undefined;
162
+ }
163
+ const origin = getExtractionOrigin(data);
164
+ return origin && origin !== scalarResult ? `${scalarResult}\n\nOrigin: ${origin}` : scalarResult;
165
+ }
166
+
109
167
  function isNavigationObservableCommand(command: string | undefined): boolean {
110
168
  return command !== undefined && NAVIGATION_SUMMARY_COMMANDS.has(command);
111
169
  }
@@ -207,8 +265,9 @@ async function buildBatchStepPresentation(options: {
207
265
  cwd: string;
208
266
  index: number;
209
267
  item: AgentBrowserBatchResult;
268
+ persistentArtifactStore?: PersistentSessionArtifactStore;
210
269
  }): Promise<{ details: BatchStepPresentationDetails; presentation: ToolPresentation }> {
211
- const { cwd, index, item } = options;
270
+ const { cwd, index, item, persistentArtifactStore } = options;
212
271
  const command = isStringArray(item.command) ? item.command : undefined;
213
272
  const commandText = formatBatchStepCommand(command, index);
214
273
 
@@ -236,6 +295,7 @@ async function buildBatchStepPresentation(options: {
236
295
  commandInfo: parseCommandInfo(command ?? []),
237
296
  cwd,
238
297
  envelope: { data: item.result, success: true },
298
+ persistentArtifactStore,
239
299
  });
240
300
  const fullOutputPaths = getPresentationPaths({
241
301
  primaryPath: presentation.fullOutputPath,
@@ -268,12 +328,28 @@ async function buildBatchStepPresentation(options: {
268
328
  async function buildBatchPresentation(options: {
269
329
  cwd: string;
270
330
  data: AgentBrowserBatchResult[];
331
+ persistentArtifactStore?: PersistentSessionArtifactStore;
271
332
  summary: string;
272
333
  }): Promise<ToolPresentation> {
273
- const { cwd, data, summary } = options;
334
+ const { cwd, data, persistentArtifactStore, summary } = options;
274
335
  const steps: Array<{ details: BatchStepPresentationDetails; presentation: ToolPresentation }> = [];
336
+ const protectedPersistentPaths: string[] = [];
275
337
  for (const [index, item] of data.entries()) {
276
- steps.push(await buildBatchStepPresentation({ cwd, index, item }));
338
+ const step = await buildBatchStepPresentation({
339
+ cwd,
340
+ index,
341
+ item,
342
+ persistentArtifactStore: persistentArtifactStore
343
+ ? { ...persistentArtifactStore, protectedPaths: protectedPersistentPaths }
344
+ : undefined,
345
+ });
346
+ steps.push(step);
347
+ protectedPersistentPaths.push(
348
+ ...getPresentationPaths({
349
+ primaryPath: step.presentation.fullOutputPath,
350
+ secondaryPaths: step.presentation.fullOutputPaths,
351
+ }),
352
+ );
277
353
  }
278
354
 
279
355
  const batchFailure = getBatchFailureDetails(steps);
@@ -354,6 +430,10 @@ function formatSummary(commandInfo: CommandInfo, data: unknown): string {
354
430
  if (commandInfo.command === "screenshot" && typeof data.path === "string") {
355
431
  return `Screenshot saved: ${data.path}`;
356
432
  }
433
+ const extractionSummary = formatExtractionSummary(commandInfo, data);
434
+ if (extractionSummary) {
435
+ return extractionSummary;
436
+ }
357
437
  const pageSummary = getPageSummary(data);
358
438
  if (pageSummary) {
359
439
  return pageSummary.split("\n", 1)[0] ?? "agent-browser result";
@@ -404,6 +484,11 @@ function formatContentText(commandInfo: CommandInfo, data: unknown): string {
404
484
  if (screenshotSummary) return screenshotSummary;
405
485
  }
406
486
 
487
+ const extractionText = formatExtractionText(commandInfo, data);
488
+ if (extractionText) {
489
+ return extractionText;
490
+ }
491
+
407
492
  const pageSummary = getPageSummary(data);
408
493
  if (pageSummary) {
409
494
  return pageSummary;
@@ -459,8 +544,9 @@ export async function buildToolPresentation(options: {
459
544
  cwd: string;
460
545
  envelope?: AgentBrowserEnvelope;
461
546
  errorText?: string;
547
+ persistentArtifactStore?: PersistentSessionArtifactStore;
462
548
  }): Promise<ToolPresentation> {
463
- const { commandInfo, cwd, envelope, errorText } = options;
549
+ const { commandInfo, cwd, envelope, errorText, persistentArtifactStore } = options;
464
550
  if (errorText) {
465
551
  return {
466
552
  content: [{ type: "text", text: errorText }],
@@ -472,9 +558,9 @@ export async function buildToolPresentation(options: {
472
558
  const summary = formatSummary(commandInfo, data);
473
559
  const presentation =
474
560
  commandInfo.command === "batch" && Array.isArray(data)
475
- ? await buildBatchPresentation({ cwd, data: data as AgentBrowserBatchResult[], summary })
561
+ ? await buildBatchPresentation({ cwd, data: data as AgentBrowserBatchResult[], persistentArtifactStore, summary })
476
562
  : commandInfo.command === "snapshot" && isRecord(data)
477
- ? await buildSnapshotPresentation(data)
563
+ ? await buildSnapshotPresentation(data, persistentArtifactStore)
478
564
  : {
479
565
  content: [{ type: "text" as const, text: formatContentText(commandInfo, data) }],
480
566
  data,
@@ -6,7 +6,7 @@
6
6
  * Invariants/Assumptions: Snapshot compaction should stay helpful even if upstream snapshot text formatting shifts, so structured parsing is best-effort and always has a resilient raw-outline fallback.
7
7
  */
8
8
 
9
- import { writeSecureTempFile } from "../temp.js";
9
+ import { type PersistentSessionArtifactStore, writePersistentSessionArtifactFile, writeSecureTempFile } from "../temp.js";
10
10
  import { type ToolPresentation, compareRefIds, countLines, isRecord, normalizeWhitespace, truncateText } from "./shared.js";
11
11
 
12
12
  const SNAPSHOT_INLINE_MAX_CHARS = 6_000;
@@ -463,12 +463,18 @@ function canUseStructuredSnapshotPreview(snapshotLines: SnapshotLine[], refEntri
463
463
  );
464
464
  }
465
465
 
466
- async function writeSnapshotSpillFile(data: Record<string, unknown>): Promise<string> {
467
- return await writeSecureTempFile({
466
+ async function writeSnapshotSpillFile(
467
+ data: Record<string, unknown>,
468
+ persistentArtifactStore: PersistentSessionArtifactStore | undefined,
469
+ ): Promise<string> {
470
+ const options = {
468
471
  content: JSON.stringify(data, null, 2),
469
472
  prefix: SNAPSHOT_SPILL_FILE_PREFIX,
470
473
  suffix: ".json",
471
- });
474
+ };
475
+ return persistentArtifactStore
476
+ ? await writePersistentSessionArtifactFile({ ...options, store: persistentArtifactStore })
477
+ : await writeSecureTempFile(options);
472
478
  }
473
479
 
474
480
  export function formatSnapshotSummary(data: Record<string, unknown>): string {
@@ -487,7 +493,10 @@ export function formatRawSnapshotText(data: Record<string, unknown>): string {
487
493
  return `Origin: ${origin}\nRefs: ${refs}\n\n${snapshot}`;
488
494
  }
489
495
 
490
- export async function buildSnapshotPresentation(data: Record<string, unknown>): Promise<ToolPresentation> {
496
+ export async function buildSnapshotPresentation(
497
+ data: Record<string, unknown>,
498
+ persistentArtifactStore: PersistentSessionArtifactStore | undefined = undefined,
499
+ ): Promise<ToolPresentation> {
491
500
  const summary = formatSnapshotSummary(data);
492
501
  const rawText = formatRawSnapshotText(data);
493
502
  if (!shouldCompactSnapshot(rawText, data)) {
@@ -501,7 +510,7 @@ export async function buildSnapshotPresentation(data: Record<string, unknown>):
501
510
  let fullOutputPath: string | undefined;
502
511
  let spillErrorText: string | undefined;
503
512
  try {
504
- fullOutputPath = await writeSnapshotSpillFile(data);
513
+ fullOutputPath = await writeSnapshotSpillFile(data, persistentArtifactStore);
505
514
  } catch (error) {
506
515
  spillErrorText = error instanceof Error ? error.message : String(error);
507
516
  }