This code creates the thread, the run, and respond to the tool outputs. I only put the relevant functions.
func (c *Assistant) retrieveAssistantFunctionCall(ctx context.Context, run openai.Run) ([]*ChatMessage, error) {
steps, err := c.client.ListRunSteps(ctx, run.ThreadID, run.ID, openai.Pagination{})
if err != nil {
return nil, err
}
if steps.HasMore {
printer.Warn("Run has more steps, we are not handling this case yet")
}
cm := make([]*ChatMessage, 0)
toolCallIDs := make([]string, 0)
for _, s := range steps.RunSteps {
if s.Type != openai.RunStepTypeToolCalls {
continue
}
for _, tc := range s.StepDetails.ToolCalls {
printer.Debug("Tool call: %v", tc.ID)
if tc.Type != openai.ToolTypeFunction {
printer.Warn("Tool call type is not a function")
continue
}
cm = append(cm, &ChatMessage{
Metadata: make(map[string]any),
Content: tc.Function.Arguments,
})
toolCallIDs = append(toolCallIDs, tc.ID)
}
}
toolOutputs := make([]openai.ToolOutput, len(toolCallIDs))
for i, tcID := range toolCallIDs {
toolOutputs[i] = openai.ToolOutput{
ToolCallID: tcID,
Output: `{"success": true}`,
}
}
// Respond to the function calls to process the next messages
if _, err = c.client.SubmitToolOutputs(ctx, run.ThreadID, run.ID, openai.SubmitToolOutputsRequest{
ToolOutputs: toolOutputs,
}); err != nil {
return nil, err
}
return cm, nil
}
func (c *Assistant) RunNewThread(ctx context.Context, messages []*ChatMessage) ([]*ChatMessage, error) {
printer.Debug("OpenAI must process %d messages", len(messages))
tm := make([]openai.ThreadMessage, len(messages))
for i, message := range messages {
tm[i] = openai.ThreadMessage{
Content: message.Content,
Role: openai.ThreadMessageRoleUser,
Metadata: message.Metadata,
}
}
run, err := c.client.CreateThreadAndRun(ctx, openai.CreateThreadAndRunRequest{
RunRequest: openai.RunRequest{
AssistantID: c.assistantID,
},
Thread: openai.ThreadRequest{
Messages: tm,
},
})
if err != nil {
return nil, err
}
log.Printf("Run id %v and thread id %v", run.ID, run.ThreadID)
status, err := c.waitForStatusToBeAcceptable(ctx, &run, openai.RunStatusCompleted, openai.RunStatusRequiresAction)
if err != nil {
return nil, err
}
l := len(messages)
processedMessage := 0
returnedMsgs := make([]*ChatMessage, 0)
for status == openai.RunStatusRequiresAction && processedMessage < l {
printer.Debug("Processed messages %d/%d", processedMessage, l)
var msgs []*ChatMessage
if msgs, err = c.retrieveAssistantFunctionCall(ctx, run); err != nil {
return nil, err
}
printer.Debug("Retrieved %d messages", len(msgs))
processedMessage += len(msgs)
returnedMsgs = append(returnedMsgs, msgs...)
status, err = c.waitForStatusToBeAcceptable(ctx, &run, openai.RunStatusCompleted, openai.RunStatusRequiresAction)
log.Printf("Status: %s & %+v", status, msgs)
}
return returnedMsgs, nil
}
Let me know if you want me to clarify something.