Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions coderd/aitasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
"github.com/coder/coder/v2/coderd/rbac/policy"
"github.com/coder/coder/v2/coderd/searchquery"
"github.com/coder/coder/v2/coderd/util/ptr"
"github.com/coder/coder/v2/coderd/util/slice"
"github.com/coder/coder/v2/codersdk"
)

Expand Down Expand Up @@ -131,31 +130,10 @@ func (api *API) tasksCreate(rw http.ResponseWriter, r *http.Request) {
}
}

// Check if the template defines the AI Prompt parameter.
templateParams, err := api.Database.GetTemplateVersionParameters(ctx, req.TemplateVersionID)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching template parameters.",
Detail: err.Error(),
})
return
}

var richParams []codersdk.WorkspaceBuildParameter
if _, hasAIPromptParam := slice.Find(templateParams, func(param database.TemplateVersionParameter) bool {
return param.Name == codersdk.AITaskPromptParameterName
}); hasAIPromptParam {
// Only add the AI Prompt parameter if the template defines it.
richParams = []codersdk.WorkspaceBuildParameter{
{Name: codersdk.AITaskPromptParameterName, Value: req.Input},
}
}

createReq := codersdk.CreateWorkspaceRequest{
Name: taskName,
TemplateVersionID: req.TemplateVersionID,
TemplateVersionPresetID: req.TemplateVersionPresetID,
RichParameterValues: richParams,
}

var owner workspaceOwner
Expand Down
58 changes: 4 additions & 54 deletions coderd/aitasks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func TestTasks(t *testing.T) {
o(&opt)
}

// Create a template version that supports AI tasks with the AI Prompt parameter.
// Create a template version that supports AI tasks.
taskAppID := uuid.New()
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
Expand Down Expand Up @@ -137,7 +137,7 @@ func TestTasks(t *testing.T) {

got, ok := slice.Find(tasks, func(t codersdk.Task) bool { return t.ID == task.ID })
require.True(t, ok, "task should be found in the list")
assert.Equal(t, wantPrompt, got.InitialPrompt, "task prompt should match the AI Prompt parameter")
assert.Equal(t, wantPrompt, got.InitialPrompt, "task prompt should match the input")
assert.Equal(t, task.WorkspaceID.UUID, got.WorkspaceID.UUID, "workspace id should match")
assert.Equal(t, task.WorkspaceName, got.WorkspaceName, "workspace name should match")
// Status should be populated via the tasks_with_status view.
Expand Down Expand Up @@ -196,7 +196,7 @@ func TestTasks(t *testing.T) {

assert.Equal(t, task.ID, updated.ID, "task ID should match")
assert.Equal(t, task.Name, updated.Name, "task name should match")
assert.Equal(t, wantPrompt, updated.InitialPrompt, "task prompt should match the AI Prompt parameter")
assert.Equal(t, wantPrompt, updated.InitialPrompt, "task prompt should match the input")
assert.Equal(t, task.WorkspaceID.UUID, updated.WorkspaceID.UUID, "workspace id should match")
assert.Equal(t, task.WorkspaceName, updated.WorkspaceName, "workspace name should match")
assert.Equal(t, ws.LatestBuild.BuildNumber, updated.WorkspaceBuildNumber, "workspace build number should match")
Expand Down Expand Up @@ -971,56 +971,6 @@ func TestTasksCreate(t *testing.T) {
require.Len(t, parameters, 0)
})

t.Run("OK AIPromptBackCompat", func(t *testing.T) {
t.Parallel()

var (
ctx = testutil.Context(t, testutil.WaitShort)

taskPrompt = "Some task prompt"
)

client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
user := coderdtest.CreateFirstUser(t, client)

// Given: A template with an "AI Prompt" parameter
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
Parse: echo.ParseComplete,
ProvisionApply: echo.ApplyComplete,
ProvisionGraph: []*proto.Response{
{Type: &proto.Response_Graph{Graph: &proto.GraphComplete{
Parameters: []*proto.RichParameter{{Name: codersdk.AITaskPromptParameterName, Type: "string"}},
HasAiTasks: true,
}}},
},
})
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)

