pi-vision-handoff 0.6.1 → 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.
- package/package.json +1 -1
- package/vision-handoff.ts +18 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-vision-handoff",
|
|
3
|
-
"version": "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
|
@@ -349,15 +349,17 @@ export default function (pi: ExtensionAPI) {
|
|
|
349
349
|
// `tool_result` as its I/O completes (poll phase), and the loader's
|
|
350
350
|
// `setImmediate` dispatch defers to the check phase AFTER the whole poll
|
|
351
351
|
// iteration, so reads completing together land in ONE batch and all resolve
|
|
352
|
-
// together.
|
|
353
|
-
// `content`, so by the time the agent's next turn starts the tool results
|
|
354
|
-
// already carry text — the agent never sees raw image blocks it can't
|
|
355
|
-
// process.
|
|
352
|
+
// together.
|
|
356
353
|
//
|
|
357
|
-
//
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
//
|
|
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.
|
|
361
363
|
pi.on("tool_result", async (event, ctx) => {
|
|
362
364
|
if (!isConfigured(config)) return;
|
|
363
365
|
if (event.toolName !== "read") return;
|
|
@@ -385,19 +387,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
385
387
|
// loader's `setImmediate` dispatch defers to the check phase, AFTER the
|
|
386
388
|
// whole poll iteration, so reads completing together (the common case for
|
|
387
389
|
// cached local files) land in ONE batch — ONE vision call for the whole
|
|
388
|
-
// read set, not N.
|
|
389
|
-
//
|
|
390
|
-
//
|
|
391
|
-
// waiting for tool results), so the batch is COMPLETE before `context`
|
|
392
|
-
// fires, making `context` a non-blocking cache hit instead of a cold miss
|
|
393
|
-
// on the critical path.
|
|
394
|
-
//
|
|
395
|
-
// We do NOT mutate the result content here for the image blocks: returning
|
|
396
|
-
// undefined keeps the image block in storage so kitty renders it inline
|
|
397
|
-
// and `/resume` retains it. The actual image→text swap happens in the
|
|
398
|
-
// `context` hook (on the cloned LLM-bound payload only), by which point
|
|
399
|
-
// these are cache hits. We DO strip pi's misleading non-vision note (below)
|
|
400
|
-
// since the handoff will replace the image with a description.
|
|
390
|
+
// read set, not N. Awaiting here runs the describer during the tool-result
|
|
391
|
+
// phase (free time), so the batch is COMPLETE before `context` fires,
|
|
392
|
+
// making `context` a non-blocking cache hit instead of a cold miss.
|
|
401
393
|
const descs = await Promise.all(imgs.map((img) => loader.loadDescription(img)));
|
|
402
394
|
|
|
403
395
|
// On user abort, leave the result untouched — pi is tearing the turn
|
|
@@ -406,12 +398,13 @@ export default function (pi: ExtensionAPI) {
|
|
|
406
398
|
|
|
407
399
|
warnFailedImages(ctx, imgs, descs, lastDescriberError ?? "unknown error");
|
|
408
400
|
|
|
409
|
-
//
|
|
410
|
-
//
|
|
401
|
+
// Warm the cache (done above) and strip pi's
|
|
402
|
+
// `[Current model does not support images…]` note from text blocks —
|
|
403
|
+
// since the handoff replaces the image with a description in the
|
|
411
404
|
// `context` hook, that note is misleading (the agent WILL receive the
|
|
412
405
|
// image's content, as text). Keep the image block itself so kitty still
|
|
413
|
-
// renders it inline and `/resume` retains it; the `context` hook swaps
|
|
414
|
-
// image for its description in the LLM-bound clone before the next turn.
|
|
406
|
+
// renders it inline and `/resume` retains it; the `context` hook swaps
|
|
407
|
+
// the image for its description in the LLM-bound clone before the next turn.
|
|
415
408
|
let stripped = false;
|
|
416
409
|
const next = content.slice();
|
|
417
410
|
for (let i = 0; i < next.length; i++) {
|