diff --git a/ops/agent-phone.mjs b/ops/agent-phone.mjs index e5c29e3..b2ab94a 100755 --- a/ops/agent-phone.mjs +++ b/ops/agent-phone.mjs @@ -422,6 +422,12 @@ export function noteSaid(pin, agent, text) { }); } catch {} } +/** + * How far back a joined leg reads the room's record as its own memory: long + * enough to rejoin a call it dropped out of, short enough that the last episode + * recorded in the same room is not mistaken for this one. + */ +export const ROOM_MEMORY_MS = 30 * 60_000; /** Where a joined leg asks the room who is on the line and what was said. */ export function statusUrlFor(base, pin) { return `${String(base).replace(/\/+$/, '')}/api/v1/agent-queue/rooms/${pin}`; @@ -817,7 +823,18 @@ async function main() { const r = await fetch(process.env.GROUPCALL_STATUS_URL, { headers: roomHeaders }).then((x) => (x.ok ? x.json() : null)).catch(() => null); const all = await fetch(`${process.env.GROUPCALL_STATUS_URL}/lines?after=0&wait=0`, { headers: roomHeaders }).then((x) => (x.ok ? x.json() : null)).catch(() => null); afterId = all?.lines?.at(-1)?.id || 0; - if (r) r.history = (all?.lines || r.history || []).slice(-80); + /** + * Recent lines only. The room's record is our memory so that a drop, a crash + * or a deploy picks the conversation up instead of starting over - and a + * redial takes seconds, a restart a minute. But a room keeps its transcript + * between calls, and Off The Record records every episode in the same room: + * unbounded, a new episode opened with eighty lines of the LAST one, so the + * hosts started the show holding things the guest had said weeks earlier. + * That is also the one thing their brief forbids - never say "you mentioned" + * about something that is not in this call. + */ + const since = Date.now() - ROOM_MEMORY_MS; + if (r) r.history = (all?.lines || r.history || []).filter((l) => Number(l?.at) >= since).slice(-80); for (const l of r?.history || []) { const at = new Date(l.at).toISOString(); if (l.kind === 'agent' && l.who === agent) transcript.push({ who: agent, text: l.text, at, history: true }); diff --git a/test/agent-phone.test.mjs b/test/agent-phone.test.mjs index 8bcbae0..4b9b063 100644 --- a/test/agent-phone.test.mjs +++ b/test/agent-phone.test.mjs @@ -327,6 +327,25 @@ test('a joined leg can work out where the room status lives', () => { assert.equal(worker.statusUrlFor('https://group.call.pit.world/', '8625'), 'https://group.call.pit.world/api/v1/agent-queue/rooms/8625'); }); +test("the room's record is memory of this call, not of the last episode", () => { + // A room keeps its transcript between calls and Off The Record records every + // episode in room 8625, so loading the last 80 lines unbounded opened a new + // episode with the previous one in the hosts' heads: "[memory] 80 earlier lines + // loaded" followed by questions about a Bitcoin loss from weeks before. Their + // brief forbids exactly that - never say "you mentioned" about something that + // is not in this call. + const lines = [ + { id: 1, who: 'Anthony', kind: 'person', text: 'from the last episode', at: now - 60 * minute }, + { id: 2, who: 'riotcoder', kind: 'agent', text: 'also last episode', at: now - 31 * minute }, + { id: 3, who: 'Anthony', kind: 'person', text: 'this call, after a drop', at: now - 2 * minute }, + ]; + const since = now - worker.ROOM_MEMORY_MS; + const kept = lines.filter((l) => Number(l.at) >= since).slice(-80); + assert.deepEqual(kept.map((l) => l.id), [3]); + // Long enough to rejoin a call that dropped a few minutes ago. + assert.ok(worker.ROOM_MEMORY_MS >= 10 * minute); +}); + 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: '' });