Compare commits

...
2 Commits
Author SHA1 Message Date
dwrz 6592bae15d Add concurrent tool calls 2026-07-08 01:59:11 +00:00
dwrz f85a9eeb3f Update go module version 2026-07-08 01:56:34 +00:00
5 changed files with 59 additions and 54 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
module code.chimeric.al/chimerical/odidere module code.chimeric.al/chimerical/odidere
go 1.25.5 go 1.26
tool ( tool (
golang.org/x/tools/cmd/deadcode golang.org/x/tools/cmd/deadcode
-2
View File
@@ -10,8 +10,6 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/sashabaranov/go-openai v1.41.2 h1:vfPRBZNMpnqu8ELsclWcAvF19lDNgh1t6TVfFFOPiSM=
github.com/sashabaranov/go-openai v1.41.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 h1:1P7xPZEwZMoBoz0Yze5Nx2/4pxj6nw9ZqHWXqP0iRgQ= golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 h1:1P7xPZEwZMoBoz0Yze5Nx2/4pxj6nw9ZqHWXqP0iRgQ=
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
+4 -8
View File
@@ -97,10 +97,7 @@ func (c *Client) Completions(
Timings: finalTimings, Timings: finalTimings,
}, nil }, nil
} }
toolResults, err := c.callTools(ctx, *message) toolResults := c.callTools(ctx, *message)
if err != nil {
return nil, fmt.Errorf("completions: %w", err)
}
messages = append(messages, toolResults...) messages = append(messages, toolResults...)
} }
@@ -126,6 +123,7 @@ func (c *Client) completions(
Tools: c.tools, Tools: c.tools,
ThinkingBudgetTokens: thinkingBudgetTokens, ThinkingBudgetTokens: thinkingBudgetTokens,
ChatTemplateKWARGS: kwargs, ChatTemplateKWARGS: kwargs,
ParallelToolCalls: new(true),
}) })
if err != nil { if err != nil {
return nil, fmt.Errorf( return nil, fmt.Errorf(
@@ -286,10 +284,7 @@ func (c *Client) CompletionsStream(
if len(message.ToolCalls) == 0 { if len(message.ToolCalls) == 0 {
return nil return nil
} }
toolResults, err := c.callTools(ctx, message) toolResults := c.callTools(ctx, message)
if err != nil {
return fmt.Errorf("completions stream: %w", err)
}
for _, tr := range toolResults { for _, tr := range toolResults {
events <- StreamEvent{ events <- StreamEvent{
Type: streamEventMessage, Type: streamEventMessage,
@@ -328,6 +323,7 @@ func (c *Client) completionsStream(ctx context.Context, messages []Message, mode
Tools: c.tools, Tools: c.tools,
ThinkingBudgetTokens: thinkingBudgetTokens, ThinkingBudgetTokens: thinkingBudgetTokens,
ChatTemplateKWARGS: kwargs, ChatTemplateKWARGS: kwargs,
ParallelToolCalls: new(true),
StreamOptions: &StreamOptions{IncludeUsage: true}, StreamOptions: &StreamOptions{IncludeUsage: true},
}) })
if err != nil { if err != nil {
+54 -42
View File
@@ -4,58 +4,70 @@ import (
"context" "context"
"fmt" "fmt"
"log/slog" "log/slog"
"runtime"
"strings" "strings"
"sync"
) )
// callTools executes each tool call in the message and returns the // callTools executes each tool call in the message concurrently and returns
// resulting tool result messages. // the resulting tool result messages in the same order as the input calls.
func (c *Client) callTools(ctx context.Context, msg Message) ( func (c *Client) callTools(ctx context.Context, msg Message) []Message {
results []Message, err error, var (
) { results = make([]Message, len(msg.ToolCalls))
for _, tc := range msg.ToolCalls { sem = make(chan struct{}, runtime.NumCPU()*2)
c.log.InfoContext( wg sync.WaitGroup
ctx, )
"calling tool", for i, tc := range msg.ToolCalls {
slog.String("name", tc.Function.Name), wg.Add(1)
slog.String("args", tc.Function.Arguments), go func(idx int, tc ToolCall) {
) defer wg.Done()
sem <- struct{}{}
defer func() { <-sem }()
result, err := c.registry.Execute(
ctx, tc.Function.Name, tc.Function.Arguments,
)
if err != nil {
c.log.ErrorContext(
ctx,
"failed to call tool",
slog.Any("error", err),
slog.String("name", tc.Function.Name),
)
result = fmt.Sprintf(
`{"ok": false, "error": %q}`, err,
)
} else {
c.log.InfoContext( c.log.InfoContext(
ctx, ctx,
"called tool", "calling tool",
slog.String("name", tc.Function.Name), slog.String("name", tc.Function.Name),
slog.String("args", tc.Function.Arguments),
) )
}
// Content cannot be empty. result, err := c.registry.Execute(
if strings.TrimSpace(result) == "" { ctx, tc.Function.Name, tc.Function.Arguments,
result = `{"ok": true, "result": null}` )
} if err != nil {
c.log.ErrorContext(
ctx,
"failed to call tool",
slog.Any("error", err),
slog.String("name", tc.Function.Name),
)
result = fmt.Sprintf(
`{"ok": false, "error": %q}`, err,
)
} else {
c.log.InfoContext(
ctx,
"called tool",
slog.String("name", tc.Function.Name),
)
}
toolResult := Message{ // Content cannot be empty.
Role: RoleTool, if strings.TrimSpace(result) == "" {
ContentParts: []ContentPart{{ result = `{"ok": true, "result": null}`
Type: ContentTypeText, Text: result, }
}},
Name: tc.Function.Name, results[idx] = Message{
ToolCallID: tc.ID, Role: RoleTool,
} ContentParts: []ContentPart{{
results = append(results, toolResult) Type: ContentTypeText, Text: result,
}},
Name: tc.Function.Name,
ToolCallID: tc.ID,
}
}(i, tc)
} }
return results, nil wg.Wait()
return results
} }
-1
View File
@@ -8,7 +8,6 @@ github.com/google/uuid
# github.com/robfig/cron/v3 v3.0.1 # github.com/robfig/cron/v3 v3.0.1
## explicit; go 1.12 ## explicit; go 1.12
github.com/robfig/cron/v3 github.com/robfig/cron/v3
## explicit; go 1.18
# golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 # golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678
## explicit; go 1.18 ## explicit; go 1.18
golang.org/x/exp/typeparams golang.org/x/exp/typeparams