Skip to content

Commit 1b492d1

Browse files
committed
Added tools for anthropic
1 parent 7b23192 commit 1b492d1

File tree

7 files changed

+187
-28
lines changed

7 files changed

+187
-28
lines changed

pkg/anthropic/message.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,26 @@ import (
2020
// TYPES
2121

2222
type reqMessage struct {
23-
Model string `json:"model"`
24-
Messages []*schema.Message `json:"messages,omitempty"`
25-
Stream bool `json:"stream,omitempty"`
26-
System string `json:"system,omitempty"`
27-
MaxTokens int `json:"max_tokens,omitempty"`
23+
Model string `json:"model"`
24+
Messages []*schema.Message `json:"messages,omitempty"`
25+
Stream bool `json:"stream,omitempty"`
26+
System string `json:"system,omitempty"`
27+
MaxTokens int `json:"max_tokens,omitempty"`
28+
Metadata *reqMetadata `json:"metadata,omitempty"`
29+
StopSequences []string `json:"stop_sequences,omitempty"`
30+
Temperature float64 `json:"temperature,omitempty"`
31+
TopK int `json:"top_k,omitempty"`
32+
TopP float64 `json:"top_p,omitempty"`
33+
Tools []schema.Tool `json:"tools,omitempty"`
2834

2935
// Callbacks
3036
delta Callback `json:"-"`
3137
}
3238

39+
type reqMetadata struct {
40+
User string `json:"user_id,omitempty"`
41+
}
42+
3343
type respMessage struct {
3444
Id string `json:"id"`
3545
Type string `json:"type,omitempty"`
@@ -87,7 +97,7 @@ const (
8797
// Send a structured list of input messages with text and/or image content,
8898
// and the model will generate the next message in the conversation. Use
8999
// a context to cancel the request, instead of the client-related timeout.
90-
func (c *Client) Messages(ctx context.Context, messages []*schema.Message, opt ...Opt) (*schema.Content, error) {
100+
func (c *Client) Messages(ctx context.Context, messages []*schema.Message, opt ...Opt) ([]schema.Content, error) {
91101
var request reqMessage
92102
var response respMessage
93103

@@ -120,10 +130,10 @@ func (c *Client) Messages(ctx context.Context, messages []*schema.Message, opt .
120130
return nil, ErrInternalAppError.With("No content returned")
121131
}
122132

123-
// TODO: Somehow return Usage and Stop information
133+
// TODO: Somehow return Usage and Stop information back to the caller
124134

125135
// Return success
126-
return &response.Content[0], nil
136+
return response.Content, nil
127137
}
128138

129139
///////////////////////////////////////////////////////////////////////////////

pkg/anthropic/message_test.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ func Test_message_001(t *testing.T) {
1717
assert.NoError(err)
1818
assert.NotNil(client)
1919
msg := schema.NewMessage("user", "What is the weather today")
20-
_, err = client.Messages(context.Background(), []*schema.Message{msg})
20+
content, err := client.Messages(context.Background(), []*schema.Message{msg})
2121
assert.NoError(err)
22+
t.Log(content)
2223
}
2324

2425
func Test_message_002(t *testing.T) {
@@ -27,8 +28,26 @@ func Test_message_002(t *testing.T) {
2728
assert.NoError(err)
2829
assert.NotNil(client)
2930
msg := schema.NewMessage("user", "What is the weather today")
30-
_, err = client.Messages(context.Background(), []*schema.Message{msg}, anthropic.OptStream(func(v *anthropic.Delta) {
31+
content, err := client.Messages(context.Background(), []*schema.Message{msg}, anthropic.OptStream(func(v *anthropic.Delta) {
3132
t.Log(v)
3233
}))
3334
assert.NoError(err)
35+
t.Log(content)
36+
}
37+
38+
func Test_message_003(t *testing.T) {
39+
assert := assert.New(t)
40+
client, err := anthropic.New(GetApiKey(t), opts.OptTrace(os.Stderr, true), opts.OptHeader("Anthropic-Beta", "tools-2024-04-04"))
41+
assert.NoError(err)
42+
assert.NotNil(client)
43+
msg := schema.NewMessage("user", "What is the weather today in Berlin, Germany")
44+
45+
// Create the weather tool
46+
weather := schema.NewTool("weather", "Get the weather for a location")
47+
weather.AddParameter("location", "The location to get the weather for", true)
48+
49+
// Request -> Response
50+
content, err := client.Messages(context.Background(), []*schema.Message{msg}, anthropic.OptTool(weather))
51+
assert.NoError(err)
52+
t.Log(content)
3453
}

pkg/anthropic/opts.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package anthropic
22

3+
import (
4+
// Namespace imports
5+
. "github.com/djthorpe/go-errors"
6+
"github.com/mutablelogic/go-client/pkg/openai/schema"
7+
)
8+
39
///////////////////////////////////////////////////////////////////////////////
410
// TYPES
511

@@ -45,3 +51,42 @@ func OptSystem(prompt string) Opt {
4551
return nil
4652
}
4753
}
54+
55+
// An external identifier for the user who is associated with the request.
56+
func OptUser(v string) Opt {
57+
return func(o *reqMessage) error {
58+
o.Metadata = &reqMetadata{User: v}
59+
return nil
60+
}
61+
}
62+
63+
// Custom text sequence that will cause the model to stop generating.
64+
func OptStopSequence(v string) Opt {
65+
return func(o *reqMessage) error {
66+
o.StopSequences = append(o.StopSequences, v)
67+
return nil
68+
}
69+
}
70+
71+
// Amount of randomness injected into the response.
72+
func OptTemperature(v float64) Opt {
73+
return func(o *reqMessage) error {
74+
if v < 0.0 || v > 1.0 {
75+
return ErrBadParameter.With("OptTemperature")
76+
}
77+
o.Temperature = v
78+
return nil
79+
}
80+
}
81+
82+
// Add a tool
83+
func OptTool(tool *schema.Tool) Opt {
84+
return func(o *reqMessage) error {
85+
if tool == nil {
86+
return ErrBadParameter.With("OptTool")
87+
} else {
88+
o.Tools = append(o.Tools, *tool)
89+
}
90+
return nil
91+
}
92+
}

pkg/openai/schema/message.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ type MessageChoice struct {
4141

4242
// Message Content
4343
type Content struct {
44+
Id string `json:"id,omitempty"`
4445
Type string `json:"type,width:4"`
45-
Text string `json:"text,wrap,width:60"`
46+
Text string `json:"text,omitempty,wrap,width:60"`
4647
Source *contentSource `json:"source,omitempty"`
48+
toolUse
4749
}
4850

4951
// Content Source
@@ -53,6 +55,12 @@ type contentSource struct {
5355
Data string `json:"data,omitempty"`
5456
}
5557

58+
// Tool arguments
59+
type toolUse struct {
60+
Name string `json:"name,omitempty"`
61+
Input map[string]any `json:"input,omitempty"`
62+
}
63+
5664
///////////////////////////////////////////////////////////////////////////////
5765
// LIFECYCLE
5866

pkg/openai/schema/providers.go

Lines changed: 0 additions & 17 deletions
This file was deleted.

pkg/openai/schema/tool.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package schema
2+
3+
import (
4+
"encoding/json"
5+
6+
// Namespace imports
7+
. "github.com/djthorpe/go-errors"
8+
)
9+
10+
///////////////////////////////////////////////////////////////////////////////
11+
// TYPES
12+
13+
// A tool function
14+
type Tool struct {
15+
Name string `json:"name"`
16+
Description string `json:"description"`
17+
Parameters *toolParameters `json:"input_schema,omitempty"`
18+
}
19+
20+
// Tool function parameters
21+
type toolParameters struct {
22+
Type string `json:"type,omitempty"`
23+
Properties map[string]toolParameter `json:"properties,omitempty"`
24+
Required []string `json:"required"`
25+
}
26+
27+
// Tool function call parameter
28+
type toolParameter struct {
29+
Name string `json:"-"`
30+
Type string `json:"type"`
31+
Enum []string `json:"enum,omitempty"`
32+
Description string `json:"description"`
33+
}
34+
35+
///////////////////////////////////////////////////////////////////////////////
36+
// LIFECYCLE
37+
38+
func NewTool(name, description string) *Tool {
39+
return &Tool{
40+
Name: name,
41+
Description: description,
42+
Parameters: &toolParameters{
43+
Type: "object",
44+
Properties: make(map[string]toolParameter),
45+
},
46+
}
47+
}
48+
49+
///////////////////////////////////////////////////////////////////////////////
50+
// STRINGIFY
51+
52+
func (t Tool) String() string {
53+
data, _ := json.MarshalIndent(t, "", " ")
54+
return string(data)
55+
}
56+
57+
///////////////////////////////////////////////////////////////////////////////
58+
// PUBLIC METHODS
59+
60+
func (t *Tool) AddParameter(name, description string, required bool) error {
61+
if name == "" {
62+
return ErrBadParameter.With("missing name")
63+
}
64+
if _, exists := t.Parameters.Properties[name]; exists {
65+
return ErrDuplicateEntry.With(name)
66+
}
67+
t.Parameters.Properties[name] = toolParameter{
68+
Name: name,
69+
Type: "string",
70+
Description: description,
71+
}
72+
if required {
73+
t.Parameters.Required = append(t.Parameters.Required, name)
74+
}
75+
76+
// Return success
77+
return nil
78+
}

pkg/openai/schema/tool_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package schema_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/mutablelogic/go-client/pkg/openai/schema"
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func Test_tool_001(t *testing.T) {
11+
assert := assert.New(t)
12+
tool := schema.NewTool("get_stock_price", "Get the current stock price for a given ticker symbol.")
13+
assert.NotNil(tool)
14+
assert.NoError(tool.AddParameter("ticker", "The stock ticker symbol, e.g. AAPL for Apple Inc.", true))
15+
t.Log(tool)
16+
}

0 commit comments

Comments
 (0)