TypeScript 97.4%
SQL 1%
JavaScript 0.9%
CSS 0.6%
1// Probe 05: (g) invalid key (SDK + REST), unknown model 404, bad param 400 raw body, countTokens, chats helper,2// Authorization: Bearer test, v1 vs v1beta, models.get, explicit cache creation minimum error, and the Interactions API surface.3import { GoogleGenAI } from "@google/genai";4import { ai, KEY, save, errInfo } from "./lib.js";56const results: any = {};7const BASE = "https://generativelanguage.googleapis.com";89// (g) invalid key — REST10{11 const r = await fetch(`${BASE}/v1beta/models/gemini-2.5-flash:generateContent`, { method: "POST", headers: { "x-goog-api-key": "AQ.invalid-key-for-probe", "content-type": "application/json" }, body: JSON.stringify({ contents: [{ parts: [{ text: "hi" }] }] }) });12 results.invalidKeyRest = { status: r.status, body: await r.json(), wwwAuthenticate: r.headers.get("www-authenticate") };13 console.log("invalid key REST", r.status, JSON.stringify(results.invalidKeyRest.body).slice(0, 400));14}15// (g) invalid key — SDK16try {17 const bad = new GoogleGenAI({ apiKey: "AQ.invalid-key-for-probe" });18 await bad.models.generateContent({ model: "gemini-2.5-flash", contents: "hi", config: { maxOutputTokens: 5 } });19} catch (e: any) { results.invalidKeySdk = { ...errInfo(e), rawMessage: String(e?.message).slice(0, 500), ctor: e?.constructor?.name }; console.log("invalid key SDK", JSON.stringify(results.invalidKeySdk).slice(0, 400)); }2021// Bearer auth (does Authorization: Bearer <api key> work?)22{23 const r = await fetch(`${BASE}/v1beta/models?pageSize=1`, { headers: { authorization: `Bearer ${KEY}` } });24 results.bearerAuth = { status: r.status, body: r.status !== 200 ? await r.json() : "(ok)" };25 console.log("bearer", r.status, JSON.stringify(results.bearerAuth.body).slice(0, 300));26}27// ?key= query param28{29 const r = await fetch(`${BASE}/v1beta/models?pageSize=1&key=${encodeURIComponent(KEY)}`);30 results.keyQueryParam = { status: r.status };31 console.log("?key=", r.status);32}33// Unknown model34try { await ai.models.generateContent({ model: "gemini-9-ultra", contents: "hi" }); } catch (e) { results.unknownModel = errInfo(e); console.log("unknown model", JSON.stringify(results.unknownModel).slice(0, 400)); }35// Raw 400 error body36{37 const r = await fetch(`${BASE}/v1beta/models/gemini-2.5-flash:generateContent`, { method: "POST", headers: { "x-goog-api-key": KEY, "content-type": "application/json" }, body: JSON.stringify({ contents: [{ parts: [{ text: "hi" }] }], generationConfig: { temperature: 5 } }) });38 results.raw400 = { status: r.status, body: await r.json() };39 console.log("raw 400", JSON.stringify(results.raw400).slice(0, 500));40}41// Streaming error (bad param) via SSE: does the error come as HTTP status or as an SSE event?42{43 const r = await fetch(`${BASE}/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse`, { method: "POST", headers: { "x-goog-api-key": KEY, "content-type": "application/json" }, body: JSON.stringify({ contents: [{ parts: [{ text: "hi" }] }], generationConfig: { temperature: 5 } }) });44 results.streamError = { status: r.status, contentType: r.headers.get("content-type"), body: (await r.text()).slice(0, 500) };45 console.log("stream error", results.streamError.status, results.streamError.contentType);46}47// countTokens48try {49 const c = await ai.models.countTokens({ model: "gemini-3.8-flash", contents: "The quick brown fox jumps over the lazy dog." });50 results.countTokens = c; console.log("countTokens", JSON.stringify(c));51} catch (e) { results.countTokens = errInfo(e); console.log("countTokens ERR", JSON.stringify(results.countTokens)); }52// countTokens with systemInstruction + tools via REST generateContentRequest53{54 const r = await fetch(`${BASE}/v1beta/models/gemini-3.8-flash:countTokens`, { method: "POST", headers: { "x-goog-api-key": KEY, "content-type": "application/json" }, body: JSON.stringify({ generateContentRequest: { model: "models/gemini-3.8-flash", contents: [{ role: "user", parts: [{ text: "The quick brown fox jumps over the lazy dog." }] }], systemInstruction: { parts: [{ text: "You are a helpful assistant that answers briefly." }] }, tools: [{ functionDeclarations: [{ name: "f", description: "A function", parameters: { type: "OBJECT", properties: { a: { type: "STRING" } } } }] }] } }) });55 results.countTokensFull = { status: r.status, body: await r.json() };56 console.log("countTokens full", JSON.stringify(results.countTokensFull));57}58// models.get59try { const m = await ai.models.get({ model: "gemini-3.8-flash" }); results.modelsGet = m; console.log("models.get", JSON.stringify(m).slice(0, 400)); } catch (e) { results.modelsGet = errInfo(e); }60// v1 API version: does gemini-3.8-flash exist on v1? does thinkingConfig work there?61try {62 const v1 = new GoogleGenAI({ apiKey: KEY, httpOptions: { apiVersion: "v1" } });63 const res = await v1.models.generateContent({ model: "gemini-3.8-flash", contents: "Say hi", config: { maxOutputTokens: 50, thinkingConfig: { thinkingLevel: "LOW" as any } } });64 results.v1 = { ok: true, text: res.text, modelVersion: res.modelVersion };65} catch (e) { results.v1 = { ok: false, error: errInfo(e) }; }66console.log("v1", JSON.stringify(results.v1).slice(0, 300));67// chats helper (client-side history)68try {69 const chat = ai.chats.create({ model: "gemini-2.5-flash-lite", config: { maxOutputTokens: 60, thinkingConfig: { thinkingBudget: 0 } } });70 await chat.sendMessage({ message: "My name is Simon. Reply OK." });71 const r2 = await chat.sendMessage({ message: "What is my name? One word." });72 results.chats = { ok: true, text: r2.text, historyLen: chat.getHistory().length, historyRoles: chat.getHistory().map((c) => c.role) };73} catch (e) { results.chats = { ok: false, error: errInfo(e) }; }74console.log("chats", JSON.stringify(results.chats));75// explicit cache: small content should fail with minimum-token error → record exact message76try {77 const c = await ai.caches.create({ model: "gemini-2.5-flash", config: { contents: [{ role: "user", parts: [{ text: "short" }] }], ttl: "60s" } });78 results.cacheCreate = { ok: true, name: c.name }; await ai.caches.delete({ name: c.name! });79} catch (e) { results.cacheCreate = { ok: false, error: errInfo(e) }; }80console.log("cache", JSON.stringify(results.cacheCreate).slice(0, 400));81// Interactions API (new recommended surface) — does the SDK expose it, and does it work with this key?82try {83 const anyAi: any = ai;84 results.interactionsExposed = typeof anyAi.interactions?.create === "function";85 if (results.interactionsExposed) {86 const it = await anyAi.interactions.create({ model: "gemini-3.8-flash", input: "Say hi in two words.", generation_config: { thinking_level: "low", max_output_tokens: 50 }, store: false });87 results.interactions = { ok: true, keys: Object.keys(it), output_text: it.output_text, usage: it.usage, stepsTypes: (it.steps ?? it.outputs ?? []).map((s: any) => s.type) };88 }89} catch (e) { results.interactions = { ok: false, error: errInfo(e), raw: String((e as any)?.message).slice(0, 300) }; }90console.log("interactions", JSON.stringify(results.interactions).slice(0, 500));91// Safety settings accepted?92try {93 const res = await ai.models.generateContent({ model: "gemini-2.5-flash-lite", contents: "Say hi", config: { maxOutputTokens: 20, thinkingConfig: { thinkingBudget: 0 }, safetySettings: [{ category: "HARM_CATEGORY_HARASSMENT" as any, threshold: "BLOCK_NONE" as any }, { category: "HARM_CATEGORY_HATE_SPEECH" as any, threshold: "OFF" as any }] } });94 results.safety = { ok: true, text: res.text, safetyRatings: res.candidates?.[0]?.safetyRatings ?? null, promptFeedback: res.promptFeedback ?? null };95} catch (e) { results.safety = { ok: false, error: errInfo(e) }; }96console.log("safety", JSON.stringify(results.safety).slice(0, 300));97// Response headers on a normal request (rate-limit headers?)98{99 const r = await fetch(`${BASE}/v1beta/models/gemini-2.5-flash-lite:generateContent`, { method: "POST", headers: { "x-goog-api-key": KEY, "content-type": "application/json" }, body: JSON.stringify({ contents: [{ parts: [{ text: "hi" }] }], generationConfig: { maxOutputTokens: 5, thinkingConfig: { thinkingBudget: 0 } } }) });100 results.responseHeaders = Object.fromEntries([...r.headers.entries()]);101 await r.text();102 console.log("headers", JSON.stringify(results.responseHeaders));103}104save("05-errors-misc.json", results);105