llm: make Tool.Run return ToolOut
This is preliminary work towards
allowing tools to add additional information.
No functional changes (at least, that's the intent).
diff --git a/loop/agent.go b/loop/agent.go
index 781f4fe..9927d68 100644
--- a/loop/agent.go
+++ b/loop/agent.go
@@ -1483,13 +1483,13 @@
},
"required": ["question", "responseOptions"]
}`),
- Run: func(ctx context.Context, input json.RawMessage) ([]llm.Content, error) {
+ Run: func(ctx context.Context, input json.RawMessage) llm.ToolOut {
// The Run logic for "multiplechoice" tool is a no-op on the server.
// The UI will present a list of options for the user to select from,
// and that's it as far as "executing" the tool_use goes.
// When the user *does* select one of the presented options, that
// responseText gets sent as a chat message on behalf of the user.
- return llm.TextContent("end your turn and wait for the user to respond"), nil
+ return llm.ToolOut{LLMContent: llm.TextContent("end your turn and wait for the user to respond")}
},
}
@@ -1533,32 +1533,32 @@
},
"required": ["slug"]
}`),
- Run: func(ctx context.Context, input json.RawMessage) ([]llm.Content, error) {
+ Run: func(ctx context.Context, input json.RawMessage) llm.ToolOut {
var params struct {
Slug string `json:"slug"`
}
if err := json.Unmarshal(input, ¶ms); err != nil {
- return nil, err
+ return llm.ErrorToolOut(err)
}
// Prevent slug changes if there have been git changes
// This lets the agent change its mind about a good slug,
// while ensuring that once a branch has been pushed, it remains stable.
if s := a.Slug(); s != "" && s != params.Slug && a.gitState.HasSeenCommits() {
- return nil, fmt.Errorf("slug already set to %q", s)
+ return llm.ErrorfToolOut("slug already set to %q", s)
}
if params.Slug == "" {
- return nil, fmt.Errorf("slug parameter cannot be empty")
+ return llm.ErrorToolOut(fmt.Errorf("slug parameter cannot be empty"))
}
slug := cleanSlugName(params.Slug)
if slug == "" {
- return nil, fmt.Errorf("slug parameter could not be converted to a valid slug")
+ return llm.ErrorToolOut(fmt.Errorf("slug parameter could not be converted to a valid slug"))
}
a.SetSlug(slug)
// TODO: do this by a call to outie, rather than semi-guessing from innie
if branchExists(a.workingDir, a.BranchName()) {
- return nil, fmt.Errorf("slug %q already exists; please choose a different slug", slug)
+ return llm.ErrorfToolOut("slug %q already exists; please choose a different slug", slug)
}
- return llm.TextContent("OK"), nil
+ return llm.ToolOut{LLMContent: llm.TextContent("OK")}
},
}
}
@@ -1569,12 +1569,12 @@
Name: "commit-message-style",
Description: description,
InputSchema: llm.EmptySchema(),
- Run: func(ctx context.Context, input json.RawMessage) ([]llm.Content, error) {
+ Run: func(ctx context.Context, input json.RawMessage) llm.ToolOut {
styleHint, err := claudetool.CommitMessageStyleHint(ctx, a.repoRoot)
if err != nil {
slog.DebugContext(ctx, "failed to get commit message style hint", "err", err)
}
- return llm.TextContent(styleHint), nil
+ return llm.ToolOut{LLMContent: llm.TextContent(styleHint)}
},
}
return preCommit
@@ -1582,11 +1582,11 @@
// patchCallback is the agent's patch tool callback.
// It warms the codereview cache in the background.
-func (a *Agent) patchCallback(input claudetool.PatchInput, result []llm.Content, err error) ([]llm.Content, error) {
+func (a *Agent) patchCallback(input claudetool.PatchInput, output llm.ToolOut) llm.ToolOut {
if a.codereview != nil {
a.codereview.WarmTestCache(input.Path)
}
- return result, err
+ return output
}
func (a *Agent) Ready() <-chan struct{} {