fix(agents): harden Cloud Code Assist compatibility
- Expand schema scrubber to strip additional constraint keywords rejected by Cloud Code Assist (examples, minLength, maxLength, minimum, maximum, multipleOf, pattern, format, minItems, maxItems, uniqueItems, minProperties, maxProperties) - Extend tool call ID sanitization to cover toolUse and toolCall block types (previously only functionCall was sanitized) - Update pi-tools test to include 'examples' in unsupported keywords Fixes 400 errors when using google-antigravity/claude-opus-4-5-thinking: - tools.N.custom.input_schema: JSON schema is invalid - messages.N.content.N.tool_use.id: String should match pattern
This commit is contained in:
committed by
Peter Steinberger
parent
ef08c3f038
commit
64babcac7a
@@ -146,18 +146,20 @@ export async function sanitizeSessionMessagesImages(
|
||||
// Also sanitize tool call IDs in assistant messages (function call blocks)
|
||||
const sanitizedContent = await Promise.all(
|
||||
filteredContent.map(async (block) => {
|
||||
if (
|
||||
block &&
|
||||
typeof block === "object" &&
|
||||
(block as { type?: unknown }).type === "functionCall" &&
|
||||
(block as { id?: unknown }).id
|
||||
) {
|
||||
const functionBlock = block as { type: string; id: string };
|
||||
if (!block || typeof block !== "object") return block;
|
||||
|
||||
const type = (block as { type?: unknown }).type;
|
||||
const id = (block as { id?: unknown }).id;
|
||||
if (typeof id !== "string" || !id) return block;
|
||||
|
||||
// Cloud Code Assist tool blocks require ids matching ^[a-zA-Z0-9_-]+$.
|
||||
if (type === "functionCall" || type === "toolUse" || type === "toolCall") {
|
||||
return {
|
||||
...functionBlock,
|
||||
id: sanitizeToolCallId(functionBlock.id),
|
||||
...((block as unknown) as Record<string, unknown>),
|
||||
id: sanitizeToolCallId(id),
|
||||
};
|
||||
}
|
||||
|
||||
return block;
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -384,6 +384,7 @@ describe("createClawdbotCodingTools", () => {
|
||||
"$ref",
|
||||
"$defs",
|
||||
"definitions",
|
||||
"examples",
|
||||
]);
|
||||
|
||||
const findUnsupportedKeywords = (
|
||||
|
||||
@@ -10,6 +10,23 @@ const UNSUPPORTED_SCHEMA_KEYWORDS = new Set([
|
||||
"$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",
|
||||
]);
|
||||
|
||||
// Check if an anyOf/oneOf array contains only literal values that can be flattened.
|
||||
@@ -134,14 +151,14 @@ function cleanSchemaForGeminiWithDefs(
|
||||
const result: Record<string, unknown> = {
|
||||
...(cleaned as Record<string, unknown>),
|
||||
};
|
||||
for (const key of ["description", "title", "default", "examples"]) {
|
||||
for (const key of ["description", "title", "default"]) {
|
||||
if (key in obj && obj[key] !== undefined) result[key] = obj[key];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const result: Record<string, unknown> = {};
|
||||
for (const key of ["description", "title", "default", "examples"]) {
|
||||
for (const key of ["description", "title", "default"]) {
|
||||
if (key in obj && obj[key] !== undefined) result[key] = obj[key];
|
||||
}
|
||||
return result;
|
||||
@@ -157,7 +174,7 @@ function cleanSchemaForGeminiWithDefs(
|
||||
type: flattened.type,
|
||||
enum: flattened.enum,
|
||||
};
|
||||
for (const key of ["description", "title", "default", "examples"]) {
|
||||
for (const key of ["description", "title", "default"]) {
|
||||
if (key in obj && obj[key] !== undefined) result[key] = obj[key];
|
||||
}
|
||||
return result;
|
||||
@@ -171,7 +188,7 @@ function cleanSchemaForGeminiWithDefs(
|
||||
type: flattened.type,
|
||||
enum: flattened.enum,
|
||||
};
|
||||
for (const key of ["description", "title", "default", "examples"]) {
|
||||
for (const key of ["description", "title", "default"]) {
|
||||
if (key in obj && obj[key] !== undefined) result[key] = obj[key];
|
||||
}
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user