10000 agents in sidebar · coder/vscode-coder@92c3bfd · GitHub
[go: up one dir, main page]

Skip to content

Commit 92c3bfd

Browse files
committed
agents in sidebar
1 parent bfa33eb commit 92c3bfd

File tree

5 files changed

+104
-30
lines changed

5 files changed

+104
-30
lines changed

package.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,12 @@
204204
"title": "Coder: View Logs",
205205
"icon": "$(list-unordered)",
206206
"when": "coder.authenticated"
207+
},
208+
{
209+
"command": "coder.viewAITasks",
210+
"title": "Coder: View AI Tasks",
211+
"icon": "$(robot)",
212+
"when": "coder.authenticated"
207213
}
208214
],
209215
"menus": {
@@ -231,6 +237,11 @@
231237
"command": "coder.refreshWorkspaces",
232238
"when": "coder.authenticated && view == myWorkspaces",
233239
"group": "navigation"
240+
},
241+
{
242+
"command": "coder.viewAITasks",
243+
10000 "when": "coder.authenticated && view == myWorkspaces",
244+
"group": "navigation"
234245
}
235246
],
236247
"view/item/context": [
@@ -259,6 +270,11 @@
259270
"command": "coder.createWorkspace",
260271
"group": "remote_11_ssh_coder@2",
261272
"when": "coder.authenticated"
273+
},
274+
{
275+
"command": "coder.viewAITasks",
276+
"group": "remote_11_ssh_coder@3",
277+
"when": "coder.authenticated"
262278
}
263279
]
264280
}

src/api.ts

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { AxiosInstance } from "axios"
22
import { spawn } from "child_process"
33
import { Api } from "coder/site/src/api/api"
4-
import { ProvisionerJobLog, Workspace, WorkspaceAgent } from "coder/site/src/api/typesGenerated"
4+
import { ProvisionerJobLog, Workspace, WorkspaceAgent, WorkspaceAgentTask } from "coder/site/src/api/typesGenerated"
55
import { FetchLikeInit } from "eventsource"
66
import fs from "fs/promises"
77
import { ProxyAgent } from "proxy-agent"
@@ -282,39 +282,26 @@ export async function getAITasksForWorkspace(
282282
restClient: Api,
283283
writeEmitter: vscode.EventEmitter<string>,
284284
workspace: Workspace,
285-
) {
285+
): Promise<WorkspaceAgentTask[]> {
286+
// We need to build up tasks
287+
let awaiting_tasks: WorkspaceAgentTask[] = [];
286288

287289
// The workspace will include agents, and within each agent you can find tasks
288290
// You can access the agents from the workspace resource
289291
const resources = workspace.latest_build.resources;
290292

291293
// Go through each resource
292294
for (const resource of resources) {
293-
// Each resource can have multiple agents
294295
if (!resource.agents) {
295296
continue
296297
}
297298

298-
for (const agent of resource.agents) {
299-
// Check if this agent has any AI tasks
300-
if (agent.tasks && agent.tasks.length > 0) {
301-
// This agent has AI tasks!
302-
console.log(`Agent ${agent.name} (${agent.id}) has ${agent.tasks.length} tasks`);
303-
304-
// Examine task details
305-
for (const task of agent.tasks) {
306-
console.log(`Task: ${task.summary}`);
307-
console.log(`Reporter: ${task.reporter}`);
308-
console.log(`Status: ${task.completion ? 'Completed' : 'In Progress'}`);
309-
console.log(`URL: ${task.url}`);
310-
console.log(`Icon: ${task.icon}`);
311-
}
312-
313-
// Check if the agent is waiting for user input
314-
if (agent.task_waiting_for_user_input) {
315-
console.log("This agent is waiting for user input!");
316-
}
299+
resource.agents.forEach((agent) => {
300+
for (const task of agent.tasks) {
301+
awaiting_tasks.push(task);
317302
}
318-
}
303+
})
319304
}
305+
306+
return awaiting_tasks;
320307
}

src/commands.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Api } from "coder/site/src/api/api"
22
import { getErrorMessage } from "coder/site/src/api/errors"
33
import { User, Workspace, WorkspaceAgent } from "coder/site/src/api/typesGenerated"
44
import * as vscode from "vscode"
5-
import { makeCoderSdk, needToken } from "./api"
5+
import { getAITasksForWorkspace, makeCoderSdk, needToken } from "./api"
66
import { extractAgents } from "./api-helper"
77
import { CertificateError } from "./error"
88
import { Storage } from "./storage"
@@ -295,6 +295,15 @@ export class Commands {
295295
const doc = await vscode.workspace.openTextDocument(uri)
296296
await vscode.window.showTextDocument(doc)
297297
}
298+
299+
/**
300+
* Open a view to show AI tasks across all workspaces
301+
*/
302+
public async viewAITasks(): Promise<void> {
303+
vscode.window.showInformationMessage("Viewing AI tasks across workspaces")
304+
// Refresh workspaces to ensure we have the latest tasks
305+
vscode.commands.executeCommand("coder.refreshWorkspaces")
306+
}
298307

