From 916f07be1840d81d649ecad145d25b57df179078 Mon Sep 17 00:00:00 2001 From: Steve Dudenhoeffer Date: Sat, 12 Apr 2025 03:41:48 -0400 Subject: [PATCH] added anthropic tool support i think --- anthropic.go | 32 +++++++++++++------------------- go.sum | 8 -------- schema/array.go | 8 ++++++++ schema/basic.go | 26 ++++++++++++++++++++++++++ schema/enum.go | 8 ++++++++ schema/object.go | 23 +++++++++++++++++++++++ schema/type.go | 1 + 7 files changed, 79 insertions(+), 27 deletions(-) diff --git a/anthropic.go b/anthropic.go index aa81a90..039bfc5 100644 --- a/anthropic.go +++ b/anthropic.go @@ -123,7 +123,6 @@ func (a anthropic) requestToAnthropicRequest(req Request) anth.MessagesRequest { // if this has the same role as the previous message, we can append it to the previous message // as anthropic expects alternating assistant and user roles - if len(msgs) > 0 && msgs[len(msgs)-1].Role == role { m2 := &msgs[len(msgs)-1] @@ -134,16 +133,13 @@ func (a anthropic) requestToAnthropicRequest(req Request) anth.MessagesRequest { } } - /* - for _, tool := range req.Toolbox.functions { - res.Tools = append(res.Tools, anth.ToolDefinition{ - Name: tool.Name, - Description: tool.Description, - InputSchema: tool.Parameters.OpenAIParameters(), - }) - } - - */ + for _, tool := range req.Toolbox.functions { + res.Tools = append(res.Tools, anth.ToolDefinition{ + Name: tool.Name, + Description: tool.Description, + InputSchema: tool.Parameters.AnthropicInputSchema(), + }) + } res.Messages = msgs @@ -158,15 +154,13 @@ func (a anthropic) requestToAnthropicRequest(req Request) anth.MessagesRequest { } func (a anthropic) responseToLLMResponse(in anth.MessagesResponse) Response { - res := Response{} - + choice := ResponseChoice{} for _, msg := range in.Content { - choice := ResponseChoice{} switch msg.Type { case anth.MessagesContentTypeText: if msg.Text != nil { - choice.Content = *msg.Text + choice.Content += *msg.Text } case anth.MessagesContentTypeToolUse: @@ -185,13 +179,13 @@ func (a anthropic) responseToLLMResponse(in anth.MessagesResponse) Response { } } } - - res.Choices = append(res.Choices, choice) } - log.Println("anthropic response to llm response", res) + log.Println("anthropic response to llm response", choice) - return res + return Response{ + Choices: []ResponseChoice{choice}, + } } func (a anthropic) ChatComplete(ctx context.Context, req Request) (Response, error) { diff --git a/go.sum b/go.sum index 331f8b6..86c95a7 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,6 @@ github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrk github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= github.com/liushuangls/go-anthropic/v2 v2.15.0 h1:zpplg7BRV/9FlMmeMPI0eDwhViB0l9SkNrF8ErYlRoQ= github.com/liushuangls/go-anthropic/v2 v2.15.0/go.mod h1:kq2yW3JVy1/rph8u5KzX7F3q95CEpCT2RXp/2nfCmb4= -github.com/openai/openai-go v0.1.0-beta.6 h1:JquYDpprfrGnlKvQQg+apy9dQ8R9mIrm+wNvAPp6jCQ= -github.com/openai/openai-go v0.1.0-beta.6/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y= github.com/openai/openai-go v0.1.0-beta.9 h1:ABpubc5yU/3ejee2GgRrbFta81SG/d7bQbB8mIdP0Xo= github.com/openai/openai-go v0.1.0-beta.9/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -71,8 +69,6 @@ go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= @@ -87,12 +83,8 @@ golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= google.golang.org/api v0.228.0 h1:X2DJ/uoWGnY5obVjewbp8icSL5U4FzuCfy9OjbLSnLs= google.golang.org/api v0.228.0/go.mod h1:wNvRS1Pbe8r4+IfBIniV8fwCpGwTrYa+kMUDiC5z5a4= -google.golang.org/genproto/googleapis/api v0.0.0-20250404141209-ee84b53bf3d0 h1:Qbb5RVn5xzI4naMJSpJ7lhvmos6UwZkbekd5Uz7rt9E= -google.golang.org/genproto/googleapis/api v0.0.0-20250404141209-ee84b53bf3d0/go.mod h1:6T35kB3IPpdw7Wul09by0G/JuOuIFkXV6OOvt8IZeT8= google.golang.org/genproto/googleapis/api v0.0.0-20250409194420-de1ac958c67a h1:OQ7sHVzkx6L57dQpzUS4ckfWJ51KDH74XHTDe23xWAs= google.golang.org/genproto/googleapis/api v0.0.0-20250409194420-de1ac958c67a/go.mod h1:2R6XrVC8Oc08GlNh8ujEpc7HkLiEZ16QeY7FxIs20ac= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250404141209-ee84b53bf3d0 h1:0K7wTWyzxZ7J+L47+LbFogJW1nn/gnnMCN0vGXNYtTI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250404141209-ee84b53bf3d0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a h1:GIqLhp/cYUkuGuiT+vJk8vhOP86L4+SP5j8yXgeVpvI= google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI= diff --git a/schema/array.go b/schema/array.go index a2977bc..a44c5b7 100644 --- a/schema/array.go +++ b/schema/array.go @@ -31,6 +31,14 @@ func (a array) GoogleParameters() *genai.Schema { } } +func (a array) AnthropicInputSchema() map[string]any { + return map[string]any{ + "type": "array", + "description": a.Description(), + "items": a.items.AnthropicInputSchema(), + } +} + func (a array) FromAny(val any) (reflect.Value, error) { v := reflect.ValueOf(val) diff --git a/schema/basic.go b/schema/basic.go index 087b794..fbb0281 100644 --- a/schema/basic.go +++ b/schema/basic.go @@ -70,6 +70,32 @@ func (b basic) GoogleParameters() *genai.Schema { } } +func (b basic) AnthropicInputSchema() map[string]any { + var t = "string" + + switch b.DataType { + case TypeString: + t = "string" + case TypeInteger: + t = "integer" + case TypeNumber: + t = "number" + case TypeBoolean: + t = "boolean" + case TypeObject: + t = "object" + case TypeArray: + t = "array" + default: + t = "unknown" + } + + return map[string]any{ + "type": t, + "description": b.description, + } +} + func (b basic) Required() bool { return b.required } diff --git a/schema/enum.go b/schema/enum.go index 02ae582..8438ff4 100644 --- a/schema/enum.go +++ b/schema/enum.go @@ -31,6 +31,14 @@ func (e enum) GoogleParameters() *genai.Schema { } } +func (e enum) AnthropicInputSchema() map[string]any { + return map[string]any{ + "type": "string", + "description": e.Description(), + "enum": e.values, + } +} + func (e enum) FromAny(val any) (reflect.Value, error) { v := reflect.ValueOf(val) if v.Kind() != reflect.String { diff --git a/schema/object.go b/schema/object.go index 7e96c44..8f98886 100644 --- a/schema/object.go +++ b/schema/object.go @@ -98,6 +98,29 @@ func (o Object) GoogleParameters() *genai.Schema { return res } +func (o Object) AnthropicInputSchema() map[string]any { + var properties = map[string]any{} + var required []string + for k, v := range o.fields { + properties[k] = v.AnthropicInputSchema() + if v.Required() { + required = append(required, k) + } + } + + var res = map[string]any{ + "type": "object", + "description": o.Description(), + "properties": properties, + } + + if len(required) > 0 { + res["required"] = required + } + + return res +} + // FromAny converts the value from any to the correct type, returning the value, and an error if any func (o Object) FromAny(val any) (reflect.Value, error) { // if the value is nil, we can't do anything diff --git a/schema/type.go b/schema/type.go index 935cbce..2f5bd83 100644 --- a/schema/type.go +++ b/schema/type.go @@ -10,6 +10,7 @@ import ( type Type interface { OpenAIParameters() openai.FunctionParameters GoogleParameters() *genai.Schema + AnthropicInputSchema() map[string]any //SchemaType() jsonschema.DataType //Definition() jsonschema.Definition