import * as vscode from 'vscode'; import { getCliClient, type SandboxCreateOptions } from '../../core/cliClient'; import { getAuthStatus } from '../../core/auth'; import { hasProject, getCurrentProject } from '../../core/project'; import { getDevServerManager } from '../devServer'; import { getSandboxManager, formatBytes } from '../../core/sandboxManager'; export interface GetAgentsInput { includeDetails?: boolean; } export class GetAgentsTool implements vscode.LanguageModelTool { async invoke( _options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { if (!hasProject()) { throw new Error('No Agentuity project found in the current workspace.'); } const cli = getCliClient(); const result = await cli.listAgents(); if (!result.success || !result.data) { throw new Error(`Failed to list agents: ${result.error || 'Unknown error'}`); } const agents = result.data; if (agents.length === 0) { return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart('No agents found in this project.'), ]); } const output = agents.map((agent) => ({ name: agent.name, id: agent.id, identifier: agent.identifier, description: agent.description, sourceFile: agent.metadata?.filename, })); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(JSON.stringify(output, null, 2)), ]); } async prepareInvocation( _options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: 'Fetching Agentuity agents...', }; } } export type GetProjectStatusInput = Record; export class GetProjectStatusTool implements vscode.LanguageModelTool { async invoke( _options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { const status: Record = {}; const authStatus = getAuthStatus(); status.authentication = { state: authStatus.state, user: authStatus.user ? { name: `${authStatus.user.firstName} ${authStatus.user.lastName}` } : null, }; const project = getCurrentProject(); status.project = project ? { projectId: project.projectId, orgId: project.orgId, region: project.region, rootPath: project.rootPath, } : null; const devServer = getDevServerManager(); status.devServer = { state: devServer.getState(), }; if (hasProject()) { const cli = getCliClient(); const agentsResult = await cli.listAgents(); status.agentCount = agentsResult.success ? agentsResult.data?.length || 0 : 0; const deploymentsResult = await cli.listDeployments(); if (deploymentsResult.success && deploymentsResult.data) { const active = deploymentsResult.data.find((d) => d.active); status.activeDeployment = active ? { id: active.id, createdAt: active.createdAt, tags: active.tags, } : null; status.totalDeployments = deploymentsResult.data.length; } } return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(JSON.stringify(status, null, 2)), ]); } async prepareInvocation( _options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: 'Getting Agentuity project status...', }; } } export interface GetSessionsInput { count?: number; agentName?: string; } export class GetSessionsTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { if (!hasProject()) { throw new Error('No Agentuity project found in the current workspace.'); } const cli = getCliClient(); const count = options.input.count || 10; const result = await cli.listSessions({ count, agentIdentifier: options.input.agentName, }); if (!result.success || !result.data) { throw new Error(`Failed to list sessions: ${result.error || 'Unknown error'}`); } const sessions = result.data.map((session) => ({ id: session.id, createdAt: session.created_at, success: session.success, duration: session.duration, trigger: session.trigger, env: session.env, })); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(JSON.stringify(sessions, null, 2)), ]); } async prepareInvocation( options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { const count = options.input.count || 10; return { invocationMessage: `Fetching last ${count} sessions...`, }; } } export interface GetSessionLogsInput { sessionId: string; } export class GetSessionLogsTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { if (!hasProject()) { throw new Error('No Agentuity project found in the current workspace.'); } const { sessionId } = options.input; if (!sessionId) { throw new Error('Session ID is required.'); } const cli = getCliClient(); const result = await cli.getSessionLogs(sessionId); if (!result.success || !result.data) { throw new Error(`Failed to get session logs: ${result.error || 'Unknown error'}`); } const logs = result.data.map((log) => ({ timestamp: log.timestamp, severity: log.severity, message: log.body, })); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(JSON.stringify(logs, null, 2)), ]); } async prepareInvocation( options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: `Fetching logs for session ${options.input.sessionId?.substring(0, 8)}...`, }; } } export interface ControlDevServerInput { action: 'start' | 'stop' | 'restart' | 'status'; } export class ControlDevServerTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { if (!hasProject()) { throw new Error('No Agentuity project found in the current workspace.'); } const devServer = getDevServerManager(); const { action } = options.input; switch (action) { case 'start': if (devServer.getState() === 'running') { return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart('Dev server is already running.'), ]); } await devServer.start(); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart('Dev server started successfully.'), ]); case 'stop': if (devServer.getState() === 'stopped') { return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart('Dev server is not running.'), ]); } await devServer.stop(); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart('Dev server stopped.'), ]); case 'restart': await devServer.restart(); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart('Dev server restarted.'), ]); case 'status': return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart( JSON.stringify({ state: devServer.getState() }, null, 2) ), ]); default: throw new Error( `Unknown action: ${action}. Valid actions: start, stop, restart, status` ); } } async prepareInvocation( options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { const { action } = options.input; if (action === 'start' || action === 'restart') { return { invocationMessage: `${action === 'start' ? 'Starting' : 'Restarting'} dev server...`, confirmationMessages: { title: `${action === 'start' ? 'Start' : 'Restart'} Dev Server`, message: new vscode.MarkdownString( `This will ${action} the Agentuity dev server for local testing.\n\nDo you want to continue?` ), }, }; } return { invocationMessage: action === 'stop' ? 'Stopping dev server...' : 'Getting dev server status...', }; } } export interface GetDeploymentsInput { limit?: number; } export class GetDeploymentsTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { if (!hasProject()) { throw new Error('No Agentuity project found in the current workspace.'); } const cli = getCliClient(); const result = await cli.listDeployments(); if (!result.success || !result.data) { throw new Error(`Failed to list deployments: ${result.error || 'Unknown error'}`); } const limit = options.input.limit || 10; const deployments = result.data.slice(0, limit).map((dep) => ({ id: dep.id, active: dep.active, state: dep.state, createdAt: dep.createdAt, tags: dep.tags, })); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(JSON.stringify(deployments, null, 2)), ]); } async prepareInvocation( _options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: 'Fetching deployments...', }; } } export interface DeployProjectInput { message?: string; } export class DeployProjectTool implements vscode.LanguageModelTool { async invoke( _options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { if (!hasProject()) { throw new Error('No Agentuity project found in the current workspace.'); } const authStatus = getAuthStatus(); if (authStatus.state !== 'authenticated') { throw new Error('You must be logged in to deploy. Run "agentuity auth login" first.'); } const terminal = vscode.window.createTerminal('Agentuity Deploy'); terminal.sendText('agentuity cloud deploy'); terminal.show(); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart( 'Deployment started in terminal. Check the terminal output for progress.' ), ]); } async prepareInvocation( _options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: 'Preparing deployment...', confirmationMessages: { title: 'Deploy to Agentuity Cloud', message: new vscode.MarkdownString( 'This will deploy your Agentuity project to the cloud.\n\n**Warning**: This will make your agents publicly accessible.\n\nDo you want to continue?' ), }, }; } } export interface GetHealthSummaryInput { sessionCount?: number; } export class GetHealthSummaryTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { if (!hasProject()) { throw new Error('No Agentuity project found in the current workspace.'); } const cli = getCliClient(); const sessionCount = options.input.sessionCount || 20; const health: Record = { timestamp: new Date().toISOString(), }; const sessionsResult = await cli.listSessions({ count: sessionCount }); if (sessionsResult.success && sessionsResult.data) { const sessions = sessionsResult.data; const successful = sessions.filter((s) => s.success).length; const failed = sessions.filter((s) => !s.success).length; health.sessions = { total: sessions.length, successful, failed, successRate: sessions.length > 0 ? ((successful / sessions.length) * 100).toFixed(1) + '%' : 'N/A', recentFailures: sessions .filter((s) => !s.success) .slice(0, 5) .map((s) => ({ id: s.id, createdAt: s.created_at, trigger: s.trigger, })), }; const durations = sessions.filter((s) => s.duration).map((s) => s.duration!); if (durations.length > 0) { const avgDuration = durations.reduce((a, b) => a + b, 0) / durations.length; health.performance = { avgDurationMs: (avgDuration / 1_000_000).toFixed(0), minDurationMs: (Math.min(...durations) / 1_000_000).toFixed(0), maxDurationMs: (Math.max(...durations) / 1_000_000).toFixed(0), }; } } const deploymentsResult = await cli.listDeployments(); if (deploymentsResult.success && deploymentsResult.data) { const deployments = deploymentsResult.data; const active = deployments.find((d) => d.active); health.deployment = { totalDeployments: deployments.length, activeDeployment: active ? { id: active.id, createdAt: active.createdAt, tags: active.tags, } : null, lastDeployment: deployments[0] ? { id: deployments[0].id, createdAt: deployments[0].createdAt, state: deployments[0].state, } : null, }; } const devServer = getDevServerManager(); health.devServer = { state: devServer.getState(), }; return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(JSON.stringify(health, null, 2)), ]); } async prepareInvocation( _options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: 'Analyzing project health...', }; } } // ==================== Sandbox Tools ==================== export interface ListSandboxesInput { status?: 'creating' | 'idle' | 'running' | 'terminated' | 'failed'; } export class ListSandboxesTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { const cli = getCliClient(); const result = await cli.sandboxList({ status: options.input.status }); if (!result.success || !result.data) { throw new Error(`Failed to list sandboxes: ${result.error || 'Unknown error'}`); } const sandboxes = result.data.map((s) => ({ id: s.sandboxId, name: s.name, description: s.description, status: s.status, runtime: s.runtime?.name ?? s.runtime?.id, runtimeId: s.runtime?.id, region: s.region, createdAt: s.createdAt, resources: s.resources, executions: s.executions, })); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(JSON.stringify(sandboxes, null, 2)), ]); } async prepareInvocation( _options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: 'Listing sandboxes...', }; } } export interface ListSandboxRuntimesInput { limit?: number; } export class ListSandboxRuntimesTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { const cli = getCliClient(); const limit = options.input.limit ?? 50; const result = await cli.sandboxRuntimeList({ limit }); if (!result.success || !result.data) { throw new Error(`Failed to list runtimes: ${result.error || 'Unknown error'}`); } const output = result.data.runtimes.map((rt) => ({ id: rt.id, name: rt.name, description: rt.description, tags: rt.tags, url: rt.url, })); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(JSON.stringify(output, null, 2)), ]); } async prepareInvocation( _options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: 'Listing sandbox runtimes...', }; } } export interface CreateSandboxInput { memory?: string; cpu?: string; network?: boolean; snapshot?: string; dependencies?: string[]; // New fields runtime?: string; runtimeId?: string; name?: string; description?: string; } export class CreateSandboxTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { const cli = getCliClient(); const createOptions: SandboxCreateOptions = { memory: options.input.memory, cpu: options.input.cpu, network: options.input.network, snapshot: options.input.snapshot, dependencies: options.input.dependencies, runtime: options.input.runtime, runtimeId: options.input.runtimeId, name: options.input.name, description: options.input.description, }; const result = await cli.sandboxCreate(createOptions); if (!result.success || !result.data) { throw new Error(`Failed to create sandbox: ${result.error || 'Unknown error'}`); } const info = result.data; const lines = [ 'Sandbox created successfully!', '', `ID: ${info.sandboxId}`, info.name ? `Name: ${info.name}` : '', info.description ? `Description: ${info.description}` : '', `Runtime: ${info.runtime?.name ?? info.runtime?.id ?? 'bun:1'}`, `Status: ${info.status}`, `Region: ${info.region}`, ].filter(Boolean); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(lines.join('\n')), ]); } async prepareInvocation( _options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: 'Creating sandbox...', confirmationMessages: { title: 'Create Sandbox', message: new vscode.MarkdownString( 'This will create a new sandbox environment in the cloud.\n\nDo you want to continue?' ), }, }; } } export interface SyncToSandboxInput { sandboxId: string; } export class SyncToSandboxTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { const { sandboxId } = options.input; if (!sandboxId) { throw new Error('Sandbox ID is required.'); } if (!vscode.workspace.workspaceFolders?.length) { throw new Error('No workspace folder open to sync.'); } try { const manager = getSandboxManager(); const result = await manager.syncToSandbox(sandboxId); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart( `Synced ${result.filesUploaded} files (${formatBytes(result.bytesTransferred)}) in ${(result.duration / 1000).toFixed(1)}s` ), ]); } catch (err) { throw new Error(`Failed to sync: ${err instanceof Error ? err.message : 'Unknown error'}`); } } async prepareInvocation( options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: `Syncing workspace to sandbox ${options.input.sandboxId?.substring(0, 8)}...`, confirmationMessages: { title: 'Sync to Sandbox', message: new vscode.MarkdownString( 'This will upload your workspace files to the sandbox.\n\nDo you want to continue?' ), }, }; } } export interface ExecuteInSandboxInput { sandboxId: string; command: string; } export class ExecuteInSandboxTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { const { sandboxId, command } = options.input; if (!sandboxId || !command) { throw new Error('Sandbox ID and command are required.'); } const cli = getCliClient(); const cliPath = cli.getCliPath(); // Execute in terminal for streaming output const terminal = vscode.window.createTerminal({ name: `Sandbox: ${sandboxId.slice(0, 8)}`, iconPath: new vscode.ThemeIcon('vm'), }); terminal.show(); terminal.sendText(`${cliPath} cloud sandbox exec ${sandboxId} -- ${command}`); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart( `Executing "${command}" in sandbox ${sandboxId}. Check the terminal for output.` ), ]); } async prepareInvocation( options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: `Executing command in sandbox ${options.input.sandboxId?.substring(0, 8)}...`, confirmationMessages: { title: 'Execute in Sandbox', message: new vscode.MarkdownString( `This will execute the following command in the sandbox:\n\n\`\`\`\n${options.input.command}\n\`\`\`\n\nDo you want to continue?` ), }, }; } } export interface CreateSnapshotInput { sandboxId: string; tag?: string; region?: string; } export class CreateSnapshotTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { const { sandboxId, tag } = options.input; if (!sandboxId) { throw new Error('Sandbox ID is required.'); } const cli = getCliClient(); const result = await cli.snapshotCreate(sandboxId, tag); if (!result.success || !result.data) { throw new Error(`Failed to create snapshot: ${result.error || 'Unknown error'}`); } return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart( `Snapshot created!\n\nID: ${result.data.snapshotId}\nSize: ${formatBytes(result.data.sizeBytes)}\nFiles: ${result.data.fileCount}${tag ? `\nTag: ${tag}` : ''}` ), ]); } async prepareInvocation( options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: `Creating snapshot of sandbox ${options.input.sandboxId?.substring(0, 8)}...`, }; } } export interface DeleteSandboxInput { sandboxId: string; } export class DeleteSandboxTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { const { sandboxId } = options.input; if (!sandboxId) { throw new Error('Sandbox ID is required.'); } const cli = getCliClient(); const result = await cli.sandboxDelete(sandboxId); if (!result.success) { throw new Error(`Failed to delete sandbox: ${result.error || 'Unknown error'}`); } return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(`Sandbox ${sandboxId} deleted successfully.`), ]); } async prepareInvocation( options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: `Deleting sandbox ${options.input.sandboxId?.substring(0, 8)}...`, confirmationMessages: { title: 'Delete Sandbox', message: new vscode.MarkdownString( `Are you sure you want to delete sandbox **${options.input.sandboxId}**?\n\nThis action cannot be undone.` ), }, }; } } // Queue tools export interface ListQueuesInput { limit?: number; } export class ListQueuesTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { if (!hasProject()) { throw new Error('No Agentuity project found in the current workspace.'); } const cli = getCliClient(); const result = await cli.listQueues({ limit: options.input.limit }); if (!result.success || !result.data) { throw new Error(`Failed to list queues: ${result.error || 'Unknown error'}`); } const queues = result.data.queues; if (queues.length === 0) { return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart('No queues found.'), ]); } const output = queues.map((q) => ({ name: q.name, type: q.queue_type, messageCount: q.message_count, dlqCount: q.dlq_count, createdAt: q.created_at, })); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(JSON.stringify(output, null, 2)), ]); } async prepareInvocation( _options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: 'Fetching queues...', }; } } export interface PublishQueueMessageInput { queueName: string; payload: string; metadata?: string; ttl?: number; } export class PublishQueueMessageTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { if (!hasProject()) { throw new Error('No Agentuity project found in the current workspace.'); } const { queueName, payload, metadata, ttl } = options.input; if (!queueName || !payload) { throw new Error('Queue name and payload are required.'); } // Validate JSON try { JSON.parse(payload); } catch { throw new Error('Payload must be valid JSON.'); } if (metadata) { try { JSON.parse(metadata); } catch { throw new Error('Metadata must be valid JSON.'); } } const cli = getCliClient(); const result = await cli.publishQueueMessage(queueName, payload, { metadata, ttl }); if (!result.success || !result.data) { throw new Error(`Failed to publish message: ${result.error || 'Unknown error'}`); } return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart( `Published message to queue "${queueName}":\n\nID: ${result.data.id}\nOffset: ${result.data.offset}\nState: ${result.data.state}` ), ]); } async prepareInvocation( options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: `Publishing message to queue "${options.input.queueName}"...`, confirmationMessages: { title: 'Publish Message', message: new vscode.MarkdownString( `Publish message to queue **${options.input.queueName}**?\n\n\`\`\`json\n${options.input.payload}\n\`\`\`` ), }, }; } } export interface ListQueueMessagesInput { queueName: string; limit?: number; } export class ListQueueMessagesTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { if (!hasProject()) { throw new Error('No Agentuity project found in the current workspace.'); } const { queueName, limit } = options.input; if (!queueName) { throw new Error('Queue name is required.'); } const cli = getCliClient(); const result = await cli.listQueueMessages(queueName, { limit: limit || 20 }); if (!result.success || !result.data) { throw new Error(`Failed to list messages: ${result.error || 'Unknown error'}`); } const messages = result.data.data?.messages || []; if (messages.length === 0) { return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(`No messages in queue "${queueName}".`), ]); } return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(JSON.stringify(messages, null, 2)), ]); } async prepareInvocation( options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: `Fetching messages from queue "${options.input.queueName}"...`, }; } } export interface PauseResumeQueueInput { queueName: string; action: 'pause' | 'resume'; } export class PauseResumeQueueTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { if (!hasProject()) { throw new Error('No Agentuity project found in the current workspace.'); } const { queueName, action } = options.input; if (!queueName || !action) { throw new Error('Queue name and action are required.'); } const cli = getCliClient(); const result = action === 'pause' ? await cli.pauseQueue(queueName) : await cli.resumeQueue(queueName); if (!result.success) { throw new Error(`Failed to ${action} queue: ${result.error || 'Unknown error'}`); } return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(`Queue "${queueName}" ${action}d successfully.`), ]); } async prepareInvocation( options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: `${options.input.action === 'pause' ? 'Pausing' : 'Resuming'} queue "${options.input.queueName}"...`, }; } } export interface ListDlqMessagesInput { queueName: string; limit?: number; } export class ListDlqMessagesTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { if (!hasProject()) { throw new Error('No Agentuity project found in the current workspace.'); } const { queueName, limit } = options.input; if (!queueName) { throw new Error('Queue name is required.'); } const cli = getCliClient(); const result = await cli.listDlqMessages(queueName, { limit: limit || 20 }); if (!result.success || !result.data) { throw new Error(`Failed to list DLQ messages: ${result.error || 'Unknown error'}`); } const messages = result.data.messages || []; if (messages.length === 0) { return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(`No messages in DLQ for queue "${queueName}".`), ]); } const output = messages.map((m) => ({ id: m.id, offset: m.offset, failureReason: m.failure_reason, deliveryAttempts: m.delivery_attempts, movedAt: m.moved_at, })); return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart(JSON.stringify(output, null, 2)), ]); } async prepareInvocation( options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: `Fetching DLQ messages from queue "${options.input.queueName}"...`, }; } } export interface ReplayDlqMessageInput { queueName: string; messageId: string; } export class ReplayDlqMessageTool implements vscode.LanguageModelTool { async invoke( options: vscode.LanguageModelToolInvocationOptions, _token: vscode.CancellationToken ): Promise { if (!hasProject()) { throw new Error('No Agentuity project found in the current workspace.'); } const { queueName, messageId } = options.input; if (!queueName || !messageId) { throw new Error('Queue name and message ID are required.'); } const cli = getCliClient(); const result = await cli.replayDlqMessage(queueName, messageId); if (!result.success || !result.data) { throw new Error(`Failed to replay message: ${result.error || 'Unknown error'}`); } return new vscode.LanguageModelToolResult([ new vscode.LanguageModelTextPart( `Replayed DLQ message ${messageId}. New offset: ${result.data.message.offset}` ), ]); } async prepareInvocation( options: vscode.LanguageModelToolInvocationPrepareOptions, _token: vscode.CancellationToken ): Promise { return { invocationMessage: `Replaying DLQ message ${options.input.messageId?.substring(0, 8)}...`, confirmationMessages: { title: 'Replay DLQ Message', message: new vscode.MarkdownString( `Replay message **${options.input.messageId}** from the dead letter queue back to queue **${options.input.queueName}**?` ), }, }; } } export function registerAgentTools(context: vscode.ExtensionContext): void { if (!vscode.lm?.registerTool) { return; } try { context.subscriptions.push( vscode.lm.registerTool('agentuity_get_agents', new GetAgentsTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_get_project_status', new GetProjectStatusTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_get_sessions', new GetSessionsTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_get_session_logs', new GetSessionLogsTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_control_dev_server', new ControlDevServerTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_get_deployments', new GetDeploymentsTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_deploy_project', new DeployProjectTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_get_health_summary', new GetHealthSummaryTool()) ); // Sandbox tools context.subscriptions.push( vscode.lm.registerTool('agentuity_list_sandboxes', new ListSandboxesTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_list_sandbox_runtimes', new ListSandboxRuntimesTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_create_sandbox', new CreateSandboxTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_sync_to_sandbox', new SyncToSandboxTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_execute_in_sandbox', new ExecuteInSandboxTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_create_snapshot', new CreateSnapshotTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_delete_sandbox', new DeleteSandboxTool()) ); // Queue tools context.subscriptions.push( vscode.lm.registerTool('agentuity_list_queues', new ListQueuesTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_publish_queue_message', new PublishQueueMessageTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_list_queue_messages', new ListQueueMessagesTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_pause_resume_queue', new PauseResumeQueueTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_list_dlq_messages', new ListDlqMessagesTool()) ); context.subscriptions.push( vscode.lm.registerTool('agentuity_replay_dlq_message', new ReplayDlqMessageTool()) ); } catch { // LM API not available } }