mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix(ai): send const as enum in Gemini tool schemas
This commit is contained in:
parent
ed76cca69b
commit
7314819f0f
2 changed files with 73 additions and 2 deletions
|
|
@ -371,11 +371,37 @@ function sanitizeForOpenApi(schema: unknown): unknown {
|
|||
return result;
|
||||
}
|
||||
|
||||
/** Schema keywords whose values map names to subschemas, so their keys are not schema keywords. */
|
||||
const JSON_SCHEMA_NAME_MAPS = new Set(["properties", "patternProperties", "$defs", "definitions", "dependentSchemas"]);
|
||||
|
||||
/**
|
||||
* Rewrite string and number `const` values to single-value `enum`s.
|
||||
* Gemini ignores `const` in `parametersJsonSchema` but honors `enum`.
|
||||
*/
|
||||
function rewriteConstAsEnum(schema: unknown, isNameMap = false): unknown {
|
||||
if (Array.isArray(schema)) return schema.map((item) => rewriteConstAsEnum(item));
|
||||
if (typeof schema !== "object" || schema === null) return schema;
|
||||
|
||||
const result: Record<string, unknown> = {};
|
||||
for (const [key, value] of Object.entries(schema)) {
|
||||
result[key] = isNameMap ? rewriteConstAsEnum(value) : rewriteConstAsEnum(value, JSON_SCHEMA_NAME_MAPS.has(key));
|
||||
}
|
||||
if (!isNameMap && "const" in result && result.enum === undefined) {
|
||||
const value = result.const;
|
||||
if (typeof value === "string" || typeof value === "number") {
|
||||
delete result.const;
|
||||
result.enum = [value];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert tools to Gemini function declarations format.
|
||||
*
|
||||
* By default uses `parametersJsonSchema` which supports full JSON Schema (including
|
||||
* anyOf, oneOf, const, etc.). Set `useParameters` to true to use the legacy `parameters`
|
||||
* anyOf, oneOf, etc.). Gemini ignores `const` there, so string and number `const`
|
||||
* values are sent as single-value `enum`s. Set `useParameters` to true to use the legacy `parameters`
|
||||
* field instead (OpenAPI 3.03 Schema). This is needed for Cloud Code Assist with Claude
|
||||
* models, where the API translates `parameters` into Anthropic's `input_schema`.
|
||||
*/
|
||||
|
|
@ -395,7 +421,7 @@ export function convertTools(
|
|||
description: tool.description,
|
||||
...(useParameters
|
||||
? { parameters: sanitizeForOpenApi(parameters as unknown) }
|
||||
: { parametersJsonSchema: parameters }),
|
||||
: { parametersJsonSchema: rewriteConstAsEnum(parameters) }),
|
||||
};
|
||||
}),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -201,3 +201,48 @@ describe("google-shared convertTools", () => {
|
|||
expect(convertTools([], true)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("google-shared convertTools const handling", () => {
|
||||
it("rewrites string and number const values to single-value enums in parametersJsonSchema", () => {
|
||||
const parameters = {
|
||||
type: "object",
|
||||
properties: {
|
||||
origin: { type: "string", const: "zq-src-7" },
|
||||
mode: {
|
||||
anyOf: [
|
||||
{ type: "string", const: "a" },
|
||||
{ type: "string", const: "b" },
|
||||
],
|
||||
},
|
||||
level: { oneOf: [{ const: 1 }, { const: 2 }] },
|
||||
flag: { type: "boolean", const: true },
|
||||
list: { type: "array", items: { const: "x" } },
|
||||
const: { type: "string" },
|
||||
},
|
||||
required: ["origin"],
|
||||
};
|
||||
const tools = [makeTool(parameters)];
|
||||
|
||||
const result = convertTools(tools);
|
||||
const decl = result?.[0]?.functionDeclarations?.[0];
|
||||
|
||||
expect(decl?.parametersJsonSchema).toEqual({
|
||||
type: "object",
|
||||
properties: {
|
||||
origin: { type: "string", enum: ["zq-src-7"] },
|
||||
mode: {
|
||||
anyOf: [
|
||||
{ type: "string", enum: ["a"] },
|
||||
{ type: "string", enum: ["b"] },
|
||||
],
|
||||
},
|
||||
level: { oneOf: [{ enum: [1] }, { enum: [2] }] },
|
||||
flag: { type: "boolean", const: true },
|
||||
list: { type: "array", items: { enum: ["x"] } },
|
||||
const: { type: "string" },
|
||||
},
|
||||
required: ["origin"],
|
||||
});
|
||||
expect(parameters.properties.origin).toEqual({ type: "string", const: "zq-src-7" });
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue