@bubblebrain-ai/bubble 0.0.64 → 0.0.65
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/dist/model-catalog.js +12 -0
- package/dist/model-pricing.js +16 -4
- package/dist/provider-ai-sdk.d.ts +2 -2
- package/dist/provider-ai-sdk.js +54 -11
- package/package.json +1 -1
package/dist/model-catalog.js
CHANGED
|
@@ -99,6 +99,10 @@ const GROK_45_LEVELS = ["low", "medium", "high"];
|
|
|
99
99
|
// Gemini 4 documents only low/medium (default)/high. Verified live on
|
|
100
100
|
// 2026-10-13: thinkingLevel=minimal returns 400, so there is no off/minimal.
|
|
101
101
|
const GEMINI_4_LEVELS = ["low", "medium", "high"];
|
|
102
|
+
// Gemini 4 Hydrogen adds xhigh above the Gemini 4 ladder and defaults to high.
|
|
103
|
+
// Verified live on 2026-11-12: xhigh returns 200, minimal still returns 400
|
|
104
|
+
// (Argon rejects xhigh).
|
|
105
|
+
const GEMINI_4_HYDROGEN_LEVELS = ["low", "medium", "high", "xhigh"];
|
|
102
106
|
const GEMINI_3_LEVELS = ["low", "medium", "high"];
|
|
103
107
|
const GEMINI_3_FLASH_LEVELS = ["minimal", "low", "medium", "high"];
|
|
104
108
|
// Verified against the native API on 2026-09-02: Gemini 3.7/3.8 Flash reject
|
|
@@ -163,6 +167,14 @@ export const BUILTIN_MODELS = [
|
|
|
163
167
|
// Gemini 4 Argon: 1,048,576-token window shared by input, thinking and output.
|
|
164
168
|
// https://ai.google.dev/gemini-api/docs/models/gemini-4-argon
|
|
165
169
|
{ id: "gemini-4-argon", name: "Gemini 4 Argon", providerId: "google", tier: "strong", reasoningLevels: GEMINI_4_LEVELS, defaultReasoningLevel: "medium", contextWindow: 1048576 },
|
|
170
|
+
// Gemini 4 Carbon (2026-11-10): Google's most capable reasoning model, same
|
|
171
|
+
// window, levels and medium default as Argon (xhigh verified 400 on 2026-11-12).
|
|
172
|
+
// Listed after Argon so the provider's default model does not change.
|
|
173
|
+
// https://ai.google.dev/gemini-api/docs/models/gemini-4-carbon
|
|
174
|
+
{ id: "gemini-4-carbon", name: "Gemini 4 Carbon", providerId: "google", tier: "strong", reasoningLevels: GEMINI_4_LEVELS, defaultReasoningLevel: "medium", contextWindow: 1048576 },
|
|
175
|
+
// Gemini 4 Hydrogen (2026-11-12): same shared 1,048,576-token window, 65,536
|
|
176
|
+
// output by default. https://ai.google.dev/gemini-api/docs/models/gemini-4-hydrogen
|
|
177
|
+
{ id: "gemini-4-hydrogen", name: "Gemini 4 Hydrogen", providerId: "google", tier: "balanced", reasoningLevels: GEMINI_4_HYDROGEN_LEVELS, defaultReasoningLevel: "high", contextWindow: 1048576 },
|
|
166
178
|
{ id: "gemini-3.8-flash", name: "Gemini 3.8 Flash", providerId: "google", tier: "fast", reasoningLevels: GEMINI_37_38_FLASH_LEVELS, contextWindow: 1048576 },
|
|
167
179
|
{ id: "gemini-3.7-flash", name: "Gemini 3.7 Flash", providerId: "google", tier: "fast", reasoningLevels: GEMINI_37_38_FLASH_LEVELS, contextWindow: 1048576 },
|
|
168
180
|
{ id: "gemini-3.5-flash", name: "Gemini 3.5 Flash", providerId: "google", tier: "fast", reasoningLevels: GEMINI_3_FLASH_LEVELS, contextWindow: 1048576 },
|
package/dist/model-pricing.js
CHANGED
|
@@ -64,12 +64,13 @@ export const MODEL_PRICING_OVERRIDES = [
|
|
|
64
64
|
outputPerMillion: 7.5,
|
|
65
65
|
},
|
|
66
66
|
})),
|
|
67
|
-
// Gemini 4 Argon
|
|
68
|
-
// 2026-12-01. Implicit caching only (95% off
|
|
67
|
+
// Gemini 4 Argon and Carbon share one tariff: introductory pricing through
|
|
68
|
+
// 2026-11-30, standard rates from 2026-12-01. Implicit caching only (95% off
|
|
69
|
+
// input), so no cache-write rate.
|
|
69
70
|
// https://ai.google.dev/gemini-api/docs/pricing
|
|
70
|
-
{
|
|
71
|
+
...["gemini-4-argon", "gemini-4-carbon"].map((modelId) => ({
|
|
71
72
|
providerId: "google",
|
|
72
|
-
modelId
|
|
73
|
+
modelId,
|
|
73
74
|
currency: "USD",
|
|
74
75
|
inputCacheHitPerMillion: 0.1,
|
|
75
76
|
inputCacheMissPerMillion: 2,
|
|
@@ -80,6 +81,17 @@ export const MODEL_PRICING_OVERRIDES = [
|
|
|
80
81
|
inputCacheMissPerMillion: 4,
|
|
81
82
|
outputPerMillion: 20,
|
|
82
83
|
},
|
|
84
|
+
})),
|
|
85
|
+
// Gemini 4 Hydrogen: one flat rate for all context lengths, implicit caching
|
|
86
|
+
// only (95% off input). Not yet on models.dev at launch (2026-11-12).
|
|
87
|
+
// https://ai.google.dev/gemini-api/docs/pricing
|
|
88
|
+
{
|
|
89
|
+
providerId: "google",
|
|
90
|
+
modelId: "gemini-4-hydrogen",
|
|
91
|
+
currency: "USD",
|
|
92
|
+
inputCacheHitPerMillion: 0.075,
|
|
93
|
+
inputCacheMissPerMillion: 1.5,
|
|
94
|
+
outputPerMillion: 7.5,
|
|
83
95
|
},
|
|
84
96
|
{
|
|
85
97
|
providerId: "deepseek",
|
|
@@ -50,8 +50,8 @@ export declare function fetchGeminiModels(options: {
|
|
|
50
50
|
}): Promise<GeminiModelDescriptor[]>;
|
|
51
51
|
/**
|
|
52
52
|
* Ranking: one entry per (version, tier) family — GA ids beat dated previews —
|
|
53
|
-
* then newest version first,
|
|
54
|
-
* flash-lite, top N.
|
|
53
|
+
* then newest version first, pro/argon before carbon before hydrogen before
|
|
54
|
+
* flash before flash-lite, top N.
|
|
55
55
|
*/
|
|
56
56
|
export declare function selectLatestGeminiModels(entries: GeminiModelListEntry[], limit?: number): GeminiModelDescriptor[];
|
|
57
57
|
/** Mirrors the static catalog's per-family thinking support. */
|
package/dist/provider-ai-sdk.js
CHANGED
|
@@ -16,13 +16,19 @@ import { RateLimitError } from "./network/errors.js";
|
|
|
16
16
|
import { ProviderStreamInterruptedError, computeRetryDelayMs, getProviderMaxRetries, isRetryableHttpStatus, sleepBeforeRetry, } from "./network/retry.js";
|
|
17
17
|
import { createProviderFetch, isProviderTransportError } from "./network/provider-transport.js";
|
|
18
18
|
const GEMINI_DEFAULT_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
|
|
19
|
+
/**
|
|
20
|
+
* Per-call channel from buildCallOptions to the fetch wrapper: carries a
|
|
21
|
+
* thinking level the pinned @ai-sdk/google schema cannot express. Stripped
|
|
22
|
+
* before the request leaves the process.
|
|
23
|
+
*/
|
|
24
|
+
const THINKING_LEVEL_OVERRIDE_HEADER = "x-bubble-thinking-level";
|
|
19
25
|
const AI_SDK_PROVIDER_FACTORIES = {
|
|
20
26
|
google: (options) => {
|
|
21
27
|
const provider = createGoogleGenerativeAI({
|
|
22
28
|
apiKey: options.apiKey,
|
|
23
29
|
...(options.baseURL ? { baseURL: normalizeBaseURL(options.baseURL) } : {}),
|
|
24
30
|
...(options.headers ? { headers: options.headers } : {}),
|
|
25
|
-
fetch: (options.fetch ?? createProviderFetch({
|
|
31
|
+
fetch: withThinkingLevelOverride(options.fetch ?? createProviderFetch({
|
|
26
32
|
providerName: "Google Gemini",
|
|
27
33
|
verboseEnvVar: "BUBBLE_AI_SDK_FETCH_VERBOSE",
|
|
28
34
|
})),
|
|
@@ -117,9 +123,12 @@ export function createAiSdkProvider(options) {
|
|
|
117
123
|
// ============================================================================
|
|
118
124
|
function buildCallOptions(messages, chatOptions, providerOptions) {
|
|
119
125
|
const prompt = convertMessages(messages);
|
|
120
|
-
const
|
|
126
|
+
const thinkingLevel = chatOptions.thinkingLevel ?? providerOptions.thinkingLevel;
|
|
127
|
+
const thinking = buildGoogleThinkingOptions(chatOptions.model, thinkingLevel);
|
|
128
|
+
const levelOverride = googleThinkingLevelOverride(chatOptions.model, thinkingLevel);
|
|
121
129
|
return {
|
|
122
130
|
prompt,
|
|
131
|
+
...(levelOverride ? { headers: { [THINKING_LEVEL_OVERRIDE_HEADER]: levelOverride } } : {}),
|
|
123
132
|
...(chatOptions.temperature !== undefined ? { temperature: chatOptions.temperature } : {}),
|
|
124
133
|
...(chatOptions.abortSignal ? { abortSignal: chatOptions.abortSignal } : {}),
|
|
125
134
|
...(chatOptions.tools?.length
|
|
@@ -139,7 +148,8 @@ function buildCallOptions(messages, chatOptions, providerOptions) {
|
|
|
139
148
|
/**
|
|
140
149
|
* Gemini 3+ models take a graded thinking_level; 2.5-era models take a token
|
|
141
150
|
* budget. "off" (budget 0) is only offered in the catalog for models that
|
|
142
|
-
* accept it (2.5 Flash); xhigh/max/ultra clamp to high
|
|
151
|
+
* accept it (2.5 Flash); xhigh/max/ultra clamp to high here, and models with
|
|
152
|
+
* a native xhigh get it back through googleThinkingLevelOverride.
|
|
143
153
|
*/
|
|
144
154
|
function buildGoogleThinkingOptions(modelId, level) {
|
|
145
155
|
if (!level)
|
|
@@ -159,6 +169,35 @@ function buildGoogleThinkingOptions(modelId, level) {
|
|
|
159
169
|
const budgets = { minimal: 512, low: 2048, medium: 8192, high: 24576 };
|
|
160
170
|
return { thinkingConfig: { thinkingBudget: budgets[clamped] ?? 8192, includeThoughts: true } };
|
|
161
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* The @ai-sdk/google v3 schema only admits minimal/low/medium/high, so a model
|
|
174
|
+
* with a native xhigh (Gemini 4 Hydrogen) is sent "high" through the SDK and
|
|
175
|
+
* the real level is written into the request body by the fetch wrapper.
|
|
176
|
+
*/
|
|
177
|
+
function googleThinkingLevelOverride(modelId, level) {
|
|
178
|
+
if (level !== "xhigh" && level !== "max" && level !== "ultra")
|
|
179
|
+
return undefined;
|
|
180
|
+
return geminiReasoningLevels(modelId).includes("xhigh") ? "xhigh" : undefined;
|
|
181
|
+
}
|
|
182
|
+
function withThinkingLevelOverride(fetchImpl) {
|
|
183
|
+
return async (input, init) => {
|
|
184
|
+
const headers = new Headers(init?.headers);
|
|
185
|
+
const level = headers.get(THINKING_LEVEL_OVERRIDE_HEADER);
|
|
186
|
+
if (!level)
|
|
187
|
+
return fetchImpl(input, init);
|
|
188
|
+
headers.delete(THINKING_LEVEL_OVERRIDE_HEADER);
|
|
189
|
+
let body = init?.body;
|
|
190
|
+
if (typeof body === "string") {
|
|
191
|
+
const parsed = JSON.parse(body);
|
|
192
|
+
parsed.generationConfig = {
|
|
193
|
+
...parsed.generationConfig,
|
|
194
|
+
thinkingConfig: { ...parsed.generationConfig?.thinkingConfig, thinkingLevel: level },
|
|
195
|
+
};
|
|
196
|
+
body = JSON.stringify(parsed);
|
|
197
|
+
}
|
|
198
|
+
return fetchImpl(input, { ...init, headers: Object.fromEntries(headers), body });
|
|
199
|
+
};
|
|
200
|
+
}
|
|
162
201
|
function convertMessages(messages) {
|
|
163
202
|
const out = [];
|
|
164
203
|
const toolNamesById = new Map();
|
|
@@ -465,13 +504,14 @@ export async function fetchGeminiModels(options) {
|
|
|
465
504
|
}
|
|
466
505
|
/**
|
|
467
506
|
* Ranking: one entry per (version, tier) family — GA ids beat dated previews —
|
|
468
|
-
* then newest version first,
|
|
469
|
-
* flash-lite, top N.
|
|
507
|
+
* then newest version first, pro/argon before carbon before hydrogen before
|
|
508
|
+
* flash before flash-lite, top N.
|
|
470
509
|
*/
|
|
471
510
|
export function selectLatestGeminiModels(entries, limit = 5) {
|
|
472
|
-
// Gemini 4 introduced named
|
|
473
|
-
// stay excluded rather than guessing whether they are text models.
|
|
474
|
-
|
|
511
|
+
// Gemini 4 introduced named tiers (argon, carbon, hydrogen). Unknown names
|
|
512
|
+
// stay excluded rather than guessing whether they are text models. Argon
|
|
513
|
+
// stays ahead of Carbon to match the static catalog's default model.
|
|
514
|
+
const TIER_RANK = { argon: 0, pro: 0, carbon: 1, hydrogen: 2, flash: 3, "flash-lite": 4 };
|
|
475
515
|
const candidates = [];
|
|
476
516
|
for (const entry of entries) {
|
|
477
517
|
const id = (entry.name ?? "").replace(/^models\//, "");
|
|
@@ -481,7 +521,7 @@ export function selectLatestGeminiModels(entries, limit = 5) {
|
|
|
481
521
|
continue;
|
|
482
522
|
if (entry.supportedGenerationMethods && !entry.supportedGenerationMethods.includes("generateContent"))
|
|
483
523
|
continue;
|
|
484
|
-
const match = /^gemini-(\d+(?:\.\d+)?)-(argon|pro|flash)(-lite)?/.exec(id);
|
|
524
|
+
const match = /^gemini-(\d+(?:\.\d+)?)-(argon|carbon|hydrogen|pro|flash)(-lite)?/.exec(id);
|
|
485
525
|
if (!match)
|
|
486
526
|
continue;
|
|
487
527
|
const tier = `${match[2]}${match[3] ?? ""}`;
|
|
@@ -490,7 +530,7 @@ export function selectLatestGeminiModels(entries, limit = 5) {
|
|
|
490
530
|
entry,
|
|
491
531
|
version: Number.parseFloat(match[1]),
|
|
492
532
|
tier,
|
|
493
|
-
tierRank: TIER_RANK[tier] ??
|
|
533
|
+
tierRank: TIER_RANK[tier] ?? 5,
|
|
494
534
|
isPreview: id.includes("preview") || id.includes("exp"),
|
|
495
535
|
});
|
|
496
536
|
}
|
|
@@ -513,7 +553,7 @@ export function selectLatestGeminiModels(entries, limit = 5) {
|
|
|
513
553
|
name: candidate.entry.displayName || candidate.id,
|
|
514
554
|
contextWindow: Number.isFinite(candidate.entry.inputTokenLimit) ? candidate.entry.inputTokenLimit : undefined,
|
|
515
555
|
reasoningLevels: geminiReasoningLevels(candidate.id),
|
|
516
|
-
// Argon
|
|
556
|
+
// Argon/Carbon (medium) and Hydrogen (high) take Google's defaults from the catalog.
|
|
517
557
|
...(candidate.tier === "pro" ? { defaultReasoningLevel: "high" } : {}),
|
|
518
558
|
}));
|
|
519
559
|
}
|
|
@@ -524,6 +564,9 @@ function geminiVersion(modelId) {
|
|
|
524
564
|
export function geminiReasoningLevels(modelId) {
|
|
525
565
|
const version = geminiVersion(modelId);
|
|
526
566
|
const isPro = modelId.includes("-pro");
|
|
567
|
+
// Hydrogen is the only Gemini 4 tier with xhigh; Argon and Carbon return 400 for it.
|
|
568
|
+
if (version >= 4 && /^gemini-[\d.]+-hydrogen/.test(modelId))
|
|
569
|
+
return ["low", "medium", "high", "xhigh"];
|
|
527
570
|
if (version >= 4)
|
|
528
571
|
return ["low", "medium", "high"];
|
|
529
572
|
// Live probes show 3.7 and 3.8 Flash share this newer ladder. Keep the
|