fix(coderd/x/chatd/chattool): parse complete goal IDs from strings

This commit is contained in:
Michael Suchacz
2026-05-29 22:55:01 +00:00
parent 8eaa0cd616
commit 4063c205f2
2 changed files with 33 additions and 5 deletions
+12 -5
View File
@@ -32,8 +32,8 @@ type GoalToolOptions struct {
type getGoalArgs struct{}
type completeGoalArgs struct {
GoalID uuid.UUID `json:"goal_id" description:"The expected current goal ID. The tool fails if the current goal changed."`
Summary string `json:"summary" description:"A concise non-empty summary of how the goal was completed."`
GoalID string `json:"goal_id" description:"The expected current goal ID. The tool fails if the current goal changed."`
Summary string `json:"summary" description:"A concise non-empty summary of how the goal was completed."`
}
type goalResult struct {
@@ -74,9 +74,16 @@ func CompleteGoal(db database.Store, options GoalToolOptions) fantasy.AgentTool
if !options.IsRootChat {
return fantasy.NewTextErrorResponse("complete_goal can only be used from the root chat"), nil
}
if args.GoalID == uuid.Nil {
goalIDStr := strings.TrimSpace(args.GoalID)
if goalIDStr == "" {
return fantasy.NewTextErrorResponse("goal_id is required"), nil
}
goalID, err := uuid.Parse(goalIDStr)
if err != nil {
return fantasy.NewTextErrorResponse(
xerrors.Errorf("invalid goal_id: %w", err).Error(),
), nil
}
summary := strings.TrimSpace(args.Summary)
if summary == "" {
return fantasy.NewTextErrorResponse("summary is required"), nil
@@ -98,7 +105,7 @@ func CompleteGoal(db database.Store, options GoalToolOptions) fantasy.AgentTool
}
return err
}
if current.ID != args.GoalID {
if current.ID != goalID {
return sql.ErrNoRows
}
if current.Status != database.ChatGoalStatusActive {
@@ -109,7 +116,7 @@ func CompleteGoal(db database.Store, options GoalToolOptions) fantasy.AgentTool
}
completed, err = tx.CompleteChatGoalByID(ctx, database.CompleteChatGoalByIDParams{
RootChatID: options.RootChatID,
ID: args.GoalID,
ID: goalID,
CompletionSummary: sql.NullString{
String: summary,
Valid: true,
+21
View File
@@ -81,6 +81,17 @@ func TestGoalTools(t *testing.T) {
require.Equal(t, database.ChatGoalStatusComplete, completedGoal.Status)
}
func TestCompleteGoalSchemaUsesStringGoalID(t *testing.T) {
t.Parallel()
tool := chattool.CompleteGoal(nil, chattool.GoalToolOptions{})
info := tool.Info()
goalIDParam, ok := info.Parameters["goal_id"].(map[string]any)
require.True(t, ok)
require.Equal(t, "string", goalIDParam["type"])
require.NotEqual(t, "array", goalIDParam["type"])
}
func TestGetGoalReturnsNullWithoutCurrentGoal(t *testing.T) {
t.Parallel()
@@ -134,6 +145,16 @@ func TestCompleteGoalValidatesInput(t *testing.T) {
input: `{"summary":"done"}`,
message: "goal_id is required",
},
{
name: "empty goal id",
input: `{"goal_id":" ","summary":"done"}`,
message: "goal_id is required",
},
{
name: "invalid goal id",
input: `{"goal_id":"not-a-uuid","summary":"done"}`,
message: "invalid goal_id",
},
{
name: "empty summary",
input: `{"goal_id":"00000000-0000-4000-8000-000000000001","summary":" "}`,