pi-vision-handoff 0.8.1 → 0.8.2
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 +9 -5
- package/src/describer.ts +36 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-vision-handoff",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
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",
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"README.md"
|
|
32
32
|
],
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@earendil-works/pi-ai": "0.80.
|
|
35
|
-
"@earendil-works/pi-coding-agent": "0.80.
|
|
36
|
-
"@earendil-works/pi-tui": "0.80.
|
|
34
|
+
"@earendil-works/pi-ai": "0.80.10",
|
|
35
|
+
"@earendil-works/pi-coding-agent": "0.80.10",
|
|
36
|
+
"@earendil-works/pi-tui": "0.80.10",
|
|
37
37
|
"@types/node": "25.9.1",
|
|
38
38
|
"@vitest/coverage-v8": "4.1.7",
|
|
39
39
|
"knip": "6.14.1",
|
|
@@ -45,7 +45,11 @@
|
|
|
45
45
|
"./vision-handoff.ts"
|
|
46
46
|
]
|
|
47
47
|
},
|
|
48
|
-
"peerDependencies": {
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"@earendil-works/pi-ai": "*",
|
|
50
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
51
|
+
"@earendil-works/pi-tui": "*"
|
|
52
|
+
},
|
|
49
53
|
"scripts": {
|
|
50
54
|
"test": "vitest run",
|
|
51
55
|
"test:watch": "vitest",
|
package/src/describer.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The vision describer
|
|
3
|
-
* `completeSimple()`
|
|
2
|
+
* The vision describer calls a vision-capable model through its registered
|
|
3
|
+
* provider stream, falling back to pi-ai's `completeSimple()` for built-ins.
|
|
4
4
|
*
|
|
5
5
|
* `completeSimple` (not `complete`) is the path that translates the `reasoning`
|
|
6
6
|
* ThinkingLevel into each provider's `reasoningEffort`/budget. `complete()` →
|
|
@@ -26,7 +26,17 @@
|
|
|
26
26
|
* abort listener.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
import type {
|
|
29
|
+
import type {
|
|
30
|
+
Api,
|
|
31
|
+
AssistantMessage,
|
|
32
|
+
Context,
|
|
33
|
+
ImageContent,
|
|
34
|
+
Message,
|
|
35
|
+
Model,
|
|
36
|
+
SimpleStreamOptions,
|
|
37
|
+
TextContent,
|
|
38
|
+
ThinkingLevel,
|
|
39
|
+
} from "@earendil-works/pi-ai";
|
|
30
40
|
import { completeSimple } from "@earendil-works/pi-ai/compat";
|
|
31
41
|
import type { ModelRegistry } from "@earendil-works/pi-coding-agent";
|
|
32
42
|
import {
|
|
@@ -117,6 +127,25 @@ function configSnapshot(cfg: VisionHandoffConfig): {
|
|
|
117
127
|
return { maxTokens: cfg.maxTokens, thinking: cfg.thinking, thinkingLevel: cfg.thinkingLevel };
|
|
118
128
|
}
|
|
119
129
|
|
|
130
|
+
/** Complete through the provider registered in Pi's model registry when one
|
|
131
|
+
* supplies a custom stream. The post-0.80 ModelRuntime keeps extension streams
|
|
132
|
+
* out of pi-ai's deprecated global compatibility registry, so calling
|
|
133
|
+
* completeSimple() directly cannot resolve custom API ids such as `makora`.
|
|
134
|
+
* The optional access preserves compatibility with older ModelRegistry versions,
|
|
135
|
+
* which registered custom streams globally and do not expose the config getter. */
|
|
136
|
+
export async function completeVisionModel(
|
|
137
|
+
model: Model<Api>,
|
|
138
|
+
modelRegistry: ModelRegistry,
|
|
139
|
+
context: Context,
|
|
140
|
+
options: SimpleStreamOptions,
|
|
141
|
+
): Promise<AssistantMessage> {
|
|
142
|
+
const provider = modelRegistry.getRegisteredProviderConfig?.(model.provider);
|
|
143
|
+
if (provider?.streamSimple && provider.api === model.api) {
|
|
144
|
+
return provider.streamSimple(model, context, options).result();
|
|
145
|
+
}
|
|
146
|
+
return completeSimple(model, context, options);
|
|
147
|
+
}
|
|
148
|
+
|
|
120
149
|
/** Dependencies the describer can't own itself (held by the engine). */
|
|
121
150
|
export interface DescriberDeps {
|
|
122
151
|
/** Report a usage+energy record for one real describer call (cache hits emit none). */
|
|
@@ -189,8 +218,9 @@ export async function runBatch(
|
|
|
189
218
|
const describeCtx: DescribeContext = { energyReader: undefined };
|
|
190
219
|
try {
|
|
191
220
|
const response = await describeAls.run(describeCtx, async () =>
|
|
192
|
-
|
|
221
|
+
completeVisionModel(
|
|
193
222
|
visionModel,
|
|
223
|
+
modelRegistry,
|
|
194
224
|
{ systemPrompt, messages: [userMessage] },
|
|
195
225
|
{ apiKey: auth.apiKey, headers: auth.headers, signal: controller.signal, maxTokens, reasoning },
|
|
196
226
|
),
|
|
@@ -360,8 +390,9 @@ export async function describeSingle(
|
|
|
360
390
|
const describeCtx: DescribeContext = { energyReader: undefined };
|
|
361
391
|
try {
|
|
362
392
|
const response = await describeAls.run(describeCtx, async () =>
|
|
363
|
-
|
|
393
|
+
completeVisionModel(
|
|
364
394
|
visionModel,
|
|
395
|
+
modelRegistry,
|
|
365
396
|
{ systemPrompt, messages: [userMessage] },
|
|
366
397
|
{ apiKey: auth.apiKey, headers: auth.headers, signal: controller.signal, maxTokens, reasoning },
|
|
367
398
|
),
|