Files
picoclaw/pkg/providers/httpapi/gemini_helpers.go
T
2026-04-23 05:47:58 +00:00

131 lines
2.9 KiB
Go

package httpapi
import (
"encoding/json"
"strings"
)
func normalizeStoredToolCall(tc ToolCall) (string, map[string]any, string) {
name := tc.Name
args := tc.Arguments
thoughtSignature := ""
if name == "" && tc.Function != nil {
name = tc.Function.Name
thoughtSignature = tc.Function.ThoughtSignature
} else if tc.Function != nil {
thoughtSignature = tc.Function.ThoughtSignature
}
if args == nil {
args = map[string]any{}
}
if len(args) == 0 && tc.Function != nil && tc.Function.Arguments != "" {
var parsed map[string]any
if err := json.Unmarshal([]byte(tc.Function.Arguments), &parsed); err == nil && parsed != nil {
args = parsed
}
}
return name, args, thoughtSignature
}
func resolveToolResponseName(toolCallID string, toolCallNames map[string]string) string {
if toolCallID == "" {
return ""
}
if name, ok := toolCallNames[toolCallID]; ok && name != "" {
return name
}
return inferToolNameFromCallID(toolCallID)
}
func inferToolNameFromCallID(toolCallID string) string {
if !strings.HasPrefix(toolCallID, "call_") {
return toolCallID
}
rest := strings.TrimPrefix(toolCallID, "call_")
if idx := strings.LastIndex(rest, "_"); idx > 0 {
candidate := rest[:idx]
if candidate != "" {
return candidate
}
}
return toolCallID
}
func extractPartThoughtSignature(thoughtSignature string, thoughtSignatureSnake string) string {
if thoughtSignature != "" {
return thoughtSignature
}
if thoughtSignatureSnake != "" {
return thoughtSignatureSnake
}
return ""
}
var geminiUnsupportedKeywords = map[string]bool{
"patternProperties": true,
"additionalProperties": true,
"$schema": true,
"$id": true,
"$ref": true,
"$defs": true,
"definitions": true,
"examples": true,
"minLength": true,
"maxLength": true,
"minimum": true,
"maximum": true,
"multipleOf": true,
"pattern": true,
"format": true,
"minItems": true,
"maxItems": true,
"uniqueItems": true,
"minProperties": true,
"maxProperties": true,
}
func sanitizeSchemaForGemini(schema map[string]any) map[string]any {
if schema == nil {
return nil
}
result := make(map[string]any)
for k, v := range schema {
if geminiUnsupportedKeywords[k] {
continue
}
switch val := v.(type) {
case map[string]any:
result[k] = sanitizeSchemaForGemini(val)
case []any:
sanitized := make([]any, len(val))
for i, item := range val {
if m, ok := item.(map[string]any); ok {
sanitized[i] = sanitizeSchemaForGemini(m)
} else {
sanitized[i] = item
}
}
result[k] = sanitized
default:
result[k] = v
}
}
if _, hasProps := result["properties"]; hasProps {
if _, hasType := result["type"]; !hasType {
result["type"] = "object"
}
}
return result
}