@warlock.js/ai-google 4.13.0 → 4.15.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/CHANGELOG.md +35 -0
- package/cjs/index.cjs +307 -65
- package/cjs/index.cjs.map +1 -1
- package/esm/config.type.d.mts +11 -3
- package/esm/config.type.d.mts.map +1 -1
- package/esm/gemini-image.d.mts +91 -0
- package/esm/gemini-image.d.mts.map +1 -0
- package/esm/gemini-image.mjs +231 -0
- package/esm/gemini-image.mjs.map +1 -0
- package/esm/image.d.mts +7 -4
- package/esm/image.d.mts.map +1 -1
- package/esm/image.mjs +8 -7
- package/esm/image.mjs.map +1 -1
- package/esm/index.d.mts +2 -2
- package/esm/index.mjs +2 -2
- package/esm/model.mjs +7 -25
- package/esm/model.mjs.map +1 -1
- package/esm/sdk.d.mts +16 -7
- package/esm/sdk.d.mts.map +1 -1
- package/esm/sdk.mjs +48 -7
- package/esm/sdk.mjs.map +1 -1
- package/esm/utils/apply-google-usage.mjs +30 -0
- package/esm/utils/apply-google-usage.mjs.map +1 -0
- package/esm/utils/index.mjs +1 -0
- package/llms-full.txt +50 -6
- package/llms.txt +1 -1
- package/package.json +6 -6
- package/skills/setup-google/SKILL.md +50 -6
- package/esm/known-image-models.d.mts +0 -30
- package/esm/known-image-models.d.mts.map +0 -1
- package/esm/known-image-models.mjs +0 -33
- package/esm/known-image-models.mjs.map +0 -1
package/esm/sdk.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { GoogleEmbedder } from "./embedder.mjs";
|
|
2
|
+
import { GeminiImageModel } from "./gemini-image.mjs";
|
|
2
3
|
import { GoogleImageModel } from "./image.mjs";
|
|
3
4
|
import { GoogleModel } from "./model.mjs";
|
|
4
5
|
import { GoogleGenAI } from "@google/genai";
|
|
@@ -6,6 +7,36 @@ import { approximateTokenCount } from "@warlock.js/ai";
|
|
|
6
7
|
|
|
7
8
|
//#region ../ai-google/src/sdk.ts
|
|
8
9
|
/**
|
|
10
|
+
* Pick the transport for an image model id.
|
|
11
|
+
*
|
|
12
|
+
* `ai.models.generateImages` calls `{model}:predict`, and a `gemini-`
|
|
13
|
+
* id sent there comes back `404 … is not supported for predict`
|
|
14
|
+
* (observed verbatim from Google). `generateContent` is what the SDK
|
|
15
|
+
* itself points `generateImages` users at — its deprecation notice
|
|
16
|
+
* reads "Please use the generateContent method with image models
|
|
17
|
+
* instead" — so the id has to choose the transport.
|
|
18
|
+
*
|
|
19
|
+
* Runs in this package establish where a `gemini-` id is ACCEPTED, not
|
|
20
|
+
* what it returns: on this transport such an id got as far as a quota
|
|
21
|
+
* error (HTTP 429) instead of the 404. That an image
|
|
22
|
+
* comes back end-to-end once billing is enabled is reported by the
|
|
23
|
+
* maintainer from a locally linked build, not measured here. Whether
|
|
24
|
+
* these models report token usage is still unknown.
|
|
25
|
+
*
|
|
26
|
+
* This is ROUTING, not validation — no id is refused here. An id this
|
|
27
|
+
* function does not recognize takes the `generateImages` route, the
|
|
28
|
+
* only route that existed before Gemini image support landed, so every
|
|
29
|
+
* id that reached Google before still reaches Google the same way and
|
|
30
|
+
* still fails (or succeeds) at the provider.
|
|
31
|
+
*
|
|
32
|
+
* A leading `models/` resource prefix is tolerated, matching the id
|
|
33
|
+
* shapes `inferVisionCapability` already accepts
|
|
34
|
+
* (`models/gemini-1.5-flash-001`).
|
|
35
|
+
*/
|
|
36
|
+
function usesGeminiImageTransport(name) {
|
|
37
|
+
return name.toLowerCase().replace(/^models\//, "").startsWith("gemini-");
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
9
40
|
* Google Gemini-backed implementation of `SDKAdapterContract`.
|
|
10
41
|
*
|
|
11
42
|
* **Role.** The package entry point for Gemini models via the
|
|
@@ -73,18 +104,27 @@ var GoogleSDK = class {
|
|
|
73
104
|
return new GoogleEmbedder(this.ai, config, this.provider);
|
|
74
105
|
}
|
|
75
106
|
/**
|
|
76
|
-
* Build
|
|
77
|
-
*
|
|
78
|
-
*
|
|
107
|
+
* Build an image model bound to this SDK's client for use with
|
|
108
|
+
* `ai.image({ model, prompt })`. `config.name` decides the transport
|
|
109
|
+
* (see {@link usesGeminiImageTransport}) — a `gemini-` id gets the
|
|
110
|
+
* `generateContent` implementation, everything else the Imagen
|
|
111
|
+
* `generateImages` one. No id is rejected locally either way, so an
|
|
112
|
+
* unsupported model fails at Google, not here.
|
|
113
|
+
*
|
|
114
|
+
* The two differ in what usage they can report, which is what the
|
|
115
|
+
* caller must price for: the Imagen path always returns a zero token
|
|
116
|
+
* `Usage` (Imagen reports none — price with `{ perImage }`), while the
|
|
117
|
+
* Gemini path passes through whatever `usageMetadata` Google attaches
|
|
118
|
+
* (price with `{ input, output }` when tokens come back).
|
|
79
119
|
*
|
|
80
120
|
* Pricing resolution mirrors `model()`: per-model `config.pricing`
|
|
81
121
|
* wins, otherwise the SDK-level registry entry keyed by `config.name`,
|
|
82
|
-
* otherwise `undefined`.
|
|
83
|
-
* entry typically carries `{ perImage }`.
|
|
122
|
+
* otherwise `undefined`.
|
|
84
123
|
*
|
|
85
124
|
* @example
|
|
86
|
-
* const
|
|
87
|
-
* const
|
|
125
|
+
* const imagen = google.image({ name: "imagen-4.0-generate-001" });
|
|
126
|
+
* const gemini = google.image({ name: "gemini-3.1-flash-lite-image" });
|
|
127
|
+
* const { data } = await ai.image({ model: gemini, prompt: "a red bicycle" });
|
|
88
128
|
*/
|
|
89
129
|
image(config) {
|
|
90
130
|
const resolvedPricing = config.pricing ?? this.pricing?.[config.name];
|
|
@@ -92,6 +132,7 @@ var GoogleSDK = class {
|
|
|
92
132
|
...config,
|
|
93
133
|
pricing: resolvedPricing
|
|
94
134
|
};
|
|
135
|
+
if (usesGeminiImageTransport(config.name)) return new GeminiImageModel(this.ai, resolvedConfig, this.provider);
|
|
95
136
|
return new GoogleImageModel(this.ai, resolvedConfig, this.provider);
|
|
96
137
|
}
|
|
97
138
|
};
|
package/esm/sdk.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.mjs","names":[],"sources":["../../../../../../ai-google/src/sdk.ts"],"sourcesContent":["import { GoogleGenAI } from \"@google/genai\";\nimport type {\n EmbedderContract,\n ImageModelContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n} from \"@warlock.js/ai\";\nimport { approximateTokenCount } from \"@warlock.js/ai\";\nimport type {\n GoogleEmbedderConfig,\n GoogleImageConfig,\n GoogleModelConfig,\n GoogleSDKConfig,\n} from \"./config.type\";\nimport { GoogleEmbedder } from \"./embedder\";\nimport { GoogleImageModel } from \"./image\";\nimport { GoogleModel } from \"./model\";\n\n/**\n * Google Gemini-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for Gemini models via the\n * `@google/genai` SDK. A single `GoogleSDK` holds one live\n * `GoogleGenAI` client, shared by every `ModelContract` /\n * `EmbedderContract` it produces. Construct one SDK per\n * account/project and reuse it everywhere.\n *\n * **Responsibility.**\n * - Owns: a long-lived `GoogleGenAI` client (auth, Vertex vs Gemini\n * API) and its lifetime. Factory for `GoogleModel` /\n * `GoogleEmbedder` instances sharing that client.\n * - Does NOT own: anything per-call — those live in `GoogleModel` /\n * `GoogleEmbedder` and the agent runtime.\n *\n * Modeled as a class (see §4.2 of code-style.md — \"long-lived state\n * across many calls\"), fronted by FP usage like the other adapters.\n *\n * @example\n * const google = new GoogleSDK({ apiKey: process.env.GEMINI_API_KEY! });\n * const model = google.model({ name: \"gemini-2.5-flash\", temperature: 0.7 });\n * const embedder = google.embedder({ name: \"gemini-embedding-001\" });\n */\nexport class GoogleSDK implements SDKAdapterContract {\n private readonly ai: GoogleGenAI;\n private readonly provider: string;\n private readonly pricing?: Record<string, ModelPricing>;\n\n public constructor(config: GoogleSDKConfig) {\n const { provider, pricing, ...clientOptions } = config;\n\n this.ai = new GoogleGenAI(clientOptions);\n this.provider = provider ?? \"google\";\n this.pricing = pricing;\n }\n\n /**\n * Build a `GoogleModel` bound to this SDK's client. Each call\n * returns a fresh instance; all instances share the underlying\n * `GoogleGenAI` client. The SDK's `provider` label is forwarded.\n *\n * Pricing resolution: per-model `config.pricing` wins; otherwise the\n * SDK-level registry entry keyed by `config.name`; otherwise\n * `undefined` (no cost computed).\n */\n public model(config: GoogleModelConfig): ModelContract {\n const resolvedPricing = config.pricing ?? this.pricing?.[config.name];\n const resolvedConfig: GoogleModelConfig =\n resolvedPricing === config.pricing ? config : { ...config, pricing: resolvedPricing };\n\n return new GoogleModel(this.ai, resolvedConfig, this.provider);\n }\n\n /**\n * Rough token-count estimate. Uses the character-heuristic\n * (`approximateTokenCount`) from the core package — Gemini's\n * `countTokens` is a network round-trip; `count()` is intentionally\n * offline. Good for budgeting/quota guards, not billing.\n */\n public async count(text: string, _model?: string): Promise<number> {\n return approximateTokenCount(text);\n }\n\n /**\n * Build a `GoogleEmbedder` bound to this SDK's client.\n *\n * @example\n * const embedder = google.embedder({ name: \"gemini-embedding-001\" });\n * const { vector } = await embedder.embed(\"Hello world\");\n */\n public embedder(config: GoogleEmbedderConfig): EmbedderContract {\n return new GoogleEmbedder(this.ai, config, this.provider);\n }\n\n /**\n * Build
|
|
1
|
+
{"version":3,"file":"sdk.mjs","names":[],"sources":["../../../../../../ai-google/src/sdk.ts"],"sourcesContent":["import { GoogleGenAI } from \"@google/genai\";\nimport type {\n EmbedderContract,\n ImageModelContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n} from \"@warlock.js/ai\";\nimport { approximateTokenCount } from \"@warlock.js/ai\";\nimport type {\n GoogleEmbedderConfig,\n GoogleImageConfig,\n GoogleModelConfig,\n GoogleSDKConfig,\n} from \"./config.type\";\nimport { GoogleEmbedder } from \"./embedder\";\nimport { GeminiImageModel } from \"./gemini-image\";\nimport { GoogleImageModel } from \"./image\";\nimport { GoogleModel } from \"./model\";\n\n/**\n * Pick the transport for an image model id.\n *\n * `ai.models.generateImages` calls `{model}:predict`, and a `gemini-`\n * id sent there comes back `404 … is not supported for predict`\n * (observed verbatim from Google). `generateContent` is what the SDK\n * itself points `generateImages` users at — its deprecation notice\n * reads \"Please use the generateContent method with image models\n * instead\" — so the id has to choose the transport.\n *\n * Runs in this package establish where a `gemini-` id is ACCEPTED, not\n * what it returns: on this transport such an id got as far as a quota\n * error (HTTP 429) instead of the 404. That an image\n * comes back end-to-end once billing is enabled is reported by the\n * maintainer from a locally linked build, not measured here. Whether\n * these models report token usage is still unknown.\n *\n * This is ROUTING, not validation — no id is refused here. An id this\n * function does not recognize takes the `generateImages` route, the\n * only route that existed before Gemini image support landed, so every\n * id that reached Google before still reaches Google the same way and\n * still fails (or succeeds) at the provider.\n *\n * A leading `models/` resource prefix is tolerated, matching the id\n * shapes `inferVisionCapability` already accepts\n * (`models/gemini-1.5-flash-001`).\n */\nfunction usesGeminiImageTransport(name: string): boolean {\n return name.toLowerCase().replace(/^models\\//, \"\").startsWith(\"gemini-\");\n}\n\n/**\n * Google Gemini-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for Gemini models via the\n * `@google/genai` SDK. A single `GoogleSDK` holds one live\n * `GoogleGenAI` client, shared by every `ModelContract` /\n * `EmbedderContract` it produces. Construct one SDK per\n * account/project and reuse it everywhere.\n *\n * **Responsibility.**\n * - Owns: a long-lived `GoogleGenAI` client (auth, Vertex vs Gemini\n * API) and its lifetime. Factory for `GoogleModel` /\n * `GoogleEmbedder` instances sharing that client.\n * - Does NOT own: anything per-call — those live in `GoogleModel` /\n * `GoogleEmbedder` and the agent runtime.\n *\n * Modeled as a class (see §4.2 of code-style.md — \"long-lived state\n * across many calls\"), fronted by FP usage like the other adapters.\n *\n * @example\n * const google = new GoogleSDK({ apiKey: process.env.GEMINI_API_KEY! });\n * const model = google.model({ name: \"gemini-2.5-flash\", temperature: 0.7 });\n * const embedder = google.embedder({ name: \"gemini-embedding-001\" });\n */\nexport class GoogleSDK implements SDKAdapterContract {\n private readonly ai: GoogleGenAI;\n private readonly provider: string;\n private readonly pricing?: Record<string, ModelPricing>;\n\n public constructor(config: GoogleSDKConfig) {\n const { provider, pricing, ...clientOptions } = config;\n\n this.ai = new GoogleGenAI(clientOptions);\n this.provider = provider ?? \"google\";\n this.pricing = pricing;\n }\n\n /**\n * Build a `GoogleModel` bound to this SDK's client. Each call\n * returns a fresh instance; all instances share the underlying\n * `GoogleGenAI` client. The SDK's `provider` label is forwarded.\n *\n * Pricing resolution: per-model `config.pricing` wins; otherwise the\n * SDK-level registry entry keyed by `config.name`; otherwise\n * `undefined` (no cost computed).\n */\n public model(config: GoogleModelConfig): ModelContract {\n const resolvedPricing = config.pricing ?? this.pricing?.[config.name];\n const resolvedConfig: GoogleModelConfig =\n resolvedPricing === config.pricing ? config : { ...config, pricing: resolvedPricing };\n\n return new GoogleModel(this.ai, resolvedConfig, this.provider);\n }\n\n /**\n * Rough token-count estimate. Uses the character-heuristic\n * (`approximateTokenCount`) from the core package — Gemini's\n * `countTokens` is a network round-trip; `count()` is intentionally\n * offline. Good for budgeting/quota guards, not billing.\n */\n public async count(text: string, _model?: string): Promise<number> {\n return approximateTokenCount(text);\n }\n\n /**\n * Build a `GoogleEmbedder` bound to this SDK's client.\n *\n * @example\n * const embedder = google.embedder({ name: \"gemini-embedding-001\" });\n * const { vector } = await embedder.embed(\"Hello world\");\n */\n public embedder(config: GoogleEmbedderConfig): EmbedderContract {\n return new GoogleEmbedder(this.ai, config, this.provider);\n }\n\n /**\n * Build an image model bound to this SDK's client for use with\n * `ai.image({ model, prompt })`. `config.name` decides the transport\n * (see {@link usesGeminiImageTransport}) — a `gemini-` id gets the\n * `generateContent` implementation, everything else the Imagen\n * `generateImages` one. No id is rejected locally either way, so an\n * unsupported model fails at Google, not here.\n *\n * The two differ in what usage they can report, which is what the\n * caller must price for: the Imagen path always returns a zero token\n * `Usage` (Imagen reports none — price with `{ perImage }`), while the\n * Gemini path passes through whatever `usageMetadata` Google attaches\n * (price with `{ input, output }` when tokens come back).\n *\n * Pricing resolution mirrors `model()`: per-model `config.pricing`\n * wins, otherwise the SDK-level registry entry keyed by `config.name`,\n * otherwise `undefined`.\n *\n * @example\n * const imagen = google.image({ name: \"imagen-4.0-generate-001\" });\n * const gemini = google.image({ name: \"gemini-3.1-flash-lite-image\" });\n * const { data } = await ai.image({ model: gemini, prompt: \"a red bicycle\" });\n */\n public image(config: GoogleImageConfig): ImageModelContract {\n const resolvedPricing = config.pricing ?? this.pricing?.[config.name];\n const resolvedConfig: GoogleImageConfig =\n resolvedPricing === config.pricing ? config : { ...config, pricing: resolvedPricing };\n\n if (usesGeminiImageTransport(config.name)) {\n return new GeminiImageModel(this.ai, resolvedConfig, this.provider);\n }\n\n return new GoogleImageModel(this.ai, resolvedConfig, this.provider);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,SAAS,yBAAyB,MAAuB;CACvD,OAAO,KAAK,YAAY,CAAC,CAAC,QAAQ,aAAa,EAAE,CAAC,CAAC,WAAW,SAAS;AACzE;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,IAAa,YAAb,MAAqD;CAKnD,AAAO,YAAY,QAAyB;EAC1C,MAAM,EAAE,UAAU,SAAS,GAAG,kBAAkB;EAEhD,KAAK,KAAK,IAAI,YAAY,aAAa;EACvC,KAAK,WAAW,YAAY;EAC5B,KAAK,UAAU;CACjB;;;;;;;;;;CAWA,AAAO,MAAM,QAA0C;EACrD,MAAM,kBAAkB,OAAO,WAAW,KAAK,UAAU,OAAO;EAChE,MAAM,iBACJ,oBAAoB,OAAO,UAAU,SAAS;GAAE,GAAG;GAAQ,SAAS;EAAgB;EAEtF,OAAO,IAAI,YAAY,KAAK,IAAI,gBAAgB,KAAK,QAAQ;CAC/D;;;;;;;CAQA,MAAa,MAAM,MAAc,QAAkC;EACjE,OAAO,sBAAsB,IAAI;CACnC;;;;;;;;CASA,AAAO,SAAS,QAAgD;EAC9D,OAAO,IAAI,eAAe,KAAK,IAAI,QAAQ,KAAK,QAAQ;CAC1D;;;;;;;;;;;;;;;;;;;;;;;;CAyBA,AAAO,MAAM,QAA+C;EAC1D,MAAM,kBAAkB,OAAO,WAAW,KAAK,UAAU,OAAO;EAChE,MAAM,iBACJ,oBAAoB,OAAO,UAAU,SAAS;GAAE,GAAG;GAAQ,SAAS;EAAgB;EAEtF,IAAI,yBAAyB,OAAO,IAAI,GACtC,OAAO,IAAI,iBAAiB,KAAK,IAAI,gBAAgB,KAAK,QAAQ;EAGpE,OAAO,IAAI,iBAAiB,KAAK,IAAI,gBAAgB,KAAK,QAAQ;CACpE;AACF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region ../ai-google/src/utils/apply-google-usage.ts
|
|
2
|
+
/**
|
|
3
|
+
* Fold a Gemini `usageMetadata` block into a running neutral `Usage`
|
|
4
|
+
* accumulator. Shared by every `generateContent`-backed surface — the
|
|
5
|
+
* chat model's `complete()`, its streaming loop (where the final chunk
|
|
6
|
+
* carries cumulative totals), and the Gemini image model — so one
|
|
7
|
+
* mapping decides what a Gemini token report means package-wide.
|
|
8
|
+
*
|
|
9
|
+
* Cache-read hits (`cachedContentTokenCount`, implicit or explicit
|
|
10
|
+
* context caching) surface as `cachedTokens`; the thinking-phase tokens
|
|
11
|
+
* of a reasoning model (`thoughtsTokenCount`) surface as
|
|
12
|
+
* `reasoningTokens`. Both are emitted only when reported `> 0` so an
|
|
13
|
+
* absent channel leaves the field undefined rather than a false zero.
|
|
14
|
+
*
|
|
15
|
+
* `total` falls back to `input + output` when Google omits
|
|
16
|
+
* `totalTokenCount`.
|
|
17
|
+
*/
|
|
18
|
+
function applyGoogleUsage(usage, raw) {
|
|
19
|
+
usage.input = raw.promptTokenCount ?? usage.input;
|
|
20
|
+
usage.output = raw.candidatesTokenCount ?? usage.output;
|
|
21
|
+
usage.total = raw.totalTokenCount ?? usage.input + usage.output;
|
|
22
|
+
const cached = raw.cachedContentTokenCount;
|
|
23
|
+
if (cached && cached > 0) usage.cachedTokens = cached;
|
|
24
|
+
const reasoning = raw.thoughtsTokenCount;
|
|
25
|
+
if (reasoning && reasoning > 0) usage.reasoningTokens = reasoning;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
export { applyGoogleUsage };
|
|
30
|
+
//# sourceMappingURL=apply-google-usage.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-google-usage.mjs","names":[],"sources":["../../../../../../../ai-google/src/utils/apply-google-usage.ts"],"sourcesContent":["import type { Usage } from \"@warlock.js/ai\";\nimport type { GenerateContentResponse } from \"@google/genai\";\n\n/** Gemini's per-response token accounting block, as the SDK types it. */\nexport type GoogleUsageMetadata = NonNullable<GenerateContentResponse[\"usageMetadata\"]>;\n\n/**\n * Fold a Gemini `usageMetadata` block into a running neutral `Usage`\n * accumulator. Shared by every `generateContent`-backed surface — the\n * chat model's `complete()`, its streaming loop (where the final chunk\n * carries cumulative totals), and the Gemini image model — so one\n * mapping decides what a Gemini token report means package-wide.\n *\n * Cache-read hits (`cachedContentTokenCount`, implicit or explicit\n * context caching) surface as `cachedTokens`; the thinking-phase tokens\n * of a reasoning model (`thoughtsTokenCount`) surface as\n * `reasoningTokens`. Both are emitted only when reported `> 0` so an\n * absent channel leaves the field undefined rather than a false zero.\n *\n * `total` falls back to `input + output` when Google omits\n * `totalTokenCount`.\n */\nexport function applyGoogleUsage(usage: Usage, raw: GoogleUsageMetadata): void {\n usage.input = raw.promptTokenCount ?? usage.input;\n usage.output = raw.candidatesTokenCount ?? usage.output;\n usage.total = raw.totalTokenCount ?? usage.input + usage.output;\n\n const cached = raw.cachedContentTokenCount;\n\n if (cached && cached > 0) {\n usage.cachedTokens = cached;\n }\n\n const reasoning = raw.thoughtsTokenCount;\n\n if (reasoning && reasoning > 0) {\n usage.reasoningTokens = reasoning;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAsBA,SAAgB,iBAAiB,OAAc,KAAgC;CAC7E,MAAM,QAAQ,IAAI,oBAAoB,MAAM;CAC5C,MAAM,SAAS,IAAI,wBAAwB,MAAM;CACjD,MAAM,QAAQ,IAAI,mBAAmB,MAAM,QAAQ,MAAM;CAEzD,MAAM,SAAS,IAAI;CAEnB,IAAI,UAAU,SAAS,GACrB,MAAM,eAAe;CAGvB,MAAM,YAAY,IAAI;CAEtB,IAAI,aAAa,YAAY,GAC3B,MAAM,kBAAkB;AAE5B"}
|
package/esm/utils/index.mjs
CHANGED
package/llms-full.txt
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
name: setup-google
|
|
11
|
-
description: 'Wire @warlock.js/ai-google — new GoogleSDK({apiKey} | {vertexai, project, location}) for Gemini API + Vertex AI. generateContent / embedContent + thoughtSignature round-trip for thinking models, batched embeddings. .model({name, vision?, reasoning?, audio?, pdf?}) with cost-truth capabilities (PDF + audio input map to Gemini inlineData), .image({name, pricing?}) for
|
|
11
|
+
description: 'Wire @warlock.js/ai-google — new GoogleSDK({apiKey} | {vertexai, project, location}) for Gemini API + Vertex AI. generateContent / embedContent + thoughtSignature round-trip for thinking models, batched embeddings. .model({name, vision?, reasoning?, audio?, pdf?}) with cost-truth capabilities (PDF + audio input map to Gemini inlineData), .image({name, pricing?}) for image generation via ai.image — the id picks the transport: gemini-* → generateContent + responseModalities IMAGE (usage passed through; generateImages is deprecated by Google), everything else → generateImages (Imagen, per-image, zero usage) — extended thinking via options.reasoning → thinkingConfig.thinkingBudget, usage reasoningTokens (thoughtsTokenCount) / cachedTokens (cachedContentTokenCount). Triggers: `GoogleSDK`, `google.model`, `google.embedder`, `google.image`, `imagen`, `generateImages`, `gemini image`, `nano banana`, `responseModalities`, `imageConfig`, `ai.image`, `inlineData`, `pdf input`, `audio input`, `thoughtSignature`, `responseJsonSchema`, `vertexai`, `reasoning`, `thinkingConfig`, `thinkingBudget`, `thoughtsTokenCount`, `reasoningTokens`, `cachedTokens`, `promptCaching`, `cacheControl`; "use gemini", "wire Vertex AI", "gemini embeddings", "gemini thinking tool calls", "gemini 2.5 thinking budget", "gemini cached content cost", "generate images with imagen", "generate an image with gemini", "gemini image model 404 not supported for predict", "send a pdf / audio to gemini"; import `import { GoogleSDK } from "@warlock.js/ai-google"`. Skip: the ai.image verb surface — `@warlock.js/ai/generate-images/SKILL.md`; agent loop `@warlock.js/ai/run-ai-agent/SKILL.md`; provider picking `@warlock.js/ai/pick-ai-provider/SKILL.md`; embedder usage `@warlock.js/ai/embed-text/SKILL.md`; siblings `@warlock.js/ai-openai`, `@warlock.js/ai-anthropic`, `@warlock.js/ai-bedrock`, `@warlock.js/ai-ollama`; raw `@google/genai`, `@google-cloud/vertexai`, Vercel `@ai-sdk/google`.'
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# `@warlock.js/ai-google`
|
|
@@ -87,9 +87,47 @@ Gemini's multimodal input is **media-agnostic** — every binary modality maps t
|
|
|
87
87
|
|
|
88
88
|
PDF and audio reach the wire only when the model declares the matching capability (inferred for the multimodal Gemini families above) — so capability ≡ behavior.
|
|
89
89
|
|
|
90
|
-
## Image generation
|
|
90
|
+
## Image generation — two transports
|
|
91
91
|
|
|
92
|
-
`google.image({ name })` returns an `ImageModelContract`
|
|
92
|
+
`google.image({ name })` returns an `ImageModelContract` for the `ai.image()` verb. **The model id picks the transport:**
|
|
93
|
+
|
|
94
|
+
| Model id | Transport | Usage it can report |
|
|
95
|
+
| --- | --- | --- |
|
|
96
|
+
| `gemini-*` (e.g. `gemini-3.1-flash-lite-image`) | `ai.models.generateContent` with `responseModalities` including `"IMAGE"` | whatever `usageMetadata` Google attaches — price with `{ input, output }` |
|
|
97
|
+
| anything else (`imagen-*`, unknown ids) | `ai.models.generateImages` (Imagen) | none, always zero — price with `{ perImage }` |
|
|
98
|
+
|
|
99
|
+
A `gemini-` id sent to `generateImages` comes back `404 … is not supported for predict` (observed verbatim from Google) — `generateImages` routes to `{model}:predict`. `generateContent` is the SDK's own named replacement: its runtime deprecation notice for `generateImages` says *"Please use the generateContent method with image models instead"*. Routing on the id is what lets both families go through one factory. A leading `models/` resource prefix is tolerated.
|
|
100
|
+
|
|
101
|
+
This is **routing, not validation** — no id is refused locally. An id matching neither family takes the `generateImages` route (the pre-existing one) and fails at Google as a typed provider error, not with a local throw.
|
|
102
|
+
|
|
103
|
+
> ⚠ **No automated test here calls Google**, so the evidence is two-tier. **Measured in this repo:** a `gemini-*` image id that 404s on `predict` reached the model on `generateContent` and returned a **quota error (HTTP 429)** — the endpoint accepts the id. **Reported by the maintainer:** once billing was enabled on the project, an image came back end-to-end through a locally linked build. What remains unknown is **token reporting** — no `usageMetadata` from a successful image call has been seen yet.
|
|
104
|
+
|
|
105
|
+
### Gemini (`generateContent`)
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
const gemini = google.image({
|
|
109
|
+
name: "gemini-3.1-flash-lite-image",
|
|
110
|
+
pricing: { input: 0.3, output: 30 }, // token-metered
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const { data, error, usage } = await ai.image({
|
|
114
|
+
model: gemini,
|
|
115
|
+
prompt: "a red bicycle on a white background",
|
|
116
|
+
aspectRatio: "16:9", // → config.imageConfig.aspectRatio
|
|
117
|
+
options: { imageSize: "2K", personGeneration: "ALLOW_ADULT" }, // → imageConfig passthroughs
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- Requests `responseModalities: ["TEXT", "IMAGE"]` by default; pass `options.responseModalities` to replace the list verbatim. Which pairing a given model requires is not established here.
|
|
122
|
+
- Inline image parts that **do** come back (`inlineData.data` + `mimeType`) map to the **same** `GeneratedImage` shape Imagen produces — `{ type: "base64", base64, mediaType }`, defaulting to `image/png` when the part declares no mime type. Callers see one shape regardless of transport.
|
|
123
|
+
- **Token usage is passed through, not zeroed.** Any `usageMetadata` Google attaches is mapped by the same rules as `model.complete()` (`promptTokenCount` → `input`, `candidatesTokenCount` → `output`, `cachedContentTokenCount` → `cachedTokens`, `thoughtsTokenCount` → `reasoningTokens`); an absent block collapses to `{ 0, 0, 0 }`. That is the difference from Imagen, which is always zero. Whether these models in fact report tokens is unconfirmed — price with `{ input, output }` and check the first live `usage`.
|
|
124
|
+
- **A response with no image part is never a silent empty success:**
|
|
125
|
+
- `promptFeedback.blockReason`, or a safety/policy `finishReason` (`SAFETY`, `IMAGE_SAFETY`, `PROHIBITED_CONTENT`, `IMAGE_PROHIBITED_CONTENT`, `RECITATION`, `IMAGE_RECITATION`, `BLOCKLIST`, `SPII`) → `ContentFilterError` carrying the reason.
|
|
126
|
+
- text only (the model answered instead of drawing) → `ProviderError` **quoting the text** it returned.
|
|
127
|
+
- nothing usable → `ProviderError` naming the part count and finish reason (e.g. `NO_IMAGE`).
|
|
128
|
+
- `count`, `negativePrompt`, and `format` are **not** forwarded on this path — `GenerateContentConfig` / `ImageConfig` expose no equivalent (`ImageConfig.outputMimeType` is documented "not supported in Gemini API"). Fold those intentions into the prompt. Every inline image part the model does return is mapped, so a multi-image answer still comes back whole.
|
|
129
|
+
|
|
130
|
+
### Imagen (`generateImages`)
|
|
93
131
|
|
|
94
132
|
```ts
|
|
95
133
|
const imagen = google.image({ name: "imagen-4.0-generate-001", pricing: { perImage: 0.04 } });
|
|
@@ -103,9 +141,15 @@ const { data, error } = await ai.image({
|
|
|
103
141
|
});
|
|
104
142
|
```
|
|
105
143
|
|
|
106
|
-
- Imagen is **per-image-metered** (price with `{ perImage }`) and returns base64 bytes — no hosted URL,
|
|
107
|
-
- When every candidate is safety-filtered, the run surfaces a typed `ContentFilterError` on `result.error`.
|
|
108
|
-
-
|
|
144
|
+
- Imagen is **per-image-metered** (price with `{ perImage }`) and returns base64 bytes — no hosted URL, and `usage` is an honest `{ input: 0, output: 0, total: 0 }`.
|
|
145
|
+
- When every candidate is safety-filtered (`raiFilteredReason`), the run surfaces a typed `ContentFilterError` on `result.error`.
|
|
146
|
+
- ⏳ **This path is on a clock.** `@google/genai` warns at runtime: *"The generateImages method is deprecated and will be removed in the next major release (not before Jan. 1 2027). Please use the generateContent method with image models instead."* This package depends on `@google/genai` `^2.17.1`, which does emit that warning. Nothing breaks today, but new work should prefer a `gemini-*` id.
|
|
147
|
+
|
|
148
|
+
### Not implemented: the `interactions` API
|
|
149
|
+
|
|
150
|
+
`@google/genai` ≥ 2.17 adds `ai.interactions.create({ model, input, response_format: { type: "image", … } })`, whose images arrive as `interaction.output_image.data` and whose usage is a different snake_case shape (`total_input_tokens` …). It is reachable from the `^2.17.1` this package depends on, but the adapter does **not** use it: it would need its own usage mapper and error surface, and its request type already marks `response_modalities` / `response_mime_type` deprecated. If it is added later it will be an **opt-in config flag**, never id routing.
|
|
151
|
+
|
|
152
|
+
The verb surface lives in [`@warlock.js/ai/generate-images/SKILL.md`](@warlock.js/ai/generate-images/SKILL.md).
|
|
109
153
|
|
|
110
154
|
## Streaming
|
|
111
155
|
|
package/llms.txt
CHANGED
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
|
|
7
7
|
## Skills
|
|
8
8
|
|
|
9
|
-
- [setup-google](@warlock.js/ai-google/setup-google/SKILL.md): Wire @warlock.js/ai-google — new GoogleSDK({apiKey} | {vertexai, project, location}) for Gemini API + Vertex AI. generateContent / embedContent + thoughtSignature round-trip for thinking models, batched embeddings. .model({name, vision?, reasoning?, audio?, pdf?}) with cost-truth capabilities (PDF + audio input map to Gemini inlineData), .image({name, pricing?}) for
|
|
9
|
+
- [setup-google](@warlock.js/ai-google/setup-google/SKILL.md): Wire @warlock.js/ai-google — new GoogleSDK({apiKey} | {vertexai, project, location}) for Gemini API + Vertex AI. generateContent / embedContent + thoughtSignature round-trip for thinking models, batched embeddings. .model({name, vision?, reasoning?, audio?, pdf?}) with cost-truth capabilities (PDF + audio input map to Gemini inlineData), .image({name, pricing?}) for image generation via ai.image — the id picks the transport: gemini-* → generateContent + responseModalities IMAGE (usage passed through; generateImages is deprecated by Google), everything else → generateImages (Imagen, per-image, zero usage) — extended thinking via options.reasoning → thinkingConfig.thinkingBudget, usage reasoningTokens (thoughtsTokenCount) / cachedTokens (cachedContentTokenCount). Triggers: `GoogleSDK`, `google.model`, `google.embedder`, `google.image`, `imagen`, `generateImages`, `gemini image`, `nano banana`, `responseModalities`, `imageConfig`, `ai.image`, `inlineData`, `pdf input`, `audio input`, `thoughtSignature`, `responseJsonSchema`, `vertexai`, `reasoning`, `thinkingConfig`, `thinkingBudget`, `thoughtsTokenCount`, `reasoningTokens`, `cachedTokens`, `promptCaching`, `cacheControl`; "use gemini", "wire Vertex AI", "gemini embeddings", "gemini thinking tool calls", "gemini 2.5 thinking budget", "gemini cached content cost", "generate images with imagen", "generate an image with gemini", "gemini image model 404 not supported for predict", "send a pdf / audio to gemini"; import `import { GoogleSDK } from "@warlock.js/ai-google"`. Skip: the ai.image verb surface — `@warlock.js/ai/generate-images/SKILL.md`; agent loop `@warlock.js/ai/run-ai-agent/SKILL.md`; provider picking `@warlock.js/ai/pick-ai-provider/SKILL.md`; embedder usage `@warlock.js/ai/embed-text/SKILL.md`; siblings `@warlock.js/ai-openai`, `@warlock.js/ai-anthropic`, `@warlock.js/ai-bedrock`, `@warlock.js/ai-ollama`; raw `@google/genai`, `@google-cloud/vertexai`, Vercel `@ai-sdk/google`.
|
package/package.json
CHANGED
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
"type": "git",
|
|
14
14
|
"url": "https://github.com/warlockjs/ai-google"
|
|
15
15
|
},
|
|
16
|
-
"dependencies": {
|
|
17
|
-
"@google/genai": "^2.4.0",
|
|
18
|
-
"@warlock.js/logger": "4.13.0"
|
|
19
|
-
},
|
|
20
16
|
"peerDependencies": {
|
|
21
|
-
"@warlock.js/ai": "4.
|
|
17
|
+
"@warlock.js/ai": "4.15.0"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@google/genai": "^2.17.1",
|
|
21
|
+
"@warlock.js/logger": "4.15.0"
|
|
22
22
|
},
|
|
23
|
-
"version": "4.
|
|
23
|
+
"version": "4.15.0",
|
|
24
24
|
"main": "./cjs/index.cjs",
|
|
25
25
|
"module": "./esm/index.mjs",
|
|
26
26
|
"types": "./esm/index.d.mts",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: setup-google
|
|
3
|
-
description: 'Wire @warlock.js/ai-google — new GoogleSDK({apiKey} | {vertexai, project, location}) for Gemini API + Vertex AI. generateContent / embedContent + thoughtSignature round-trip for thinking models, batched embeddings. .model({name, vision?, reasoning?, audio?, pdf?}) with cost-truth capabilities (PDF + audio input map to Gemini inlineData), .image({name, pricing?}) for
|
|
3
|
+
description: 'Wire @warlock.js/ai-google — new GoogleSDK({apiKey} | {vertexai, project, location}) for Gemini API + Vertex AI. generateContent / embedContent + thoughtSignature round-trip for thinking models, batched embeddings. .model({name, vision?, reasoning?, audio?, pdf?}) with cost-truth capabilities (PDF + audio input map to Gemini inlineData), .image({name, pricing?}) for image generation via ai.image — the id picks the transport: gemini-* → generateContent + responseModalities IMAGE (usage passed through; generateImages is deprecated by Google), everything else → generateImages (Imagen, per-image, zero usage) — extended thinking via options.reasoning → thinkingConfig.thinkingBudget, usage reasoningTokens (thoughtsTokenCount) / cachedTokens (cachedContentTokenCount). Triggers: `GoogleSDK`, `google.model`, `google.embedder`, `google.image`, `imagen`, `generateImages`, `gemini image`, `nano banana`, `responseModalities`, `imageConfig`, `ai.image`, `inlineData`, `pdf input`, `audio input`, `thoughtSignature`, `responseJsonSchema`, `vertexai`, `reasoning`, `thinkingConfig`, `thinkingBudget`, `thoughtsTokenCount`, `reasoningTokens`, `cachedTokens`, `promptCaching`, `cacheControl`; "use gemini", "wire Vertex AI", "gemini embeddings", "gemini thinking tool calls", "gemini 2.5 thinking budget", "gemini cached content cost", "generate images with imagen", "generate an image with gemini", "gemini image model 404 not supported for predict", "send a pdf / audio to gemini"; import `import { GoogleSDK } from "@warlock.js/ai-google"`. Skip: the ai.image verb surface — `@warlock.js/ai/generate-images/SKILL.md`; agent loop `@warlock.js/ai/run-ai-agent/SKILL.md`; provider picking `@warlock.js/ai/pick-ai-provider/SKILL.md`; embedder usage `@warlock.js/ai/embed-text/SKILL.md`; siblings `@warlock.js/ai-openai`, `@warlock.js/ai-anthropic`, `@warlock.js/ai-bedrock`, `@warlock.js/ai-ollama`; raw `@google/genai`, `@google-cloud/vertexai`, Vercel `@ai-sdk/google`.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# `@warlock.js/ai-google`
|
|
@@ -79,9 +79,47 @@ Gemini's multimodal input is **media-agnostic** — every binary modality maps t
|
|
|
79
79
|
|
|
80
80
|
PDF and audio reach the wire only when the model declares the matching capability (inferred for the multimodal Gemini families above) — so capability ≡ behavior.
|
|
81
81
|
|
|
82
|
-
## Image generation
|
|
82
|
+
## Image generation — two transports
|
|
83
83
|
|
|
84
|
-
`google.image({ name })` returns an `ImageModelContract`
|
|
84
|
+
`google.image({ name })` returns an `ImageModelContract` for the `ai.image()` verb. **The model id picks the transport:**
|
|
85
|
+
|
|
86
|
+
| Model id | Transport | Usage it can report |
|
|
87
|
+
| --- | --- | --- |
|
|
88
|
+
| `gemini-*` (e.g. `gemini-3.1-flash-lite-image`) | `ai.models.generateContent` with `responseModalities` including `"IMAGE"` | whatever `usageMetadata` Google attaches — price with `{ input, output }` |
|
|
89
|
+
| anything else (`imagen-*`, unknown ids) | `ai.models.generateImages` (Imagen) | none, always zero — price with `{ perImage }` |
|
|
90
|
+
|
|
91
|
+
A `gemini-` id sent to `generateImages` comes back `404 … is not supported for predict` (observed verbatim from Google) — `generateImages` routes to `{model}:predict`. `generateContent` is the SDK's own named replacement: its runtime deprecation notice for `generateImages` says *"Please use the generateContent method with image models instead"*. Routing on the id is what lets both families go through one factory. A leading `models/` resource prefix is tolerated.
|
|
92
|
+
|
|
93
|
+
This is **routing, not validation** — no id is refused locally. An id matching neither family takes the `generateImages` route (the pre-existing one) and fails at Google as a typed provider error, not with a local throw.
|
|
94
|
+
|
|
95
|
+
> ⚠ **No automated test here calls Google**, so the evidence is two-tier. **Measured in this repo:** a `gemini-*` image id that 404s on `predict` reached the model on `generateContent` and returned a **quota error (HTTP 429)** — the endpoint accepts the id. **Reported by the maintainer:** once billing was enabled on the project, an image came back end-to-end through a locally linked build. What remains unknown is **token reporting** — no `usageMetadata` from a successful image call has been seen yet.
|
|
96
|
+
|
|
97
|
+
### Gemini (`generateContent`)
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
const gemini = google.image({
|
|
101
|
+
name: "gemini-3.1-flash-lite-image",
|
|
102
|
+
pricing: { input: 0.3, output: 30 }, // token-metered
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const { data, error, usage } = await ai.image({
|
|
106
|
+
model: gemini,
|
|
107
|
+
prompt: "a red bicycle on a white background",
|
|
108
|
+
aspectRatio: "16:9", // → config.imageConfig.aspectRatio
|
|
109
|
+
options: { imageSize: "2K", personGeneration: "ALLOW_ADULT" }, // → imageConfig passthroughs
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
- Requests `responseModalities: ["TEXT", "IMAGE"]` by default; pass `options.responseModalities` to replace the list verbatim. Which pairing a given model requires is not established here.
|
|
114
|
+
- Inline image parts that **do** come back (`inlineData.data` + `mimeType`) map to the **same** `GeneratedImage` shape Imagen produces — `{ type: "base64", base64, mediaType }`, defaulting to `image/png` when the part declares no mime type. Callers see one shape regardless of transport.
|
|
115
|
+
- **Token usage is passed through, not zeroed.** Any `usageMetadata` Google attaches is mapped by the same rules as `model.complete()` (`promptTokenCount` → `input`, `candidatesTokenCount` → `output`, `cachedContentTokenCount` → `cachedTokens`, `thoughtsTokenCount` → `reasoningTokens`); an absent block collapses to `{ 0, 0, 0 }`. That is the difference from Imagen, which is always zero. Whether these models in fact report tokens is unconfirmed — price with `{ input, output }` and check the first live `usage`.
|
|
116
|
+
- **A response with no image part is never a silent empty success:**
|
|
117
|
+
- `promptFeedback.blockReason`, or a safety/policy `finishReason` (`SAFETY`, `IMAGE_SAFETY`, `PROHIBITED_CONTENT`, `IMAGE_PROHIBITED_CONTENT`, `RECITATION`, `IMAGE_RECITATION`, `BLOCKLIST`, `SPII`) → `ContentFilterError` carrying the reason.
|
|
118
|
+
- text only (the model answered instead of drawing) → `ProviderError` **quoting the text** it returned.
|
|
119
|
+
- nothing usable → `ProviderError` naming the part count and finish reason (e.g. `NO_IMAGE`).
|
|
120
|
+
- `count`, `negativePrompt`, and `format` are **not** forwarded on this path — `GenerateContentConfig` / `ImageConfig` expose no equivalent (`ImageConfig.outputMimeType` is documented "not supported in Gemini API"). Fold those intentions into the prompt. Every inline image part the model does return is mapped, so a multi-image answer still comes back whole.
|
|
121
|
+
|
|
122
|
+
### Imagen (`generateImages`)
|
|
85
123
|
|
|
86
124
|
```ts
|
|
87
125
|
const imagen = google.image({ name: "imagen-4.0-generate-001", pricing: { perImage: 0.04 } });
|
|
@@ -95,9 +133,15 @@ const { data, error } = await ai.image({
|
|
|
95
133
|
});
|
|
96
134
|
```
|
|
97
135
|
|
|
98
|
-
- Imagen is **per-image-metered** (price with `{ perImage }`) and returns base64 bytes — no hosted URL,
|
|
99
|
-
- When every candidate is safety-filtered, the run surfaces a typed `ContentFilterError` on `result.error`.
|
|
100
|
-
-
|
|
136
|
+
- Imagen is **per-image-metered** (price with `{ perImage }`) and returns base64 bytes — no hosted URL, and `usage` is an honest `{ input: 0, output: 0, total: 0 }`.
|
|
137
|
+
- When every candidate is safety-filtered (`raiFilteredReason`), the run surfaces a typed `ContentFilterError` on `result.error`.
|
|
138
|
+
- ⏳ **This path is on a clock.** `@google/genai` warns at runtime: *"The generateImages method is deprecated and will be removed in the next major release (not before Jan. 1 2027). Please use the generateContent method with image models instead."* This package depends on `@google/genai` `^2.17.1`, which does emit that warning. Nothing breaks today, but new work should prefer a `gemini-*` id.
|
|
139
|
+
|
|
140
|
+
### Not implemented: the `interactions` API
|
|
141
|
+
|
|
142
|
+
`@google/genai` ≥ 2.17 adds `ai.interactions.create({ model, input, response_format: { type: "image", … } })`, whose images arrive as `interaction.output_image.data` and whose usage is a different snake_case shape (`total_input_tokens` …). It is reachable from the `^2.17.1` this package depends on, but the adapter does **not** use it: it would need its own usage mapper and error surface, and its request type already marks `response_modalities` / `response_mime_type` deprecated. If it is added later it will be an **opt-in config flag**, never id routing.
|
|
143
|
+
|
|
144
|
+
The verb surface lives in [`@warlock.js/ai/generate-images/SKILL.md`](@warlock.js/ai/generate-images/SKILL.md).
|
|
101
145
|
|
|
102
146
|
## Streaming
|
|
103
147
|
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
//#region ../ai-google/src/known-image-models.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Model-id prefixes Google exposes through the **Imagen** image API
|
|
4
|
-
* (`ai.models.generateImages`) — `imagen-3.0-*`, `imagen-4.0-*`, and
|
|
5
|
-
* their fast/ultra variants. All are per-image-metered and return
|
|
6
|
-
* base64 bytes.
|
|
7
|
-
*
|
|
8
|
-
* Gemini's *native* image output (`gemini-2.5-flash-image`) is a
|
|
9
|
-
* different surface (`generateContent` with `responseModalities`) and
|
|
10
|
-
* is intentionally NOT routed here — `google.image()` targets the
|
|
11
|
-
* dedicated Imagen endpoint only.
|
|
12
|
-
*
|
|
13
|
-
* Used by {@link isGoogleImageModel} for the construction-time guard so
|
|
14
|
-
* `google.image({ name: "gemini-2.5-flash" })` fails fast with a
|
|
15
|
-
* curated error rather than a downstream 400.
|
|
16
|
-
*/
|
|
17
|
-
declare const GOOGLE_IMAGE_MODEL_PREFIXES: readonly ["imagen-"];
|
|
18
|
-
/**
|
|
19
|
-
* True when `name` is a recognized Google Imagen model. A prefix match
|
|
20
|
-
* so dated/variant ids (`imagen-4.0-ultra-generate-001`) are covered
|
|
21
|
-
* without an exact-list maintenance burden.
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* isGoogleImageModel("imagen-4.0-generate-001"); // true
|
|
25
|
-
* isGoogleImageModel("gemini-2.5-flash"); // false
|
|
26
|
-
*/
|
|
27
|
-
declare function isGoogleImageModel(name: string): boolean;
|
|
28
|
-
//#endregion
|
|
29
|
-
export { GOOGLE_IMAGE_MODEL_PREFIXES, isGoogleImageModel };
|
|
30
|
-
//# sourceMappingURL=known-image-models.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"known-image-models.d.mts","names":[],"sources":["../../../../../../ai-google/src/known-image-models.ts"],"mappings":";;AAeA;;;;AAA+D;AAW/D;;;;AAA+C;;;;;cAXlC,2BAAA;;;;;;;;;;iBAWG,kBAAA,CAAmB,IAAY"}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
//#region ../ai-google/src/known-image-models.ts
|
|
2
|
-
/**
|
|
3
|
-
* Model-id prefixes Google exposes through the **Imagen** image API
|
|
4
|
-
* (`ai.models.generateImages`) — `imagen-3.0-*`, `imagen-4.0-*`, and
|
|
5
|
-
* their fast/ultra variants. All are per-image-metered and return
|
|
6
|
-
* base64 bytes.
|
|
7
|
-
*
|
|
8
|
-
* Gemini's *native* image output (`gemini-2.5-flash-image`) is a
|
|
9
|
-
* different surface (`generateContent` with `responseModalities`) and
|
|
10
|
-
* is intentionally NOT routed here — `google.image()` targets the
|
|
11
|
-
* dedicated Imagen endpoint only.
|
|
12
|
-
*
|
|
13
|
-
* Used by {@link isGoogleImageModel} for the construction-time guard so
|
|
14
|
-
* `google.image({ name: "gemini-2.5-flash" })` fails fast with a
|
|
15
|
-
* curated error rather than a downstream 400.
|
|
16
|
-
*/
|
|
17
|
-
const GOOGLE_IMAGE_MODEL_PREFIXES = ["imagen-"];
|
|
18
|
-
/**
|
|
19
|
-
* True when `name` is a recognized Google Imagen model. A prefix match
|
|
20
|
-
* so dated/variant ids (`imagen-4.0-ultra-generate-001`) are covered
|
|
21
|
-
* without an exact-list maintenance burden.
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* isGoogleImageModel("imagen-4.0-generate-001"); // true
|
|
25
|
-
* isGoogleImageModel("gemini-2.5-flash"); // false
|
|
26
|
-
*/
|
|
27
|
-
function isGoogleImageModel(name) {
|
|
28
|
-
return GOOGLE_IMAGE_MODEL_PREFIXES.some((prefix) => name.startsWith(prefix));
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
//#endregion
|
|
32
|
-
export { GOOGLE_IMAGE_MODEL_PREFIXES, isGoogleImageModel };
|
|
33
|
-
//# sourceMappingURL=known-image-models.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"known-image-models.mjs","names":[],"sources":["../../../../../../ai-google/src/known-image-models.ts"],"sourcesContent":["/**\n * Model-id prefixes Google exposes through the **Imagen** image API\n * (`ai.models.generateImages`) — `imagen-3.0-*`, `imagen-4.0-*`, and\n * their fast/ultra variants. All are per-image-metered and return\n * base64 bytes.\n *\n * Gemini's *native* image output (`gemini-2.5-flash-image`) is a\n * different surface (`generateContent` with `responseModalities`) and\n * is intentionally NOT routed here — `google.image()` targets the\n * dedicated Imagen endpoint only.\n *\n * Used by {@link isGoogleImageModel} for the construction-time guard so\n * `google.image({ name: \"gemini-2.5-flash\" })` fails fast with a\n * curated error rather than a downstream 400.\n */\nexport const GOOGLE_IMAGE_MODEL_PREFIXES = [\"imagen-\"] as const;\n\n/**\n * True when `name` is a recognized Google Imagen model. A prefix match\n * so dated/variant ids (`imagen-4.0-ultra-generate-001`) are covered\n * without an exact-list maintenance burden.\n *\n * @example\n * isGoogleImageModel(\"imagen-4.0-generate-001\"); // true\n * isGoogleImageModel(\"gemini-2.5-flash\"); // false\n */\nexport function isGoogleImageModel(name: string): boolean {\n return GOOGLE_IMAGE_MODEL_PREFIXES.some((prefix) => name.startsWith(prefix));\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,MAAa,8BAA8B,CAAC,SAAS;;;;;;;;;;AAWrD,SAAgB,mBAAmB,MAAuB;CACxD,OAAO,4BAA4B,MAAM,WAAW,KAAK,WAAW,MAAM,CAAC;AAC7E"}
|