Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit22a1b98

Browse files
refactor: modify task creation endpoint to return a task, not workspace
1 parentf721f3d commit22a1b98

File tree

10 files changed

+410
-108
lines changed

10 files changed

+410
-108
lines changed

‎coderd/aitasks.go‎

Lines changed: 82 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package coderd
33
import (
44
"context"
55
"database/sql"
6+
"encoding/json"
67
"errors"
78
"fmt"
89
"net/http"
@@ -22,6 +23,7 @@ import (
2223
"github.com/coder/coder/v2/coderd/rbac/policy"
2324
"github.com/coder/coder/v2/coderd/searchquery"
2425
"github.com/coder/coder/v2/coderd/taskname"
26+
"github.com/coder/coder/v2/coderd/util/rwsink"
2527
"github.com/coder/coder/v2/codersdk"
2628
)
2729

@@ -186,9 +188,86 @@ func (api *API) tasksCreate(rw http.ResponseWriter, r *http.Request) {
186188
WorkspaceOwner:owner.Username,
187189
},
188190
})
189-
190191
defercommitAudit()
191-
createWorkspace(ctx,aReq,apiKey.UserID,api,owner,createReq,rw,r)
192+
193+
rwSink:=rwsink.New()
194+
createWorkspace(ctx,aReq,apiKey.UserID,api,owner,createReq,rwSink,r)
195+
196+
ifrwSink.StatusCode!=nil&&*rwSink.StatusCode==http.StatusCreated {
197+
bytes:=rwSink.ResetBody()
198+
199+
varws codersdk.Workspace
200+
iferr:=json.Unmarshal(bytes,&ws);err!=nil {
201+
httpapi.Write(ctx,rw,http.StatusInternalServerError, codersdk.Response{
202+
Message:"Internal error decoding created workspace",
203+
Detail:err.Error(),
204+
})
205+
return
206+
}
207+
208+
task:=taskFromWorkspace(ws,req.Prompt)
209+
210+
httpapi.Write(ctx,rwSink,http.StatusCreated,task)
211+
}
212+
213+
_=rwSink.FlushTo(rw)
214+
}
215+
216+
functaskFromWorkspace(ws codersdk.Workspace,initialPromptstring) codersdk.Task {
217+
// TODO(DanielleMaywood):
218+
// This just picks up the first agent it discovers.
219+
// This approach _might_ break when a task has multiple agents,
220+
// depending on which agent was found first.
221+
//
222+
// We explicitly do not have support for running tasks
223+
// inside of a sub agent at the moment, so we can be sure
224+
// that any sub agents are not the agent we're looking for.
225+
vartaskAgentID uuid.NullUUID
226+
vartaskAgentLifecycle*codersdk.WorkspaceAgentLifecycle
227+
vartaskAgentHealth*codersdk.WorkspaceAgentHealth
228+
for_,resource:=rangews.LatestBuild.Resources {
229+
for_,agent:=rangeresource.Agents {
230+
ifagent.ParentID.Valid {
231+
continue
232+
}
233+
234+
taskAgentID= uuid.NullUUID{Valid:true,UUID:agent.ID}
235+
taskAgentLifecycle=&agent.LifecycleState
236+
taskAgentHealth=&agent.Health
237+
break
238+
}
239+
}
240+
241+
varcurrentState*codersdk.TaskStateEntry
242+
ifws.LatestAppStatus!=nil {
243+
currentState=&codersdk.TaskStateEntry{
244+
Timestamp:ws.LatestAppStatus.CreatedAt,
245+
State:codersdk.TaskState(ws.LatestAppStatus.State),
246+
Message:ws.LatestAppStatus.Message,
247+
URI:ws.LatestAppStatus.URI,
248+
}
249+
}
250+
251+
return codersdk.Task{
252+
ID:ws.ID,
253+
OrganizationID:ws.OrganizationID,
254+
OwnerID:ws.OwnerID,
255+
OwnerName:ws.OwnerName,
256+
Name:ws.Name,
257+
TemplateID:ws.TemplateID,
258+
TemplateName:ws.TemplateName,
259+
TemplateDisplayName:ws.TemplateDisplayName,
260+
TemplateIcon:ws.TemplateIcon,
261+
WorkspaceID: uuid.NullUUID{Valid:true,UUID:ws.ID},
262+
WorkspaceAgentID:taskAgentID,
263+
WorkspaceAgentLifecycle:taskAgentLifecycle,
264+
WorkspaceAgentHealth:taskAgentHealth,
265+
CreatedAt:ws.CreatedAt,
266+
UpdatedAt:ws.UpdatedAt,
267+
InitialPrompt:initialPrompt,
268+
Status:ws.LatestBuild.Status,
269+
CurrentState:currentState,
270+
}
192271
}
193272

