|
|
@@ -316,7 +316,7 @@ def test_chat_capture_off_still_allows_typed_turns_and_triage():
|
|
|
|
|
|
assert service.submit_chat_text("typed") is True
|
|
|
assert service.chat_history == ["typed"]
|
|
|
- assert service.triage_history == ["spoken"]
|
|
|
+ assert service.triage_history == ["Unknown: spoken"]
|
|
|
|
|
|
|
|
|
def test_set_chat_capture_emits_once_and_reports_status():
|
|
|
@@ -782,6 +782,9 @@ class FakeTriage:
|
|
|
def is_regression(self, prior_brief, new_brief):
|
|
|
return _real_analyzer.is_regression(prior_brief, new_brief)
|
|
|
|
|
|
+ def should_escalate(self, signals):
|
|
|
+ return _real_analyzer.should_escalate(signals)
|
|
|
+
|
|
|
def parse_facts(self, block):
|
|
|
return _real_analyzer.parse_facts(block)
|
|
|
|
|
|
@@ -790,8 +793,10 @@ class FakeTriage:
|
|
|
return text if text else None
|
|
|
return self._parsed
|
|
|
|
|
|
- def should_update_brief(self, signals):
|
|
|
+ def should_update_brief(self, signals, prior=None):
|
|
|
self.gate_calls.append(signals)
|
|
|
+ if self._gate is _AUTO:
|
|
|
+ return _real_analyzer.should_update_brief(signals, prior)
|
|
|
return self._gate
|
|
|
|
|
|
|
|
|
@@ -1017,12 +1022,12 @@ def test_maybe_triage_runs_in_idle_mode():
|
|
|
|
|
|
assert len(lane.submits) == 1
|
|
|
state, questions, lang, gen = lane.submits[0]
|
|
|
- assert state == "- hello"
|
|
|
+ assert state == "- Unknown: hello"
|
|
|
assert questions is triage.questions
|
|
|
assert lang is None
|
|
|
assert gen == 0
|
|
|
- assert triage.build_state_calls == [("hello",)]
|
|
|
- assert service.triage_history == ["hello"]
|
|
|
+ assert triage.build_state_calls == [("Unknown: hello",)]
|
|
|
+ assert service.triage_history == ["Unknown: hello"]
|
|
|
|
|
|
|
|
|
def test_maybe_triage_uses_transcript_buffer_not_chat_history():
|
|
|
@@ -1039,7 +1044,7 @@ def test_maybe_triage_uses_transcript_buffer_not_chat_history():
|
|
|
service.tick()
|
|
|
|
|
|
assert len(lane.submits) == 1
|
|
|
- assert triage.build_state_calls == [("hello",)]
|
|
|
+ assert triage.build_state_calls == [("Unknown: hello",)]
|
|
|
|
|
|
|
|
|
def test_maybe_triage_requires_settled_turn():
|
|
|
@@ -1061,7 +1066,7 @@ def test_maybe_triage_periodic_fires_before_turn_settles():
|
|
|
|
|
|
assert service.turn_ended() is False
|
|
|
assert len(lane.submits) == 1
|
|
|
- assert lane.submits[0][0] == "- hello"
|
|
|
+ assert lane.submits[0][0] == "- Unknown: hello"
|
|
|
|
|
|
|
|
|
def test_maybe_triage_periodic_disabled_ignores_accumulating_speech():
|
|
|
@@ -1092,7 +1097,7 @@ def test_maybe_triage_periodic_rearms_after_submit():
|
|
|
clock.advance(0.25)
|
|
|
service.tick()
|
|
|
assert len(lane.submits) == 2
|
|
|
- assert lane.submits[1][0] == "- first\n- second"
|
|
|
+ assert lane.submits[1][0] == "- Unknown: first\n- Unknown: second"
|
|
|
|
|
|
|
|
|
def test_triage_debug_emits_submit_and_result():
|
|
|
@@ -1191,7 +1196,7 @@ def test_maybe_triage_dedupes_identical_window():
|
|
|
|
|
|
assert len(lane.submits) == 1
|
|
|
state, questions, lang, gen = lane.submits[0]
|
|
|
- assert state == "- hello"
|
|
|
+ assert state == "- Unknown: hello"
|
|
|
assert questions is triage.questions
|
|
|
assert lang is None
|
|
|
assert gen == 0
|
|
|
@@ -1204,7 +1209,7 @@ def test_maybe_triage_dedupes_identical_window():
|
|
|
clock.advance(service.cfg.assistant.turn_gap_s + 0.1)
|
|
|
service.tick()
|
|
|
assert len(lane.submits) == 2
|
|
|
- assert lane.submits[1][0] == "- hello\n- second"
|
|
|
+ assert lane.submits[1][0] == "- Unknown: hello\n- Unknown: second"
|
|
|
|
|
|
|
|
|
def test_second_transcript_produces_second_submit():
|
|
|
@@ -1219,7 +1224,7 @@ def test_second_transcript_produces_second_submit():
|
|
|
service.tick()
|
|
|
|
|
|
assert len(lane.submits) == 2
|
|
|
- assert lane.submits[1][0] == "- first\n- second"
|
|
|
+ assert lane.submits[1][0] == "- Unknown: first\n- Unknown: second"
|
|
|
|
|
|
|
|
|
def test_tick_under_50ms_with_blocked_lane():
|
|
|
@@ -1319,7 +1324,7 @@ def test_pending_brief_capped_by_char_budget():
|
|
|
service.handle_event(_transcript(clock, "ccccc"))
|
|
|
|
|
|
assert service._pending_brief == ["Unknown: bbbb", "Unknown: ccccc"]
|
|
|
- assert service.triage_history == ["aaa", "bbbb", "ccccc"]
|
|
|
+ assert service.triage_history == ["Unknown: aaa", "Unknown: bbbb", "Unknown: ccccc"]
|
|
|
|
|
|
|
|
|
def test_pending_brief_untouched_without_triage():
|
|
|
@@ -1327,7 +1332,7 @@ def test_pending_brief_untouched_without_triage():
|
|
|
service.handle_event(_transcript(clock, "hello"))
|
|
|
|
|
|
assert service._pending_brief == []
|
|
|
- assert service.triage_history == ["hello"]
|
|
|
+ assert service.triage_history == ["Unknown: hello"]
|
|
|
|
|
|
|
|
|
def test_on_triage_result_accepts_non_chat_mode():
|
|
|
@@ -2057,8 +2062,8 @@ def test_exit_chat_does_not_reset_triage():
|
|
|
assert service.modes.mode.value == "idle"
|
|
|
assert service._triage_generation == 0
|
|
|
assert service.last_triage is not None
|
|
|
- assert service._last_triage_window == ("hello",)
|
|
|
- assert service.triage_history == ["hello"]
|
|
|
+ assert service._last_triage_window == ("Unknown: hello",)
|
|
|
+ assert service.triage_history == ["Unknown: hello"]
|
|
|
assert service._pending_brief == ["Unknown: hello"]
|
|
|
assert service._last_brief_signals is not None
|
|
|
assert service._brief_outstanding is True
|
|
|
@@ -2092,8 +2097,8 @@ def test_toggle_chat_enter_does_not_touch_triage():
|
|
|
assert service.modes.mode.value == "chat"
|
|
|
assert service._triage_generation == 0
|
|
|
assert service.last_triage is triage_before
|
|
|
- assert service._last_triage_window == ("hello",)
|
|
|
- assert service.triage_history == ["hello"]
|
|
|
+ assert service._last_triage_window == ("Unknown: hello",)
|
|
|
+ assert service.triage_history == ["Unknown: hello"]
|
|
|
assert service._pending_brief == pending_before
|
|
|
assert service._last_brief_signals is not None
|
|
|
assert service._brief_outstanding is True
|
|
|
@@ -2247,7 +2252,7 @@ def test_triage_end_to_end_signals_content_cleared():
|
|
|
clock.advance(service.cfg.assistant.turn_gap_s + 0.1)
|
|
|
service.tick()
|
|
|
assert len(lane.submits) == 3
|
|
|
- assert lane.submits[2][0].endswith("- idle thought")
|
|
|
+ assert lane.submits[2][0].endswith("- Unknown: idle thought")
|
|
|
|
|
|
|
|
|
def test_tick_emits_status_on_triage_state_change():
|
|
|
@@ -2428,7 +2433,7 @@ def test_dump_writes_full_laya_and_llm_io(tmp_path):
|
|
|
data = json.loads(files[0].read_text(encoding="utf-8"))
|
|
|
assert data["ts"] == clock()
|
|
|
assert isinstance(data["iso"], str) and data["iso"]
|
|
|
- assert data["laya"]["request"]["state"] == "- hello"
|
|
|
+ assert data["laya"]["request"]["state"] == "- Unknown: hello"
|
|
|
assert data["laya"]["request"]["questions"] == triage.questions
|
|
|
assert data["laya"]["request"]["model"] == "multilingual"
|
|
|
assert data["laya"]["request"]["max_len"] == 1024
|
|
|
@@ -2742,7 +2747,7 @@ def test_live_transcript_session_sets_session_without_wiping_utterance():
|
|
|
|
|
|
assert service.status()["session_dir"] == session
|
|
|
assert brief_file.directories == [session]
|
|
|
- assert service.triage_history == ["hello"]
|
|
|
+ assert service.triage_history == ["Unknown: hello"]
|
|
|
assert service._pending_brief == ["Unknown: hello"]
|
|
|
assert service._triage_generation == 0
|
|
|
|
|
|
@@ -2835,7 +2840,7 @@ def test_replay_single_session_adopts_without_reset():
|
|
|
assert brief_file.directories == [session]
|
|
|
assert service._triage_generation == 0
|
|
|
assert _cleared(emitted) == []
|
|
|
- assert service.triage_history == ["hello"]
|
|
|
+ assert service.triage_history == ["Unknown: hello"]
|
|
|
|
|
|
|
|
|
def test_replay_two_sessions_commits_newest_and_resets_once():
|
|
|
@@ -2961,3 +2966,59 @@ def test_daemon_restart_new_session_resets_once():
|
|
|
assert service._triage_generation == 1
|
|
|
assert service.last_triage is None
|
|
|
assert brief_file.directories == ["transcripts/a", "transcripts/b"]
|
|
|
+
|
|
|
+
|
|
|
+def _dwell_service(confirm):
|
|
|
+ service, emitted, clock, _, lane = _triage_service(
|
|
|
+ triage=FakeTriage(questions={"blocker": {"type": "noul", "instructions": "x"}})
|
|
|
+ )
|
|
|
+ service.cfg.triage.confirm_windows = confirm
|
|
|
+ return service, emitted, clock, lane
|
|
|
+
|
|
|
+
|
|
|
+def _blocker_payload(p):
|
|
|
+ return {
|
|
|
+ "order": ["blocker"],
|
|
|
+ "items": {
|
|
|
+ "blocker": {
|
|
|
+ "kind": "noul",
|
|
|
+ "p": p,
|
|
|
+ "threshold": 0.5,
|
|
|
+ "flagged": p >= 0.5,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ "escalated": p >= 0.5,
|
|
|
+ "input_tokens": 0,
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+def test_dwell_holds_a_single_window_spike_back():
|
|
|
+ service, emitted, _, _ = _dwell_service(2)
|
|
|
+ service._on_triage_result(0, _blocker_payload(0.95))
|
|
|
+ assert service.last_triage["items"]["blocker"]["flagged"] is False
|
|
|
+ service._on_triage_result(0, _blocker_payload(0.95))
|
|
|
+ assert service.last_triage["items"]["blocker"]["flagged"] is True
|
|
|
+
|
|
|
+
|
|
|
+def test_dwell_resets_when_the_signal_drops():
|
|
|
+ service, _, _, _ = _dwell_service(2)
|
|
|
+ service._on_triage_result(0, _blocker_payload(0.95))
|
|
|
+ service._on_triage_result(0, _blocker_payload(0.10))
|
|
|
+ service._on_triage_result(0, _blocker_payload(0.95))
|
|
|
+ assert service.last_triage["items"]["blocker"]["flagged"] is False
|
|
|
+ service._on_triage_result(0, _blocker_payload(0.95))
|
|
|
+ assert service.last_triage["items"]["blocker"]["flagged"] is True
|
|
|
+
|
|
|
+
|
|
|
+def test_dwell_disabled_with_one_confirm_window():
|
|
|
+ service, _, _, _ = _dwell_service(1)
|
|
|
+ service._on_triage_result(0, _blocker_payload(0.95))
|
|
|
+ assert service.last_triage["items"]["blocker"]["flagged"] is True
|
|
|
+
|
|
|
+
|
|
|
+def test_clear_resets_dwell_streaks():
|
|
|
+ service, _, _, _ = _dwell_service(2)
|
|
|
+ service._on_triage_result(0, _blocker_payload(0.95))
|
|
|
+ assert service._signal_streaks["blocker"] == 1
|
|
|
+ service.clear()
|
|
|
+ assert service._signal_streaks == {}
|