mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
keep typed and tool-follow-up responses attached to their original requests reject duplicate events before they affect newer work preserve newer input and Radio handoffs during old callback cleanup integrate the tested main snapshot without dropping existing history
475 lines
15 KiB
JavaScript
475 lines
15 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { GevRealtimeController } from './realtimeController.js';
|
|
import {
|
|
readVoiceUserTurnText,
|
|
subscribeVoiceUserTurn,
|
|
} from './userTurnIntent.js';
|
|
|
|
function fixture({ via, onEvent, send } = {}) {
|
|
const sent = [],
|
|
calls = [],
|
|
events = [];
|
|
let armed = false;
|
|
const c = new GevRealtimeController({
|
|
runner: async (_name, _args, options) => {
|
|
calls.push(options.userTurn);
|
|
return { ok: true };
|
|
},
|
|
backend: {},
|
|
debugSink: null,
|
|
onSessionEvent: (event) => {
|
|
events.push(event);
|
|
if (armed && via === 'boundary' && event.type === 'user-turn-start') {
|
|
armed = false;
|
|
c.sendTextCommand('newer typed request');
|
|
}
|
|
onEvent?.(event, c);
|
|
},
|
|
ui: {
|
|
root: {
|
|
dataset: {},
|
|
classList: { remove() {} },
|
|
querySelectorAll: () => [],
|
|
},
|
|
status: {},
|
|
detail: {},
|
|
},
|
|
});
|
|
const channel = () => ({
|
|
readyState: 'open',
|
|
send: (value) => {
|
|
const payload = JSON.parse(value);
|
|
sent.push(payload);
|
|
send?.(payload, c);
|
|
},
|
|
close() {
|
|
this.readyState = 'closed';
|
|
},
|
|
});
|
|
c.dc = channel();
|
|
c.status = 'listening';
|
|
c._turns.narration = null;
|
|
const event = (payload) =>
|
|
c.handleRealtimeEvent({
|
|
data: JSON.stringify(payload),
|
|
currentTarget: c.dc,
|
|
});
|
|
const start = (id) =>
|
|
event({ type: 'input_audio_buffer.speech_started', item_id: id });
|
|
const transcript = (id, text) =>
|
|
event({
|
|
type: 'conversation.item.input_audio_transcription.completed',
|
|
item_id: id,
|
|
transcript: text,
|
|
});
|
|
const commit = (id) =>
|
|
event({ type: 'input_audio_buffer.committed', item_id: id });
|
|
const created = (id, metadata) =>
|
|
event({
|
|
type: 'response.created',
|
|
response: { id, ...(metadata === undefined ? {} : { metadata }) },
|
|
});
|
|
const done = (id, tool = false) =>
|
|
event({
|
|
type: 'response.done',
|
|
response: {
|
|
id,
|
|
status: 'completed',
|
|
output: tool ? [{ type: 'function_call' }] : [],
|
|
},
|
|
});
|
|
const tool = (id, call) =>
|
|
event({
|
|
type: 'response.function_call_arguments.done',
|
|
response_id: id,
|
|
call_id: call,
|
|
name: 'get_entity_context',
|
|
arguments: '{}',
|
|
});
|
|
const request = () =>
|
|
sent.findLast(
|
|
(e) =>
|
|
e.type === 'response.create' &&
|
|
e.response?.metadata?.gev !== 'progress',
|
|
);
|
|
const output = () =>
|
|
sent
|
|
.filter((e) => e.item?.type === 'function_call_output')
|
|
.map((e) => JSON.parse(e.item.output));
|
|
const prepare = async () => {
|
|
await start('B');
|
|
await transcript('B', 'old B');
|
|
await commit('B');
|
|
await created('R0');
|
|
if (via === 'token')
|
|
subscribeVoiceUserTurn(
|
|
c._turns.userTurnIntent.forResponse('R0'),
|
|
(token) => {
|
|
if (armed && !readVoiceUserTurnText(token)) {
|
|
armed = false;
|
|
c.sendTextCommand('newer typed request');
|
|
}
|
|
},
|
|
);
|
|
armed = true;
|
|
await start('C');
|
|
await transcript('C', 'older C speech');
|
|
};
|
|
return {
|
|
c,
|
|
sent,
|
|
calls,
|
|
events,
|
|
channel,
|
|
event,
|
|
start,
|
|
transcript,
|
|
commit,
|
|
created,
|
|
done,
|
|
tool,
|
|
request,
|
|
output,
|
|
prepare,
|
|
close: () => c.stop(),
|
|
};
|
|
}
|
|
|
|
for (const via of ['boundary', 'token'])
|
|
for (const commitFirst of [false, true])
|
|
for (const typedFirst of [false, true]) {
|
|
test(`OpenAI correlation ${via}: commit ${commitFirst ? 'before' : 'after'} old done, ${typedFirst ? 'typed' : 'speech'} response first`, async () => {
|
|
const f = fixture({ via });
|
|
try {
|
|
await f.prepare();
|
|
assert.equal(f.c._turns.userTurnIntent.reservationState().pending, 0);
|
|
if (commitFirst) await f.commit('C');
|
|
await f.done('R0');
|
|
const request = f.request();
|
|
if (!commitFirst) await f.commit('C');
|
|
if (typedFirst) {
|
|
await f.created('typed-T', request?.response?.metadata);
|
|
await f.created('automatic-C');
|
|
} else {
|
|
await f.created('automatic-C');
|
|
await f.created('typed-T', request?.response?.metadata);
|
|
}
|
|
const typed = f.c._turns.userTurnIntent.forResponse('typed-T');
|
|
await f.tool('automatic-C', 'C-call');
|
|
assert.equal(
|
|
f.calls.length,
|
|
0,
|
|
'spoken C must never run with typed T authority',
|
|
);
|
|
assert.equal(f.output().at(-1).superseded, true);
|
|
assert.equal(f.c.pendingResponseInstructions, null);
|
|
assert.equal(readVoiceUserTurnText(typed), 'newer typed request');
|
|
await f.tool('typed-T', 'T-call');
|
|
assert.equal(f.calls.length, 1);
|
|
assert.equal(f.calls[0], typed);
|
|
assert.equal(
|
|
readVoiceUserTurnText(f.calls[0]),
|
|
'newer typed request',
|
|
);
|
|
assert.equal(
|
|
request.response.metadata.gev_request_id,
|
|
request.event_id,
|
|
);
|
|
} finally {
|
|
f.close();
|
|
}
|
|
});
|
|
}
|
|
|
|
for (const tag of ['unknown', '', 7, {}, [], null]) {
|
|
test(`OpenAI unknown or malformed client correlation ${JSON.stringify(tag)} cannot consume speech or typed reservations`, async () => {
|
|
const f = fixture();
|
|
try {
|
|
await f.start('B');
|
|
await f.transcript('B', 'older speech');
|
|
await f.commit('B');
|
|
f.c.sendTextCommand('newer typed request');
|
|
const request = f.request();
|
|
assert.equal(f.c._turns.userTurnIntent.reservationState().pending, 2);
|
|
await f.created('foreign', { gev_request_id: tag });
|
|
await f.tool('foreign', 'foreign-tool');
|
|
assert.equal(f.calls.length, 0);
|
|
assert.equal(f.output().at(-1).superseded, true);
|
|
assert.equal(f.c.pendingResponseInstructions, null);
|
|
assert.equal(f.c._turns.userTurnIntent.reservationState().pending, 2);
|
|
await f.created('automatic-B');
|
|
assert.equal(f.c._turns.isSupersededResponse('automatic-B'), true);
|
|
await f.created('typed-T', request.response.metadata);
|
|
await f.tool('typed-T', 'typed-tool');
|
|
assert.equal(readVoiceUserTurnText(f.calls[0]), 'newer typed request');
|
|
} finally {
|
|
f.close();
|
|
}
|
|
});
|
|
}
|
|
|
|
test('OpenAI absent client metadata cannot borrow typed authority or pass it through an unverified followup', async () => {
|
|
const f = fixture();
|
|
try {
|
|
f.c.sendTextCommand('newer typed request');
|
|
const request = f.request();
|
|
await f.created('unrelated-automatic');
|
|
await f.tool('unrelated-automatic', 'unverified-call');
|
|
assert.equal(f.calls.length, 0);
|
|
assert.equal(f.output().at(-1).voiceIntentUnverified, true);
|
|
assert.equal(
|
|
f.c.pendingResponseInstructions,
|
|
null,
|
|
'untracked response cannot queue a followup with current typed authority',
|
|
);
|
|
assert.equal(f.c._turns.userTurnIntent.reservationState().pending, 1);
|
|
await f.created('typed-T', request.response.metadata);
|
|
await f.tool('typed-T', 'real-T');
|
|
assert.equal(readVoiceUserTurnText(f.calls[0]), 'newer typed request');
|
|
} finally {
|
|
f.close();
|
|
}
|
|
});
|
|
|
|
test('OpenAI tagged followup keeps the exact originating request and ignores out-of-band progress', async () => {
|
|
const f = fixture();
|
|
try {
|
|
f.c.sendTextCommand('newer typed request');
|
|
await f.created('typed-T', f.request().response.metadata);
|
|
const token = f.c._turns.userTurnIntent.forResponse('typed-T');
|
|
await f.tool('typed-T', 'T-tool');
|
|
await f.done('typed-T', true);
|
|
const followup = f.request();
|
|
assert.ok(followup.response.instructions);
|
|
assert.equal(followup.response.metadata.gev_request_id, followup.event_id);
|
|
await f.created('progress', { gev: 'progress' });
|
|
assert.equal(f.c._turns.userTurnIntent.reservationState().pending, 1);
|
|
await f.created('followup', followup.response.metadata);
|
|
assert.equal(f.c._turns.userTurnIntent.forResponse('followup'), token);
|
|
await f.done('followup');
|
|
assert.equal(readVoiceUserTurnText(token), undefined);
|
|
} finally {
|
|
f.close();
|
|
}
|
|
});
|
|
|
|
test('OpenAI duplicate tagged response events do not consume another request or speech slot', async () => {
|
|
const f = fixture();
|
|
try {
|
|
f.c.sendTextCommand('newer typed request');
|
|
const metadata = f.request().response.metadata;
|
|
await f.created('typed-T', metadata);
|
|
const token = f.c._turns.userTurnIntent.forResponse('typed-T');
|
|
await f.created('typed-T', metadata);
|
|
assert.equal(f.c._turns.userTurnIntent.forResponse('typed-T'), token);
|
|
await f.start('C');
|
|
await f.transcript('C', 'new speech');
|
|
await f.commit('C');
|
|
await f.created('duplicate-request-response', metadata);
|
|
assert.equal(
|
|
f.c._turns.isSupersededResponse('duplicate-request-response'),
|
|
true,
|
|
);
|
|
assert.equal(f.c._turns.userTurnIntent.reservationState().pending, 1);
|
|
await f.created('C-response');
|
|
await f.tool('C-response', 'C-tool');
|
|
assert.equal(readVoiceUserTurnText(f.calls[0]), 'new speech');
|
|
} finally {
|
|
f.close();
|
|
}
|
|
});
|
|
|
|
for (const lifecycle of ['stop', 'replace', 'new typed']) {
|
|
test(`OpenAI synchronous ${lifecycle} during actual response send cannot reserve newer authority`, async () => {
|
|
let armed = true;
|
|
let sentRequest;
|
|
let f;
|
|
f = fixture({
|
|
send: (payload, c) => {
|
|
if (!armed || payload.type !== 'response.create') return;
|
|
armed = false;
|
|
sentRequest = payload;
|
|
if (lifecycle === 'new typed') c.sendTextCommand('new typed successor');
|
|
else {
|
|
c.stop();
|
|
if (lifecycle === 'replace') {
|
|
c.dc = f.channel();
|
|
c.status = 'listening';
|
|
}
|
|
}
|
|
},
|
|
});
|
|
try {
|
|
f.c.sendTextCommand('original typed request');
|
|
if (lifecycle === 'stop') {
|
|
assert.equal(f.c.dc, null);
|
|
assert.equal(f.c._turns.userTurnIntent.reservationState().pending, 0);
|
|
} else {
|
|
if (lifecycle === 'replace') {
|
|
assert.equal(f.c._turns.userTurnIntent.reservationState().pending, 0);
|
|
f.c.sendTextCommand('new typed successor');
|
|
}
|
|
await f.created('old-sent-response', sentRequest.response.metadata);
|
|
await f.tool('old-sent-response', 'old-tool');
|
|
assert.equal(f.calls.length, 0);
|
|
assert.equal(f.output().at(-1).superseded, true);
|
|
if (lifecycle === 'new typed') await f.done('old-sent-response');
|
|
const latest = f.request();
|
|
assert.notEqual(latest.event_id, sentRequest.event_id);
|
|
await f.created('new-response', latest.response.metadata);
|
|
await f.tool('new-response', 'new-tool');
|
|
assert.equal(readVoiceUserTurnText(f.calls[0]), 'new typed successor');
|
|
}
|
|
} finally {
|
|
f.close();
|
|
}
|
|
});
|
|
}
|
|
|
|
for (const stage of ['conversation.item.create', 'response.create']) {
|
|
test(`OpenAI failed ${stage} never reserves a response or authorizes an automatic reply`, async () => {
|
|
const f = fixture({
|
|
send: (payload) => {
|
|
if (payload.type === stage) throw new Error('synthetic send failure');
|
|
},
|
|
});
|
|
try {
|
|
f.c.sendTextCommand('newer typed request');
|
|
assert.equal(f.c._turns.userTurnIntent.reservationState().pending, 0);
|
|
await f.created('untracked');
|
|
await f.tool('untracked', 'untracked-tool');
|
|
assert.equal(f.calls.length, 0);
|
|
} finally {
|
|
f.close();
|
|
}
|
|
});
|
|
}
|
|
|
|
test('OpenAI rejected tagged request cannot consume later genuine speech authority', async () => {
|
|
const f = fixture();
|
|
try {
|
|
f.c.sendTextCommand('old typed request');
|
|
const rejected = f.request();
|
|
await f.start('C');
|
|
await f.transcript('C', 'genuine speech');
|
|
await f.commit('C');
|
|
await f.event({
|
|
type: 'error',
|
|
event_id: 'server-error',
|
|
error: {
|
|
code: 'conversation_already_has_active_response',
|
|
event_id: rejected.event_id,
|
|
message: 'synthetic overlap',
|
|
},
|
|
});
|
|
await f.created('rejected-request-response', rejected.response.metadata);
|
|
assert.equal(
|
|
f.c._turns.isSupersededResponse('rejected-request-response'),
|
|
true,
|
|
);
|
|
await f.created('C-response');
|
|
await f.tool('C-response', 'C-tool');
|
|
assert.equal(readVoiceUserTurnText(f.calls[0]), 'genuine speech');
|
|
} finally {
|
|
f.close();
|
|
}
|
|
});
|
|
|
|
test('OpenAI local barge-in drops a deferred typed capture before a late old completion', async () => {
|
|
const f = fixture();
|
|
try {
|
|
await f.created('R0');
|
|
f.c.sendTextCommand('deferred typed');
|
|
assert.equal(f.c.pendingUserTextResponse, true);
|
|
f.c._turns.bargeIn();
|
|
await f.done('R0');
|
|
assert.equal(f.sent.filter((e) => e.type === 'response.create').length, 0);
|
|
assert.equal(f.c.pendingUserTextResponse, false);
|
|
assert.equal(f.c._turns.userTurnIntent.reservationState().pending, 0);
|
|
} finally {
|
|
f.close();
|
|
}
|
|
});
|
|
|
|
test('OpenAI unrelated explicit out-of-band response never consumes a tagged typed request', async () => {
|
|
const f = fixture();
|
|
try {
|
|
f.c.sendTextCommand('newer typed request');
|
|
const request = f.request();
|
|
await f.event({
|
|
type: 'response.created',
|
|
response: {
|
|
id: 'foreign-oob',
|
|
conversation_id: null,
|
|
metadata: request.response.metadata,
|
|
},
|
|
});
|
|
await f.tool('foreign-oob', 'oob-tool');
|
|
assert.equal(f.calls.length, 0);
|
|
assert.equal(f.c.pendingResponseInstructions, null);
|
|
assert.equal(f.c._turns.userTurnIntent.reservationState().pending, 1);
|
|
await f.created('typed-T', request.response.metadata);
|
|
await f.tool('typed-T', 'T-tool');
|
|
assert.equal(readVoiceUserTurnText(f.calls[0]), 'newer typed request');
|
|
} finally {
|
|
f.close();
|
|
}
|
|
});
|
|
|
|
test('OpenAI duplicate late commits for retained retired C do not duplicate reservations', async () => {
|
|
const f = fixture({ via: 'boundary' });
|
|
try {
|
|
await f.prepare();
|
|
await f.done('R0');
|
|
const request = f.request();
|
|
await f.commit('C');
|
|
await f.commit('C');
|
|
assert.equal(f.c._turns.userTurnIntent.reservationState().pending, 2);
|
|
await f.created('automatic-C');
|
|
await f.commit('C');
|
|
assert.equal(f.c._turns.userTurnIntent.reservationState().pending, 1);
|
|
await f.created('typed-T', request.response.metadata);
|
|
await f.tool('typed-T', 'T-tool');
|
|
assert.equal(readVoiceUserTurnText(f.calls[0]), 'newer typed request');
|
|
assert.equal(f.c._turns.userTurnIntent.reservationState().pending, 0);
|
|
} finally {
|
|
f.close();
|
|
}
|
|
});
|
|
|
|
test('OpenAI a newer typed input during a followup send cannot own the old followup response', async () => {
|
|
let armed = true;
|
|
const f = fixture({
|
|
send: (payload, c) => {
|
|
if (
|
|
armed &&
|
|
payload.type === 'response.create' &&
|
|
payload.response?.instructions
|
|
) {
|
|
armed = false;
|
|
c.sendTextCommand('new typed successor');
|
|
}
|
|
},
|
|
});
|
|
try {
|
|
f.c.sendTextCommand('original typed request');
|
|
await f.created('T-original', f.request().response.metadata);
|
|
await f.tool('T-original', 'original-tool');
|
|
await f.done('T-original', true);
|
|
const oldFollowup = f.request();
|
|
await f.created('old-followup', oldFollowup.response.metadata);
|
|
await f.tool('old-followup', 'old-followup-tool');
|
|
assert.equal(f.calls.length, 1);
|
|
assert.equal(f.output().at(-1).superseded, true);
|
|
await f.done('old-followup');
|
|
const latest = f.request();
|
|
assert.notEqual(latest.event_id, oldFollowup.event_id);
|
|
await f.created('T-successor', latest.response.metadata);
|
|
await f.tool('T-successor', 'successor-tool');
|
|
assert.equal(readVoiceUserTurnText(f.calls[1]), 'new typed successor');
|
|
} finally {
|
|
f.close();
|
|
}
|
|
});
|