Skip to content

Commit a2d782f

Browse files
feat(coderd): allow specifying a name for a task
1 parent 776231d commit a2d782f

File tree

4 files changed

+96
-8
lines changed

4 files changed

+96
-8
lines changed

coderd/aitasks.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,27 @@ func (api *API) tasksCreate(rw http.ResponseWriter, r *http.Request) {
113113
return
114114
}
115115

116-
taskName := taskname.GenerateFallback()
117-
if anthropicAPIKey := taskname.GetAnthropicAPIKeyFromEnv(); anthropicAPIKey != "" {
118-
anthropicModel := taskname.GetAnthropicModelFromEnv()
116+
taskName := req.Name
117+
if err := codersdk.NameValid(taskName); taskName != "" && err != nil {
118+
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
119+
Message: "Unable to create a Task with the provided name.",
120+
Detail: err.Error(),
121+
})
122+
return
123+
}
119124

120-
generatedName, err := taskname.Generate(ctx, req.Prompt, taskname.WithAPIKey(anthropicAPIKey), taskname.WithModel(anthropicModel))
121-
if err != nil {
122-
api.Logger.Error(ctx, "unable to generate task name", slog.Error(err))
123-
} else {
124-
taskName = generatedName
125+
if taskName == "" {
126+
taskName = taskname.GenerateFallback()
127+
128+
if anthropicAPIKey := taskname.GetAnthropicAPIKeyFromEnv(); anthropicAPIKey != "" {
129+
anthropicModel := taskname.GetAnthropicModelFromEnv()
130+
131+
generatedName, err := taskname.Generate(ctx, req.Prompt, taskname.WithAPIKey(anthropicAPIKey), taskname.WithModel(anthropicModel))
132+
if err != nil {
133+
api.Logger.Error(ctx, "unable to generate task name", slog.Error(err))
134+
} else {
135+
taskName = generatedName
136+
}
125137
}
126138
}
127139

coderd/aitasks_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,80 @@ func TestTasksCreate(t *testing.T) {
441441
assert.Equal(t, taskPrompt, parameters[0].Value)
442442
})
443443

444+
t.Run("CustomNames", func(t *testing.T) {
445+
t.Parallel()
446+
447+
tests := []struct {
448+
name string
449+
taskName string
450+
expectFallbackName bool
451+
expectError string
452+
}{
453+
{
454+
name: "ValidName",
455+
taskName: "a-valid-task-name",
456+
},
457+
{
458+
name: "NotValidName",
459+
taskName: "this is not a valid task name",
460+
expectError: "Unable to create a Task with the provided name.",
461+
},
462+
{
463+
name: "NoNameProvided",
464+
taskName: "",
465+
expectFallbackName: true,
466+
},
467+
}
468+
469+
for _, tt := range tests {
470+
t.Run(tt.name, func(t *testing.T) {
471+
t.Parallel()
472+
473+
var (
474+
ctx = testutil.Context(t, testutil.WaitShort)
475+
client = coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
476+
expClient = codersdk.NewExperimentalClient(client)
477+
user = coderdtest.CreateFirstUser(t, client)
478+
version = coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
479+
Parse: echo.ParseComplete,
480+
ProvisionApply: echo.ApplyComplete,
481+
ProvisionPlan: []*proto.Response{
482+
{Type: &proto.Response_Plan{Plan: &proto.PlanComplete{
483+
Parameters: []*proto.RichParameter{{Name: "AI Prompt", Type: "string"}},
484+
HasAiTasks: true,
485+
}}},
486+
},
487+
})
488+
template = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
489+
)
490+
491+
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
492+
493+
// When: We attempt to create a Task.
494+
task, err := expClient.CreateTask(ctx, "me", codersdk.CreateTaskRequest{
495+
TemplateVersionID: template.ActiveVersionID,
496+
Prompt: "Some prompt",
497+
Name: tt.taskName,
498+
})
499+
if tt.expectError == "" {
500+
require.NoError(t, err)
501+
require.True(t, task.WorkspaceID.Valid)
502+
503+
// Then: We expect the correct name to have been picked.
504+
err = codersdk.NameValid(task.Name)
505+
require.NoError(t, err, "Generated task name should be valid")
506+
507+
require.NotEmpty(t, task.Name)
508+
if !tt.expectFallbackName {
509+
require.Equal(t, tt.taskName, task.Name)
510+
}
511+
} else {
512+
require.ErrorContains(t, err, tt.expectError)
513+
}
514+
})
515+
}
516+
})
517+
444518
t.Run("FailsOnNonTaskTemplate", func(t *testing.T) {
445519
t.Parallel()
446520

codersdk/aitasks.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type CreateTaskRequest struct {
5151
TemplateVersionID uuid.UUID `json:"template_version_id" format:"uuid"`
5252
TemplateVersionPresetID uuid.UUID `json:"template_version_preset_id,omitempty" format:"uuid"`
5353
Prompt string `json:"prompt"`
54+
Name string `json:"name,omitempty"`
5455
}
5556

5657
func (c *ExperimentalClient) CreateTask(ctx context.Context, user string, request CreateTaskRequest) (Task, error) {

site/src/api/typesGenerated.ts

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)