src/voice/voiceAddressing.test.ts

import { describe, test } from "bun:test"; import assert from "node:assert/strict"; import { annotateLatestVoiceTurnAddressing, buildVoiceAddressingState, findLatestVoiceTurnIndex, mergeVoiceAddressingAnnotation, normalizeVoiceAddressingAnnotation } from "./voiceAddressing.ts";

describe("normalizeVoiceAddressingAnnotation", () => { test("normalizes canonical targets, clamps confidence, and cleans metadata", () => { const result = normalizeVoiceAddressingAnnotation({ rawAddressing: { talkingTo: " everyone ", directedConfidence: 1.8 }, source: "Model Output", reason: " asked the whole room " });

assert.deepEqual(result, {
  talkingTo: "ALL",
  directedConfidence: 1,
  source: "model_output",
  reason: "asked the whole room"
});

});

test("infers ME and floors confidence when the turn was directly addressed", () => { const result = normalizeVoiceAddressingAnnotation({ rawAddressing: {}, directAddressed: true, directedConfidence: 0.1 });

assert.deepEqual(result, {
  talkingTo: "ME",
  directedConfidence: 0.72,
  source: null,
  reason: null
});

});

test("returns null when neither a target nor confidence is present", () => { const result = normalizeVoiceAddressingAnnotation({ rawAddressing: { talkingTo: " " } });

assert.equal(result, null);

}); });

describe("mergeVoiceAddressingAnnotation", () => { test("returns the incoming annotation when there is no current state", () => { const incoming = { talkingTo: "ME", directedConfidence: 0.8, source: "generation", reason: "clear vocative" };

assert.deepEqual(mergeVoiceAddressingAnnotation(null, incoming), incoming);

});

test("keeps the current annotation when the incoming signal is only marginally stronger", () => { const current = { talkingTo: "ALL", directedConfidence: 0.6, source: "classifier", reason: "broad address" }; const incoming = { talkingTo: "ME", directedConfidence: 0.61, source: "heuristic", reason: "weak cue" };

assert.deepEqual(mergeVoiceAddressingAnnotation(current, incoming), current);

});

test("lets generation replace the current target within the confidence slack window", () => { const current = { talkingTo: "ALL", directedConfidence: 0.6, source: "classifier", reason: "broad address" }; const incoming = { talkingTo: "ME", directedConfidence: 0.56, source: "generation", reason: "named the bot" };

assert.deepEqual(mergeVoiceAddressingAnnotation(current, incoming), {
  talkingTo: "ME",
  directedConfidence: 0.56,
  source: "generation",
  reason: "named the bot"
});

}); });

describe("findLatestVoiceTurnIndex", () => { test("matches the latest turn by normalized text, role, and user id", () => { const turns = [ null, { role: "assistant", userId: null, speakerName: "bot", text: "hello there", at: 1 }, { role: "user", userId: "u1", speakerName: "alice", text: "hello world", at: 2 }, { role: "user", userId: "u1", speakerName: "alice", text: "hello world", at: 3 } ];

const index = findLatestVoiceTurnIndex(turns, {
  role: "user",
  userId: "u1",
  text: "  hello world  "
});

assert.equal(index, 3);

});

test("returns the latest matching turn when text is omitted", () => { const turns = [ { role: "user", userId: "u1", speakerName: "alice", text: "first", at: 1 }, { role: "user", userId: "u2", speakerName: "bob", text: "second", at: 2 }, { role: "user", userId: "u1", speakerName: "alice", text: "third", at: 3 } ];

const index = findLatestVoiceTurnIndex(turns, {
  role: "user",
  userId: "u1"
});

assert.equal(index, 2);

}); });

describe("annotateLatestVoiceTurnAddressing", () => { test("annotates only the latest matching turns in both model and transcript histories", () => { const session = { recentVoiceTurns: [ { role: "user" as const, userId: "u1", speakerName: "alice", text: "hey bot", at: 1 }, { role: "user" as const, userId: "u2", speakerName: "bob", text: "different", at: 2 }, { role: "user" as const, userId: "u1", speakerName: "alice", text: "hey bot", at: 3 } ], transcriptTurns: [ { role: "user" as const, userId: "u1", speakerName: "alice", text: "hey bot", at: 10 }, { role: "assistant" as const, userId: null, speakerName: "bot", text: "yo", at: 11 }, { role: "user" as const, userId: "u1", speakerName: "alice", text: "hey bot", at: 12 } ] };

const annotated = annotateLatestVoiceTurnAddressing({
  session,
  role: "user",
  userId: "u1",
  text: "hey bot",
  addressing: {
    talkingTo: "ME",
    directedConfidence: 0.85,
    source: "generation"
  }
});

assert.equal(annotated, true);
assert.equal(session.recentVoiceTurns[0]?.addressing, undefined);
assert.deepEqual(session.recentVoiceTurns[2]?.addressing, {
  talkingTo: "ME",
  directedConfidence: 0.85,
  source: null,
  reason: null
});
assert.equal(session.transcriptTurns[0]?.addressing, undefined);
assert.deepEqual(session.transcriptTurns[2]?.addressing, {
  talkingTo: "ME",
  directedConfidence: 0.85,
  source: null,
  reason: null
});

});

test("returns false when it cannot find a matching turn to annotate", () => { const session = { recentVoiceTurns: [], transcriptTurns: [] };

const annotated = annotateLatestVoiceTurnAddressing({
  session,
  role: "user",
  userId: "u1",
  text: "missing",
  addressing: {
    talkingTo: "ME",
    directedConfidence: 0.9
  }
});

assert.equal(annotated, false);

}); });

describe("buildVoiceAddressingState", () => { test("builds the current speaker target, last direct address, and recent guesses", () => { const state = buildVoiceAddressingState({ userId: "u1", now: 2201, maxItems: 2, session: { transcriptTurns: [ { role: "assistant", userId: null, speakerName: "bot", text: "reply", at: 1000, addressing: { talkingTo: "OTHER", directedConfidence: 0.4, source: "classifier", reason: null } }, { role: "user", userId: "u2", speakerName: "Bob", text: "hi", at: 1200, addressing: { talkingTo: "ME", directedConfidence: 0.25, source: "classifier", reason: null } }, { role: "user", userId: "u1", speakerName: "Alice", text: "first", at: 1500, addressing: { talkingTo: "everyone", directedConfidence: 0.8, source: "classifier", reason: null } }, { role: "user", userId: "u1", speakerName: "Alice", text: "second", at: 1700, addressing: { talkingTo: "ME", directedConfidence: 0.3333 } }, { role: "user", userId: "u3", speakerName: " ", text: "third", at: 0, addressing: { talkingTo: "friend", directedConfidence: 2 } } ] } });

assert.deepEqual(state, {
  currentSpeakerTarget: "ME",
  currentSpeakerDirectedConfidence: 0.333,
  lastDirectedToMe: {
    speakerName: "Alice",
    directedConfidence: 0.333,
    ageMs: 501
  },
  recentAddressingGuesses: [
    {
      speakerName: "Alice",
      talkingTo: "ME",
      directedConfidence: 0.333,
      ageMs: 501
    },
    {
      speakerName: "someone",
      talkingTo: "friend",
      directedConfidence: 1,
      ageMs: null
    }
  ]
});

});

test("returns null when there are no transcript annotations to summarize", () => { const state = buildVoiceAddressingState({ session: { transcriptTurns: [ { role: "user", userId: "u1", speakerName: "alice", text: "hello", at: 1 } ] } });

assert.equal(state, null);

}); });