diff --git a/apps/gateway/src/chat/chat.gateway.ts b/apps/gateway/src/chat/chat.gateway.ts index 9f55d4a..15a36d1 100644 --- a/apps/gateway/src/chat/chat.gateway.ts +++ b/apps/gateway/src/chat/chat.gateway.ts @@ -1,4 +1,4 @@ -import { Inject, Logger } from '@nestjs/common'; +import { Inject, Logger, Optional } from '@nestjs/common'; import { WebSocketGateway, WebSocketServer, @@ -39,6 +39,7 @@ import { import { BRAIN } from '../brain/brain.tokens.js'; import { CommandRegistryService } from '../commands/command-registry.service.js'; import { CommandExecutorService } from '../commands/command-executor.service.js'; +import { CommandAuthorizationService } from '../commands/command-authorization.service.js'; import { RoutingEngineService } from '../agent/routing/routing-engine.service.js'; import { v4 as uuid } from 'uuid'; import { ChatSocketMessageDto } from './chat.dto.js'; @@ -124,6 +125,9 @@ export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa @Inject(CommandRegistryService) private readonly commandRegistry: CommandRegistryService, @Inject(CommandExecutorService) private readonly commandExecutor: CommandExecutorService, @Inject(RoutingEngineService) private readonly routingEngine: RoutingEngineService, + @Optional() + @Inject(CommandAuthorizationService) + private readonly commandAuthorization: CommandAuthorizationService | null = null, ) {} afterInit(): void { @@ -646,19 +650,28 @@ export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa ): Promise { if (!client.data.discordService) return; const ingress = this.resolveDiscordIngress(client, envelope, 'approve'); - const command = ingress?.content.match(/^\/approve\s+([a-z][\w-]*)$/i)?.[1]; + const actionParts = ingress?.content.match(/^\/approve\s+([^\s]+)\s+([^\s]+)$/i); const serviceUserId = process.env['DISCORD_SERVICE_USER_ID']; - if (!ingress || !command || !serviceUserId) return; - const approval = await this.commandExecutor.createApproval( - { command, conversationId: ingress.conversationId }, - { - userId: serviceUserId, - tenantId: process.env['DISCORD_SERVICE_TENANT_ID'] ?? serviceUserId, - }, + if (!ingress || !actionParts || !serviceUserId || !this.commandAuthorization) return; + const binding = resolveDiscordInteractionBinding( + parseDiscordInteractionBindings(process.env['DISCORD_INTERACTION_BINDINGS']), + ingress.guildId, + ingress.channelId, + ingress.userId, + 'approve', ); + if (!binding) return; + const approval = await this.commandAuthorization.createRuntimeTerminationApproval({ + providerId: actionParts[1]!, + sessionId: actionParts[2]!, + actorId: serviceUserId, + tenantId: process.env['DISCORD_SERVICE_TENANT_ID'] ?? serviceUserId, + channelId: ingress.channelId, + correlationId: ingress.correlationId, + agentName: binding.instanceId, + }); client.emit('discord:approval', { correlationId: ingress.correlationId, - command, success: approval !== null, approvalId: approval?.approvalId, expiresAt: approval?.expiresAt,