feat(sidecar): supervisor barge endpoints — initiate, mode switch, end

Endpoints:
- GET  /api/supervisor/barge/sip-credentials — fetch SIP number from pool
- POST /api/supervisor/barge — initiate barge via Ozonetel apiId 63
- POST /api/supervisor/barge/mode — update mode (listen/whisper/barge)
- POST /api/supervisor/barge/end — cleanup session + Redis

SupervisorService extended with barge session tracking (in-memory Map).
Mode changes emit SSE events to agent: supervisor-whisper, supervisor-barge,
supervisor-left. Listen mode is silent (no event to agent).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-12 16:06:57 +05:30
parent c23792496b
commit ea60787da0
3 changed files with 213 additions and 2 deletions

View File

@@ -34,7 +34,16 @@ export class SupervisorService implements OnModuleInit {
private readonly activeCalls = new Map<string, ActiveCall>();
private readonly agentStates = new Map<string, AgentStateEntry>();
private readonly acwTimers = new Map<string, NodeJS.Timeout>();
readonly agentStateSubject = new Subject<{ agentId: string; state: AgentOzonetelState; timestamp: string }>();
readonly agentStateSubject = new Subject<{ agentId: string; state: AgentOzonetelState | string; timestamp: string }>();
// Barge session tracking — key is agentId
private readonly bargeSessions = new Map<string, {
supervisorId: string;
agentId: string;
sipNumber: string;
mode: 'listen' | 'whisper' | 'barge';
startedAt: string;
}>();
constructor(
private platform: PlatformGraphqlService,
@@ -234,4 +243,42 @@ export class SupervisorService implements OnModuleInit {
return { date, agents: summaries, teamTotals };
}
// --- Barge session management ---
getBargeSession(agentId: string) {
return this.bargeSessions.get(agentId) ?? null;
}
startBargeSession(session: { supervisorId: string; agentId: string; sipNumber: string; mode: 'listen' | 'whisper' | 'barge'; startedAt: string }) {
this.bargeSessions.set(session.agentId, session);
this.logger.log(`[BARGE] Started: ${session.supervisorId}${session.agentId} (${session.mode})`);
}
updateBargeMode(agentId: string, mode: 'listen' | 'whisper' | 'barge') {
const session = this.bargeSessions.get(agentId);
if (!session) return;
const previousMode = session.mode;
session.mode = mode;
// Emit SSE to agent — whisper/barge show indicator, listen is silent
if (mode === 'whisper' || mode === 'barge') {
this.agentStateSubject.next({ agentId, state: `supervisor-${mode}`, timestamp: new Date().toISOString() });
} else if (previousMode !== 'listen') {
// Switching back to listen from whisper/barge
this.agentStateSubject.next({ agentId, state: 'supervisor-left', timestamp: new Date().toISOString() });
}
this.logger.log(`[BARGE] Mode: ${agentId}${mode}`);
}
endBargeSession(agentId: string) {
const session = this.bargeSessions.get(agentId);
if (!session) return;
this.bargeSessions.delete(agentId);
this.agentStateSubject.next({ agentId, state: 'supervisor-left', timestamp: new Date().toISOString() });
this.logger.log(`[BARGE] Ended: ${session.supervisorId}${agentId}`);
}
}