Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions ops/agent-phone.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,19 @@ async function main() {
const last = [...transcript].reverse().find((t) => !t.history && t.who !== agent);
return Boolean(last && last.who === partnerAgent);
})();
if (join && a.interview && !firstTurn) {
/**
* Co-host coordination, on EVERY turn including the first one.
*
* This used to be gated on `!firstTurn`, and `firstTurn` is true
* whenever the agent has not spoken for three minutes. The hosts dial in
* and then wait in an empty room while the guest is rung, which is nearly
* always longer than that - so on the guest's very first words both hosts
* counted as introducing themselves, skipped the stagger, the reservation
* and the do-not-answer-your-co-host rule, and talked over each other in
* the first ten seconds of the show. Episode 9 ended twenty seconds after
* Anthony said hello and got two overlapping introductions.
*/
if (join && a.interview) {
// Never answer a question the co-host put to the guest.
if (partnerSpokeLast && !mine) return;
if (!mine) {
Expand Down Expand Up @@ -1213,7 +1225,13 @@ async function main() {
const lastHeard = recentSpeech();
const mine = addressed(agent, lastHeard);
const otherNamed = Object.keys(NAME_ALIASES).some((o) => o !== agent && addressed(o, lastHeard)) && !mine;
const introduced = !shouldIntroduce(agent, transcript, Date.now());
/**
* Whether this agent has spoken on this call at all - NOT whether it
* spoke recently. These guards stop two hosts answering the same line,
* and tying them to introduction staleness turned them off after any
* three-minute lull: exactly the long guest answer the format asks for.
*/
const introduced = transcript.some((t) => t.who === agent && !t.history);
if (introduced && kind !== 'hangup' && otherNamed) return;
// The other agent already answered what we are answering: leave it, unless it was ours by name.
const lineAt = Date.parse([...transcript].reverse().find((t) => t.who === 'them')?.at || '') || 0;
Expand Down
19 changes: 19 additions & 0 deletions test/agent-phone.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,25 @@ test('a host saying its own name is not the guest, however the transcriber spell
assert.equal(worker.echoesFloor('We run our own security and nothing else', 'rootkey handles the scanning for us'), false);
});

test('a host that has gone quiet is still introduced, so it keeps coordinating', () => {
// shouldIntroduce() is about the PROMPT: say hello if you have not spoken for
// three minutes. It used to gate co-host coordination too, and the hosts wait
// in an empty room while the guest is rung - always longer than three minutes.
// So on the guest's first words both hosts counted as introducing themselves,
// skipped the stagger and the reservation, and talked over each other. Episode
// 9 ended twenty seconds after Anthony said hello.
const transcript = [
{ who: 'riotcoder', text: 'Welcome to Off The Record.', at: new Date(now - 4 * minute).toISOString() },
{ who: 'them', text: 'Hello? This is Anthony.', at: new Date(now).toISOString() },
];
// Four minutes quiet: the prompt should still ask for a hello...
assert.equal(worker.shouldIntroduce('riotcoder', transcript, now), true);
// ...but having spoken on this call is a different fact, and the one the
// coordination guards now use.
assert.equal(transcript.some((l) => l.who === 'riotcoder' && !l.history), true);
assert.equal(transcript.some((l) => l.who === 'cha0spunk' && !l.history), false);
});

test('a model that says PASS is saying nothing, not reading the word out', () => {
assert.deepEqual(worker.parseTurn('SAY: PASS'), { kind: 'pass', text: '' });
assert.deepEqual(worker.parseTurn('PASS'), { kind: 'pass', text: '' });
Expand Down
Loading