import type { TSchema } from "typebox"; import {
cleanSchemaForGemini,
GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS,
} from "../agents/schema/clean-for-gemini.js"; import type { ModelCompatConfig } from "../config/types.models.js"; import { applyModelCompatPatch } from "../plugins/provider-model-compat.js"; import type {
AnyAgentTool,
ProviderNormalizeToolSchemasContext,
ProviderToolSchemaDiagnostic,
} from "./plugin-entry.js";
export function applyXaiModelCompat<T extends { compat?: unknown }>(model: T): T { return applyModelCompatPatch(
model as T & { compat?: ModelCompatConfig },
resolveXaiModelCompatPatch(),
) as T;
}
export function findUnsupportedSchemaKeywords(
schema: unknown,
path: string,
unsupportedKeywords: ReadonlySet<string>,
): string[] { if (!schema || typeof schema !== "object") { return [];
} if (Array.isArray(schema)) { return schema.flatMap((item, index) =>
findUnsupportedSchemaKeywords(item, `${path}[${index}]`, unsupportedKeywords),
);
} const record = schema as Record<string, unknown>; const violations: string[] = []; const properties =
record.properties && typeof record.properties === "object" && !Array.isArray(record.properties)
? (record.properties as Record<string, unknown>)
: undefined; if (properties) { for (const [key, value] of Object.entries(properties)) {
violations.push(
...findUnsupportedSchemaKeywords(value, `${path}.properties.${key}`, unsupportedKeywords),
);
}
} for (const [key, value] of Object.entries(record)) { if (key === "properties") { continue;
} if (unsupportedKeywords.has(key)) {
violations.push(`${path}.${key}`);
} if (value && typeof value === "object") {
violations.push(
...findUnsupportedSchemaKeywords(value, `${path}.${key}`, unsupportedKeywords),
);
}
} return violations;
}
if (
normalized.type === "object" &&
hasEmptyProperties &&
!("additionalProperties" in normalized)
) {
normalized.additionalProperties = false;
changed = true;
}
return changed ? normalized : schema;
}
export function findOpenAIStrictSchemaViolations(
schema: unknown,
path: string,
options?: { requireObjectRoot?: boolean },
): string[] { if (Array.isArray(schema)) { if (options?.requireObjectRoot) { return [`${path}.type`];
} return schema.flatMap((item, index) =>
findOpenAIStrictSchemaViolations(item, `${path}[${index}]`),
);
} if (!schema || typeof schema !== "object") { if (options?.requireObjectRoot) { return [`${path}.type`];
} return [];
}
const record = schema as Record<string, unknown>; const violations: string[] = []; for (const key of ["anyOf", "oneOf", "allOf"] as const) { if (Array.isArray(record[key])) {
violations.push(`${path}.${key}`);
}
} if (Array.isArray(record.type)) {
violations.push(`${path}.type`);
}
if (record.type === "object") { if (record.additionalProperties !== false) {
violations.push(`${path}.additionalProperties`);
} const required = Array.isArray(record.required)
? record.required.filter((entry): entry is string => typeof entry === "string")
: undefined; if (!required) {
violations.push(`${path}.required`);
} elseif (properties) { const requiredSet = new Set(required); for (const key of Object.keys(properties)) { if (!requiredSet.has(key)) {
violations.push(`${path}.required.${key}`);
}
}
}
}
if (properties) { for (const [key, value] of Object.entries(properties)) {
violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.properties.${key}`));
}
}
for (const [key, value] of Object.entries(record)) { if (key === "properties") { continue;
} if (value && typeof value === "object") {
violations.push(...findOpenAIStrictSchemaViolations(value, `${path}.${key}`));
}
}
return violations;
}
export function inspectOpenAIToolSchemas(
ctx: ProviderNormalizeToolSchemasContext,
): ProviderToolSchemaDiagnostic[] { if (!shouldApplyOpenAIToolCompat(ctx)) { return [];
} // Native OpenAI transports fall back to `strict: false` when any tool schema is not // strict-compatible, so these findings are expected for optional-heavy tool schemas. return [];
}
export type ProviderToolCompatFamily = "gemini" | "openai";
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.