@@ -21,7 +21,7 @@ type Deps struct {
21
21
}
22
22
23
23
// HandlerFunc is a function that handles a tool call.
24
- type HandlerFunc [Arg ,Ret any ]func (tb Deps ,args Arg ) (Ret ,error )
24
+ type HandlerFunc [Arg ,Ret any ]func (context. Context , Deps ,Arg ) (Ret ,error )
25
25
26
26
type Tool [Arg ,Ret any ]struct {
27
27
aisdk.Tool
@@ -32,12 +32,12 @@ type Tool[Arg, Ret any] struct {
32
32
func (t Tool [Arg ,Ret ])Generic ()Tool [any ,any ] {
33
33
return Tool [any ,any ]{
34
34
Tool :t .Tool ,
35
- Handler :func (tb Deps ,args any ) (any ,error ) {
35
+ Handler :func (ctx context. Context , tb Deps ,args any ) (any ,error ) {
36
36
typedArg ,ok := args .(Arg )
37
37
if ! ok {
38
38
return nil ,xerrors .Errorf ("developer error: invalid argument type for tool %s" ,t .Tool .Name )
39
39
}
40
- return t .Handler (tb ,typedArg )
40
+ return t .Handler (ctx , tb ,typedArg )
41
41
},
42
42
}
43
43
}
@@ -115,13 +115,41 @@ type UploadTarFileArgs struct {
115
115
116
116
// WithRecover wraps a HandlerFunc to recover from panics and return an error.
117
117
func WithRecover [Arg ,Ret any ](h HandlerFunc [Arg ,Ret ])HandlerFunc [Arg ,Ret ] {
118
- return func (tb Deps ,args Arg ) (ret Ret ,err error ) {
118
+ return func (ctx context. Context , tb Deps ,args Arg ) (ret Ret ,err error ) {
119
119
defer func () {
120
120
if r := recover ();r != nil {
121
121
err = xerrors .Errorf ("tool handler panic: %v" ,r )
122
122
}
123
123
}()
124
- return h (tb ,args )
124
+ return h (ctx ,tb ,args )
125
+ }
126
+ }
127
+
128
+ // WithCleanContext wraps a HandlerFunc to provide it with a new context.
129
+ // This ensures that no data is passed using context.Value.
130
+ // If a deadline is set on the parent context, it will be passed to the child
131
+ // context.
132
+ func WithCleanContext [Arg ,Ret any ](h HandlerFunc [Arg ,Ret ])HandlerFunc [Arg ,Ret ] {
133
+ return func (parent context.Context ,tb Deps ,args Arg ) (ret Ret ,err error ) {
134
+ child ,childCancel := context .WithCancel (context .Background ())
135
+ defer childCancel ()
136
+ // Ensure that cancellation propagates from the parent context to the child context.
137
+ go func () {
138
+ select {
139
+ case <- child .Done ():
140
+ return
141
+ case <- parent .Done ():
142
+ childCancel ()
143
+ }
144
+ }()
145
+ // Also ensure that the child context has the same deadline as the parent
146
+ // context.
147
+ if deadline ,ok := parent .Deadline ();ok {
148
+ deadlineCtx ,deadlineCancel := context .WithDeadline (child ,deadline )
149
+ defer deadlineCancel ()
150
+ child = deadlineCtx
151
+ }
152
+ return h (child ,tb ,args )
125
153
}
126
154
}
127
155
@@ -137,7 +165,7 @@ func wrapAll(mw func(HandlerFunc[any, any]) HandlerFunc[any, any], tools ...Tool
137
165
var (
138
166
// All is a list of all tools that can be used in the Coder CLI.
139
167
// When you add a new tool, be sure to include it here!
140
- All = wrapAll (WithRecover ,
168
+ All = wrapAll (WithCleanContext , wrapAll ( WithRecover ,
141
169
CreateTemplate .Generic (),
142
170
CreateTemplateVersion .Generic (),
143
171
CreateWorkspace .Generic (),
@@ -154,7 +182,7 @@ var (
154
182
ReportTask .Generic (),
155
183
UploadTarFile .Generic (),
156
184
UpdateTemplateActiveVersion .Generic (),
157
- )
185
+ )... )
158
186
159
187
ReportTask = Tool [ReportTaskArgs ,string ]{
160
188
Tool : aisdk.Tool {
@@ -183,14 +211,14 @@ var (
183
211
Required : []string {"summary" ,"link" ,"state" },
184
212
},
185
213
},
186
- Handler :func (tb Deps ,args ReportTaskArgs ) (string ,error ) {
214
+ Handler :func (ctx context. Context , tb Deps ,args ReportTaskArgs ) (string ,error ) {
187
215
if tb .AgentClient == nil {
188
216
return "" ,xerrors .New ("tool unavailable as CODER_AGENT_TOKEN or CODER_AGENT_TOKEN_FILE not set" )
189
217
}
190
218
if tb .AppStatusSlug == "" {
191
219
return "" ,xerrors .New ("workspace app status slug not found in toolbox" )
192
220
}
193
- if err := tb .AgentClient .PatchAppStatus (context . TODO () , agentsdk.PatchAppStatus {
221
+ if err := tb .AgentClient .PatchAppStatus (ctx , agentsdk.PatchAppStatus {
194
222
AppSlug :tb .AppStatusSlug ,
195
223
Message :args .Summary ,
196
224
URI :args .Link ,
@@ -217,12 +245,12 @@ This returns more data than list_workspaces to reduce token usage.`,
217
245
Required : []string {"workspace_id" },
218
246
},
219
247
},
220
- Handler :func (tb Deps ,args GetWorkspaceArgs ) (codersdk.Workspace ,error ) {
248
+ Handler :func (ctx context. Context , tb Deps ,args GetWorkspaceArgs ) (codersdk.Workspace ,error ) {
221
249
wsID ,err := uuid .Parse (args .WorkspaceID )
222
250
if err != nil {
223
251
return codersdk.Workspace {},xerrors .New ("workspace_id must be a valid UUID" )
224
252
}
225
- return tb .CoderClient .Workspace (context . TODO () ,wsID )
253
+ return tb .CoderClient .Workspace (ctx ,wsID )
226
254
},
227
255
}
228
256
@@ -257,7 +285,7 @@ is provisioned correctly and the agent can connect to the control plane.
257
285
Required : []string {"user" ,"template_version_id" ,"name" ,"rich_parameters" },
258
286
},
259
287
},
260
- Handler :func (tb Deps ,args CreateWorkspaceArgs ) (codersdk.Workspace ,error ) {
288
+ Handler :func (ctx context. Context , tb Deps ,args CreateWorkspaceArgs ) (codersdk.Workspace ,error ) {
261
289
tvID ,err := uuid .Parse (args .TemplateVersionID )
262
290
if err != nil {
263
291
return codersdk.Workspace {},xerrors .New ("template_version_id must be a valid UUID" )
@@ -272,7 +300,7 @@ is provisioned correctly and the agent can connect to the control plane.
272
300
Value :v ,
273
301
})
274
302
}
275
- workspace ,err := tb .CoderClient .CreateUserWorkspace (context . TODO () ,args .User , codersdk.CreateWorkspaceRequest {
303
+ workspace ,err := tb .CoderClient .CreateUserWorkspace (ctx ,args .User , codersdk.CreateWorkspaceRequest {
276
304
TemplateVersionID :tvID ,
277
305
Name :args .Name ,
278
306
RichParameterValues :buildParams ,
@@ -297,12 +325,12 @@ is provisioned correctly and the agent can connect to the control plane.
297
325
},
298
326
},
299
327
},
300
- Handler :func (tb Deps ,args ListWorkspacesArgs ) ([]MinimalWorkspace ,error ) {
328
+ Handler :func (ctx context. Context , tb Deps ,args ListWorkspacesArgs ) ([]MinimalWorkspace ,error ) {
301
329
owner := args .Owner
302
330
if owner == "" {
303
331
owner = codersdk .Me
304
332
}
305
- workspaces ,err := tb .CoderClient .Workspaces (context . TODO () , codersdk.WorkspaceFilter {
333
+ workspaces ,err := tb .CoderClient .Workspaces (ctx , codersdk.WorkspaceFilter {
306
334
Owner :owner ,
307
335
})
308
336
if err != nil {
@@ -334,8 +362,8 @@ is provisioned correctly and the agent can connect to the control plane.
334
362
Required : []string {},
335
363
},
336
364
},
337
- Handler :func (tb Deps ,_ NoArgs ) ([]MinimalTemplate ,error ) {
338
- templates ,err := tb .CoderClient .Templates (context . TODO () , codersdk.TemplateFilter {})
365
+ Handler :func (ctx context. Context , tb Deps ,_ NoArgs ) ([]MinimalTemplate ,error ) {
366
+ templates ,err := tb .CoderClient .Templates (ctx , codersdk.TemplateFilter {})
339
367
if err != nil {
340
368
return nil ,err
341
369
}
@@ -367,12 +395,12 @@ is provisioned correctly and the agent can connect to the control plane.
367
395
Required : []string {"template_version_id" },
368
396
},
369
397
},
370
- Handler :func (tb Deps ,args ListTemplateVersionParametersArgs ) ([]codersdk.TemplateVersionParameter ,error ) {
398
+ Handler :func (ctx context. Context , tb Deps ,args ListTemplateVersionParametersArgs ) ([]codersdk.TemplateVersionParameter ,error ) {
371
399
templateVersionID ,err := uuid .Parse (args .TemplateVersionID )
372
400
if err != nil {
373
401
return nil ,xerrors .Errorf ("template_version_id must be a valid UUID: %w" ,err )
374
402
}
375
- parameters ,err := tb .CoderClient .TemplateVersionRichParameters (context . TODO () ,templateVersionID )
403
+ parameters ,err := tb .CoderClient .TemplateVersionRichParameters (ctx ,templateVersionID )
376
404
if err != nil {
377
405
return nil ,err
378
406
}
@@ -389,8 +417,8 @@ is provisioned correctly and the agent can connect to the control plane.
389
417
Required : []string {},
390
418
},
391
419
},
392
- Handler :func (tb Deps ,_ NoArgs ) (codersdk.User ,error ) {
393
- return tb .CoderClient .User (context . TODO () ,"me" )
420
+ Handler :func (ctx context. Context , tb Deps ,_ NoArgs ) (codersdk.User ,error ) {
421
+ return tb .CoderClient .User (ctx ,"me" )
394
422
},
395
423
}
396
424
@@ -416,7 +444,7 @@ is provisioned correctly and the agent can connect to the control plane.
416
444
Required : []string {"workspace_id" ,"transition" },
417
445
},
418
446
},
419
- Handler :func (tb Deps ,args CreateWorkspaceBuildArgs ) (codersdk.WorkspaceBuild ,error ) {
447
+ Handler :func (ctx context. Context , tb Deps ,args CreateWorkspaceBuildArgs ) (codersdk.WorkspaceBuild ,error ) {
420
448
workspaceID ,err := uuid .Parse (args .WorkspaceID )
421
449
if err != nil {
422
450
return codersdk.WorkspaceBuild {},xerrors .Errorf ("workspace_id must be a valid UUID: %w" ,err )
@@ -435,7 +463,7 @@ is provisioned correctly and the agent can connect to the control plane.
435
463
if templateVersionID != uuid .Nil {
436
464
cbr .TemplateVersionID = templateVersionID
437
465
}
438
- return tb .CoderClient .CreateWorkspaceBuild (context . TODO () ,workspaceID ,cbr )
466
+ return tb .CoderClient .CreateWorkspaceBuild (ctx ,workspaceID ,cbr )
439
467
},
440
468
}
441
469
@@ -897,8 +925,8 @@ The file_id provided is a reference to a tar file you have uploaded containing t
897
925
Required : []string {"file_id" },
898
926
},
899
927
},
900
- Handler :func (tb Deps ,args CreateTemplateVersionArgs ) (codersdk.TemplateVersion ,error ) {
901
- me ,err := tb .CoderClient .User (context . TODO () ,"me" )
928
+ Handler :func (ctx context. Context , tb Deps ,args CreateTemplateVersionArgs ) (codersdk.TemplateVersion ,error ) {
929
+ me ,err := tb .CoderClient .User (ctx ,"me" )
902
930
if err != nil {
903
931
return codersdk.TemplateVersion {},err
904
932
}
@@ -910,7 +938,7 @@ The file_id provided is a reference to a tar file you have uploaded containing t
910
938
if err != nil {
911
939
return codersdk.TemplateVersion {},xerrors .Errorf ("template_id must be a valid UUID: %w" ,err )
912
940
}
913
- templateVersion ,err := tb .CoderClient .CreateTemplateVersion (context . TODO () ,me .OrganizationIDs [0 ], codersdk.CreateTemplateVersionRequest {
941
+ templateVersion ,err := tb .CoderClient .CreateTemplateVersion (ctx ,me .OrganizationIDs [0 ], codersdk.CreateTemplateVersionRequest {
914
942
Message :"Created by AI" ,
915
943
StorageMethod :codersdk .ProvisionerStorageMethodFile ,
916
944
FileID :fileID ,
@@ -939,12 +967,12 @@ The file_id provided is a reference to a tar file you have uploaded containing t
939
967
Required : []string {"workspace_agent_id" },
940
968
},
941
969
},
942
- Handler :func (tb Deps ,args GetWorkspaceAgentLogsArgs ) ([]string ,error ) {
970
+ Handler :func (ctx context. Context , tb Deps ,args GetWorkspaceAgentLogsArgs ) ([]string ,error ) {
943
971
workspaceAgentID ,err := uuid .Parse (args .WorkspaceAgentID )
944
972
if err != nil {
945
973
return nil ,xerrors .Errorf ("workspace_agent_id must be a valid UUID: %w" ,err )
946
974
}
947
- logs ,closer ,err := tb .CoderClient .WorkspaceAgentLogsAfter (context . TODO () ,workspaceAgentID ,0 ,false )
975
+ logs ,closer ,err := tb .CoderClient .WorkspaceAgentLogsAfter (ctx ,workspaceAgentID ,0 ,false )
948
976
if err != nil {
949
977
return nil ,err
950
978
}
@@ -974,12 +1002,12 @@ The file_id provided is a reference to a tar file you have uploaded containing t
974
1002
Required : []string {"workspace_build_id" },
975
1003
},
976
1004
},
977
- Handler :func (tb Deps ,args GetWorkspaceBuildLogsArgs ) ([]string ,error ) {
1005
+ Handler :func (ctx context. Context , tb Deps ,args GetWorkspaceBuildLogsArgs ) ([]string ,error ) {
978
1006
workspaceBuildID ,err := uuid .Parse (args .WorkspaceBuildID )
979
1007
if err != nil {
980
1008
return nil ,xerrors .Errorf ("workspace_build_id must be a valid UUID: %w" ,err )
981
1009
}
982
- logs ,closer ,err := tb .CoderClient .WorkspaceBuildLogsAfter (context . TODO () ,workspaceBuildID ,0 )
1010
+ logs ,closer ,err := tb .CoderClient .WorkspaceBuildLogsAfter (ctx ,workspaceBuildID ,0 )
983
1011
if err != nil {
984
1012
return nil ,err
985
1013
}
@@ -1005,13 +1033,13 @@ The file_id provided is a reference to a tar file you have uploaded containing t
1005
1033
Required : []string {"template_version_id" },
1006
1034
},
1007
1035
},
1008
- Handler :func (tb Deps ,args GetTemplateVersionLogsArgs ) ([]string ,error ) {
1036
+ Handler :func (ctx context. Context , tb Deps ,args GetTemplateVersionLogsArgs ) ([]string ,error ) {
1009
1037
templateVersionID ,err := uuid .Parse (args .TemplateVersionID )
1010
1038
if err != nil {
1011
1039
return nil ,xerrors .Errorf ("template_version_id must be a valid UUID: %w" ,err )
1012
1040
}
1013
1041
1014
- logs ,closer ,err := tb .CoderClient .TemplateVersionLogsAfter (context . TODO () ,templateVersionID ,0 )
1042
+ logs ,closer ,err := tb .CoderClient .TemplateVersionLogsAfter (ctx ,templateVersionID ,0 )
1015
1043
if err != nil {
1016
1044
return nil ,err
1017
1045
}
@@ -1040,7 +1068,7 @@ The file_id provided is a reference to a tar file you have uploaded containing t
1040
1068
Required : []string {"template_id" ,"template_version_id" },
1041
1069
},
1042
1070
},
1043
- Handler :func (tb Deps ,args UpdateTemplateActiveVersionArgs ) (string ,error ) {
1071
+ Handler :func (ctx context. Context , tb Deps ,args UpdateTemplateActiveVersionArgs ) (string ,error ) {
1044
1072
templateID ,err := uuid .Parse (args .TemplateID )
1045
1073
if err != nil {
1046
1074
return "" ,xerrors .Errorf ("template_id must be a valid UUID: %w" ,err )
@@ -1049,7 +1077,7 @@ The file_id provided is a reference to a tar file you have uploaded containing t
1049
1077
if err != nil {
1050
1078
return "" ,xerrors .Errorf ("template_version_id must be a valid UUID: %w" ,err )
1051
1079
}
1052
- err = tb .CoderClient .UpdateActiveTemplateVersion (context . TODO () ,templateID , codersdk.UpdateActiveTemplateVersion {
1080
+ err = tb .CoderClient .UpdateActiveTemplateVersion (ctx ,templateID , codersdk.UpdateActiveTemplateVersion {
1053
1081
ID :templateVersionID ,
1054
1082
})
1055
1083
if err != nil {
@@ -1073,7 +1101,7 @@ The file_id provided is a reference to a tar file you have uploaded containing t
1073
1101
Required : []string {"mime_type" ,"files" },
1074
1102
},
1075
1103
},
1076
- Handler :func (tb Deps ,args UploadTarFileArgs ) (codersdk.UploadResponse ,error ) {
1104
+ Handler :func (ctx context. Context , tb Deps ,args UploadTarFileArgs ) (codersdk.UploadResponse ,error ) {
1077
1105
pipeReader ,pipeWriter := io .Pipe ()
1078
1106
go func () {
1079
1107
defer pipeWriter .Close ()
@@ -1098,7 +1126,7 @@ The file_id provided is a reference to a tar file you have uploaded containing t
1098
1126
}
1099
1127
}()
1100
1128
1101
- resp ,err := tb .CoderClient .Upload (context . TODO () ,codersdk .ContentTypeTar ,pipeReader )
1129
+ resp ,err := tb .CoderClient .Upload (ctx ,codersdk .ContentTypeTar ,pipeReader )
1102
1130
if err != nil {
1103
1131
return codersdk.UploadResponse {},err
1104
1132
}
@@ -1133,16 +1161,16 @@ The file_id provided is a reference to a tar file you have uploaded containing t
1133
1161
Required : []string {"name" ,"display_name" ,"description" ,"version_id" },
1134
1162
},
1135
1163
},
1136
- Handler :func (tb Deps ,args CreateTemplateArgs ) (codersdk.Template ,error ) {
1137
- me ,err := tb .CoderClient .User (context . TODO () ,"me" )
1164
+ Handler :func (ctx context. Context , tb Deps ,args CreateTemplateArgs ) (codersdk.Template ,error ) {
1165
+ me ,err := tb .CoderClient .User (ctx ,"me" )
1138
1166
if err != nil {
1139
1167
return codersdk.Template {},err
1140
1168
}
1141
1169
versionID ,err := uuid .Parse (args .VersionID )
1142
1170
if err != nil {
1143
1171
return codersdk.Template {},xerrors .Errorf ("version_id must be a valid UUID: %w" ,err )
1144
1172
}
1145
- template ,err := tb .CoderClient .CreateTemplate (context . TODO () ,me .OrganizationIDs [0 ], codersdk.CreateTemplateRequest {
1173
+ template ,err := tb .CoderClient .CreateTemplate (ctx ,me .OrganizationIDs [0 ], codersdk.CreateTemplateRequest {
1146
1174
Name :args .Name ,
1147
1175
DisplayName :args .DisplayName ,
1148
1176
Description :args .Description ,
@@ -1167,12 +1195,12 @@ The file_id provided is a reference to a tar file you have uploaded containing t
1167
1195
},
1168
1196
},
1169
1197
},
1170
- Handler :func (tb Deps ,args DeleteTemplateArgs ) (string ,error ) {
1198
+ Handler :func (ctx context. Context , tb Deps ,args DeleteTemplateArgs ) (string ,error ) {
1171
1199
templateID ,err := uuid .Parse (args .TemplateID )
1172
1200
if err != nil {
1173
1201
return "" ,xerrors .Errorf ("template_id must be a valid UUID: %w" ,err )
1174
1202
}
1175
- err = tb .CoderClient .DeleteTemplate (context . TODO () ,templateID )
1203
+ err = tb .CoderClient .DeleteTemplate (ctx ,templateID )
1176
1204
if err != nil {
1177
1205
return "" ,err
1178
1206
}