mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 02:02:45 +00:00
refactor(schema): share gemini union cleanup
This commit is contained in:
@@ -29,6 +29,16 @@ export const GEMINI_UNSUPPORTED_SCHEMA_KEYWORDS = new Set([
|
|||||||
"maxProperties",
|
"maxProperties",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
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.
|
// Check if an anyOf/oneOf array contains only literal values that can be flattened.
|
||||||
// TypeBox Type.Literal generates { const: "value", type: "string" }.
|
// TypeBox Type.Literal generates { const: "value", type: "string" }.
|
||||||
// Some schemas may use { enum: ["value"], type: "string" }.
|
// Some schemas may use { enum: ["value"], type: "string" }.
|
||||||
@@ -164,6 +174,39 @@ function tryResolveLocalRef(ref: string, defs: SchemaDefs | undefined): unknown
|
|||||||
return defs.get(name);
|
return defs.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function simplifyUnionVariants(params: { obj: Record<string, unknown>; variants: unknown[] }): {
|
||||||
|
variants: unknown[];
|
||||||
|
simplified?: unknown;
|
||||||
|
} {
|
||||||
|
const { obj, variants } = params;
|
||||||
|
|
||||||
|
const { variants: nonNullVariants, stripped } = stripNullVariants(variants);
|
||||||
|
|
||||||
|
const flattened = tryFlattenLiteralAnyOf(nonNullVariants);
|
||||||
|
if (flattened) {
|
||||||
|
const result: Record<string, unknown> = {
|
||||||
|
type: flattened.type,
|
||||||
|
enum: flattened.enum,
|
||||||
|
};
|
||||||
|
copySchemaMeta(obj, result);
|
||||||
|
return { variants: nonNullVariants, simplified: result };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stripped && nonNullVariants.length === 1) {
|
||||||
|
const lone = nonNullVariants[0];
|
||||||
|
if (lone && typeof lone === "object" && !Array.isArray(lone)) {
|
||||||
|
const result: Record<string, unknown> = {
|
||||||
|
...(lone as Record<string, unknown>),
|
||||||
|
};
|
||||||
|
copySchemaMeta(obj, result);
|
||||||
|
return { variants: nonNullVariants, simplified: result };
|
||||||
|
}
|
||||||
|
return { variants: nonNullVariants, simplified: lone };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { variants: stripped ? nonNullVariants : variants };
|
||||||
|
}
|
||||||
|
|
||||||
function cleanSchemaForGeminiWithDefs(
|
function cleanSchemaForGeminiWithDefs(
|
||||||
schema: unknown,
|
schema: unknown,
|
||||||
defs: SchemaDefs | undefined,
|
defs: SchemaDefs | undefined,
|
||||||
@@ -198,20 +241,12 @@ function cleanSchemaForGeminiWithDefs(
|
|||||||
const result: Record<string, unknown> = {
|
const result: Record<string, unknown> = {
|
||||||
...(cleaned as Record<string, unknown>),
|
...(cleaned as Record<string, unknown>),
|
||||||
};
|
};
|
||||||
for (const key of ["description", "title", "default"]) {
|
copySchemaMeta(obj, result);
|
||||||
if (key in obj && obj[key] !== undefined) {
|
|
||||||
result[key] = obj[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result: Record<string, unknown> = {};
|
const result: Record<string, unknown> = {};
|
||||||
for (const key of ["description", "title", "default"]) {
|
copySchemaMeta(obj, result);
|
||||||
if (key in obj && obj[key] !== undefined) {
|
|
||||||
result[key] = obj[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,74 +264,18 @@ function cleanSchemaForGeminiWithDefs(
|
|||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
if (hasAnyOf) {
|
if (hasAnyOf) {
|
||||||
const { variants: nonNullVariants, stripped } = stripNullVariants(cleanedAnyOf ?? []);
|
const simplified = simplifyUnionVariants({ obj, variants: cleanedAnyOf ?? [] });
|
||||||
if (stripped) {
|
cleanedAnyOf = simplified.variants;
|
||||||
cleanedAnyOf = nonNullVariants;
|
if ("simplified" in simplified) {
|
||||||
}
|
return simplified.simplified;
|
||||||
|
|
||||||
const flattened = tryFlattenLiteralAnyOf(nonNullVariants);
|
|
||||||
if (flattened) {
|
|
||||||
const result: Record<string, unknown> = {
|
|
||||||
type: flattened.type,
|
|
||||||
enum: flattened.enum,
|
|
||||||
};
|
|
||||||
for (const key of ["description", "title", "default"]) {
|
|
||||||
if (key in obj && obj[key] !== undefined) {
|
|
||||||
result[key] = obj[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (stripped && nonNullVariants.length === 1) {
|
|
||||||
const lone = nonNullVariants[0];
|
|
||||||
if (lone && typeof lone === "object" && !Array.isArray(lone)) {
|
|
||||||
const result: Record<string, unknown> = {
|
|
||||||
...(lone as Record<string, unknown>),
|
|
||||||
};
|
|
||||||
for (const key of ["description", "title", "default"]) {
|
|
||||||
if (key in obj && obj[key] !== undefined) {
|
|
||||||
result[key] = obj[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return lone;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasOneOf) {
|
if (hasOneOf) {
|
||||||
const { variants: nonNullVariants, stripped } = stripNullVariants(cleanedOneOf ?? []);
|
const simplified = simplifyUnionVariants({ obj, variants: cleanedOneOf ?? [] });
|
||||||
if (stripped) {
|
cleanedOneOf = simplified.variants;
|
||||||
cleanedOneOf = nonNullVariants;
|
if ("simplified" in simplified) {
|
||||||
}
|
return simplified.simplified;
|
||||||
|
|
||||||
const flattened = tryFlattenLiteralAnyOf(nonNullVariants);
|
|
||||||
if (flattened) {
|
|
||||||
const result: Record<string, unknown> = {
|
|
||||||
type: flattened.type,
|
|
||||||
enum: flattened.enum,
|
|
||||||
};
|
|
||||||
for (const key of ["description", "title", "default"]) {
|
|
||||||
if (key in obj && obj[key] !== undefined) {
|
|
||||||
result[key] = obj[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (stripped && nonNullVariants.length === 1) {
|
|
||||||
const lone = nonNullVariants[0];
|
|
||||||
if (lone && typeof lone === "object" && !Array.isArray(lone)) {
|
|
||||||
const result: Record<string, unknown> = {
|
|
||||||
...(lone as Record<string, unknown>),
|
|
||||||
};
|
|
||||||
for (const key of ["description", "title", "default"]) {
|
|
||||||
if (key in obj && obj[key] !== undefined) {
|
|
||||||
result[key] = obj[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return lone;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user