mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-03 05:45:04 +03:00
fix(gemini): harden schema sanitizing and streaming defaults
Remove unsupported Gemini schema fields including vendor-prefixed `x-` properties so translated tool definitions avoid rejected keywords. Emit an empty `content` field with the initial assistant role delta to keep OpenAI-compatible streaming output consistent for clients that expect content on the first chunk. Also force undici's fetch whenever a dispatcher is provided and treat `onRequestStart` version mismatches as fatal instead of falling back to native fetch, preventing broken proxy requests under mixed undici versions.
This commit is contained in:
@@ -42,6 +42,7 @@ export const UNSUPPORTED_SCHEMA_CONSTRAINTS = [
|
||||
"contentMediaType",
|
||||
"contentEncoding",
|
||||
// Non-standard schema fields (not recognized by Gemini API)
|
||||
"deprecated",
|
||||
"optional",
|
||||
// UI/Styling properties (from Cursor tools - NOT JSON Schema standard)
|
||||
"cornerRadius",
|
||||
@@ -185,9 +186,9 @@ function removeUnsupportedKeywords(obj, keywords) {
|
||||
}
|
||||
} else {
|
||||
// Delete unsupported keys at current level
|
||||
for (const keyword of keywords) {
|
||||
if (keyword in obj) {
|
||||
delete obj[keyword];
|
||||
for (const key of Object.keys(obj)) {
|
||||
if (keywords.includes(key) || key.startsWith("x-")) {
|
||||
delete obj[key];
|
||||
}
|
||||
}
|
||||
// Recurse into remaining values
|
||||
|
||||
@@ -28,7 +28,7 @@ export function geminiToOpenAIResponse(chunk, state) {
|
||||
choices: [
|
||||
{
|
||||
index: 0,
|
||||
delta: { role: "assistant" },
|
||||
delta: { role: "assistant", content: "" },
|
||||
finish_reason: null,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -165,6 +165,9 @@ export async function runWithProxyContext(proxyConfig, fn) {
|
||||
|
||||
async function patchedFetch(input: RequestInfo | URL, options: FetchWithDispatcherOptions = {}) {
|
||||
if (options?.dispatcher) {
|
||||
// When a dispatcher is present, we MUST use the undici library fetch
|
||||
// to ensure version compatibility. Node 22 built-in fetch (undici v6)
|
||||
// is incompatible with undici v8 dispatchers (missing onRequestStart, etc.)
|
||||
return (undiciFetch as unknown as (...args: unknown[]) => Promise<Response>)(input, options);
|
||||
}
|
||||
|
||||
@@ -206,7 +209,16 @@ async function patchedFetch(input: RequestInfo | URL, options: FetchWithDispatch
|
||||
dispatcher: getDefaultDispatcher(),
|
||||
});
|
||||
} catch (dispatcherError) {
|
||||
const msg = dispatcherError instanceof Error ? dispatcherError.message : String(dispatcherError);
|
||||
const msg =
|
||||
dispatcherError instanceof Error ? dispatcherError.message : String(dispatcherError);
|
||||
// CAUTION: Do NOT fallback to native fetch if the error is a version mismatch (invalid onRequestStart)
|
||||
// because the native fetch will definitely fail with the undici v8 dispatcher.
|
||||
if (msg.includes("onRequestStart")) {
|
||||
console.error(
|
||||
`[ProxyFetch] Fatal version mismatch: Dispatcher (v8) vs Fetch (v6/native). Hardware upgrade or SOCKS5 config isolation required. Error: ${msg}`
|
||||
);
|
||||
throw dispatcherError;
|
||||
}
|
||||
// Only fallback for connection/dispatcher errors, not HTTP errors
|
||||
if (msg.includes("fetch failed") || msg.includes("ECONNREFUSED") || msg.includes("UND_ERR")) {
|
||||
console.warn(`[ProxyFetch] Undici dispatcher failed, falling back to native fetch: ${msg}`);
|
||||
|
||||
Reference in New Issue
Block a user