// When: We attempt to create a Task.
task, err := client.CreateTask(ctx, "me", codersdk.CreateTaskRequest{
TemplateVersionID: template.ActiveVersionID,
Input: taskPrompt,
})
require.NoError(t, err)
require.True(t, task.WorkspaceID.Valid)

ws, err := client.Workspace(ctx, task.WorkspaceID.UUID)
require.NoError(t, err)
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, ws.LatestBuild.ID)

// Then: We expect a workspace to have been created.
assert.NotEmpty(t, task.Name)
assert.Equal(t, template.ID, task.TemplateID)

// And: We expect it to have the "AI Prompt" parameter correctly set.
parameters, err := client.WorkspaceBuildParameters(ctx, ws.LatestBuild.ID)
require.NoError(t, err)
require.Len(t, parameters, 1)
assert.Equal(t, codersdk.AITaskPromptParameterName, parameters[0].Name)
assert.Equal(t, taskPrompt, parameters[0].Value)
})

t.Run("CustomNames", func(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -1147,7 +1097,7 @@ func TestTasksCreate(t *testing.T) {
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
user := coderdtest.CreateFirstUser(t, client)

// Given: A template without an "AI Prompt" parameter
// Given: A template without AI task support (no coder_ai_task resource)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
Expand Down
6 changes: 1 addition & 5 deletions coderd/database/dbfake/dbfake.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"github.com/coder/coder/v2/coderd/rbac"
"github.com/coder/coder/v2/coderd/telemetry"
"github.com/coder/coder/v2/coderd/wspubsub"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/provisionersdk"
sdkproto "github.com/coder/coder/v2/provisionersdk/proto"
)
Expand Down Expand Up @@ -130,10 +129,7 @@ func (b WorkspaceBuildBuilder) WithTask(taskSeed database.TaskTable, appSeed *sd
b.taskAppID, err = uuid.Parse(takeFirst(appSeed.Id, uuid.NewString()))
require.NoError(b.t, err)

return b.Params(database.WorkspaceBuildParameter{
Name: codersdk.AITaskPromptParameterName,
Value: b.taskSeed.Prompt,
}).WithAgent(func(a []*sdkproto.Agent) []*sdkproto.Agent {
return b.WithAgent(func(a []*sdkproto.Agent) []*sdkproto.Agent {
a[0].Apps = []*sdkproto.App{
{
Id: b.taskAppID.String(),
Expand Down
15 changes: 0 additions & 15 deletions codersdk/aitasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,8 @@ import (

"github.com/google/uuid"
"golang.org/x/xerrors"

"github.com/coder/terraform-provider-coder/v2/provider"
)

// AITaskPromptParameterName is the name of the parameter used to pass prompts
// to AI tasks.
//
// Deprecated: This constant is deprecated and maintained only for backwards
// compatibility with older templates. Task prompts are now stored directly
// in the tasks.prompt database column. New code should access prompts via
// the Task.InitialPrompt field returned from task endpoints.
//
// This constant will be removed in a future major version. Templates should
// not rely on this parameter name, as the backend will continue to create it
// automatically for compatibility but reads from tasks.prompt.
const AITaskPromptParameterName = provider.TaskPromptParameterName

// CreateTaskRequest represents the request to create a new task.
type CreateTaskRequest struct {
TemplateVersionID uuid.UUID `json:"template_version_id" format:"uuid"`
Expand Down
1 change: 0 additions & 1 deletion codersdk/toolsdk/toolsdk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1017,7 +1017,6 @@ func TestTools(t *testing.T) {
ProvisionApply: echo.ApplyComplete,
ProvisionGraph: []*proto.Response{
{Type: &proto.Response_Graph{Graph: &proto.GraphComplete{
Parameters: []*proto.RichParameter{{Name: "AI Prompt", Type: "string"}},
HasAiTasks: true,
}}},
},
Expand Down
14 changes: 11 additions & 3 deletions docs/ai-coder/ai-bridge/client-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ data "coder_workspace_owner" "me" {}

data "coder_workspace" "me" {}

data "coder_task" "me" {}

resource "coder_agent" "dev" {
arch = "amd64"
os = "linux"
Expand All @@ -71,15 +73,21 @@ resource "coder_agent" "dev" {

# See https://registry.coder.com/modules/coder/claude-code for more information
module "claude-code" {
count = local.has_ai_prompt ? data.coder_workspace.me.start_count : 0
count = data.coder_task.me.enabled ? data.coder_workspace.me.start_count : 0
source = "dev.registry.coder.com/coder/claude-code/coder"
version = ">= 3.4.0"
version = ">= 4.0.0"
agent_id = coder_agent.dev.id
workdir = "/home/coder/project"
claude_api_key = data.coder_workspace_owner.me.session_token # Use the Coder session token to authenticate with AI Bridge
ai_prompt = data.coder_parameter.ai_prompt.value
ai_prompt = data.coder_task.me.prompt
... # other claude-code configuration
}

# The coder_ai_task resource associates the task to the app.
resource "coder_ai_task" "task" {
count = data.coder_task.me.enabled ? data.coder_workspace.me.start_count : 0
app_id = module.claude-code[0].task_app_id
}
```

## External and Desktop Clients
Expand Down
5 changes: 3 additions & 2 deletions docs/ai-coder/tasks-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ Prior to Coder version 2.28.0, the definition of a Coder task was different to t

Note that 2 and 3 were generally handled by the `coder/agentapi` Terraform module.

The pre-2.28.0 definition will be supported until the release of 2.29.0. You will need to update your Tasks-enabled templates to continue using Tasks after this release.
> [!IMPORTANT]
> The pre-2.28.0 definition is no longer supported as of Coder 2.30.0. You must update your Tasks-enabled templates to use the new format described below.

You can view an [example migration here](https://github.com/coder/coder/pull/20420). Alternatively, follow the steps below:

Expand Down Expand Up @@ -114,7 +115,7 @@ resource "coder_ai_task" "task" {

In v2.28 and above, the following changes were made:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to modify/bump the version number specified here?

Copy link
Member Author

@mafredri mafredri Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this statement is still true. 🤔 It's more that in 2.29 we still allowed the syntax and had back-combat, but in 2.30 we're removing the back-compat too. But please correct me if I'm overlooking something.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was a non-blocking suggestion so I'm happy to merge as-is


- The explicitly named "AI Prompt" parameter is deprecated. The task prompt is now available in the `coder_ai_task` resource (provider version 2.12 and above) and `coder_task` data source (provider version 2.13 and above).
- The explicitly named "AI Prompt" parameter is no longer supported. The task prompt is now available in the `coder_ai_task` resource (provider version 2.12 and above) and `coder_task` data source (provider version 2.13 and above).
- Modules no longer define the `coder_ai_task` resource. These must be defined explicitly in the template.
- The `sidebar_app` field of the `coder_ai_task` resource is now deprecated. In its place, use `app_id`.

Expand Down
16 changes: 8 additions & 8 deletions docs/tutorials/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,16 +268,16 @@ Coder maintains the [Tasks on Docker](https://registry.coder.com/templates/coder
coder template push tasks-docker -d . --variable anthropic_api_key="your-api-key"
```

1. **Create the new Workspace**
1. In your Coder Deployment, click **Workspaces** in the upper left hand corner
1. Click **New workspace** and choose **tasks-docker**
1. Fill in the Workspace name. Add in an AI Prompt for Claude Code like "Make the background yellow". Click **Create workspace**
1. **Create a Task**
1. In your Coder deployment, click **Tasks** in the navigation
1. In the "Prompt your AI agent to start a task" box, enter a prompt like "Make the background yellow"
1. Select the **tasks-docker** template from the dropdown and click the submit button
1. **See Tasks in action**
1. Once your workspace is running, click **View tasks** with your workspace. This will bring you to the Tasks view where you can see Claude Code (left panel), preview the sample application, and interact with the code in code-server. You might need to wait for Claude Code to finish changing the background color of the application.
1. Navigate to the **Tasks** tab in the upper left hand corner
1. Your task will appear in the table below. Click on it to open the task view where you can follow the initialization
1. Once active, you'll see Claude Code on the left panel and can preview the sample application or interact with the code in code-server on the right. You might need to wait for Claude Code to finish changing the background color of the application.
1. Try typing in a new request to Claude Code: "make the background red"
1. Let's exit out of this specific Task view, so we can see all the running tasks
1. You can start a new task by prompting in the "Prompt your AI agent to start a task" box. You can select which template to run this from, so tasks-docker here, and that will spin up a new Workspace
1. Click the back arrow to return to the task overview (you can also see all your tasks in the sidebar)
1. You can start a new task from the prompt box at the top of the page

![Tasks changing background color of demo application](../images/screenshots/quickstart-tasks-background-change.png)

Expand Down
21 changes: 4 additions & 17 deletions provisioner/terraform/provision_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/coder/terraform-provider-coder/v2/provider"

"cdr.dev/slog"
"cdr.dev/slog/sloggers/slogtest"

Expand Down Expand Up @@ -941,18 +939,15 @@ func TestProvision(t *testing.T) {
{
Name: "ai-task-multiple-allowed-in-plan",
Files: map[string]string{
"main.tf": fmt.Sprintf(`terraform {
"main.tf": `terraform {
required_providers {
coder = {
source = "coder/coder"
version = ">= 2.7.0"
version = ">= 2.13.0"
}
}
}
data "coder_parameter" "prompt" {
name = "%s"
type = "string"
}
data "coder_task" "me" {}
resource "coder_ai_task" "a" {
sidebar_app {
id = "7128be08-8722-44cb-bbe1-b5a391c4d94b" # fake ID, irrelevant here anyway but needed for validation
Expand All @@ -963,7 +958,7 @@ func TestProvision(t *testing.T) {
id = "7128be08-8722-44cb-bbe1-b5a391c4d94b" # fake ID, irrelevant here anyway but needed for validation
}
}
`, provider.TaskPromptParameterName),
`,
},
Request: &proto.PlanRequest{},
Response: &proto.GraphComplete{
Expand All @@ -977,14 +972,6 @@ func TestProvision(t *testing.T) {
Type: "coder_ai_task",
},
},
Parameters: []*proto.RichParameter{
{
Name: provider.TaskPromptParameterName,
Type: "string",
Required: true,
FormType: proto.ParameterFormType_INPUT,
},
},
AiTasks: []*proto.AITask{
{
Id: "a",
Expand Down
16 changes: 0 additions & 16 deletions site/src/api/typesGenerated.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 3 additions & 5 deletions site/src/modules/tasks/TaskPrompt/TaskPrompt.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
MockAIPromptPresets,
MockPresets,
MockTask,
MockTaskPresets,
MockTasks,
MockTemplate,
MockTemplateVersion,
Expand Down Expand Up @@ -72,11 +72,9 @@ export const WithPresets: Story = {
},
};

export const ReadOnlyPresetPrompt: Story = {
export const WithAIPresets: Story = {
beforeEach: () => {
spyOn(API, "getTemplateVersionPresets").mockResolvedValue(
MockAIPromptPresets,
);
spyOn(API, "getTemplateVersionPresets").mockResolvedValue(MockTaskPresets);
},
};

Expand Down
Loading
Loading