pi-banana 2.1.4 → 2.3.0
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/extensions/index.ts +75 -18
- package/package.json +1 -1
package/extensions/index.ts
CHANGED
|
@@ -9,9 +9,13 @@
|
|
|
9
9
|
* pi-coding-agent renders them inline (Kitty / iTerm2). Also writes the file
|
|
10
10
|
* to disk so the agent and the user always have a path to refer back to.
|
|
11
11
|
*
|
|
12
|
-
* Auth
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* Auth (checked in this order — first match wins):
|
|
13
|
+
* 1. pi modelRegistry → auth.json / env vars / models.json
|
|
14
|
+
* (set via /login → Google, or GEMINI_API_KEY env var)
|
|
15
|
+
* 2. Vertex AI ADC — gcloud auth application-default login,
|
|
16
|
+
* GOOGLE_APPLICATION_CREDENTIALS, or GOOGLE_CLOUD_PROJECT
|
|
17
|
+
* 3. GOOGLE_API_KEY env var (AIza… or AQ.…) — pi-banana backward compat
|
|
18
|
+
* Vertex AI Express keys (AQ.…) automatically switch to Vertex.
|
|
15
19
|
*/
|
|
16
20
|
|
|
17
21
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
@@ -25,6 +29,7 @@ import {
|
|
|
25
29
|
} from "@earendil-works/pi-tui";
|
|
26
30
|
import { GoogleGenAI } from "@google/genai";
|
|
27
31
|
import { existsSync } from "node:fs";
|
|
32
|
+
import { homedir } from "node:os";
|
|
28
33
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
29
34
|
import { extname, isAbsolute, resolve } from "node:path";
|
|
30
35
|
import { Type } from "typebox";
|
|
@@ -76,19 +81,71 @@ const SUPPORTED_INPUT_MIME = new Set([
|
|
|
76
81
|
|
|
77
82
|
// ─── Helpers ───────────────────────────────────────────────────────────────
|
|
78
83
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
// Well-known path for gcloud Application Default Credentials.
|
|
85
|
+
const ADC_CREDENTIALS_PATH = resolve(
|
|
86
|
+
homedir(),
|
|
87
|
+
".config/gcloud/application_default_credentials.json",
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Check whether Vertex AI Application Default Credentials are available.
|
|
92
|
+
* Returns true when any of these are configured:
|
|
93
|
+
* - GOOGLE_APPLICATION_CREDENTIALS points to an existing file
|
|
94
|
+
* - gcloud ADC file exists (~/.config/gcloud/application_default_credentials.json)
|
|
95
|
+
* - GOOGLE_CLOUD_PROJECT is set (implies GKE / Cloud Run / Compute Engine default SA)
|
|
96
|
+
*/
|
|
97
|
+
function hasVertexADC(): boolean {
|
|
98
|
+
const gac = process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
99
|
+
if (gac && existsSync(gac)) return true;
|
|
100
|
+
if (existsSync(ADC_CREDENTIALS_PATH)) return true;
|
|
101
|
+
if (process.env.GOOGLE_CLOUD_PROJECT) return true;
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function buildClient(
|
|
106
|
+
modelRegistry: ExtensionAPI["modelRegistry"] | undefined,
|
|
107
|
+
): Promise<GoogleGenAI> {
|
|
108
|
+
// 1. Pi's model registry — the pi-native auth chain
|
|
109
|
+
// (auth.json → env vars → models.json fallback)
|
|
110
|
+
if (modelRegistry) {
|
|
111
|
+
try {
|
|
112
|
+
const apiKey = await modelRegistry.getApiKeyForProvider("google");
|
|
113
|
+
if (apiKey) {
|
|
114
|
+
return new GoogleGenAI({
|
|
115
|
+
apiKey,
|
|
116
|
+
...(apiKey.startsWith("AQ.") ? { vertexai: true } : {}),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
} catch {
|
|
120
|
+
// ignore — fall through
|
|
121
|
+
}
|
|
86
122
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
123
|
+
|
|
124
|
+
// 2. Vertex AI ADC (no API key needed — SDK picks up ADC automatically)
|
|
125
|
+
if (hasVertexADC()) {
|
|
126
|
+
return new GoogleGenAI({ vertexai: true });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// 3. GOOGLE_API_KEY env var — backward compat for pi-banana users
|
|
130
|
+
// (pi's standard GEMINI_API_KEY is already covered by modelRegistry above)
|
|
131
|
+
if (process.env.GOOGLE_API_KEY) {
|
|
132
|
+
const key = process.env.GOOGLE_API_KEY;
|
|
133
|
+
return new GoogleGenAI({
|
|
134
|
+
apiKey: key,
|
|
135
|
+
...(key.startsWith("AQ.") ? { vertexai: true } : {}),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
throw new Error(
|
|
140
|
+
"No Google credentials found. pi-banana looked in this order:\n" +
|
|
141
|
+
" 1. pi model registry (auth.json → env vars → models.json)\n" +
|
|
142
|
+
" Run /login → Google, or set GEMINI_API_KEY, or configure in models.json\n" +
|
|
143
|
+
" 2. Vertex AI ADC (gcloud auth application-default login,\n" +
|
|
144
|
+
" GOOGLE_APPLICATION_CREDENTIALS, or GOOGLE_CLOUD_PROJECT)\n" +
|
|
145
|
+
" 3. GOOGLE_API_KEY env var (AIza… or AQ.…)\n\n" +
|
|
146
|
+
"For Gemini API: get a key at https://aistudio.google.com/apikey\n" +
|
|
147
|
+
"For Vertex AI: gcloud auth application-default login",
|
|
148
|
+
);
|
|
92
149
|
}
|
|
93
150
|
|
|
94
151
|
function slugify(text: string): string {
|
|
@@ -193,7 +250,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
193
250
|
"inline in the terminal AND saved to disk so it can be re-used. " +
|
|
194
251
|
"Pass `referenceImages` (array of paths) to iterate on existing pictures.",
|
|
195
252
|
promptSnippet:
|
|
196
|
-
"Generate or edit images with Google Nano Banana via
|
|
253
|
+
"Generate or edit images with Google Nano Banana. Requires Google credentials (via /login, GOOGLE_API_KEY / GEMINI_API_KEY, or Vertex AI ADC).",
|
|
197
254
|
promptGuidelines: [
|
|
198
255
|
"Call banana_image when the user asks to create, draw, illustrate, or edit a picture.",
|
|
199
256
|
"For tweaks like 'make the sky purple', pass the previous file path (or paths) as referenceImages to banana_image.",
|
|
@@ -269,7 +326,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
269
326
|
);
|
|
270
327
|
}
|
|
271
328
|
|
|
272
|
-
const client = buildClient();
|
|
329
|
+
const client = await buildClient(ctx.modelRegistry);
|
|
273
330
|
|
|
274
331
|
// Build content parts — text + (optional) reference image.
|
|
275
332
|
const parts: Array<{
|
|
@@ -528,7 +585,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
528
585
|
return { content: [{ type: "text", text: "Cancelled." }], details: {} };
|
|
529
586
|
}
|
|
530
587
|
|
|
531
|
-
const client = buildClient();
|
|
588
|
+
const client = await buildClient(ctx.modelRegistry);
|
|
532
589
|
const parts: Array<{
|
|
533
590
|
text?: string;
|
|
534
591
|
inlineData?: { mimeType: string; data: string };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-banana",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Generate, edit, and analyze images in pi using Google Nano Banana (image gen) and Gemini Vision (analysis). Inline terminal preview, reference-image editing, auto-save.",
|
|
5
5
|
"author": "Francesco Frapporti <effedue@gmail.com>",
|
|
6
6
|
"license": "MIT",
|