



























@@ -394,13 +394,127 @@ export function inspectOpenAIToolSchemas(
394394return [];
395395}
396396397-export type ProviderToolCompatFamily = "gemini" | "openai";
397+export const DEEPSEEK_UNSUPPORTED_SCHEMA_KEYWORDS = new Set(["anyOf", "oneOf"]);
398+399+function isNullSchemaVariant(schema: unknown): boolean {
400+if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
401+return false;
402+}
403+const record = schema as Record<string, unknown>;
404+if (record.type === "null") {
405+return true;
406+}
407+if (Array.isArray(record.type) && record.type.length === 1 && record.type[0] === "null") {
408+return true;
409+}
410+if ("const" in record && record.const === null) {
411+return true;
412+}
413+return Array.isArray(record.enum) && record.enum.length === 1 && record.enum[0] === null;
414+}
415+416+function normalizeDeepSeekSchema(schema: unknown): unknown {
417+if (Array.isArray(schema)) {
418+let changed = false;
419+const normalized = schema.map((entry) => {
420+const next = normalizeDeepSeekSchema(entry);
421+changed ||= next !== entry;
422+return next;
423+});
424+return changed ? normalized : schema;
425+}
426+if (!schema || typeof schema !== "object") {
427+return schema;
428+}
429+430+const record = schema as Record<string, unknown>;
431+const unionKey = Array.isArray(record.anyOf)
432+ ? "anyOf"
433+ : Array.isArray(record.oneOf)
434+ ? "oneOf"
435+ : undefined;
436+437+let changed = false;
438+const normalized: Record<string, unknown> = {};
439+for (const [key, value] of Object.entries(record)) {
440+if (key === "anyOf" || key === "oneOf") {
441+if (key === unionKey) {
442+changed = true;
443+continue;
444+}
445+}
446+const next = normalizeDeepSeekSchema(value);
447+normalized[key] = next;
448+changed ||= next !== value;
449+}
450+451+if (!unionKey) {
452+return changed ? normalized : schema;
453+}
454+455+const variants = record[unionKey] as unknown[];
456+const normalizedVariants = variants.map((entry) => normalizeDeepSeekSchema(entry));
457+const nonNullVariants = normalizedVariants.filter((entry) => !isNullSchemaVariant(entry));
458+const selected = nonNullVariants[0] ?? normalizedVariants[0];
459+if (!selected || typeof selected !== "object" || Array.isArray(selected)) {
460+return normalized;
461+}
462+463+const merged = {
464+ ...(selected as Record<string, unknown>),
465+ ...normalized,
466+};
467+if (nonNullVariants.length < normalizedVariants.length) {
468+merged.nullable = true;
469+}
470+return merged;
471+}
472+473+export function normalizeDeepSeekToolSchemas(
474+ctx: ProviderNormalizeToolSchemasContext,
475+): AnyAgentTool[] {
476+return ctx.tools.map((tool) => {
477+if (!tool.parameters || typeof tool.parameters !== "object") {
478+return tool;
479+}
480+const parameters = normalizeDeepSeekSchema(tool.parameters);
481+return parameters === tool.parameters
482+ ? tool
483+ : {
484+ ...tool,
485+parameters: parameters as TSchema,
486+};
487+});
488+}
489+490+export function inspectDeepSeekToolSchemas(
491+ctx: ProviderNormalizeToolSchemasContext,
492+): ProviderToolSchemaDiagnostic[] {
493+return ctx.tools.flatMap((tool, toolIndex) => {
494+const violations = findUnsupportedSchemaKeywords(
495+tool.parameters,
496+`${tool.name}.parameters`,
497+DEEPSEEK_UNSUPPORTED_SCHEMA_KEYWORDS,
498+);
499+if (violations.length === 0) {
500+return [];
501+}
502+return [{ toolName: tool.name, toolIndex, violations }];
503+});
504+}
505+506+export type ProviderToolCompatFamily = "deepseek" | "gemini" | "openai";
398507399508export function buildProviderToolCompatFamilyHooks(family: ProviderToolCompatFamily): {
400509normalizeToolSchemas: (ctx: ProviderNormalizeToolSchemasContext) => AnyAgentTool[];
401510inspectToolSchemas: (ctx: ProviderNormalizeToolSchemasContext) => ProviderToolSchemaDiagnostic[];
402511} {
403512switch (family) {
513+case "deepseek":
514+return {
515+normalizeToolSchemas: normalizeDeepSeekToolSchemas,
516+inspectToolSchemas: inspectDeepSeekToolSchemas,
517+};
404518case "gemini":
405519return {
406520normalizeToolSchemas: normalizeGeminiToolSchemas,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。