299308
/**
300309
* Log out from the currently logged-in deployment.

src/extension.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,15 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
136136
allWorkspacesProvider.fetchAndRefresh()
137137
})
138138
vscode.commands.registerCommand("coder.viewLogs", commands.viewLogs.bind(commands))
139+
vscode.commands.registerCommand("coder.viewAITasks", commands.viewAITasks.bind(commands))
140+
vscode.commands.registerCommand("coder.openAITask", (task) => {
141+
// Open the task URL if available
142+
if (task && task.url) {
143+
vscode.env.openExternal(vscode.Uri.parse(task.url))
144+
} else {
145+
vscode.window.showInformationMessage("This AI task has no associated URL")
146+
}
147+
})
139148

140149
// Since the "onResolveRemoteAuthority:ssh-remote" activation event exists
141150
// in package.json we're able to perform actions before the authority is

src/workspacesProvider.ts

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { Api } from "coder/site/src/api/api"
2-
import { Workspace, WorkspaceAgent } from "coder/site/src/api/typesGenerated"
2+
import { Workspace, WorkspaceAgent, WorkspaceAgentTask } from "coder/site/src/api/typesGenerated"
33
import { EventSource } from "eventsource"
44
import * as path from "path"
55
import * as vscode from "vscode"
6-
import { createStreamingFetchAdapter } from "./api"
6+
import { createStreamingFetchAdapter, getAITasksForWorkspace } from "./api"
77
import {
88
AgentMetadataEvent,
99
AgentMetadataEventSchemaArray,
@@ -146,9 +146,32 @@ export class WorkspaceProvider implements vscode.TreeDataProvider<vscode.TreeIte
146146
}
147147
})
148148

149-
return resp.workspaces.map((workspace) => {
150-
return new WorkspaceTreeItem(workspace, this.getWorkspacesQuery === WorkspaceQuery.All, showMetadata)
151-
})
149+
// Create tree items for each workspace
150+
const workspaceTreeItems = await Promise.all(resp.workspaces.map(async (workspace) => {
151+
const workspaceTreeItem = new WorkspaceTreeItem(
152+
workspace,
153+
this.getWorkspacesQuery === WorkspaceQuery.All,
154+
showMetadata
155+
)
156+
157+
// Fetch AI tasks for the workspace
158+
try {
159+
// Create a dummy emitter for logs
160+
const emitter = new vscode.EventEmitter<string>()
161+
const aiTasks = await getAITasksForWorkspace(restClient, emitter, workspace)
162+
workspaceTreeItem.aiTasks = aiTasks
163+
this.storage.writeToCoderOutputChannel(aiTasks.length.toString())
164+
console.log(aiTasks.length.toString())
165+
} catch (error) {
166+
// Log the error but continue - we don't want to fail the whole tree if AI tasks fail
167+
this.storage.writeToCoderOutputChannel(`Failed to fetch AI tasks for workspace ${workspace.name}: ${errToStr(error, "unknown error")}`)
168+
169+
}
170+
171+
return workspaceTreeItem
172+
}))
173+
174+
return workspaceTreeItems
152175
}
153176

154177
/**
@@ -207,7 +230,20 @@ export class WorkspaceProvider implements vscode.TreeDataProvider<vscode.TreeIte
207230
const agentTreeItems = agents.map(
208231
(agent) => new AgentTreeItem(agent, element.workspaceOwner, element.workspaceName, element.watchMetadata),
209232
)
210-
return Promise.resolve(agentTreeItems)
233+
234+
// Add AI task items to the workspace children if there are any
235+
const aiTaskItems = element.aiTasks.map(task => new AITaskTreeItem(task))
236+
237+
// If there are AI tasks, add them at the beginning of the list
238+
if (aiTaskItems.length == 0) {
239+
return Promise.resolve(agentTreeItems)
240+
}
241+
// Create a separator item
242+
const separator = new vscode.TreeItem("AI Tasks", vscode.TreeItemCollapsibleState.None)
243+
separator.contextValue = "coderAITaskHeader"
244+
245+
// Return AI task items first, then a separator, then agent items
246+
return Promise.resolve([...aiTaskItems, separator, ...agentTreeItems])
211247
} else if (element instanceof AgentTreeItem) {
212248
const watcher = this.agentWatchers[element.agent.id]
213249
if (watcher?.error) {
@@ -285,6 +321,21 @@ class AgentMetadataTreeItem extends vscode.TreeItem {
285321
}
286322
}
287323

324+
class AITaskTreeItem extends vscode.TreeItem {
325+
constructor(public readonly task: WorkspaceAgentTask) {
326+
super(task.summary, vscode.TreeItemCollapsibleState.None)
327+
this.description = task.summary
328+
this.contextValue = "coderAITask"
329+
330+
// Add command to handle clicking on the task
331+
this.command = {
332+
command: "coder.openAITask",
333+
title: "Open AI Task",
334+
arguments: [task]
335+
}
336+
}
337+
}
338+
288339
type CoderOpenableTreeItemType = "coderWorkspaceSingleAgent" | "coderWorkspaceMultipleAgents" | "coderAgent"
289340

290341
export class OpenableTreeItem extends vscode.TreeItem {
@@ -335,6 +386,8 @@ class AgentTreeItem extends OpenableTreeItem {
335386
}
336387

337388
export class WorkspaceTreeItem extends OpenableTreeItem {
389+
public aiTasks: WorkspaceAgentTask[] = []
390+
338391
constructor(
339392
public readonly workspace: Workspace,
340393
public readonly showOwner: boolean,

0 commit comments

Comments
 (0)
0