Files
coder/coderd/taskname/taskname_test.go
T
Susana Ferreira 3011207519 feat: add display name field for tasks (#20856)
## Problem

Tasks currently only expose a machine-friendly name field (e.g.
`task-python-debug-a1b2`), but this value is primarily an identifier
rather than a clean, descriptive label. We need a separate
display-friendly name for use in the UI.

This PR introduces a new `display_name` field and updates the task-name
generation flow. The Claude system prompt was updated to return valid
JSON with both `name` and `display_name`. The name generation logic
follows a fallback chain (Anthropic > prompt sanitization > random
fallback). To make task names more closely resemble their display names,
the legacy `task-` prefix has been removed. For context, PR
https://github.com/coder/coder/pull/20834 introduced a small Task icon
to the workspace list to help identify workspaces associated to tasks.

## Changes

- Database migration: Added `display_name` column to tasks table
- Updated system prompt to generate both task name and display name as
valid JSON
- Task name generation now follows a fallback chain: Anthropic > prompt
sanitization > random fallback
- Removed `task-` prefix from task names to allow more descriptive names
- Note: PR https://github.com/coder/coder/pull/20834 adds a Task icon to
workspaces in the workspace list to distinguish task-created workspaces

**Note:** UI changes will be addressed in a follow-up PR

Related to: https://github.com/coder/coder/issues/20801
2025-11-25 13:00:59 +00:00

66 lines
1.8 KiB
Go

package taskname_test
import (
"os"
"testing"
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/coderd/taskname"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/testutil"
)
const (
anthropicEnvVar = "ANTHROPIC_API_KEY"
)
func TestGenerate(t *testing.T) {
t.Run("FromPrompt", func(t *testing.T) {
// Ensure no API key in env for this test
t.Setenv("ANTHROPIC_API_KEY", "")
ctx := testutil.Context(t, testutil.WaitShort)
taskName := taskname.Generate(ctx, testutil.Logger(t), "Create a finance planning app")
// Should succeed via prompt sanitization
require.NoError(t, codersdk.NameValid(taskName.Name))
require.Contains(t, taskName.Name, "create-a-finance-planning-")
require.NotEmpty(t, taskName.DisplayName)
require.Equal(t, "Create a finance planning app", taskName.DisplayName)
})
t.Run("FromAnthropic", func(t *testing.T) {
apiKey := os.Getenv(anthropicEnvVar)
if apiKey == "" {
t.Skipf("Skipping test as %s not set", anthropicEnvVar)
}
// Set API key for this test
t.Setenv("ANTHROPIC_API_KEY", apiKey)
ctx := testutil.Context(t, testutil.WaitShort)
taskName := taskname.Generate(ctx, testutil.Logger(t), "Create a finance planning app")
// Should succeed with Claude-generated names
require.NoError(t, codersdk.NameValid(taskName.Name))
require.NotEmpty(t, taskName.DisplayName)
})
t.Run("Fallback", func(t *testing.T) {
// Ensure no API key
t.Setenv("ANTHROPIC_API_KEY", "")
ctx := testutil.Context(t, testutil.WaitShort)
// Use a prompt that can't be sanitized (only special chars)
taskName := taskname.Generate(ctx, testutil.Logger(t), "!@#$%^&*()")
// Should fall back to random name
require.NoError(t, codersdk.NameValid(taskName.Name))
require.NotEmpty(t, taskName.DisplayName)
})
}