Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | 7x 7x 7x 7x 7x 7x 7x 12x 12x 12x 3x 7x 1x 7x 1x 7x 2x 2x 1x 1x 2x 7x 2x 2x 2x 2x 2x 2x 2x | import {
Controller,
Get,
Post,
Param,
HttpCode,
HttpStatus,
ParseUUIDPipe,
Logger,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
import { ModuleRef } from '@nestjs/core';
import { SubAgentRunsService } from './sub-agent-runs.service';
import { SubAgentRun } from './sub-agent-run.entity';
import { ChatService } from '../interactive-chat/chat.service';
/**
* Sub-agent runs track active executions of specialized agents.
*
* Sub-agents are specialized AI configurations for specific tasks (bug fixing, refactoring, etc.).
* When invoked, they create a child session and this run record.
*
* Use these endpoints to:
* - Monitor active sub-agent runs
* - Cancel a running sub-agent
* - Cancel all sub-agents for a session
*
* The SubAgentRun entity tracks status (running/completed/failed/timeout/cancelled),
* duration, and result of the execution.
*/
@ApiTags('sub-agent-runs')
@Controller('sub-agent-runs')
export class SubAgentRunsController {
private readonly logger = new Logger(SubAgentRunsController.name);
constructor(
private readonly subAgentRunsService: SubAgentRunsService,
private readonly moduleRef: ModuleRef,
) {}
/**
* Lazily resolves ChatService to avoid circular module dependency
* (SubAgentsModule → InteractiveChatModule → LlmOrchestrationModule → SubAgentsModule).
*/
private getChatService(): ChatService {
return this.moduleRef.get(ChatService, { strict: false });
}
@Get('active')
@ApiOperation({
summary: 'Get all active sub-agent runs',
description:
'Returns all currently running sub-agent executions across all sessions.',
})
@ApiResponse({
status: 200,
description: 'List of active runs',
type: [SubAgentRun],
})
async getAllActiveRuns(): Promise<SubAgentRun[]> {
return this.subAgentRunsService.getAllActiveRuns();
}
@Get('active/:sessionId')
@ApiOperation({
summary: 'Get active runs for a session',
description:
'Returns all currently running sub-agent executions for a specific session.',
})
@ApiParam({
name: 'sessionId',
description: 'Parent session UUID',
format: 'uuid',
})
@ApiResponse({
status: 200,
description: 'List of active runs for session',
type: [SubAgentRun],
})
async getActiveRuns(
@Param('sessionId', ParseUUIDPipe) sessionId: string,
): Promise<SubAgentRun[]> {
return this.subAgentRunsService.getActiveRuns(sessionId);
}
@Post(':runId/cancel')
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: 'Cancel a sub-agent run',
description:
'Cancels a running sub-agent by marking it as cancelled and stopping any active LLM streaming.',
})
@ApiParam({
name: 'runId',
description: 'Run UUID to cancel',
format: 'uuid',
})
@ApiResponse({
status: 200,
description: 'Run cancelled',
schema: {
properties: {
success: { type: 'boolean' },
run: { $ref: '#/components/schemas/SubAgentRun', nullable: true },
},
},
})
async cancelRun(
@Param('runId', ParseUUIDPipe) runId: string,
): Promise<{ success: boolean; run: SubAgentRun | null }> {
const run = await this.subAgentRunsService.cancel(runId);
if (run) {
// Also stop any active LLM streaming for the child session
this.logger.log(
`Stopping LLM streaming for child session ${run.child_session_id}`,
);
this.getChatService().cancelRequest(run.child_session_id);
}
return { success: run !== null, run };
}
@Post('session/:sessionId/cancel-all')
@HttpCode(HttpStatus.OK)
@ApiOperation({
summary: 'Cancel all runs for a session',
description:
'Cancels all active sub-agent runs for a session. Useful when aborting a complex multi-agent workflow.',
})
@ApiParam({
name: 'sessionId',
description: 'Parent session UUID',
format: 'uuid',
})
@ApiResponse({
status: 200,
description: 'Runs cancelled',
schema: {
properties: {
count: { type: 'number', description: 'Number of runs cancelled' },
},
},
})
async cancelAllRuns(
@Param('sessionId', ParseUUIDPipe) sessionId: string,
): Promise<{ count: number }> {
// Get all active runs first to get child session IDs
const activeRuns = await this.subAgentRunsService.getActiveRuns(sessionId);
const chatService = this.getChatService();
// Cancel LLM streaming for each child session
for (const run of activeRuns) {
this.logger.log(
`Stopping LLM streaming for child session ${run.child_session_id}`,
);
chatService.cancelRequest(run.child_session_id);
}
// Mark all runs as cancelled
const count = await this.subAgentRunsService.cancelAllActiveRuns(sessionId);
return { count };
}
}
|