Skip to content

Commit 542d2ed

Browse files
waleedlatif1claude
andcommitted
fix(knowledge): require explicit Azure deployment per OpenAI embedding model
Greptile P1: when AZURE_OPENAI_* was set, every OpenAI embedding model was routed to the single KB_OPENAI_MODEL_NAME deployment. A KB created with text-embedding-3-large would be embedded by whatever model that deployment serves while billing tracked 3-large pricing — and chunks ingested via Azure versus queried via real OpenAI would land in mismatched vector spaces. Now require AZURE_OPENAI_DEPLOYMENT_TEXT_EMBEDDING_3_(SMALL|LARGE) per model. Falls back to KB_OPENAI_MODEL_NAME only for text-embedding-3-small (legacy). If no deployment is configured for the chosen model, route to direct OpenAI instead of silently routing to the wrong deployment. Also fix type predicate in search/route.ts to use KnowledgeBaseAccessResult so the build passes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 553021a commit 542d2ed

3 files changed

Lines changed: 27 additions & 21 deletions

File tree

apps/sim/app/api/knowledge/search/route.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {
2121
handleVectorOnlySearch,
2222
type SearchResult,
2323
} from '@/app/api/knowledge/search/utils'
24-
import { checkKnowledgeBaseAccess } from '@/app/api/knowledge/utils'
24+
import { checkKnowledgeBaseAccess, type KnowledgeBaseAccessResult } from '@/app/api/knowledge/utils'
2525
import { getRerankModelPricing } from '@/providers/models'
2626
import { calculateCost } from '@/providers/utils'
2727

@@ -243,18 +243,7 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
243243
}
244244

245245
const accessibleKbs = accessChecks
246-
.filter(
247-
(
248-
ac
249-
): ac is {
250-
hasAccess: true
251-
knowledgeBase: {
252-
id: string
253-
embeddingModel: string
254-
workspaceId?: string | null
255-
}
256-
} => Boolean(ac?.hasAccess)
257-
)
246+
.filter((ac): ac is KnowledgeBaseAccessResult => Boolean(ac?.hasAccess))
258247
.map((ac) => ac.knowledgeBase)
259248
const workspaceId = accessibleKbs[0]?.workspaceId
260249

apps/sim/lib/core/config/env.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ export const env = createEnv({
122122
AZURE_ANTHROPIC_ENDPOINT: z.string().url().optional(), // Azure Anthropic service endpoint
123123
AZURE_ANTHROPIC_API_KEY: z.string().min(1).optional(), // Azure Anthropic API key
124124
AZURE_ANTHROPIC_API_VERSION: z.string().min(1).optional(), // Azure Anthropic API version (e.g. 2023-06-01)
125-
KB_OPENAI_MODEL_NAME: z.string().optional(), // Knowledge base OpenAI model name (works with both regular OpenAI and Azure OpenAI)
125+
KB_OPENAI_MODEL_NAME: z.string().optional(), // Knowledge base OpenAI model name (works with both regular OpenAI and Azure OpenAI). Used as the Azure deployment for text-embedding-3-small (legacy/default).
126+
AZURE_OPENAI_DEPLOYMENT_TEXT_EMBEDDING_3_SMALL: z.string().optional(), // Azure deployment name serving text-embedding-3-small. If unset, falls back to KB_OPENAI_MODEL_NAME.
127+
AZURE_OPENAI_DEPLOYMENT_TEXT_EMBEDDING_3_LARGE: z.string().optional(), // Azure deployment name serving text-embedding-3-large. Required to use 3-large via Azure.
126128
WAND_OPENAI_MODEL_NAME: z.string().optional(), // Wand generation OpenAI model name (works with both regular OpenAI and Azure OpenAI)
127129
OCR_AZURE_ENDPOINT: z.string().url().optional(), // Azure Mistral OCR service endpoint
128130
OCR_AZURE_MODEL_NAME: z.string().optional(), // Azure Mistral OCR model name for document processing

apps/sim/lib/knowledge/embeddings.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,25 +173,40 @@ function buildGeminiProvider(modelName: string, apiKey: string): ResolvedProvide
173173
})
174174
}
175175

176+
/**
177+
* Resolve the Azure deployment name for a given OpenAI embedding model.
178+
* Returns null if no deployment is configured for that model — caller falls
179+
* back to direct OpenAI rather than risk routing to a wrong-model deployment
180+
* (which would silently produce mismatched vectors).
181+
*/
182+
function resolveAzureDeployment(embeddingModel: string): string | null {
183+
if (embeddingModel === 'text-embedding-3-small') {
184+
return env.AZURE_OPENAI_DEPLOYMENT_TEXT_EMBEDDING_3_SMALL || env.KB_OPENAI_MODEL_NAME || null
185+
}
186+
if (embeddingModel === 'text-embedding-3-large') {
187+
return env.AZURE_OPENAI_DEPLOYMENT_TEXT_EMBEDDING_3_LARGE || null
188+
}
189+
return null
190+
}
191+
176192
async function resolveProvider(
177193
embeddingModel: string,
178194
workspaceId?: string | null
179195
): Promise<ResolvedProvider> {
180196
const azureApiKey = env.AZURE_OPENAI_API_KEY
181197
const azureEndpoint = env.AZURE_OPENAI_ENDPOINT
182198
const azureApiVersion = env.AZURE_OPENAI_API_VERSION
183-
const useAzure =
184-
!!(azureApiKey && azureEndpoint) &&
185-
SUPPORTED_EMBEDDING_MODELS[embeddingModel]?.provider === 'openai'
199+
const isOpenAIModel = SUPPORTED_EMBEDDING_MODELS[embeddingModel]?.provider === 'openai'
200+
const azureDeployment =
201+
isOpenAIModel && azureApiKey && azureEndpoint ? resolveAzureDeployment(embeddingModel) : null
186202

187-
if (useAzure) {
188-
const deployment = env.KB_OPENAI_MODEL_NAME || embeddingModel
203+
if (azureDeployment) {
189204
return {
190-
modelName: deployment,
205+
modelName: azureDeployment,
191206
pricingId: getEmbeddingModelInfo(embeddingModel).pricingId,
192207
isBYOK: false,
193208
buildRequest: buildAzureOpenAIProvider(
194-
deployment,
209+
azureDeployment,
195210
azureApiKey!,
196211
azureEndpoint!,
197212
azureApiVersion!,

0 commit comments

Comments
 (0)