fix: convert schema types to Google uppercase format (fixes #82)

The /compact command was failing with 'Proto field is not repeating,
cannot start list' error for Claude models because tool schemas were
sent with lowercase JSON Schema types (array, object, string) but
Google's Cloud Code API expects uppercase protobuf types (ARRAY,
OBJECT, STRING).

Changes:
- Add toGoogleType() function to convert JSON Schema types to Google format
- Add Phase 5 to cleanSchemaForGemini() for type conversion
- Apply cleanSchemaForGemini() for ALL models (not just Gemini) since
  all requests go through Cloud Code API which validates schema format
- Add comprehensive test suite with 10 tests covering nested arrays,
  complex schemas, and real-world Claude Code tool scenarios

Fixes #82
This commit is contained in:
Tiago Rodrigues
2026-01-09 18:36:19 +00:00
parent 348fdc3f94
commit 90214c43b0
3 changed files with 301 additions and 4 deletions

View File

@@ -210,10 +210,11 @@ export function convertAnthropicToGoogle(anthropicRequest) {
// Sanitize schema for general compatibility
let parameters = sanitizeSchema(schema);
// For Gemini models, apply additional cleaning for VALIDATED mode
if (isGeminiModel) {
parameters = cleanSchemaForGemini(parameters);
}
// Apply Google-format cleaning for ALL models since they all go through
// Cloud Code API which validates schemas using Google's protobuf format.
// This fixes issue #82: /compact command fails with schema transformation error
// "Proto field is not repeating, cannot start list" for Claude models.
parameters = cleanSchemaForGemini(parameters);
return {
name: String(name).replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 64),

View File

@@ -564,6 +564,27 @@ export function sanitizeSchema(schema) {
return sanitized;
}
/**
* Convert JSON Schema type names to Google's Protobuf-style uppercase type names.
* Google's Generative AI API expects uppercase types: STRING, OBJECT, ARRAY, etc.
*
* @param {string} type - JSON Schema type name (lowercase)
* @returns {string} Google-format type name (uppercase)
*/
function toGoogleType(type) {
if (!type || typeof type !== 'string') return type;
const typeMap = {
'string': 'STRING',
'number': 'NUMBER',
'integer': 'INTEGER',
'boolean': 'BOOLEAN',
'array': 'ARRAY',
'object': 'OBJECT',
'null': 'STRING' // Fallback for null type
};
return typeMap[type.toLowerCase()] || type.toUpperCase();
}
/**
* Cleans JSON schema for Gemini API compatibility.
* Uses a multi-phase pipeline matching opencode-antigravity-auth approach.
@@ -642,5 +663,11 @@ export function cleanSchemaForGemini(schema) {
}
}
// Phase 5: Convert type to Google's uppercase format (STRING, OBJECT, ARRAY, etc.)
// Only convert at current level - nested types already converted by recursive cleanSchemaForGemini calls
if (result.type && typeof result.type === 'string') {
result.type = toGoogleType(result.type);
}
return result;
}