pi-vision-handoff 0.7.0 → 0.7.1

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 +1 -1
  2. package/vision-handoff.ts +10 -68
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-vision-handoff",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
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",
package/vision-handoff.ts CHANGED
@@ -56,18 +56,6 @@ import { resizeImage } from "@earendil-works/pi-coding-agent";
56
56
  import { VisionModelSelectorComponent, type VisionModelSelectorResult } from "./src/vision-model-selector.js";
57
57
  import { PrewarmEditor } from "./src/prewarm-editor.js";
58
58
 
59
- /**
60
- * pi-fabric prepends this prefix to every nested tool-call id it generates
61
- * inside a fabric_exec run (one per pi.* invocation in full-code mode). The
62
- * LLM's own tool-call ids (e.g. openai "call_…", anthropic "toolu_…") never use
63
- * it, so a tool_result whose toolCallId starts with this prefix is a nested
64
- * fabric call whose result returns to the sandbox program — not the agent's
65
- * message context — so the context hook will never see its image blocks. We
66
- * therefore swap image→description inline in the tool_result handler for
67
- * nested calls. Mirror of pi-fabric's NESTED_TOOL_CALL_ID_PREFIX.
68
- */
69
- const FABRIC_NESTED_TOOL_CALL_ID_PREFIX = "fabric_";
70
-
71
59
  let config: VisionHandoffConfig = readConfig();
72
60
 
73
61
  /** Most recent describer failure message (auth error, network error, abort,
@@ -363,21 +351,15 @@ export default function (pi: ExtensionAPI) {
363
351
  // iteration, so reads completing together land in ONE batch and all resolve
364
352
  // together.
365
353
  //
366
- // Two shapes of caller reach this handler:
367
- // • Normal flow — the agent called `read` directly, so this tool result IS
368
- // the agent's tool result. The `context` hook will swap image→text on the
369
- // LLM-bound clone, so here we only WARM the cache (during the free
370
- // tool-result phase) and strip pi's misleading non-vision note, KEEPING
371
- // the image block so kitty renders it inline and /resume retains it.
372
- // • pi-fabric full-code mode — `pi.read` runs NESTED inside fabric_exec, so
373
- // the result returns to the sandbox program, not the agent's message
374
- // context. The `context` hook never sees these image blocks, and the
375
- // nested result is transient (never rendered by kitty or stored in
376
- // /resume). So we SWAP image→description inline here, mirroring the
377
- // `context` handler, so the description becomes pi.read's return value:
378
- // pi-fabric's normalizeResult extracts the text and the text-only agent
379
- // receives the description instead of a dropped image block. Nested
380
- // fabric calls are tagged with a `fabric_`-prefixed toolCallId.
354
+ // Both a direct agent `read` and a NESTED `pi.read` inside fabric_exec reach
355
+ // this handler and take the SAME path: WARM the cache (during the free
356
+ // tool-result phase), strip pi's misleading non-vision note, and KEEP the
357
+ // image block so kitty renders it inline and /resume retains it. The
358
+ // `context` hook swaps image→description on the LLM-bound clone before the
359
+ // next turn, so the text-only agent receives the description as text. This
360
+ // holds for fabric too: pi-fabric re-attaches the nested read's image to the
361
+ // fabric_exec tool-result content, which IS the agent's message context — so
362
+ // the `context` hook sees and swaps it, exactly like a direct read.
381
363
  pi.on("tool_result", async (event, ctx) => {
382
364
  if (!isConfigured(config)) return;
383
365
  if (event.toolName !== "read") return;
@@ -416,47 +398,7 @@ export default function (pi: ExtensionAPI) {
416
398
 
417
399
  warnFailedImages(ctx, imgs, descs, lastDescriberError ?? "unknown error");
418
400
 
419
- // pi-fabric full-code mode: swap image→description inline (see the header
420
- // comment). The descriptions are already wrapped ([Image: …]) by the
421
- // dataloader, so push them directly; strip pi's non-vision note from any
422
- // surviving text blocks since the description replaces the omitted image.
423
- if (
424
- typeof event.toolCallId === "string" &&
425
- event.toolCallId.startsWith(FABRIC_NESTED_TOOL_CALL_ID_PREFIX)
426
- ) {
427
- const descByHash = new Map<string, string>();
428
- for (let i = 0; i < imgs.length; i++) {
429
- descByHash.set(imageHash(imgs[i].mimeType, imgs[i].data), descs[i]);
430
- }
431
- const next: (TextContent | ImageContent)[] = [];
432
- for (const block of content) {
433
- const img = extractImageFromBlock(block);
434
- if (img) {
435
- next.push({
436
- type: "text",
437
- text: descByHash.get(imageHash(img.mimeType, img.data)) ?? UNAVAILABLE,
438
- });
439
- continue;
440
- }
441
- if (
442
- block &&
443
- typeof block === "object" &&
444
- (block as { type: string }).type === "text" &&
445
- typeof (block as { text: string }).text === "string" &&
446
- (block as { text: string }).text.includes(NON_VISION_IMAGE_NOTE)
447
- ) {
448
- next.push({
449
- type: "text",
450
- text: stripNonVisionImageNote((block as { text: string }).text),
451
- });
452
- } else {
453
- next.push(block as TextContent | ImageContent);
454
- }
455
- }
456
- return { content: next };
457
- }
458
-
459
- // Normal flow: warm the cache (done above) and strip pi's
401
+ // Warm the cache (done above) and strip pi's
460
402
  // `[Current model does not support images…]` note from text blocks —
461
403
  // since the handoff replaces the image with a description in the
462
404
  // `context` hook, that note is misleading (the agent WILL receive the