diff --git a/CLAUDE.md b/CLAUDE.md index 66184bd..a8d4498 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -47,7 +47,7 @@ The stack is entirely TypeScript and Firebase. A Python Flask backend (`backend/ - **State management**: React hooks with Firebase hooks (`react-firebase-hooks`) ### Cloud Functions (`/functions`) -- **Built with**: TypeScript, Genkit, `@genkit-ai/googleai`, Firebase Admin SDK +- **Built with**: TypeScript, Genkit, `@genkit-ai/google-genai`, Firebase Admin SDK - **Entry point**: `src/index.ts` — all callables and triggers - `runAccountant` / `runAuditor` - agent entry points - `getTaxDocuments` / `getTaxSummary` / `createUserProfile` @@ -127,10 +127,13 @@ Not currently implemented. A previous Python implementation used Chromium automa ## Key Dependencies & Versions - **Frontend**: React 18.3, Vite 6.4, TailwindCSS 3.4, TypeScript 5.7 -- **Cloud Functions**: Node 22, TypeScript 5.6, Genkit 1.34, `@genkit-ai/googleai` 1.28, firebase-admin 13 +- **Cloud Functions**: Node 22, TypeScript 5.6, Genkit 1.41, `@genkit-ai/google-genai` 1.41, firebase-admin 13 ## AI Model Standards - **Mandatory Model**: AI agents (Accountant and Auditor) MUST use `googleai/gemini-2.5-flash`. - **Tool Calling**: Agents must be configured with `maxTurns: 5` in `ai.generate()` to ensure multi-turn tool calling completes automatically. -- **Why not gemini-3-flash-preview**: Gemini 3 requires mandatory `thoughtSignature` fields on every function call part in multi-turn history. The current `@genkit-ai/googleai` SDK (v1.28.0) drops these signatures in `fromFunctionCall`, causing 400 errors during tool-calling loops. Revisit when Genkit ships the fix. -- **Why gemini-2.5-flash**: Thought signatures are optional (not mandatory) for Gemini 2.5 function calls, so Genkit's current implementation works correctly. It is a newer and more capable model than what was originally used. +- **Plugin**: Use `@genkit-ai/google-genai`. The old `@genkit-ai/googleai` is deprecated by npm ("Use @genkit-ai/google-genai package instead") and was last published 2026-03-26. Model reference strings are unchanged — `googleAI.model('gemini-2.5-flash')` still resolves to `googleai/gemini-2.5-flash`. +- **Why gemini-2.5-flash**: Thought signatures are optional (not mandatory) for Gemini 2.5 function calls, so tool calling works correctly. +- **gemini-3 status — the SDK blocker is resolved, but not yet enabled here.** Gemini 3 requires a `thoughtSignature` on every function call part in multi-turn history. The old plugin's `fromFunctionCall` returned `{ toolRequest: { name, input, ref } }` and dropped the signature, causing 400 errors mid tool-calling loop. `@genkit-ai/google-genai` round-trips it: `fromGeminiToolCall` stashes it via `maybeAddThoughtSignatureAndMetadata` into `part.metadata.thoughtSignature`, and `toGeminiToolRequest` reattaches it via `maybeAddGeminiThoughtSignatureAndMetadata`. The old plugin also knows no gemini-3 model names at all; the new one ships ten. + + This was verified by reading the published sources, **not** by a live run. Before switching the mandate to gemini-3, exercise a real multi-turn tool-calling loop against the API and confirm no 400s — the offline suite never reaches the model, so it cannot catch this. diff --git a/README.md b/README.md index 5221723..344642e 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Key routes and views include login, registration, dashboard, accountant dashboar ### Production Cloud Functions (`functions/`) -The root `functions/` package is the backend. It uses Node 22, Firebase Functions v2, Firebase Admin, Genkit, and `@genkit-ai/googleai`. +The root `functions/` package is the backend. It uses Node 22, Firebase Functions v2, Firebase Admin, Genkit, and `@genkit-ai/google-genai`. Callable functions: diff --git a/functions/package-lock.json b/functions/package-lock.json index 1cb2b25..fd0d535 100644 --- a/functions/package-lock.json +++ b/functions/package-lock.json @@ -6,7 +6,7 @@ "": { "name": "taxfront-functions", "dependencies": { - "@genkit-ai/googleai": "^1.28.0", + "@genkit-ai/google-genai": "^1.41.0", "@google-cloud/recaptcha-enterprise": "^4.0.0", "firebase-admin": "^13.0.0", "firebase-functions": "^6.3.2", @@ -272,19 +272,17 @@ "genkit": "^1.41.0" } }, - "node_modules/@genkit-ai/googleai": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@genkit-ai/googleai/-/googleai-1.28.0.tgz", - "integrity": "sha512-K39g1UbuZbaQaX0CyJbLW5nLKxv8HkghyQqezy4EtDK92SqoCEXK4DQKtEi+9JLRa9MHutaBxX9+fSHu7KPE1A==", - "deprecated": "Use @genkit-ai/google-genai package instead. See: https://genkit.dev/docs/js/integrations/google-genai/", + "node_modules/@genkit-ai/google-genai": { + "version": "1.41.0", + "resolved": "https://registry.npmjs.org/@genkit-ai/google-genai/-/google-genai-1.41.0.tgz", + "integrity": "sha512-1e5go7ZHwYSq5zXQlRvNu6KwhBk7LEDfy1qFMj/1fJzwzxT1t5Nj+lBSbqrmpNSN82Kzxk7c8C3xj5bGlX+U6g==", "license": "Apache-2.0", "dependencies": { - "@google/generative-ai": "^0.24.0", - "google-auth-library": "^9.6.3", - "node-fetch": "^3.3.2" + "google-auth-library": "^9.14.2", + "jsonpath-plus": "^10.3.0" }, "peerDependencies": { - "genkit": "^1.28.0" + "genkit": "^1.41.0" } }, "node_modules/@google-cloud/common": { @@ -1214,15 +1212,6 @@ "node": ">=18" } }, - "node_modules/@google/generative-ai": { - "version": "0.24.1", - "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz", - "integrity": "sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==", - "license": "Apache-2.0", - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@grpc/grpc-js": { "version": "1.14.4", "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.4.tgz", @@ -1392,6 +1381,30 @@ "url": "https://opencollective.com/js-sdsl" } }, + "node_modules/@jsep-plugin/assignment": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", + "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@jsep-plugin/regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", + "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, "node_modules/@nodable/entities": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.0.tgz", @@ -5293,6 +5306,15 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + } + }, "node_modules/json-bigint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", @@ -5326,6 +5348,24 @@ "node": ">=6" } }, + "node_modules/jsonpath-plus": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.4.0.tgz", + "integrity": "sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==", + "license": "MIT", + "dependencies": { + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" + }, + "bin": { + "jsonpath": "bin/jsonpath-cli.js", + "jsonpath-plus": "bin/jsonpath-cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", diff --git a/functions/package.json b/functions/package.json index 66dff1c..fe19670 100644 --- a/functions/package.json +++ b/functions/package.json @@ -12,7 +12,7 @@ }, "main": "lib/index.js", "dependencies": { - "@genkit-ai/googleai": "^1.28.0", + "@genkit-ai/google-genai": "^1.41.0", "@google-cloud/recaptcha-enterprise": "^4.0.0", "firebase-admin": "^13.0.0", "firebase-functions": "^6.3.2", diff --git a/functions/src/ai.ts b/functions/src/ai.ts index 45f36ad..7d58461 100644 --- a/functions/src/ai.ts +++ b/functions/src/ai.ts @@ -1,5 +1,5 @@ import { genkit } from "genkit"; -import { googleAI } from "@genkit-ai/googleai"; +import { googleAI } from "@genkit-ai/google-genai"; let _ai: ReturnType | null = null;