pi-vision-handoff 0.10.8 → 0.10.10

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.
Files changed (2) hide show
  1. package/package.json +4 -4
  2. package/vision-handoff.ts +11 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-vision-handoff",
3
- "version": "0.10.8",
3
+ "version": "0.10.10",
4
4
  "description": "Give text-only pi models vision — describe images with a vision model you pick via an interactive picker, then hand off the text description to non-vision models",
5
5
  "type": "module",
6
6
  "author": "Tom X Nguyen",
@@ -39,9 +39,9 @@
39
39
  "lint:dead": "knip --no-gitignore"
40
40
  },
41
41
  "devDependencies": {
42
- "@earendil-works/pi-ai": "1.0.0",
43
- "@earendil-works/pi-coding-agent": "1.0.0",
44
- "@earendil-works/pi-tui": "1.0.0",
42
+ "@earendil-works/pi-ai": "1.2.0",
43
+ "@earendil-works/pi-coding-agent": "1.2.0",
44
+ "@earendil-works/pi-tui": "1.2.0",
45
45
  "@types/node": "25.9.1",
46
46
  "@vitest/coverage-v8": "4.1.7",
47
47
  "knip": "6.14.1",
package/vision-handoff.ts CHANGED
@@ -431,7 +431,13 @@ export default function (pi: ExtensionAPI) {
431
431
  });
432
432
 
433
433
  pi.on("before_agent_start", async (event, ctx) => {
434
- cancelAsyncClipboardHandoff();
434
+ // Since pi 1.2.0 this also fires for custom-message runs (continuations,
435
+ // our own async handoff). They carry no prompt or images, so they only get
436
+ // the per-run setup below and must not cancel a pending handoff or replace
437
+ // the user's turn prompt.
438
+ const userTurn =
439
+ event.messageType === "custom" ? undefined : { prompt: event.prompt || "", images: event.images ?? [] };
440
+ if (userTurn) cancelAsyncClipboardHandoff();
435
441
  if (!isConfigured(config)) return;
436
442
  if (!isHandoffTarget(ctx.model, config)) return;
437
443
 
@@ -467,8 +473,9 @@ export default function (pi: ExtensionAPI) {
467
473
 
468
474
  // Capture this turn's user prompt so every image in the turn — attached or
469
475
  // read via the read tool — is described in the same request context.
470
- loader.setPendingTurnPrompt(event.prompt || "");
476
+ if (userTurn) loader.setPendingTurnPrompt(userTurn.prompt);
471
477
  loader.bindTurnContext(ctx);
478
+ if (!userTurn) return awareSystemPrompt !== undefined ? { systemPrompt: awareSystemPrompt } : undefined;
472
479
 
473
480
  if (!isAnyVisionModelResolvable(ctx.modelRegistry, config)) {
474
481
  notifyUnresolvedVisionModel(ctx, config.visionModel!);
@@ -496,7 +503,7 @@ export default function (pi: ExtensionAPI) {
496
503
  // memoized, so all images in this frame (attached + clipboard-path)
497
504
  // coalesce into ONE batch dispatched via `setImmediate` after the
498
505
  // microtask cascade settles.
499
- for (const image of event.images ?? []) {
506
+ for (const image of userTurn.images) {
500
507
  if (!image || image.type !== "image" || !image.data) continue;
501
508
  loader.loadDescription({ data: image.data, mimeType: image.mimeType || "image/png" }).catch(() => {});
502
509
  }
@@ -514,7 +521,7 @@ export default function (pi: ExtensionAPI) {
514
521
  // describes an image the agent will see). A file that can't be read, isn't
515
522
  // a supported image, or fails to resize is skipped (the agent's `read`
516
523
  // will still describe it via `tool_result` if it emits an image block).
517
- const clipboardPaths = findPastedImagePaths(event.prompt || "");
524
+ const clipboardPaths = findPastedImagePaths(userTurn.prompt);
518
525
  const resizeImage = await loadResizeImage();
519
526
  const preparedClipboardImages = clipboardPaths.map(
520
527
  async (path): Promise<PreparedClipboardImage | null> => {