package schema import ( "encoding/json" "fmt" "reflect" "github.com/openai/openai-go" "google.golang.org/genai" ) // Raw represents a raw JSON schema that is passed through directly. // This is used for MCP tools where we receive the schema from the server. type Raw struct { schema map[string]any } // NewRaw creates a new Raw schema from a map. func NewRaw(schema map[string]any) Raw { if schema == nil { schema = map[string]any{ "type": "object", "properties": map[string]any{}, } } return Raw{schema: schema} } // NewRawFromJSON creates a new Raw schema from JSON bytes. func NewRawFromJSON(data []byte) (Raw, error) { var schema map[string]any if err := json.Unmarshal(data, &schema); err != nil { return Raw{}, fmt.Errorf("failed to parse JSON schema: %w", err) } return NewRaw(schema), nil } func (r Raw) OpenAIParameters() openai.FunctionParameters { return openai.FunctionParameters(r.schema) } func (r Raw) GoogleParameters() *genai.Schema { return mapToGenaiSchema(r.schema) } func (r Raw) AnthropicInputSchema() map[string]any { return r.schema } func (r Raw) Required() bool { return false } func (r Raw) Description() string { if desc, ok := r.schema["description"].(string); ok { return desc } return "" } func (r Raw) FromAny(val any) (reflect.Value, error) { return reflect.ValueOf(val), nil } func (r Raw) SetValueOnField(obj reflect.Value, val reflect.Value) { // No-op for raw schemas } // mapToGenaiSchema converts a map[string]any JSON schema to genai.Schema func mapToGenaiSchema(m map[string]any) *genai.Schema { if m == nil { return nil } schema := &genai.Schema{} // Type if t, ok := m["type"].(string); ok { switch t { case "string": schema.Type = genai.TypeString case "number": schema.Type = genai.TypeNumber case "integer": schema.Type = genai.TypeInteger case "boolean": schema.Type = genai.TypeBoolean case "array": schema.Type = genai.TypeArray case "object": schema.Type = genai.TypeObject } } // Description if desc, ok := m["description"].(string); ok { schema.Description = desc } // Enum if enum, ok := m["enum"].([]any); ok { for _, e := range enum { if s, ok := e.(string); ok { schema.Enum = append(schema.Enum, s) } } } // Properties (for objects) if props, ok := m["properties"].(map[string]any); ok { schema.Properties = make(map[string]*genai.Schema) for k, v := range props { if vm, ok := v.(map[string]any); ok { schema.Properties[k] = mapToGenaiSchema(vm) } } } // Required if req, ok := m["required"].([]any); ok { for _, r := range req { if s, ok := r.(string); ok { schema.Required = append(schema.Required, s) } } } // Items (for arrays) if items, ok := m["items"].(map[string]any); ok { schema.Items = mapToGenaiSchema(items) } return schema }