// Cloud Code Assist API rejects a subset of JSON Schema keywords. // This module scrubs/normalizes tool schemas to keep Gemini happy.
import type { TSchema } from "typebox";
// Keywords that Cloud Code Assist API rejects (not compliant with their JSON Schema subset)
export const GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS = new Set([ "patternProperties", "additionalProperties", "$schema", "$id", "$ref", "$defs", "definitions", // Non-standard (OpenAPI) keyword; Claude validators reject it. "examples",
// Cloud Code Assist appears to validate tool schemas more strictly/quirkily than // draft 2020-12 in practice; these constraints frequently trigger 400s. "minLength", "maxLength", "minimum", "maximum", "multipleOf", "pattern", "format", "minItems", "maxItems", "uniqueItems", "minProperties", "maxProperties",
// JSON Schema composition keywords not supported by OpenAPI 3.0 subset. // `const` is handled separately (converted to enum) in the cleaning loop, // but `not` has no safe equivalent and must be stripped. "not",
]);
const SCHEMA_META_KEYS = ["description", "title", "default"] as const;
function copySchemaMeta(from: Record<string, unknown>, to: Record<string, unknown>): void { for (const key of SCHEMA_META_KEYS) { if (key in from && from[key] !== undefined) {
to[key] = from[key];
}
}
}
// Check if an anyOf/oneOf array contains only literal values that can be flattened. // TypeBox Type.Literal generates { const: "value", type: "string" }. // Some schemas may use { enum: ["value"], type: "string" }. // Both patterns are flattened to { type: "string", enum: ["a", "b", ...] }. function tryFlattenLiteralAnyOf(variants: unknown[]): { type: string; enum: unknown[] } | null { if (variants.length === 0) { returnnull;
}
if (!defsEntry && !legacyDefsEntry) { return defs;
}
const next = defs ? new Map(defs) : new Map<string, unknown>(); if (defsEntry) { for (const [key, value] of Object.entries(defsEntry)) {
next.set(key, value);
}
} if (legacyDefsEntry) { for (const [key, value] of Object.entries(legacyDefsEntry)) {
next.set(key, value);
}
} return next;
}
function decodeJsonPointerSegment(segment: string): string { return segment.replaceAll("~1", "/").replaceAll("~0", "~");
}
function tryResolveLocalRef(ref: string, defs: SchemaDefs | undefined): unknown { if (!defs) { return undefined;
} const match = ref.match(/^#\/(?:\$defs|definitions)\/(.+)$/); if (!match) { return undefined;
} const name = decodeJsonPointerSegment(match[1] ?? ""); if (!name) { return undefined;
} return defs.get(name);
}
// Cloud Code Assist API rejects anyOf/oneOf in nested schemas even after // simplifyUnionVariants runs above. Flatten remaining unions as a fallback: // pick the common type or use the first variant's type so the tool // declaration is accepted by Google's validation layer. if (cleaned.anyOf && Array.isArray(cleaned.anyOf)) { const flattened = flattenUnionFallback(cleaned, cleaned.anyOf); if (flattened) { return sanitizeRequiredFields(flattened);
}
} if (cleaned.oneOf && Array.isArray(cleaned.oneOf)) { const flattened = flattenUnionFallback(cleaned, cleaned.oneOf); if (flattened) { return sanitizeRequiredFields(flattened);
}
}
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.