194273
// tasksFromWorkspaces converts a slice of API workspaces into tasks, fetching
@@ -213,60 +292,7 @@ func (api *API) tasksFromWorkspaces(ctx context.Context, apiWorkspaces []codersd
213292

214293
tasks:=make([]codersdk.Task,0,len(apiWorkspaces))
215294
for_,ws:=rangeapiWorkspaces {
216-
// TODO(DanielleMaywood):
217-
// This just picks up the first agent it discovers.
218-
// This approach _might_ break when a task has multiple agents,
219-
// depending on which agent was found first.
220-
//
221-
// We explicitly do not have support for running tasks
222-
// inside of a sub agent at the moment, so we can be sure
223-
// that any sub agents are not the agent we're looking for.
224-
vartaskAgentID uuid.NullUUID
225-
vartaskAgentLifecycle*codersdk.WorkspaceAgentLifecycle
226-
vartaskAgentHealth*codersdk.WorkspaceAgentHealth
227-
for_,resource:=rangews.LatestBuild.Resources {
228-
for_,agent:=rangeresource.Agents {
229-
ifagent.ParentID.Valid {
230-
continue
231-
}
232-
233-
taskAgentID= uuid.NullUUID{Valid:true,UUID:agent.ID}
234-
taskAgentLifecycle=&agent.LifecycleState
235-
taskAgentHealth=&agent.Health
236-
break
237-
}
238-
}
239-
240-
varcurrentState*codersdk.TaskStateEntry
241-
ifws.LatestAppStatus!=nil {
242-
currentState=&codersdk.TaskStateEntry{
243-
Timestamp:ws.LatestAppStatus.CreatedAt,
244-
State:codersdk.TaskState(ws.LatestAppStatus.State),
245-
Message:ws.LatestAppStatus.Message,
246-
URI:ws.LatestAppStatus.URI,
247-
}
248-
}
249-
250-
tasks=append(tasks, codersdk.Task{
251-
ID:ws.ID,
252-
OrganizationID:ws.OrganizationID,
253-
OwnerID:ws.OwnerID,
254-
OwnerName:ws.OwnerName,
255-
Name:ws.Name,
256-
TemplateID:ws.TemplateID,
257-
TemplateName:ws.TemplateName,
258-
TemplateDisplayName:ws.TemplateDisplayName,
259-
TemplateIcon:ws.TemplateIcon,
260-
WorkspaceID: uuid.NullUUID{Valid:true,UUID:ws.ID},
261-
WorkspaceAgentID:taskAgentID,
262-
WorkspaceAgentLifecycle:taskAgentLifecycle,
263-
WorkspaceAgentHealth:taskAgentHealth,
264-
CreatedAt:ws.CreatedAt,
265-
UpdatedAt:ws.UpdatedAt,
266-
InitialPrompt:promptsByBuildID[ws.LatestBuild.ID],
267-
Status:ws.LatestBuild.Status,
268-
CurrentState:currentState,
269-
})
295+
tasks=append(tasks,taskFromWorkspace(ws,promptsByBuildID[ws.LatestBuild.ID]))
270296
}
271297

272298
returntasks,nil

‎coderd/aitasks_test.go‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -299,19 +299,22 @@ func TestTasksCreate(t *testing.T) {
299299
expClient:=codersdk.NewExperimentalClient(client)
300300

301301
// When: We attempt to create a Task.
302-
workspace,err:=expClient.CreateTask(ctx,"me", codersdk.CreateTaskRequest{
302+
task,err:=expClient.CreateTask(ctx,"me", codersdk.CreateTaskRequest{
303303
TemplateVersionID:template.ActiveVersionID,
304304
Prompt:taskPrompt,
305305
})
306306
require.NoError(t,err)
307-
coderdtest.AwaitWorkspaceBuildJobCompleted(t,client,workspace.LatestBuild.ID)
307+
308+
ws,err:=client.Workspace(ctx,task.ID)
309+
require.NoError(t,err)
310+
coderdtest.AwaitWorkspaceBuildJobCompleted(t,client,ws.LatestBuild.ID)
308311

309312
// Then: We expect a workspace to have been created.
310-
assert.NotEmpty(t,workspace.Name)
311-
assert.Equal(t,template.ID,workspace.TemplateID)
313+
assert.NotEmpty(t,task.Name)
314+
assert.Equal(t,template.ID,task.TemplateID)
312315

313316
// And: We expect it to have the "AI Prompt" parameter correctly set.
314-
parameters,err:=client.WorkspaceBuildParameters(ctx,workspace.LatestBuild.ID)
317+
parameters,err:=client.WorkspaceBuildParameters(ctx,ws.ID)
315318
require.NoError(t,err)
316319
require.Len(t,parameters,1)
317320
assert.Equal(t,codersdk.AITaskPromptParameterName,parameters[0].Name)

‎coderd/util/rwsink/rwsink.go‎

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package rwsink
2+
3+
import (
4+
"bytes"
5+
"maps"
6+
"net/http"
7+
"slices"
8+
)
9+
10+
typeResponseWriterSinkstruct {
11+
StatusCode*int
12+
header http.Header
13+
body bytes.Buffer
14+
}
15+
16+
var_ http.ResponseWriter= (*ResponseWriterSink)(nil)
17+
18+
funcNew()*ResponseWriterSink {
19+
return&ResponseWriterSink{
20+
StatusCode:nil,
21+
header:make(http.Header),
22+
body: bytes.Buffer{},
23+
}
24+
}
25+
26+
func (rw*ResponseWriterSink)Header() http.Header {
27+
returnrw.header
28+
}
29+
30+
func (rw*ResponseWriterSink)Write(data []byte) (int,error) {
31+
returnrw.body.Write(data)
32+
}
33+
34+
func (rw*ResponseWriterSink)ResetBody() []byte {
35+
body:=slices.Clone(rw.body.Bytes())
36+
rw.body= bytes.Buffer{}
37+
returnbody
38+
}
39+
40+
func (rw*ResponseWriterSink)WriteHeader(statusCodeint) {
41+
ifrw.StatusCode==nil {
42+
rw.StatusCode=&statusCode
43+
}
44+
}
45+
46+
func (rw*ResponseWriterSink)Bytes() []byte {
47+
returnrw.body.Bytes()
48+
}
49+
50+
func (rw*ResponseWriterSink)FlushTo(to http.ResponseWriter)error {
51+
maps.Copy(to.Header(),rw.header)
52+
53+
ifrw.StatusCode!=nil {
54+
to.WriteHeader(*rw.StatusCode)
55+
}
56+
57+
if_,err:=to.Write(rw.body.Bytes());err!=nil {
58+
returnerr
59+
}
60+
61+
returnnil
62+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp