Skip to content

Commit 303187f

Browse files
refactor(gateway): centralize request normalization (#3642)
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
1 parent fcaad53 commit 303187f

2 files changed

Lines changed: 38 additions & 32 deletions

File tree

apps/web/src/app/api/openrouter/[...path]/route.ts

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { NextResponse, type NextResponse as NextResponseType } from 'next/server';
22
import { type NextRequest } from 'next/server';
3-
import { isOpenCodeBasedClient, stripRequiredPrefix } from '@/lib/utils';
4-
import { applyTrackingIds } from '@/lib/ai-gateway/providerHash';
3+
import { stripRequiredPrefix } from '@/lib/utils';
54
import { extractPromptInfo } from '@/lib/ai-gateway/extractPromptInfo';
65
import { determineFallbackFeature } from '@/lib/ai-gateway/determineFallbackFeature';
76
import {
@@ -57,7 +56,6 @@ import {
5756
} from '@/lib/ai-gateway/llm-proxy-helpers';
5857
import { ProxyErrorType } from '@/lib/proxy-error-types';
5958
import { getBalanceAndOrgSettings } from '@/lib/organizations/organization-usage';
60-
import { repairTools, sanitizeBinaryToolResults } from '@/lib/ai-gateway/tool-calling';
6159
import { isDataCollectionExplicitlyDisallowed } from '@/lib/ai-gateway/providers/openrouter/types';
6260
import {
6361
rewriteFreeModelResponse_ChatCompletions,
@@ -98,11 +96,8 @@ import { isForbiddenFreeModel } from '@/lib/ai-gateway/forbidden-free-models';
9896
import { isCloudflareIP } from '@/lib/cloudflare-ip';
9997
import { isKiloAutoModel, KILO_AUTO_FREE_MODEL } from '@/lib/ai-gateway/auto-model';
10098
import { applyResolvedAutoModel } from '@/lib/ai-gateway/auto-model/resolution';
101-
import { fixOpenCodeDuplicateReasoning } from '@/lib/ai-gateway/providers/fixOpenCodeDuplicateReasoning';
10299
import type { MicrodollarUsageContext } from '@/lib/ai-gateway/processUsage.types';
103100
import {
104-
enableReasoningSummaries,
105-
fixResponsesRequest,
106101
getMaxTokens,
107102
hasMiddleOutTransform,
108103
} from '@/lib/ai-gateway/providers/openrouter/request-helpers';
@@ -678,39 +673,21 @@ export async function POST(request: NextRequest): Promise<NextResponseType<unkno
678673
op: 'http.client',
679674
});
680675

681-
applyTrackingIds(requestBodyParsed, effectiveProviderContext.provider, user.id, taskId ?? null);
682-
683-
sanitizeBinaryToolResults(requestBodyParsed);
684-
685-
if (requestBodyParsed.kind === 'chat_completions') {
686-
// Mostly a workaround for bugs in the old extension.
687-
repairTools(requestBodyParsed.body);
688-
689-
if (isOpenCodeBasedClient(fraudHeaders)) {
690-
// Workaround for bugs in the chat completions client.
691-
fixOpenCodeDuplicateReasoning(effectiveModelIdLowerCased, requestBodyParsed.body, taskId);
692-
}
693-
}
694-
695-
if (requestBodyParsed.kind === 'responses') {
696-
fixResponsesRequest(requestBodyParsed.body);
697-
}
698-
699-
enableReasoningSummaries(requestBodyParsed);
700-
701-
const toolsAvailable = getToolsAvailable(requestBodyParsed);
702-
const toolsUsed = getToolsUsed(requestBodyParsed);
703-
704676
const extraHeaders: Record<string, string> = {};
705677
applyProviderSpecificLogic(
706678
effectiveProviderContext.provider,
707679
effectiveModelIdLowerCased,
708680
requestBodyParsed,
709681
extraHeaders,
710682
effectiveProviderContext.userByok,
711-
fraudHeaders
683+
fraudHeaders,
684+
user.id,
685+
taskId ?? null
712686
);
713687

688+
const toolsAvailable = getToolsAvailable(requestBodyParsed);
689+
const toolsUsed = getToolsUsed(requestBodyParsed);
690+
714691
// Capture the bounded prompt for experimented requests AFTER provider
715692
// transforms have produced the canonical upstream body. Stored on the
716693
// usage context so the async `after()` hook can persist it without

apps/web/src/lib/ai-gateway/providers/apply-provider-specific-logic.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,14 @@ import { isMinimaxModel } from '@/lib/ai-gateway/providers/minimax';
1616
import type { BYOKResult, Provider } from '@/lib/ai-gateway/providers/types';
1717
import { isStepModel } from '@/lib/ai-gateway/providers/stepfun';
1818
import { isDeepseekModel } from '@/lib/ai-gateway/providers/deepseek';
19-
import type { FraudDetectionHeaders } from '@/lib/utils';
19+
import { isOpenCodeBasedClient, type FraudDetectionHeaders } from '@/lib/utils';
20+
import { applyTrackingIds } from '@/lib/ai-gateway/providerHash';
21+
import { repairTools, sanitizeBinaryToolResults } from '@/lib/ai-gateway/tool-calling';
22+
import { fixOpenCodeDuplicateReasoning } from '@/lib/ai-gateway/providers/fixOpenCodeDuplicateReasoning';
23+
import {
24+
enableReasoningSummaries,
25+
fixResponsesRequest,
26+
} from '@/lib/ai-gateway/providers/openrouter/request-helpers';
2027

2128
export function getPreferredProviderOrder(requestedModel: string): string[] {
2229
if (isClaudeModel(requestedModel)) {
@@ -79,8 +86,30 @@ export function applyProviderSpecificLogic(
7986
requestToMutate: GatewayRequest,
8087
extraHeaders: Record<string, string>,
8188
userByok: BYOKResult[] | null,
82-
originalHeaders: FraudDetectionHeaders
89+
originalHeaders: FraudDetectionHeaders,
90+
userId: string,
91+
taskId: string | null
8392
) {
93+
applyTrackingIds(requestToMutate, provider, userId, taskId);
94+
95+
sanitizeBinaryToolResults(requestToMutate);
96+
97+
if (requestToMutate.kind === 'chat_completions') {
98+
// Mostly a workaround for bugs in the old extension.
99+
repairTools(requestToMutate.body);
100+
101+
if (isOpenCodeBasedClient(originalHeaders)) {
102+
// Workaround for bugs in the chat completions client.
103+
fixOpenCodeDuplicateReasoning(requestedModel, requestToMutate.body, taskId ?? undefined);
104+
}
105+
}
106+
107+
if (requestToMutate.kind === 'responses') {
108+
fixResponsesRequest(requestToMutate.body);
109+
}
110+
111+
enableReasoningSummaries(requestToMutate);
112+
84113
const kiloExclusiveModel = findKiloExclusiveModel(requestedModel);
85114
if (kiloExclusiveModel) {
86115
applyKiloExclusiveModelSettings(requestToMutate, kiloExclusiveModel);

0 commit comments

Comments
 (0)