mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-14 11:12:17 +03:00
fix(types): normalize executor result contracts (#10256)
This commit is contained in:
@@ -387,6 +387,12 @@ import {
|
||||
isRpmExhausted,
|
||||
} from "../services/geminiRateLimitTracker.ts";
|
||||
import { isSmallEnoughForSemanticCache } from "../utils/estimateSize.ts";
|
||||
|
||||
type ChatCoreExecutorResult = ReturnType<typeof normalizeExecutorResult> & {
|
||||
_executionCredentials?: Record<string, unknown>;
|
||||
_accountSemaphoreRelease?: () => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Core chat handler - shared between SSE and Worker
|
||||
* Returns { success, response, status, error } for caller to handle fallback
|
||||
@@ -2731,7 +2737,7 @@ export async function handleChatCore({
|
||||
|
||||
let releaseRawResultAccountSemaphore = () => {};
|
||||
try {
|
||||
const rawResult = await (async () => {
|
||||
const rawResult: ChatCoreExecutorResult = await (async () => {
|
||||
let attempts = 0;
|
||||
const isModelScopeForRequest = isModelScope();
|
||||
const maxAttempts = isModelScopeForRequest ? 3 : provider === "codex" ? 3 : 1;
|
||||
@@ -3550,22 +3556,24 @@ export async function handleChatCore({
|
||||
// stay aligned if this block ever runs after a path that mutates body.model (e.g. fallback).
|
||||
try {
|
||||
const retryModelId = String(translatedBody.model || effectiveModel);
|
||||
const retryResult = await runWithCapture(providerRequestCapture, () =>
|
||||
executor.execute({
|
||||
model: retryModelId,
|
||||
body: translatedBody,
|
||||
stream: upstreamStream,
|
||||
credentials: getExecutionCredentials(),
|
||||
signal: streamController.signal,
|
||||
log,
|
||||
extendedContext,
|
||||
upstreamExtraHeaders: buildUpstreamHeadersForExecute(retryModelId),
|
||||
clientHeaders: buildExecutorClientHeaders(clientRawRequest?.headers, userAgent),
|
||||
clientResponseFormat,
|
||||
onCredentialsRefreshed,
|
||||
skipUpstreamRetry: isCombo,
|
||||
contextEditing: { enabled: contextEditingEnabled },
|
||||
})
|
||||
const retryResult = normalizeExecutorResult(
|
||||
await runWithCapture(providerRequestCapture, () =>
|
||||
executor.execute({
|
||||
model: retryModelId,
|
||||
body: translatedBody,
|
||||
stream: upstreamStream,
|
||||
credentials: getExecutionCredentials(),
|
||||
signal: streamController.signal,
|
||||
log,
|
||||
extendedContext,
|
||||
upstreamExtraHeaders: buildUpstreamHeadersForExecute(retryModelId),
|
||||
clientHeaders: buildExecutorClientHeaders(clientRawRequest?.headers, userAgent),
|
||||
clientResponseFormat,
|
||||
onCredentialsRefreshed,
|
||||
skipUpstreamRetry: isCombo,
|
||||
contextEditing: { enabled: contextEditingEnabled },
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
if (retryResult.response.ok) {
|
||||
|
||||
@@ -20,6 +20,10 @@ type CredentialsLike =
|
||||
| null
|
||||
| undefined;
|
||||
|
||||
type ResolvedExecutionCredentials = Record<string, unknown> & {
|
||||
providerSpecificData: Record<string, unknown>;
|
||||
};
|
||||
|
||||
function buildKimiThinkingMetadata(
|
||||
modelInfo: Record<string, unknown> | null | undefined,
|
||||
staticThinkingPolicy: ReturnType<typeof getKimiCodeStaticThinkingPolicy>
|
||||
@@ -79,7 +83,7 @@ export function resolveExecutionCredentials(opts: {
|
||||
provider: string | null | undefined;
|
||||
ccSessionId: string | null;
|
||||
modelInfo?: Record<string, unknown> | null;
|
||||
}) {
|
||||
}): ResolvedExecutionCredentials {
|
||||
const {
|
||||
credentials,
|
||||
nativeCodexPassthrough,
|
||||
|
||||
@@ -98,17 +98,7 @@ export function getExecutorTimeoutMs(executor: unknown, provider?: string, model
|
||||
return resolveProviderTimeoutMs(executor);
|
||||
}
|
||||
|
||||
export function normalizeExecutorResult(
|
||||
result:
|
||||
| Response
|
||||
| {
|
||||
response: Response;
|
||||
url?: string;
|
||||
headers?: Record<string, string>;
|
||||
transformedBody?: unknown;
|
||||
transport?: string;
|
||||
}
|
||||
): {
|
||||
export function normalizeExecutorResult(result: unknown): {
|
||||
response: Response;
|
||||
url: string;
|
||||
headers: Record<string, string>;
|
||||
@@ -118,12 +108,27 @@ export function normalizeExecutorResult(
|
||||
if (result instanceof Response) {
|
||||
return { response: result, url: "", headers: {}, transformedBody: null };
|
||||
}
|
||||
if (
|
||||
!result ||
|
||||
typeof result !== "object" ||
|
||||
!("response" in result) ||
|
||||
!(result.response instanceof Response)
|
||||
) {
|
||||
throw new TypeError("Executor result must contain a Response");
|
||||
}
|
||||
const normalized = result as {
|
||||
response: Response;
|
||||
url?: string;
|
||||
headers?: Record<string, string>;
|
||||
transformedBody?: unknown;
|
||||
transport?: string;
|
||||
};
|
||||
return {
|
||||
response: result.response,
|
||||
url: result.url || "",
|
||||
headers: result.headers || {},
|
||||
transformedBody: result.transformedBody ?? null,
|
||||
transport: result.transport,
|
||||
response: normalized.response,
|
||||
url: normalized.url || "",
|
||||
headers: normalized.headers || {},
|
||||
transformedBody: normalized.transformedBody ?? null,
|
||||
transport: normalized.transport,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -49,3 +49,11 @@ test("normalizeExecutorResult wraps bare Response and passes through rich result
|
||||
assert.equal(rich.url, "u");
|
||||
assert.equal(rich.headers.a, "b");
|
||||
});
|
||||
|
||||
test("normalizeExecutorResult rejects malformed executor output", () => {
|
||||
assert.throws(() => normalizeExecutorResult({}), /must contain a Response/);
|
||||
assert.throws(
|
||||
() => normalizeExecutorResult({ response: "not-a-response" }),
|
||||
/must contain a Response/
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user