Skip to content

Commit f72ba0c

Browse files
committed
Updated claude code
1 parent ba7653d commit f72ba0c

File tree

8 files changed

+405
-41
lines changed

8 files changed

+405
-41
lines changed

cmd/api/anthropic.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ package main
22

33
import (
44
"fmt"
5-
"strings"
65

76
"github.com/djthorpe/go-tablewriter"
87
"github.com/mutablelogic/go-client"
98
"github.com/mutablelogic/go-client/pkg/anthropic"
9+
"github.com/mutablelogic/go-client/pkg/openai/schema"
1010
)
1111

1212
///////////////////////////////////////////////////////////////////////////////
@@ -54,8 +54,13 @@ func anthropicParse(flags *Flags, opts ...client.ClientOpt) error {
5454

5555
func anthropicChat(w *tablewriter.Writer, args []string) error {
5656
// Request -> Response
57-
message := anthropic.NewMessage("user", strings.Join(args, " "))
58-
responses, err := anthropicClient.Messages(message)
57+
message := schema.NewMessage(schema.Anthropic, "user", nil)
58+
for _, arg := range args {
59+
message.Add(arg)
60+
}
61+
62+
// Request -> Response
63+
responses, err := anthropicClient.Messages([]*schema.Message{message})
5964
if err != nil {
6065
return err
6166
}

etc/test/mu.png

36.5 KB
Loading

pkg/anthropic/message.go

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ package anthropic
22

33
import (
44
// Packages
5-
"github.com/mutablelogic/go-client"
5+
client "github.com/mutablelogic/go-client"
66
schema "github.com/mutablelogic/go-client/pkg/openai/schema"
7+
8+
// Namespace imports
9+
. "github.com/djthorpe/go-errors"
710
)
811

912
///////////////////////////////////////////////////////////////////////////////
@@ -32,32 +35,30 @@ type respMessage struct {
3235
///////////////////////////////////////////////////////////////////////////////
3336
// PUBLIC METHODS
3437

35-
func NewMessage(role, text string) schema.Message {
36-
return schema.Message{
37-
Role: role,
38-
Content: text,
39-
}
40-
}
41-
42-
///////////////////////////////////////////////////////////////////////////////
43-
// API CALLS
44-
4538
// Send a structured list of input messages with text and/or image content,
4639
// and the model will generate the next message in the conversation.
47-
func (c *Client) Messages(message schema.Message) ([]schema.Content, error) {
40+
func (c *Client) Messages(messages []*schema.Message) (*schema.Content, error) {
4841
var request reqMessage
4942
var response respMessage
5043

44+
// Check parameters
45+
if len(messages) == 0 {
46+
return nil, ErrBadParameter.With("messages")
47+
}
48+
49+
// Set defaults
5150
request.Model = defaultMessageModel
5251
request.MaxTokens = defaultMaxTokens
53-
request.Messages = []schema.Message{message}
5452

5553
// Return the response
5654
if payload, err := client.NewJSONRequest(request); err != nil {
5755
return nil, err
5856
} else if err := c.Do(payload, &response, client.OptPath("messages")); err != nil {
5957
return nil, err
60-
} else {
61-
return response.Content, nil
58+
} else if len(response.Content) == 0 {
59+
return nil, ErrInternalAppError.With("No content returned")
6260
}
61+
62+
// Return success
63+
return &response.Content[0], nil
6364
}

pkg/anthropic/message_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ func Test_message_001(t *testing.T) {
1515
client, err := anthropic.New(GetApiKey(t), opts.OptTrace(os.Stderr, true))
1616
assert.NoError(err)
1717
assert.NotNil(client)
18-
_, err = client.Messages(schema.Message{
19-
Role: "user",
20-
Content: "What is the weather today",
21-
})
18+
msg := schema.NewMessage(schema.Anthropic, "user", "What is the weather today")
19+
_, err = client.Messages(msg)
2220
assert.NoError(err)
2321
}

pkg/openai/schema/chat.go

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

pkg/openai/schema/message.go

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
package schema
2+
3+
import (
4+
"encoding/base64"
5+
"encoding/json"
6+
"io"
7+
"net/http"
8+
"os"
9+
"reflect"
10+
"strings"
11+
12+
// Namespace imports
13+
. "github.com/djthorpe/go-errors"
14+
)
15+
16+
///////////////////////////////////////////////////////////////////////////////
17+
// TYPES
18+
19+
// A chat completion message
20+
type Message struct {
21+
// user or assistant
22+
Role string `json:"role"`
23+
24+
// Content can be a string, array of strings, content
25+
// object or an array of content objects
26+
Content any `json:"content,omitempty"`
27+
}
28+
29+
// One choice of chat completion messages
30+
type MessageChoice struct {
31+
Message `json:"message"`
32+
Index int `json:"index"`
33+
FinishReason string `json:"finish_reason"`
34+
}
35+
36+
// Message Content
37+
type Content struct {
38+
Type string `json:"type,width:4"`
39+
Text string `json:"text,wrap,width:60"`
40+
Source *contentSource `json:"source,omitempty"`
41+
}
42+
43+
// Content Source
44+
type contentSource struct {
45+
Type string `json:"type"`
46+
MediaType string `json:"media_type,omitempty"`
47+
Data string `json:"data,omitempty"`
48+
}
49+
50+
///////////////////////////////////////////////////////////////////////////////
51+
// LIFECYCLE
52+
53+
// Create a new message, with optional content
54+
func NewMessage(role string, content ...any) *Message {
55+
message := new(Message)
56+
message.Role = role
57+
58+
// Append content to messages
59+
if len(content) > 0 && message.Add(content...) == nil {
60+
return nil
61+
}
62+
63+
// Return success
64+
return message
65+
}
66+
67+
// Return a new content object of type text
68+
func Text(v string) *Content {
69+
return &Content{Type: "text", Text: v}
70+
}
71+
72+
// Return a new content object of type image, from a io.Reader
73+
func Image(r io.Reader) (*Content, error) {
74+
data, err := io.ReadAll(r)
75+
if err != nil {
76+
return nil, err
77+
}
78+
79+
mimetype := http.DetectContentType(data)
80+
if !strings.HasPrefix(mimetype, "image/") {
81+
return nil, ErrBadParameter.With("Image: not an image file")
82+
}
83+
84+
return &Content{Type: "image", Source: &contentSource{
85+
Type: "base64",
86+
MediaType: mimetype,
87+
Data: base64.StdEncoding.EncodeToString(data),
88+
}}, nil
89+
}
90+
91+
// Return a new content object of type image, from a file
92+
func ImageData(path string) (*Content, error) {
93+
r, err := os.Open(path)
94+
if err != nil {
95+
return nil, err
96+
}
97+
defer r.Close()
98+
return Image(r)
99+
}
100+
101+
///////////////////////////////////////////////////////////////////////////////
102+
// STRINGIFY
103+
104+
func (m Message) String() string {
105+
data, _ := json.MarshalIndent(m, "", " ")
106+
return string(data)
107+
}
108+
109+
///////////////////////////////////////////////////////////////////////////////
110+
// PUBLIC METHODS
111+
112+
func (m *Message) IsValid() bool {
113+
if m.Role == "" {
114+
return false
115+
}
116+
return reflect.ValueOf(m.Content).IsValid()
117+
}
118+
119+
// Append content to the message
120+
func (m *Message) Add(content ...any) *Message {
121+
if len(content) == 0 {
122+
return nil
123+
}
124+
for i := 0; i < len(content); i++ {
125+
if err := m.append(content[i]); err != nil {
126+
panic(err)
127+
}
128+
}
129+
return m
130+
}
131+
132+
///////////////////////////////////////////////////////////////////////////////
133+
// PRIVATE METHODS
134+
135+
// Append message content
136+
func (m *Message) append(v any) error {
137+
// Set if no content
138+
if m.Content == nil {
139+
return m.set(v)
140+
}
141+
// Promote content to array
142+
switch m.Content.(type) {
143+
case string:
144+
switch v := v.(type) {
145+
case string:
146+
// string, string => []string
147+
m.Content = []string{m.Content.(string), v}
148+
return nil
149+
case Content:
150+
// string, Content => []Content
151+
m.Content = []Content{{Type: "text", Text: m.Content.(string)}, v}
152+
return nil
153+
case *Content:
154+
// string, *Content => []Content
155+
m.Content = []Content{{Type: "text", Text: m.Content.(string)}, *v}
156+
return nil
157+
}
158+
case []string:
159+
switch v := v.(type) {
160+
case string:
161+
// []string, string => []string
162+
m.Content = append(m.Content.([]string), v)
163+
return nil
164+
}
165+
case Content:
166+
switch v := v.(type) {
167+
case string:
168+
// Content, string => []Content
169+
m.Content = []Content{m.Content.(Content), {Type: "text", Text: v}}
170+
return nil
171+
case Content:
172+
// Content, Content => []Content
173+
m.Content = []Content{m.Content.(Content), v}
174+
return nil
175+
case *Content:
176+
// Content, *Content => []Content
177+
m.Content = []Content{m.Content.(Content), *v}
178+
return nil
179+
}
180+
case []Content:
181+
switch v := v.(type) {
182+
case string:
183+
// []Content, string => []Content
184+
m.Content = append(m.Content.([]Content), Content{Type: "text", Text: v})
185+
return nil
186+
case *Content:
187+
// []Content, *Content => []Content
188+
m.Content = append(m.Content.([]Content), *v)
189+
return nil
190+
case Content:
191+
// []Content, Content => []Content
192+
m.Content = append(m.Content.([]Content), v)
193+
return nil
194+
}
195+
}
196+
return ErrBadParameter.With("append: not implemented for ", reflect.TypeOf(m.Content), ",", reflect.TypeOf(v))
197+
}
198+
199+
// Set the message content
200+
func (m *Message) set(v any) error {
201+
// Append content to messages,
202+
// m.Content will be of type string, []string, Content or []Content
203+
switch v := v.(type) {
204+
case string:
205+
m.Content = v
206+
case []string:
207+
m.Content = v
208+
case *Content:
209+
m.Content = *v
210+
case Content:
211+
m.Content = v
212+
case []*Content:
213+
if len(v) > 0 {
214+
m.Content = make([]Content, 0, len(v))
215+
for _, v := range v {
216+
m.Content = append(m.Content.([]Content), *v)
217+
}
218+
}
219+
case []Content:
220+
if len(v) > 0 {
221+
m.Content = make([]Content, 0, len(v))
222+
for _, v := range v {
223+
m.Content = append(m.Content.([]Content), v)
224+
}
225+
}
226+
default:
227+
return ErrBadParameter.With("Add: not implemented for type", reflect.TypeOf(v))
228+
}
229+
230+
// Return success
231+
return nil
232+
}

0 commit comments

Comments
 (0)