159type geminiContent struct { 160 Role string `json:"role,omitempty"` 161 Parts []geminiPart `json:"parts"` 162} 163 164type geminiPart struct { 165 Text string `json:"text,omitempty"` 166 InlineData *geminiInline `json:"inlineData,omitempty"` 167 FunctionCall *geminiFunctionCall `json:"functionCall,omitempty"` 168 FunctionResponse *geminiFunctionResponse `json:"functionResponse,omitempty"` 169 ThoughtSignature string `json:"thoughtSignature,omitempty"` 170} 171 172type geminiFunctionCall struct { 173 ID string `json:"id,omitempty"` 174 Name string `json:"name"` 175 Args map[string]any `json:"args"` 176} 177 178type geminiFunctionResponse struct { 179 ID string `json:"id,omitempty"` 180 Name string `json:"name"` 181 Response map[string]any `json:"response"` 182} 183 184type geminiInline struct { 185 MimeType string `json:"mimeType"` 186 Data string `json:"data"` 187} 188 189func geminiToolParameters(schema map[string]any) map[string]any { 190 normalized, ok := normalizeGeminiSchema("", schema).(map[string]any) 191 if !ok || len(normalized) == 0 { 192 return map[string]any{"type": "object"} 193 } 194 if _, ok := normalized["type"]; !ok { 195 normalized["type"] = "object" 196 } 197 return normalized 198} 199 200func normalizeGeminiSchema(name string, v any) any { 201 switch x := v.(type) { 202 case map[string]any: 203 out := make(map[string]any, len(x)+1) 204 for k, val := range x { 205 if k == "properties" { 206 props, ok := val.(map[string]any) 207 if !ok { 208 out[k] = normalizeGeminiSchema(k, val) 209 continue 210 } 211 normalizedProps := make(map[string]any, len(props)) 212 for propName, propSchema := range props { 213 normalizedProps[propName] = normalizeGeminiSchema(propName, propSchema) 214 } 215 out[k] = normalizedProps 216 continue 217 } 218 out[k] = normalizeGeminiSchema(k, val) 219 } 220 if schemaTypeIncludes(out["type"], "array") { 221 if items, ok := out["items"]; !ok || isEmptyGeminiSchema(items) { 222 out["items"] = defaultGeminiArrayItems(name) 223 } 224 } 225 return out 226 case []any: 227 out := make([]any, len(x)) 228 for i, val := range x { 229 out[i] = normalizeGeminiSchema(name, val) 230 } 231 return out 232 default: 233 return v 234 } 235} 236 237func defaultGeminiArrayItems(name string) map[string]any { 238 switch name { 239 case "attributes", "channels", "definition", "filters": 240 return map[string]any{"type": "object"} 241 case "enum_values", "list_ids", "tags": 242 return map[string]any{"type": "string"} 243 default: 244 return map[string]any{"type": "object"} 245 } 246} 247 248func schemaTypeIncludes(raw any, want string) bool { 249 switch x := raw.(type) { 250 case string: 251 return strings.EqualFold(x, want) 252 case []any: 253 for _, val := range x { 254 if s, ok := val.(string); ok && strings.EqualFold(s, want) { 255 return true 256 } 257 } 258 case []string: 259 for _, s := range x { 260 if strings.EqualFold(s, want) { 261 return true 262 } 263 } 264 } 265 return false