refactor: remover todos providers de IA exceto Google Gemini - #48
refactor: remover todos providers de IA exceto Google Gemini#48thaleslaray wants to merge 4 commits into
Conversation
- Remove OpenAI, Voyage, Cohere e Together de toda a stack de IA - AIProvider, AiProviderType, EmbeddingProvider agora são literalmente 'google' - unified-ai-service: remove branch OpenAI do createModelInstance - ai-center-config: remove openai_api_key de SETTINGS_KEYS e fetch - ai/models route: simplifica para buscar só modelos Google - llm-providers e embedding-providers: remove providers não-Google - settings routes: remove handling de openai_api_key - AIGatewayPanel, AIAgentForm, settings/ai/page: remove UI de seleção de provider - scripts/ai-quality-suite: remove comparação com OpenAI embeddings -533 linhas removidas em 26 arquivos. TypeScript: 0 erros. Testes: 3810/3810. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
O AIGatewayPanel já tem o seletor de modelo inline no card do provider. A seção separada 'Modelo principal' abaixo era duplicata — removida. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A RPC get_contact_stats estava retornando no máximo 1000 por causa do limite padrão do PostgREST. Substituído por 3 queries paralelas com count: 'exact' + head: true — o mesmo mecanismo que a listagem usa e que já retorna o count correto (3640+) via header HTTP. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThis pull request removes OpenAI, Voyage, and Cohere provider support across the codebase, consolidating all AI functionality to use Google Gemini exclusively. Provider selection UI, conditional model instantiation logic, and multi-provider API key management are eliminated. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b6e039c78c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Sempre usa google — único provider suportado | ||
| const provider: AiProviderType = DEFAULT_AI_DIRECT.provider | ||
|
|
||
| const model = | ||
| typeof input?.model === 'string' && input.model.trim() |
There was a problem hiding this comment.
Normalize model when coercing provider to Google
This normalization now forces provider to Google but keeps any previously saved input.model, so an existing ai_direct like {"provider":"openai","model":"gpt-4o"} is converted into an invalid Google config instead of being reset. Downstream callers (e.g. chat/inbox/template services) will try to instantiate Gemini with a non-Gemini model ID and fail at runtime until someone manually edits settings. When provider is coerced, the model should also be validated against supported Google IDs (or reset to DEFAULT_AI_DIRECT.model).
Useful? React with 👍 / 👎.
| const EMBEDDING_API_KEY_MAP: Record<EmbeddingProvider, { settingKey: string; envVar: string }> = { | ||
| google: { settingKey: 'google_api_key', envVar: 'GOOGLE_GENERATIVE_AI_API_KEY' }, | ||
| openai: { settingKey: 'openai_api_key', envVar: 'OPENAI_API_KEY' }, | ||
| voyage: { settingKey: 'voyage_api_key', envVar: 'VOYAGE_API_KEY' }, | ||
| cohere: { settingKey: 'cohere_api_key', envVar: 'COHERE_API_KEY' }, | ||
| } |
There was a problem hiding this comment.
Guard legacy embedding providers before map lookup
EMBEDDING_API_KEY_MAP now only has google, but this route still reads agent.embedding_provider from the database and later dereferences config.settingKey/config.envVar without a fallback. Any pre-existing agent with openai, voyage, or cohere in embedding_provider will make config undefined and crash KB-enabled chat requests. Add a fallback/migration path for legacy provider values (the same pattern is present in [id]/test).
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (7)
app/api/ai/models/route.ts (1)
77-95:⚠️ Potential issue | 🟠 MajorAuthenticate this route before using the stored Google key.
GETcurrently lets any caller hit/api/ai/modelsand spend the tenant's saved Google quota to enumerate models. AddverifyApiKey()before reading settings or calling Google. As per coding guidelines, "Enforce authentication per-route viaverifyApiKey()fromlib/auth.tsin API routes (no middleware.ts)".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/api/ai/models/route.ts` around lines 77 - 95, The GET handler currently reads the tenant Google key and calls fetchGoogleModels without authenticating; before calling getSettingValue or fetchGoogleModels, call and await verifyApiKey() (importing it from lib/auth.ts) and return an appropriate unauthorized response if it throws or returns a falsy value. Update the GET function to first run verifyApiKey(), then proceed to call getSettingValue('google_api_key') and fetchGoogleModels(apiKey) only after successful verification, and ensure error handling still returns NextResponse.json with status 502 for fetch errors and a 401/403 NextResponse for auth failures.app/api/ai-agents/[id]/test/route.ts (1)
23-25:⚠️ Potential issue | 🔴 CriticalSame schema mismatch issue as chat route.
This route has the same
EMBEDDING_API_KEY_MAPlimitation. The lookup at line 190 will fail for agents with non-Googleembedding_providervalues stored in the database.The fix recommended for
app/api/ai-agents/[id]/chat/route.ts(updating the agent creation schema inapp/api/ai-agents/route.ts) will resolve this for both routes.Also applies to: 189-190
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/api/ai-agents/`[id]/test/route.ts around lines 23 - 25, EMBEDDING_API_KEY_MAP in app/api/ai-agents/[id]/test/route.ts only contains a google entry so lookups for agents whose embedding_provider is not "google" will fail; fix by (a) updating the agent creation schema in app/api/ai-agents/route.ts to ensure embedding_provider is validated/defaulted to supported providers (matching DB values used elsewhere) and (b) making EMBEDDING_API_KEY_MAP and the lookup in test/route.ts robust: either add entries for all supported providers or guard the lookup (e.g., fall back to a safe default or throw a clear error) so getEmbeddingApiKey(embedding_provider) cannot return undefined for valid DB values. Ensure you update the symbols EMBEDDING_API_KEY_MAP and the agent creation schema (where embedding_provider is defined) so both routes (chat and test) handle non-google providers consistently.lib/ai/ai-center-defaults.ts (1)
14-29:⚠️ Potential issue | 🟡 MinorRemove dead references to
openaiApiKeyinlib/mcp/tools/system.ts.The destructuring of
openaiApiKeyon line 74 and thehasOpenAIKeycheck on line 78 reference a property that no longer exists in theAiDirectConfigtype. These will always beundefined/falseand should be removed along with their corresponding destructuring assignments.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/ai/ai-center-defaults.ts` around lines 14 - 29, Remove the stale openaiApiKey handling: delete the destructuring that pulls openaiApiKey and any derived boolean like hasOpenAIKey in the module (e.g., the openaiApiKey variable and hasOpenAIKey check in system.ts), and remove any conditional branches that only run when hasOpenAIKey is true; ensure all remaining logic uses the current AiDirectConfig fields (like googleApiKey) and that no other references to openaiApiKey or hasOpenAIKey remain.app/api/ai-agents/[id]/chat/route.ts (1)
46-48:⚠️ Potential issue | 🔴 CriticalCritical: Schema validation mismatch will cause runtime errors.
The
embedding_providerschemas inapp/api/ai-agents/route.ts(line 32) andapp/api/ai-agents/[id]/route.ts(line 32) accept['google', 'openai', 'voyage', 'cohere'], but:
- The
EmbeddingProvidertype inlib/ai/embeddings.tsis restricted to only'google'EMBEDDING_API_KEY_MAPin the chat route (lines 46-48) only containsIf an agent with a non-Google
embedding_providerexists in the database, line 281's lookup will returnundefined, and line 286 will throwCannot read properties of undefined (reading 'settingKey').Update both schemas to match the actual
EmbeddingProvidertype:- embedding_provider: z.enum(['google', 'openai', 'voyage', 'cohere']).default('google'), + embedding_provider: z.enum(['google']).default('google'),Also update the optional variant in the update endpoint:
- embedding_provider: z.enum(['google', 'openai', 'voyage', 'cohere']).optional(), + embedding_provider: z.enum(['google']).optional(),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/api/ai-agents/`[id]/chat/route.ts around lines 46 - 48, The schema enum for embedding_provider in app/api/ai-agents/route.ts and app/api/ai-agents/[id]/route.ts must match the actual EmbeddingProvider type (lib/ai/embeddings.ts) and the chat logic: change the allowed values from ['google','openai','voyage','cohere'] to only ['google'] and update the update-endpoint variant to the optional form (e.g., use the z.enum(['google']).optional() or equivalent) so that validation matches the EmbeddingProvider type and EMBEDDING_API_KEY_MAP lookups won't return undefined.lib/mcp/tools/settings.ts (1)
81-103:⚠️ Potential issue | 🟠 Major
sz.settings.set_aistill sends the pre-refactor route keys.This tool posts
inbox_suggest/inbox_chat/template_generation/ocr, but the backend now normalizes AI routes throughprepareAiRoutesUpdate()intogenerateUtilityTemplatesandgenerateFlowForm. The call will succeed while silently dropping the requested route changes.Suggested contract alignment
inputSchema: { model: z.string().optional().describe('Model ID (ex: gemini-2.5-flash)'), google_api_key: z.string().optional().describe('Chave API do Google Gemini'), routes: z .object({ - inbox_suggest: z.boolean().optional(), - inbox_chat: z.boolean().optional(), - template_generation: z.boolean().optional(), - ocr: z.boolean().optional(), + generateUtilityTemplates: z.boolean().optional(), + generateFlowForm: z.boolean().optional(), }) .optional() .describe('Rotas que usam IA (habilitar/desabilitar individualmente)'), },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/mcp/tools/settings.ts` around lines 81 - 103, The tool sz.settings.set_ai currently sends the old route keys (inbox_suggest, inbox_chat, template_generation, ocr) which the backend silently drops; fix this by normalizing the routes before sending—import and call prepareAiRoutesUpdate(routes) (or otherwise map the incoming routes to the backend's expected keys like generateUtilityTemplates/generateFlowForm) and include the normalized result in the POST body instead of the raw routes variable; update the async handler in settings.ts to use the output of prepareAiRoutesUpdate when building JSON.stringify({ model, google_api_key, routes: normalizedRoutes }).app/api/settings/ai/route.ts (2)
58-119:⚠️ Potential issue | 🔴 CriticalAuthenticate
/api/settings/aibefore exposing or mutating AI config.
GET,POST, andDELETEstill execute withoutverifyApiKey(). That leaves key-state metadata readable and AI settings / API keys writable by any caller that can hit the route, which is too much surface area for a settings endpoint.Based on learnings: Enforce authentication per-route via
verifyApiKey()fromlib/auth.tsin API routes (no middleware.ts).Also applies to: 126-220, 227-263
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/api/settings/ai/route.ts` around lines 58 - 119, This route exposes AI settings without auth; import and call verifyApiKey() from lib/auth.ts at the start of each handler (GET, POST, DELETE) in this file and return an unauthorized NextResponse if verification fails; ensure the call is awaited (e.g., const ok = await verifyApiKey(req) or wrap in try/catch if verifyApiKey throws) so no settings logic (prepareAiDirectUpdate, prepareAiRoutesUpdate, etc.) runs for unauthenticated requests.
126-196:⚠️ Potential issue | 🟠 MajorValidate the POST payload before merging it into persisted settings.
routes,prompts, andocr_gemini_modelare accepted as arbitrary JSON and then written intosettings. A malformed payload here can poison stored config and break every downstream reader that assumes the normalized shapes.Based on learnings: In API route files under
app/api/**/route.ts, use Zod validation only for user input (request body, query params, path params).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/api/settings/ai/route.ts` around lines 126 - 196, The POST handler accepts arbitrary JSON for routes, prompts, and ocr_gemini_model and merges it into persisted settings which can corrupt downstream readers; add explicit Zod validation in the POST function to parse and validate the incoming body (provider, model, google_api_key, routes, prompts, ocr_gemini_model) before any merges, rejecting invalid payloads with a 400; for routes and prompts validate against the existing normalized shapes used by prepareAiRoutesUpdate and the prompts normalization (utilityGenerationTemplate, utilityJudgeTemplate, flowFormTemplate and optional strategyMarketing/strategyUtility/strategyBypass) and only write validated fields to updates, and validate ocr_gemini_model against an allowed string/enum schema before pushing key 'ocr_gemini_model' to updates.
🧹 Nitpick comments (5)
lib/ai/services/ai-judge.ts (1)
30-32: Honoroptions.apiKeyor remove it from the public contract.The new Google-only path ignores
JudgeOptions.apiKey, so callers that pass an explicit key will still fail whenever the DB setting is empty. Either preferoptions.apiKey ?? config.googleApiKeyhere or deleteapiKeyfromJudgeOptionsto avoid a broken override.Suggested fix
- if (!config.googleApiKey) throw new Error('Chave Google não configurada. Acesse Configurações → IA.') - const google = createGoogleGenerativeAI({ apiKey: config.googleApiKey }) + const apiKey = options.apiKey || config.googleApiKey + if (!apiKey) throw new Error('Chave Google não configurada. Acesse Configurações → IA.') + const google = createGoogleGenerativeAI({ apiKey }) const model = google(targetModelId)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/ai/services/ai-judge.ts` around lines 30 - 32, The Google-only path in ai-judge.ts ignores the caller-supplied key in JudgeOptions, so update the Google client creation to prefer options.apiKey over the DB setting (use options.apiKey ?? config.googleApiKey when calling createGoogleGenerativeAI) and pass that value into google(targetModelId); alternatively remove apiKey from JudgeOptions if intentional. Locate the code around createGoogleGenerativeAI, the google variable and the model assignment (google(targetModelId)) and apply the key preference or remove the option from the public contract accordingly.app/api/ai/models/route.ts (1)
87-93: Expose the provider failure indetails.This catch block returns only
{ error }, so clients following the repository-wide API convention lose the actual Google error text. Returndetails: messagehere as well.Suggested fix
return NextResponse.json( - { error: `Falha ao buscar modelos: ${message}` }, + { error: 'Falha ao buscar modelos', details: message }, { status: 502 } )Based on learnings: "In this repository, API error responses should return { details: error.message } ... Ensure catch blocks map the error to a response with details set to error.message."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/api/ai/models/route.ts` around lines 87 - 93, The catch block in route.ts currently returns only { error } losing the provider error text; update the error response inside the catch (where message is derived and NextResponse.json is returned) to include details: message (i.e., return { error: `Falha ao buscar modelos: ${message}`, details: message } with the existing status 502) so clients following the repository-wide API convention receive the provider failure text.app/(dashboard)/settings/ai/page.tsx (1)
481-502: Unused variables from hook destructuring.After removing the provider/model selection UI, the following destructured values appear unused:
models,modelsLoading, andfetchModels. Consider removing them to reduce confusion:const { isDevMode, provider, model, - models, - modelsLoading, routes, prompts, // ... - fetchModels, } = useSettingsAIController()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/`(dashboard)/settings/ai/page.tsx around lines 481 - 502, The destructuring of useSettingsAIController includes unused values models, modelsLoading, and fetchModels; remove these three identifiers from the destructuring assignment in page.tsx and also remove them from the return object of useSettingsAIController (or cease returning them) so the hook signature and its consumers stay consistent (refer to useSettingsAIController and the destructured list including isDevMode/provider/model/.../handleStrategiesToggle).lib/ai/ai-center-defaults.ts (1)
25-25: Stale comment example.The comment mentions
'gpt-5.4'as an example model ID, but OpenAI support has been removed. Consider updating to only show Gemini examples:- /** Model ID no formato bare, sem prefixo de provider (ex: 'gemini-2.5-flash', 'gpt-5.4'). */ + /** Model ID no formato bare, sem prefixo de provider (ex: 'gemini-2.5-flash'). */🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/ai/ai-center-defaults.ts` at line 25, Update the stale JSDoc comment that currently reads "Model ID no formato bare, sem prefixo de provider (ex: 'gemini-2.5-flash', 'gpt-5.4')" to remove the OpenAI example and only show valid Gemini examples; locate the comment in lib/ai/ai-center-defaults.ts (the "Model ID no formato bare..." JSDoc above the model ID declaration) and replace the example list so it only includes Gemini model IDs (e.g., 'gemini-2.5-flash') and any other supported provider examples if applicable.components/features/settings/AIGatewayPanel.tsx (1)
60-183: This component is acting as a second AI-settings controller.It now duplicates
loadConfig, key save/remove, and model-fetch flows that already exist inhooks/useSettingsAI.ts. That makescomponents/features/settings/AIGatewayPanel.tsxand the hook two separate API clients for the same feature, which will drift quickly.As per coding guidelines:
components/features/**/*.tsx: Component files incomponents/features/should be pure presentational components with typed props interfaces.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/features/settings/AIGatewayPanel.tsx` around lines 60 - 183, This component duplicates API/client logic (loadConfig, fetchModels, handleSaveKey, handleRemoveKey, handleSelectModel) that already lives in hooks/useSettingsAI.ts; refactor AIGatewayPanel to be a pure presentational component that consumes the hook instead of re-implementing it: remove the internal loadConfig, fetchModels, handleSaveKey, handleRemoveKey, handleSelectModel and providerState management, import and call useSettingsAI to get state (providerState, activeModel, loading, saving) and handlers (loadConfig/fetchModels/saveKey/removeKey/selectModel or similarly named functions exported by the hook), wire those hook values/handlers into the JSX props/controls, and ensure any local UI-only state (e.g., showKey, modelSearch) remains minimal or is lifted into typed props; keep component file purely presentational with typed props if needed and rely on unique symbols loadConfig, fetchModels, handleSaveKey, handleRemoveKey, handleSelectModel and the hook useSettingsAI for the remote logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/ai/ai-center-config.ts`:
- Around line 132-139: The getAiDirectConfig() path currently reads only
Supabase keys and a legacy 'gemini_api_key' row; restore the
environment-variable fallback by checking
process.env.GOOGLE_GENERATIVE_AI_API_KEY and process.env.GEMINI_API_KEY when
resolving googleApiKey before calling normalizeDirect. Concretely, update the
Promise.all result handling around getSettingValue(SETTINGS_KEYS.googleApiKey)
and the assignment to cachedDirect so that googleApiKey falls back to
process.env.GOOGLE_GENERATIVE_AI_API_KEY || process.env.GEMINI_API_KEY ||
geminiApiKeyLegacy, then pass that resolved value into normalizeDirect (retain
parseJsonSetting and normalizeDirect usages).
In `@types.ts`:
- Line 588: The EmbeddingProvider type was narrowed to 'google' causing a
mismatch with route schemas that still accept 'openai' | 'voyage' | 'cohere';
revert or widen EmbeddingProvider so it includes 'openai' | 'voyage' | 'cohere'
(and 'google' if intended) to restore compatibility with
AIAgent.embedding_provider and the API routes (or alternatively update the route
schemas to match the new narrowed set); locate the type alias EmbeddingProvider
in types.ts and adjust its union to match the accepted values used in the
ai-agents route handlers and data contracts.
---
Outside diff comments:
In `@app/api/ai-agents/`[id]/chat/route.ts:
- Around line 46-48: The schema enum for embedding_provider in
app/api/ai-agents/route.ts and app/api/ai-agents/[id]/route.ts must match the
actual EmbeddingProvider type (lib/ai/embeddings.ts) and the chat logic: change
the allowed values from ['google','openai','voyage','cohere'] to only ['google']
and update the update-endpoint variant to the optional form (e.g., use the
z.enum(['google']).optional() or equivalent) so that validation matches the
EmbeddingProvider type and EMBEDDING_API_KEY_MAP lookups won't return undefined.
In `@app/api/ai-agents/`[id]/test/route.ts:
- Around line 23-25: EMBEDDING_API_KEY_MAP in
app/api/ai-agents/[id]/test/route.ts only contains a google entry so lookups for
agents whose embedding_provider is not "google" will fail; fix by (a) updating
the agent creation schema in app/api/ai-agents/route.ts to ensure
embedding_provider is validated/defaulted to supported providers (matching DB
values used elsewhere) and (b) making EMBEDDING_API_KEY_MAP and the lookup in
test/route.ts robust: either add entries for all supported providers or guard
the lookup (e.g., fall back to a safe default or throw a clear error) so
getEmbeddingApiKey(embedding_provider) cannot return undefined for valid DB
values. Ensure you update the symbols EMBEDDING_API_KEY_MAP and the agent
creation schema (where embedding_provider is defined) so both routes (chat and
test) handle non-google providers consistently.
In `@app/api/ai/models/route.ts`:
- Around line 77-95: The GET handler currently reads the tenant Google key and
calls fetchGoogleModels without authenticating; before calling getSettingValue
or fetchGoogleModels, call and await verifyApiKey() (importing it from
lib/auth.ts) and return an appropriate unauthorized response if it throws or
returns a falsy value. Update the GET function to first run verifyApiKey(), then
proceed to call getSettingValue('google_api_key') and fetchGoogleModels(apiKey)
only after successful verification, and ensure error handling still returns
NextResponse.json with status 502 for fetch errors and a 401/403 NextResponse
for auth failures.
In `@app/api/settings/ai/route.ts`:
- Around line 58-119: This route exposes AI settings without auth; import and
call verifyApiKey() from lib/auth.ts at the start of each handler (GET, POST,
DELETE) in this file and return an unauthorized NextResponse if verification
fails; ensure the call is awaited (e.g., const ok = await verifyApiKey(req) or
wrap in try/catch if verifyApiKey throws) so no settings logic
(prepareAiDirectUpdate, prepareAiRoutesUpdate, etc.) runs for unauthenticated
requests.
- Around line 126-196: The POST handler accepts arbitrary JSON for routes,
prompts, and ocr_gemini_model and merges it into persisted settings which can
corrupt downstream readers; add explicit Zod validation in the POST function to
parse and validate the incoming body (provider, model, google_api_key, routes,
prompts, ocr_gemini_model) before any merges, rejecting invalid payloads with a
400; for routes and prompts validate against the existing normalized shapes used
by prepareAiRoutesUpdate and the prompts normalization
(utilityGenerationTemplate, utilityJudgeTemplate, flowFormTemplate and optional
strategyMarketing/strategyUtility/strategyBypass) and only write validated
fields to updates, and validate ocr_gemini_model against an allowed string/enum
schema before pushing key 'ocr_gemini_model' to updates.
In `@lib/ai/ai-center-defaults.ts`:
- Around line 14-29: Remove the stale openaiApiKey handling: delete the
destructuring that pulls openaiApiKey and any derived boolean like hasOpenAIKey
in the module (e.g., the openaiApiKey variable and hasOpenAIKey check in
system.ts), and remove any conditional branches that only run when hasOpenAIKey
is true; ensure all remaining logic uses the current AiDirectConfig fields (like
googleApiKey) and that no other references to openaiApiKey or hasOpenAIKey
remain.
In `@lib/mcp/tools/settings.ts`:
- Around line 81-103: The tool sz.settings.set_ai currently sends the old route
keys (inbox_suggest, inbox_chat, template_generation, ocr) which the backend
silently drops; fix this by normalizing the routes before sending—import and
call prepareAiRoutesUpdate(routes) (or otherwise map the incoming routes to the
backend's expected keys like generateUtilityTemplates/generateFlowForm) and
include the normalized result in the POST body instead of the raw routes
variable; update the async handler in settings.ts to use the output of
prepareAiRoutesUpdate when building JSON.stringify({ model, google_api_key,
routes: normalizedRoutes }).
---
Nitpick comments:
In `@app/`(dashboard)/settings/ai/page.tsx:
- Around line 481-502: The destructuring of useSettingsAIController includes
unused values models, modelsLoading, and fetchModels; remove these three
identifiers from the destructuring assignment in page.tsx and also remove them
from the return object of useSettingsAIController (or cease returning them) so
the hook signature and its consumers stay consistent (refer to
useSettingsAIController and the destructured list including
isDevMode/provider/model/.../handleStrategiesToggle).
In `@app/api/ai/models/route.ts`:
- Around line 87-93: The catch block in route.ts currently returns only { error
} losing the provider error text; update the error response inside the catch
(where message is derived and NextResponse.json is returned) to include details:
message (i.e., return { error: `Falha ao buscar modelos: ${message}`, details:
message } with the existing status 502) so clients following the repository-wide
API convention receive the provider failure text.
In `@components/features/settings/AIGatewayPanel.tsx`:
- Around line 60-183: This component duplicates API/client logic (loadConfig,
fetchModels, handleSaveKey, handleRemoveKey, handleSelectModel) that already
lives in hooks/useSettingsAI.ts; refactor AIGatewayPanel to be a pure
presentational component that consumes the hook instead of re-implementing it:
remove the internal loadConfig, fetchModels, handleSaveKey, handleRemoveKey,
handleSelectModel and providerState management, import and call useSettingsAI to
get state (providerState, activeModel, loading, saving) and handlers
(loadConfig/fetchModels/saveKey/removeKey/selectModel or similarly named
functions exported by the hook), wire those hook values/handlers into the JSX
props/controls, and ensure any local UI-only state (e.g., showKey, modelSearch)
remains minimal or is lifted into typed props; keep component file purely
presentational with typed props if needed and rely on unique symbols loadConfig,
fetchModels, handleSaveKey, handleRemoveKey, handleSelectModel and the hook
useSettingsAI for the remote logic.
In `@lib/ai/ai-center-defaults.ts`:
- Line 25: Update the stale JSDoc comment that currently reads "Model ID no
formato bare, sem prefixo de provider (ex: 'gemini-2.5-flash', 'gpt-5.4')" to
remove the OpenAI example and only show valid Gemini examples; locate the
comment in lib/ai/ai-center-defaults.ts (the "Model ID no formato bare..." JSDoc
above the model ID declaration) and replace the example list so it only includes
Gemini model IDs (e.g., 'gemini-2.5-flash') and any other supported provider
examples if applicable.
In `@lib/ai/services/ai-judge.ts`:
- Around line 30-32: The Google-only path in ai-judge.ts ignores the
caller-supplied key in JudgeOptions, so update the Google client creation to
prefer options.apiKey over the DB setting (use options.apiKey ??
config.googleApiKey when calling createGoogleGenerativeAI) and pass that value
into google(targetModelId); alternatively remove apiKey from JudgeOptions if
intentional. Locate the code around createGoogleGenerativeAI, the google
variable and the model assignment (google(targetModelId)) and apply the key
preference or remove the option from the public contract accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 495d4853-9037-4529-a86b-063dc5833b2e
📒 Files selected for processing (27)
app/(dashboard)/settings/ai/page.tsxapp/api/ai-agents/[id]/chat/route.tsapp/api/ai-agents/[id]/test/route.tsapp/api/ai-agents/embedding-providers/route.tsapp/api/ai-agents/knowledge/route.tsapp/api/ai-agents/llm-providers/route.tsapp/api/ai/models/route.tsapp/api/inbox/chat/route.tsapp/api/inbox/suggest/route.tsapp/api/settings/ai/route.tsapp/api/settings/all/route.tscomponents/features/settings/AIGatewayPanel.tsxcomponents/features/settings/ai-agents/AIAgentForm.tsxcomponents/features/settings/types.tshooks/useSettingsAI.tslib/ai/agents/chat-agent.tslib/ai/ai-center-config.tslib/ai/ai-center-defaults.tslib/ai/embeddings.tslib/ai/providers.tslib/ai/services/ai-judge.tslib/ai/services/template-agent.tslib/ai/unified-ai-service.tslib/mcp/tools/settings.tslib/supabase-db.tsservices/settingsService.tstypes.ts
💤 Files with no reviewable changes (3)
- app/api/ai-agents/knowledge/route.ts
- app/api/ai-agents/llm-providers/route.ts
- app/api/ai-agents/embedding-providers/route.ts
| const [rawDirect, googleApiKey, geminiApiKeyLegacy] = await Promise.all([ | ||
| getSettingValue(SETTINGS_KEYS.direct), | ||
| getSettingValue(SETTINGS_KEYS.googleApiKey), | ||
| getSettingValue('gemini_api_key'), // retrocompatibilidade: chave pode estar salva com nome antigo | ||
| getSettingValue(SETTINGS_KEYS.openaiApiKey), | ||
| ]) | ||
|
|
||
| const parsed = parseJsonSetting<Partial<Pick<AiDirectConfig, 'provider' | 'model'>>>(rawDirect, {}) | ||
| cachedDirect = normalizeDirect(parsed, googleApiKey || geminiApiKeyLegacy, openaiApiKey) | ||
| cachedDirect = normalizeDirect(parsed, googleApiKey || geminiApiKeyLegacy) |
There was a problem hiding this comment.
Restore env-key fallback in getAiDirectConfig().
This path now only checks Supabase plus the legacy gemini_api_key row. Deployments relying on GEMINI_API_KEY or GOOGLE_GENERATIVE_AI_API_KEY will suddenly look unconfigured, and downstream callers like lib/ai/agents/chat-agent.ts will fail with the new “Chave Google não configurada” path.
Suggested fix
export async function getAiDirectConfig(): Promise<AiDirectConfig> {
if (cachedDirect && isCacheValid()) return cachedDirect
const [rawDirect, googleApiKey, geminiApiKeyLegacy] = await Promise.all([
getSettingValue(SETTINGS_KEYS.direct),
getSettingValue(SETTINGS_KEYS.googleApiKey),
getSettingValue('gemini_api_key'), // retrocompatibilidade: chave pode estar salva com nome antigo
])
+ const envGoogleApiKey =
+ process.env.GEMINI_API_KEY ||
+ process.env.GOOGLE_GENERATIVE_AI_API_KEY ||
+ null
const parsed = parseJsonSetting<Partial<Pick<AiDirectConfig, 'provider' | 'model'>>>(rawDirect, {})
- cachedDirect = normalizeDirect(parsed, googleApiKey || geminiApiKeyLegacy)
+ cachedDirect = normalizeDirect(
+ parsed,
+ googleApiKey || geminiApiKeyLegacy || envGoogleApiKey
+ )
cacheTime = Date.now()
return cachedDirect
}Based on learnings: Support environment variable aliases: GEMINI_API_KEY/GOOGLE_GENERATIVE_AI_API_KEY.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const [rawDirect, googleApiKey, geminiApiKeyLegacy] = await Promise.all([ | |
| getSettingValue(SETTINGS_KEYS.direct), | |
| getSettingValue(SETTINGS_KEYS.googleApiKey), | |
| getSettingValue('gemini_api_key'), // retrocompatibilidade: chave pode estar salva com nome antigo | |
| getSettingValue(SETTINGS_KEYS.openaiApiKey), | |
| ]) | |
| const parsed = parseJsonSetting<Partial<Pick<AiDirectConfig, 'provider' | 'model'>>>(rawDirect, {}) | |
| cachedDirect = normalizeDirect(parsed, googleApiKey || geminiApiKeyLegacy, openaiApiKey) | |
| cachedDirect = normalizeDirect(parsed, googleApiKey || geminiApiKeyLegacy) | |
| const [rawDirect, googleApiKey, geminiApiKeyLegacy] = await Promise.all([ | |
| getSettingValue(SETTINGS_KEYS.direct), | |
| getSettingValue(SETTINGS_KEYS.googleApiKey), | |
| getSettingValue('gemini_api_key'), // retrocompatibilidade: chave pode estar salva com nome antigo | |
| ]) | |
| const envGoogleApiKey = | |
| process.env.GEMINI_API_KEY || | |
| process.env.GOOGLE_GENERATIVE_AI_API_KEY || | |
| null | |
| const parsed = parseJsonSetting<Partial<Pick<AiDirectConfig, 'provider' | 'model'>>>(rawDirect, {}) | |
| cachedDirect = normalizeDirect( | |
| parsed, | |
| googleApiKey || geminiApiKeyLegacy || envGoogleApiKey | |
| ) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/ai/ai-center-config.ts` around lines 132 - 139, The getAiDirectConfig()
path currently reads only Supabase keys and a legacy 'gemini_api_key' row;
restore the environment-variable fallback by checking
process.env.GOOGLE_GENERATIVE_AI_API_KEY and process.env.GEMINI_API_KEY when
resolving googleApiKey before calling normalizeDirect. Concretely, update the
Promise.all result handling around getSettingValue(SETTINGS_KEYS.googleApiKey)
and the assignment to cachedDirect so that googleApiKey falls back to
process.env.GOOGLE_GENERATIVE_AI_API_KEY || process.env.GEMINI_API_KEY ||
geminiApiKeyLegacy, then pass that resolved value into normalizeDirect (retain
parseJsonSetting and normalizeDirect usages).
|
|
||
| // T004: AIAgent interface | ||
| export type EmbeddingProvider = 'google' | 'openai' | 'voyage' | 'cohere'; | ||
| export type EmbeddingProvider = 'google'; |
There was a problem hiding this comment.
Keep this type aligned with the route schemas until those endpoints are narrowed too.
app/api/ai-agents/route.ts and app/api/ai-agents/[id]/route.ts still accept 'openai' | 'voyage' | 'cohere' for embedding_provider, so narrowing EmbeddingProvider to 'google' makes AIAgent.embedding_provider incompatible with the current API/data contract. Loading or editing legacy agents will now require casts or fail type checks.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@types.ts` at line 588, The EmbeddingProvider type was narrowed to 'google'
causing a mismatch with route schemas that still accept 'openai' | 'voyage' |
'cohere'; revert or widen EmbeddingProvider so it includes 'openai' | 'voyage' |
'cohere' (and 'google' if intended) to restore compatibility with
AIAgent.embedding_provider and the API routes (or alternatively update the route
schemas to match the new narrowed set); locate the type alias EmbeddingProvider
in types.ts and adjust its union to match the accepted values used in the
ai-agents route handlers and data contracts.
Code reviewFound 1 issue:
smartzap/app/api/ai-agents/[id]/chat/route.ts Lines 279 to 287 in b6e039c smartzap/app/api/ai-agents/[id]/test/route.ts Lines 188 to 192 in b6e039c smartzap/app/api/ai-agents/route.ts Lines 31 to 33 in b6e039c Fix: add 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
Summary
AIProvidereEmbeddingProviderpara tipo literal'google'openai_api_keydo Supabase settings, da config, dos endpoints e da UI/settings/aiArquivos principais
lib/ai/providers.tsAIProvider = 'google'(era union com openai)lib/ai/ai-center-defaults.tsopenaiApiKeydeAiDirectConfiglib/ai/embeddings.tsEmbeddingProvider = 'google', removidos OpenAI/Voyage/Coherelib/ai/unified-ai-service.tscreateModelInstance()lib/ai/agents/chat-agent.tsapp/api/ai/models/route.tsfetchOpenAIModels, sem param?provider=lib/supabase-db.tscontactDb.getStats()usacount: 'exact', head: trueem paraleloapp/(dashboard)/settings/ai/page.tsxVerificação
tsc --noEmit— 0 erros🤖 Generated with Claude Code
Summary by CodeRabbit