Skip to content

Commit b7cac70

Browse files
urjitbhatiahenomis
andauthored
Feat/messages api (#546)
* fix test server setup: - go map access is not deterministic - this can lead to a route: /foo/bar/1 matching /foo/bar before matching /foo/bar/1 if the map iteration go through /foo/bar first since the regex match wasn't bound to start and end anchors - registering handlers now converts * in routes to .* for proper regex matching - test server route handling now tries to fully match the handler route * add missing /v1 prefix to fine-tuning job cancel test server handler * add create message call * add messages list call * add get message call * add modify message call, fix return types for other message calls * add message file retrieve call * add list message files call * code style fixes * add test for list messages with pagination options * add beta header to msg calls now that #545 is merged * Update messages.go Co-authored-by: Simone Vellei <[email protected]> * Update messages.go Co-authored-by: Simone Vellei <[email protected]> * add missing object details for message, fix tests * fix merge formatting * minor style fixes --------- Co-authored-by: Simone Vellei <[email protected]>
1 parent 9fefd50 commit b7cac70

File tree

3 files changed

+431
-0
lines changed

3 files changed

+431
-0
lines changed

client_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,24 @@ func TestClientReturnsRequestBuilderErrors(t *testing.T) {
301301
{"DeleteAssistantFile", func() (any, error) {
302302
return nil, client.DeleteAssistantFile(ctx, "", "")
303303
}},
304+
{"CreateMessage", func() (any, error) {
305+
return client.CreateMessage(ctx, "", MessageRequest{})
306+
}},
307+
{"ListMessage", func() (any, error) {
308+
return client.ListMessage(ctx, "", nil, nil, nil, nil)
309+
}},
310+
{"RetrieveMessage", func() (any, error) {
311+
return client.RetrieveMessage(ctx, "", "")
312+
}},
313+
{"ModifyMessage", func() (any, error) {
314+
return client.ModifyMessage(ctx, "", "", nil)
315+
}},
316+
{"RetrieveMessageFile", func() (any, error) {
317+
return client.RetrieveMessageFile(ctx, "", "", "")
318+
}},
319+
{"ListMessageFiles", func() (any, error) {
320+
return client.ListMessageFiles(ctx, "", "")
321+
}},
304322
{"CreateThread", func() (any, error) {
305323
return client.CreateThread(ctx, ThreadRequest{})
306324
}},

messages.go

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package openai
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
"net/url"
8+
)
9+
10+
const (
11+
messagesSuffix = "messages"
12+
)
13+
14+
type Message struct {
15+
ID string `json:"id"`
16+
Object string `json:"object"`
17+
CreatedAt int `json:"created_at"`
18+
ThreadID string `json:"thread_id"`
19+
Role string `json:"role"`
20+
Content []MessageContent `json:"content"`
21+
FileIds []string `json:"file_ids"`
22+
AssistantID *string `json:"assistant_id,omitempty"`
23+
RunID *string `json:"run_id,omitempty"`
24+
Metadata map[string]any `json:"metadata"`
25+
26+
httpHeader
27+
}
28+
29+
type MessagesList struct {
30+
Messages []Message `json:"data"`
31+
32+
httpHeader
33+
}
34+
35+
type MessageContent struct {
36+
Type string `json:"type"`
37+
Text *MessageText `json:"text,omitempty"`
38+
ImageFile *ImageFile `json:"image_file,omitempty"`
39+
}
40+
type MessageText struct {
41+
Value string `json:"value"`
42+
Annotations []any `json:"annotations"`
43+
}
44+
45+
type ImageFile struct {
46+
FileID string `json:"file_id"`
47+
}
48+
49+
type MessageRequest struct {
50+
Role string `json:"role"`
51+
Content string `json:"content"`
52+
FileIds []string `json:"file_ids,omitempty"`
53+
Metadata map[string]any `json:"metadata,omitempty"`
54+
}
55+
56+
type MessageFile struct {
57+
ID string `json:"id"`
58+
Object string `json:"object"`
59+
CreatedAt int `json:"created_at"`
60+
MessageID string `json:"message_id"`
61+
62+
httpHeader
63+
}
64+
65+
type MessageFilesList struct {
66+
MessageFiles []MessageFile `json:"data"`
67+
68+
httpHeader
69+
}
70+
71+
// CreateMessage creates a new message.
72+
func (c *Client) CreateMessage(ctx context.Context, threadID string, request MessageRequest) (msg Message, err error) {
73+
urlSuffix := fmt.Sprintf("/threads/%s/%s", threadID, messagesSuffix)
74+
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix), withBody(request))
75+
if err != nil {
76+
return
77+
}
78+
79+
err = c.sendRequest(req, &msg)
80+
return
81+
}
82+
83+
// ListMessage fetches all messages in the thread.
84+
func (c *Client) ListMessage(ctx context.Context, threadID string,
85+
limit *int,
86+
order *string,
87+
after *string,
88+
before *string,
89+
) (messages MessagesList, err error) {
90+
urlValues := url.Values{}
91+
if limit != nil {
92+
urlValues.Add("limit", fmt.Sprintf("%d", *limit))
93+
}
94+
if order != nil {
95+
urlValues.Add("order", *order)
96+
}
97+
if after != nil {
98+
urlValues.Add("after", *after)
99+
}
100+
if before != nil {
101+
urlValues.Add("before", *before)
102+
}
103+
encodedValues := ""
104+
if len(urlValues) > 0 {
105+
encodedValues = "?" + urlValues.Encode()
106+
}
107+
108+
urlSuffix := fmt.Sprintf("/threads/%s/%s%s", threadID, messagesSuffix, encodedValues)
109+
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix), withBetaAssistantV1())
110+
if err != nil {
111+
return
112+
}
113+
114+
err = c.sendRequest(req, &messages)
115+
return
116+
}
117+
118+
// RetrieveMessage retrieves a Message.
119+
func (c *Client) RetrieveMessage(
120+
ctx context.Context,
121+
threadID, messageID string,
122+
) (msg Message, err error) {
123+
urlSuffix := fmt.Sprintf("/threads/%s/%s/%s", threadID, messagesSuffix, messageID)
124+
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix), withBetaAssistantV1())
125+
if err != nil {
126+
return
127+
}
128+
129+
err = c.sendRequest(req, &msg)
130+
return
131+
}
132+
133+
// ModifyMessage modifies a message.
134+
func (c *Client) ModifyMessage(
135+
ctx context.Context,
136+
threadID, messageID string,
137+
metadata map[string]any,
138+
) (msg Message, err error) {
139+
urlSuffix := fmt.Sprintf("/threads/%s/%s/%s", threadID, messagesSuffix, messageID)
140+
req, err := c.newRequest(ctx, http.MethodPost, c.fullURL(urlSuffix),
141+
withBody(metadata), withBetaAssistantV1())
142+
if err != nil {
143+
return
144+
}
145+
146+
err = c.sendRequest(req, &msg)
147+
return
148+
}
149+
150+
// RetrieveMessageFile fetches a message file.
151+
func (c *Client) RetrieveMessageFile(
152+
ctx context.Context,
153+
threadID, messageID, fileID string,
154+
) (file MessageFile, err error) {
155+
urlSuffix := fmt.Sprintf("/threads/%s/%s/%s/files/%s", threadID, messagesSuffix, messageID, fileID)
156+
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix), withBetaAssistantV1())
157+
if err != nil {
158+
return
159+
}
160+
161+
err = c.sendRequest(req, &file)
162+
return
163+
}
164+
165+
// ListMessageFiles fetches all files attached to a message.
166+
func (c *Client) ListMessageFiles(
167+
ctx context.Context,
168+
threadID, messageID string,
169+
) (files MessageFilesList, err error) {
170+
urlSuffix := fmt.Sprintf("/threads/%s/%s/%s/files", threadID, messagesSuffix, messageID)
171+
req, err := c.newRequest(ctx, http.MethodGet, c.fullURL(urlSuffix), withBetaAssistantV1())
172+
if err != nil {
173+
return
174+
}
175+
176+
err = c.sendRequest(req, &files)
177+
return
178+
}

0 commit comments

Comments
 (0)