@@ -55,9 +55,11 @@ func createObjectID(objectType ObjectType, id string) ObjectID {
55
55
}
56
56
}
57
57
58
- func searchTemplates (ctx context.Context , deps Deps ) ([]SearchResultItem , error ) {
58
+ func searchTemplates (ctx context.Context , deps Deps , query string ) ([]SearchResultItem , error ) {
59
59
serverURL := getServerURL (deps )
60
- templates , err := deps .coderClient .Templates (ctx , codersdk.TemplateFilter {})
60
+ templates , err := deps .coderClient .Templates (ctx , codersdk.TemplateFilter {
61
+ SearchQuery : query ,
62
+ })
61
63
if err != nil {
62
64
return nil , err
63
65
}
@@ -73,13 +75,10 @@ func searchTemplates(ctx context.Context, deps Deps) ([]SearchResultItem, error)
73
75
return results , nil
74
76
}
75
77
76
- func searchWorkspaces (ctx context.Context , deps Deps , owner string ) ([]SearchResultItem , error ) {
78
+ func searchWorkspaces (ctx context.Context , deps Deps , query string ) ([]SearchResultItem , error ) {
77
79
serverURL := getServerURL (deps )
78
- if owner == "" {
79
- owner = "me"
80
- }
81
80
workspaces , err := deps .coderClient .Workspaces (ctx , codersdk.WorkspaceFilter {
82
- Owner : owner ,
81
+ FilterQuery : query ,
83
82
})
84
83
if err != nil {
85
84
return nil , err
@@ -89,8 +88,8 @@ func searchWorkspaces(ctx context.Context, deps Deps, owner string) ([]SearchRes
89
88
results [i ] = SearchResultItem {
90
89
ID : createObjectID (ObjectTypeWorkspace , workspace .ID .String ()).String (),
91
90
Title : workspace .Name ,
92
- Text : fmt .Sprintf ("Owner: %s\n Template: %s\n Latest transition: %s" , owner , workspace .TemplateDisplayName , workspace .LatestBuild .Transition ),
93
- URL : fmt .Sprintf ("%s/%s/%s" , serverURL , owner , workspace .Name ),
91
+ Text : fmt .Sprintf ("Owner: %s\n Template: %s\n Latest transition: %s" , workspace . OwnerName , workspace .TemplateDisplayName , workspace .LatestBuild .Transition ),
92
+ URL : fmt .Sprintf ("%s/%s/%s" , serverURL , workspace . OwnerName , workspace .Name ),
94
93
}
95
94
}
96
95
return results , nil
@@ -104,32 +103,24 @@ const (
104
103
)
105
104
106
105
type SearchQuery struct {
107
- Type SearchQueryType
108
- WorkspaceOwner string
106
+ Type SearchQueryType
107
+ Query string
109
108
}
110
109
111
110
func parseSearchQuery (query string ) (SearchQuery , error ) {
112
- parts := strings .Split (query , ":" )
113
- switch SearchQueryType (parts [0 ]) {
114
- case SearchQueryTypeTemplates :
115
- // expected format: templates
116
- return SearchQuery {
117
- Type : SearchQueryTypeTemplates ,
118
- }, nil
119
- case SearchQueryTypeWorkspaces :
120
- // expected format: workspaces:owner
121
- owner := "me"
122
- if len (parts ) == 2 {
123
- owner = parts [1 ]
124
- } else if len (parts ) != 1 {
125
- return SearchQuery {}, xerrors .Errorf ("invalid query: %s" , query )
126
- }
127
- return SearchQuery {
128
- Type : SearchQueryTypeWorkspaces ,
129
- WorkspaceOwner : owner ,
130
- }, nil
111
+ parts := strings .Split (query , "/" )
112
+ queryType := SearchQueryType (parts [0 ])
113
+ if ! (queryType == SearchQueryTypeTemplates || queryType == SearchQueryTypeWorkspaces ) {
114
+ return SearchQuery {}, xerrors .Errorf ("invalid query: %s" , query )
131
115
}
132
- return SearchQuery {}, xerrors .Errorf ("invalid query: %s" , query )
116
+ queryString := ""
117
+ if len (parts ) > 1 {
118
+ queryString = strings .Join (parts [1 :], "/" )
119
+ }
120
+ return SearchQuery {
121
+ Type : queryType ,
122
+ Query : queryString ,
123
+ }, nil
133
124
}
134
125
135
126
type SearchArgs struct {
@@ -154,32 +145,100 @@ type SearchResult struct {
154
145
var ChatGPTSearch = Tool [SearchArgs , SearchResult ]{
155
146
Tool : aisdk.Tool {
156
147
Name : ToolNameChatGPTSearch ,
148
+ // Note: the queries are passed directly to the list workspaces and list templates
149
+ // endpoints. The list of accepted parameters below is not exhaustive - some are omitted
150
+ // because they are not as useful in ChatGPT.
157
151
Description : `Search for templates, workspaces, and files in workspaces.
158
152
159
153
To pick what you want to search for, use the following query formats:
160
154
161
- - ` + "`" + `templates` + "`" + `: List all templates. This query is not parameterized.
162
- - ` + "`" + `workspaces:$owner` + "`" + `: List workspaces belonging to a user. If owner is not specified, the current user is used. The special value ` + "`" + `me` + "`" + ` can be used to search for workspaces owned by the current user.
155
+ - ` + "`" + `templates/<template-query>` + "`" + `: List templates. The query accepts the following, optional parameters delineated by whitespace:
156
+ - "name:<name>" - Fuzzy search by template name (substring matching). Example: "name:docker"
157
+ - "organization:<organization>" - Filter by organization ID or name. Example: "organization:coder"
158
+ - "deprecated:<true|false>" - Filter by deprecated status. Example: "deprecated:true"
159
+ - "deleted:<true|false>" - Filter by deleted status. Example: "deleted:true"
160
+ - "has-ai-task:<true|false>" - Filter by whether the template has an AI task. Example: "has-ai-task:true"
161
+ - ` + "`" + `workspaces/<workspace-query>` + "`" + `: List workspaces. The query accepts the following, optional parameters delineated by whitespace:
162
+ - "owner:<username>" - Filter by workspace owner (username or "me"). Example: "owner:alice" or "owner:me"
163
+ - "template:<template-name>" - Filter by template name. Example: "template:web-development"
164
+ - "name:<workspace-name>" - Filter by workspace name (substring matching). Example: "name:project"
165
+ - "organization:<organization>" - Filter by organization ID or name. Example: "organization:engineering"
166
+ - "status:<status>" - Filter by workspace/build status. Values: starting, stopping, deleting, deleted, stopped, started, running, pending, canceling, canceled, failed. Example: "status:running"
167
+ - "has-agent:<agent-status>" - Filter by agent connectivity status. Values: connecting, connected, disconnected, timeout. Example: "has-agent:connected"
168
+ - "dormant:<true|false>" - Filter dormant workspaces. Example: "dormant:true"
169
+ - "outdated:<true|false>" - Filter workspaces using outdated template versions. Example: "outdated:true"
170
+ - "last_used_after:<timestamp>" - Filter workspaces last used after a specific date. Example: "last_used_after:2023-12-01T00:00:00Z"
171
+ - "last_used_before:<timestamp>" - Filter workspaces last used before a specific date. Example: "last_used_before:2023-12-31T23:59:59Z"
172
+ - "has-ai-task:<true|false>" - Filter workspaces with AI tasks. Example: "has-ai-task:true"
173
+ - "param:<name>" or "param:<name>=<value>" - Match workspaces by build parameters. Example: "param:environment=production" or "param:gpu"
163
174
164
175
# Examples
165
176
166
177
## Listing templates
167
178
168
- List all templates.
179
+ List all templates without any filters .
169
180
170
181
` + "```" + `json
171
182
{
172
183
"query": "templates"
173
184
}
174
185
` + "```" + `
175
186
187
+ List all templates with a "docker" substring in the name.
188
+
189
+ ` + "```" + `json
190
+ {
191
+ "query": "templates/name:docker"
192
+ }
193
+ ` + "```" + `
194
+
195
+ List templates in a specific organization.
196
+
197
+ ` + "```" + `json
198
+ {
199
+ "query": "templates/organization:engineering"
200
+ }
201
+ ` + "```" + `
202
+
203
+ List deprecated templates.
204
+
205
+ ` + "```" + `json
206
+ {
207
+ "query": "templates/deprecated:true"
208
+ }
209
+ ` + "```" + `
210
+
211
+ List templates that have AI tasks.
212
+
213
+ ` + "```" + `json
214
+ {
215
+ "query": "templates/has-ai-task:true"
216
+ }
217
+ ` + "```" + `
218
+
219
+ List templates with multiple filters - non-deprecated templates with "web" in the name.
220
+
221
+ ` + "```" + `json
222
+ {
223
+ "query": "templates/name:web deprecated:false"
224
+ }
225
+ ` + "```" + `
226
+
227
+ List deleted templates (requires appropriate permissions).
228
+
229
+ ` + "```" + `json
230
+ {
231
+ "query": "templates/deleted:true"
232
+ }
233
+ ` + "```" + `
234
+
176
235
## Listing workspaces
177
236
178
237
List all workspaces belonging to the current user.
179
238
180
239
` + "```" + `json
181
240
{
182
- "query": "workspaces:me"
241
+ "query": "workspaces/owner :me"
183
242
}
184
243
` + "```" + `
185
244
@@ -195,7 +254,47 @@ List all workspaces belonging to a user with username "josh".
195
254
196
255
` + "```" + `json
197
256
{
198
- "query": "workspaces:josh"
257
+ "query": "workspaces/owner:josh"
258
+ }
259
+ ` + "```" + `
260
+
261
+ List all running workspaces.
262
+
263
+ ` + "```" + `json
264
+ {
265
+ "query": "workspaces/status:running"
266
+ }
267
+ ` + "```" + `
268
+
269
+ List workspaces using a specific template.
270
+
271
+ ` + "```" + `json
272
+ {
273
+ "query": "workspaces/template:web-development"
274
+ }
275
+ ` + "```" + `
276
+
277
+ List dormant workspaces.
278
+
279
+ ` + "```" + `json
280
+ {
281
+ "query": "workspaces/dormant:true"
282
+ }
283
+ ` + "```" + `
284
+
285
+ List workspaces with connected agents.
286
+
287
+ ` + "```" + `json
288
+ {
289
+ "query": "workspaces/has-agent:connected"
290
+ }
291
+ ` + "```" + `
292
+
293
+ List workspaces with multiple filters - running workspaces owned by "alice".
294
+
295
+ ` + "```" + `json
296
+ {
297
+ "query": "workspaces/owner:alice status:running"
199
298
}
200
299
` + "```" + `
201
300
` ,
@@ -215,13 +314,17 @@ List all workspaces belonging to a user with username "josh".
215
314
}
216
315
switch query .Type {
217
316
case SearchQueryTypeTemplates :
218
- results , err := searchTemplates (ctx , deps )
317
+ results , err := searchTemplates (ctx , deps , query . Query )
219
318
if err != nil {
220
319
return SearchResult {}, err
221
320
}
222
321
return SearchResult {Results : results }, nil
223
322
case SearchQueryTypeWorkspaces :
224
- results , err := searchWorkspaces (ctx , deps , query .WorkspaceOwner )
323
+ searchQuery := query .Query
324
+ if searchQuery == "" {
325
+ searchQuery = "owner:me"
326
+ }
327
+ results , err := searchWorkspaces (ctx , deps , searchQuery )
225
328
if err != nil {
226
329
return SearchResult {}, err
227
330
}
0 commit comments