feat(vela): add mocked turn transcript response slice
This commit is contained in:
@@ -11,6 +11,8 @@ const {
|
||||
|
||||
const WEBSOCKET_ROUTE = '/ws';
|
||||
const WEBSOCKET_GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
|
||||
const MOCKED_USER_TRANSCRIPT = '[mocked user] What is the current mocked vertical slice?';
|
||||
const MOCKED_ASSISTANT_RESPONSE = '[mocked assistant] This is a deterministic mocked response from the gateway vertical slice.';
|
||||
|
||||
function createSessionRecord() {
|
||||
return {
|
||||
@@ -18,10 +20,62 @@ function createSessionRecord() {
|
||||
connectedAt: new Date().toISOString(),
|
||||
state: 'idle',
|
||||
audioChunkCount: 0,
|
||||
started: false
|
||||
started: false,
|
||||
mockedTurnInFlight: false,
|
||||
mockedTurnTimers: []
|
||||
};
|
||||
}
|
||||
|
||||
function clearMockedTurn(session) {
|
||||
for (const timer of session.mockedTurnTimers) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
|
||||
session.mockedTurnTimers = [];
|
||||
session.mockedTurnInFlight = false;
|
||||
}
|
||||
|
||||
function scheduleMockedTurnStep(session, delay, callback) {
|
||||
const timer = setTimeout(() => {
|
||||
session.mockedTurnTimers = session.mockedTurnTimers.filter((activeTimer) => activeTimer !== timer);
|
||||
callback();
|
||||
}, delay);
|
||||
|
||||
session.mockedTurnTimers.push(timer);
|
||||
}
|
||||
|
||||
function startMockedTurn(socket, session) {
|
||||
if (session.mockedTurnInFlight) {
|
||||
sendSocketError(socket, 'mocked_turn_in_flight', 'Only one mocked turn can run per session at a time.');
|
||||
return;
|
||||
}
|
||||
|
||||
clearMockedTurn(session);
|
||||
session.audioChunkCount = 0;
|
||||
session.mockedTurnInFlight = true;
|
||||
updateSessionState(socket, session, 'listening');
|
||||
|
||||
scheduleMockedTurnStep(session, 75, () => {
|
||||
sendSocketMessage(socket, 'transcript.final', { text: MOCKED_USER_TRANSCRIPT });
|
||||
updateSessionState(socket, session, 'thinking');
|
||||
});
|
||||
|
||||
scheduleMockedTurnStep(session, 150, () => {
|
||||
updateSessionState(socket, session, 'speaking');
|
||||
sendSocketMessage(socket, 'response.text.delta', { text: '[mocked assistant] ' });
|
||||
});
|
||||
|
||||
scheduleMockedTurnStep(session, 225, () => {
|
||||
sendSocketMessage(socket, 'response.text.delta', { text: MOCKED_ASSISTANT_RESPONSE.replace('[mocked assistant] ', '') });
|
||||
});
|
||||
|
||||
scheduleMockedTurnStep(session, 300, () => {
|
||||
sendSocketMessage(socket, 'response.completed', {});
|
||||
clearMockedTurn(session);
|
||||
updateSessionState(socket, session, 'idle');
|
||||
});
|
||||
}
|
||||
|
||||
function createWebSocketAcceptValue(key) {
|
||||
return crypto.createHash('sha1').update(`${key}${WEBSOCKET_GUID}`).digest('base64');
|
||||
}
|
||||
@@ -164,15 +218,29 @@ function handleClientMessage(socket, session, rawMessage) {
|
||||
sendSocketMessage(socket, 'session.ready', { sessionId: session.id });
|
||||
sendSocketMessage(socket, 'session.state', { value: session.state });
|
||||
break;
|
||||
case 'mocked.turn.trigger':
|
||||
startMockedTurn(socket, session);
|
||||
break;
|
||||
case 'input_audio.append':
|
||||
if (session.mockedTurnInFlight) {
|
||||
sendSocketError(socket, 'mocked_turn_in_flight', 'Wait for the mocked turn to finish before sending more input.');
|
||||
break;
|
||||
}
|
||||
|
||||
session.audioChunkCount += 1;
|
||||
updateSessionState(socket, session, 'listening');
|
||||
break;
|
||||
case 'input_audio.commit':
|
||||
if (session.mockedTurnInFlight) {
|
||||
sendSocketError(socket, 'mocked_turn_in_flight', 'Wait for the mocked turn to finish before committing input.');
|
||||
break;
|
||||
}
|
||||
|
||||
session.audioChunkCount = 0;
|
||||
updateSessionState(socket, session, 'idle');
|
||||
break;
|
||||
case 'response.cancel':
|
||||
clearMockedTurn(session);
|
||||
session.audioChunkCount = 0;
|
||||
updateSessionState(socket, session, 'idle');
|
||||
break;
|
||||
@@ -241,6 +309,7 @@ function registerWebSocketSessionRoute(app) {
|
||||
}
|
||||
|
||||
closed = true;
|
||||
clearMockedTurn(session);
|
||||
app.websocketSessions.delete(session.id);
|
||||
app.log.info({ sessionId: session.id }, 'websocket session disconnected');
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user