|
@@ -518,7 +518,9 @@ class FakeTriage:
|
|
|
return signals
|
|
return signals
|
|
|
|
|
|
|
|
def build_extraction_prompt(self, window, signals):
|
|
def build_extraction_prompt(self, window, signals):
|
|
|
- self.prompt_calls.append((tuple(window), dict(signals)))
|
|
|
|
|
|
|
+ self.prompt_calls.append(
|
|
|
|
|
+ (tuple(window), dict(signals) if isinstance(signals, dict) else signals)
|
|
|
|
|
+ )
|
|
|
return "EXTRACT"
|
|
return "EXTRACT"
|
|
|
|
|
|
|
|
def parse_extraction(self, text):
|
|
def parse_extraction(self, text):
|
|
@@ -832,6 +834,46 @@ def test_on_triage_result_ignores_none_payload():
|
|
|
assert _triage_events(emitted) == []
|
|
assert _triage_events(emitted) == []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+def test_none_payload_enqueues_state_only_extract():
|
|
|
|
|
+ service, emitted, clock, triage, lane = _triage_service(
|
|
|
|
|
+ extract_fn=lambda prompt: "RAW"
|
|
|
|
|
+ )
|
|
|
|
|
+ service.toggle_chat()
|
|
|
|
|
+ service.handle_event(_transcript(clock, "hello"))
|
|
|
|
|
+ clock.advance(service.cfg.assistant.turn_gap_s + 0.1)
|
|
|
|
|
+ service.tick()
|
|
|
|
|
+ _, _, _, gen = lane.submits[0]
|
|
|
|
|
+
|
|
|
|
|
+ service._on_triage_result(gen, None)
|
|
|
|
|
+
|
|
|
|
|
+ assert service.last_triage is None
|
|
|
|
|
+ assert [e.get("stage") for e in _triage_events(emitted)] == []
|
|
|
|
|
+ assert [j.name for j in service._inference._queue] == ["chat", "triage-extract"]
|
|
|
|
|
+ job = [j for j in service._inference._queue if j.name == "triage-extract"][0]
|
|
|
|
|
+ job.run()
|
|
|
|
|
+
|
|
|
|
|
+ contents = [e for e in _triage_events(emitted) if e.get("stage") == "content"]
|
|
|
|
|
+ assert len(contents) == 1
|
|
|
|
|
+ assert contents[0]["triage"] == {"content": triage.parse_extraction("RAW")}
|
|
|
|
|
+ assert service.last_triage == contents[0]["triage"]
|
|
|
|
|
+ assert triage.prompt_calls == [(service._last_triage_window, None)]
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def test_none_payload_without_extract_fn_enqueues_nothing():
|
|
|
|
|
+ service, emitted, clock, _, lane = _triage_service()
|
|
|
|
|
+ service.toggle_chat()
|
|
|
|
|
+ service.handle_event(_transcript(clock, "hello"))
|
|
|
|
|
+ clock.advance(service.cfg.assistant.turn_gap_s + 0.1)
|
|
|
|
|
+ service.tick()
|
|
|
|
|
+ _, _, _, gen = lane.submits[0]
|
|
|
|
|
+
|
|
|
|
|
+ service._on_triage_result(gen, None)
|
|
|
|
|
+
|
|
|
|
|
+ assert service.last_triage is None
|
|
|
|
|
+ assert _triage_events(emitted) == []
|
|
|
|
|
+ assert [j.name for j in service._inference._queue] == ["chat"]
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
def test_on_triage_result_ignores_empty_signals():
|
|
def test_on_triage_result_ignores_empty_signals():
|
|
|
service, emitted, clock, _, lane = _triage_service(
|
|
service, emitted, clock, _, lane = _triage_service(
|
|
|
triage=FakeTriage(normalized={})
|
|
triage=FakeTriage(normalized={})
|
|
@@ -869,7 +911,7 @@ def test_escalation_enqueues_extract_job():
|
|
|
assert [e.get("stage") for e in _triage_events(emitted)] == ["signals"]
|
|
assert [e.get("stage") for e in _triage_events(emitted)] == ["signals"]
|
|
|
|
|
|
|
|
|
|
|
|
|
-def test_no_extract_without_escalation():
|
|
|
|
|
|
|
+def test_extract_runs_without_escalation():
|
|
|
service, _, clock, _, lane = _triage_service(extract_fn=lambda prompt: "RAW")
|
|
service, _, clock, _, lane = _triage_service(extract_fn=lambda prompt: "RAW")
|
|
|
service.toggle_chat()
|
|
service.toggle_chat()
|
|
|
service.handle_event(_transcript(clock, "all calm"))
|
|
service.handle_event(_transcript(clock, "all calm"))
|
|
@@ -882,8 +924,8 @@ def test_no_extract_without_escalation():
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
assert service.last_triage is not None
|
|
assert service.last_triage is not None
|
|
|
- assert service._inference.depth() == 1
|
|
|
|
|
- assert [j.name for j in service._inference._queue] == ["chat"]
|
|
|
|
|
|
|
+ assert service._inference.depth() == 2
|
|
|
|
|
+ assert [j.name for j in service._inference._queue] == ["chat", "triage-extract"]
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_no_extract_when_disabled_in_config():
|
|
def test_no_extract_when_disabled_in_config():
|
|
@@ -1093,7 +1135,7 @@ def test_triage_end_to_end_signals_content_cleared():
|
|
|
assert prompts == []
|
|
assert prompts == []
|
|
|
assert service.last_triage is not None
|
|
assert service.last_triage is not None
|
|
|
assert service.last_triage["escalated"] is False
|
|
assert service.last_triage["escalated"] is False
|
|
|
- assert [j.name for j in service._inference._queue] == ["chat"]
|
|
|
|
|
|
|
+ assert [j.name for j in service._inference._queue] == ["chat", "triage-extract"]
|
|
|
|
|
|
|
|
triage._escalate = True
|
|
triage._escalate = True
|
|
|
service.handle_event(_transcript(clock, "we might churn"))
|
|
service.handle_event(_transcript(clock, "we might churn"))
|
|
@@ -1106,19 +1148,21 @@ def test_triage_end_to_end_signals_content_cleared():
|
|
|
assert [e.get("stage") for e in _triage_events(emitted)] == ["signals", "signals"]
|
|
assert [e.get("stage") for e in _triage_events(emitted)] == ["signals", "signals"]
|
|
|
assert [j.name for j in service._inference._queue] == [
|
|
assert [j.name for j in service._inference._queue] == [
|
|
|
"chat",
|
|
"chat",
|
|
|
|
|
+ "triage-extract",
|
|
|
"chat",
|
|
"chat",
|
|
|
"triage-extract",
|
|
"triage-extract",
|
|
|
]
|
|
]
|
|
|
- job = [j for j in service._inference._queue if j.name == "triage-extract"][0]
|
|
|
|
|
- job.run()
|
|
|
|
|
|
|
+ for job in [j for j in service._inference._queue if j.name == "triage-extract"]:
|
|
|
|
|
+ job.run()
|
|
|
|
|
|
|
|
contents = [e for e in _triage_events(emitted) if e.get("stage") == "content"]
|
|
contents = [e for e in _triage_events(emitted) if e.get("stage") == "content"]
|
|
|
- assert len(contents) == 1
|
|
|
|
|
- assert len(prompts) == 1
|
|
|
|
|
- assert contents[0]["triage"]["escalated"] is True
|
|
|
|
|
- assert contents[0]["triage"]["content"] == triage.parse_extraction("x")
|
|
|
|
|
- assert service.last_triage == contents[0]["triage"]
|
|
|
|
|
- assert service.status()["triage"] == contents[0]["triage"]
|
|
|
|
|
|
|
+ assert len(contents) == 2
|
|
|
|
|
+ assert len(prompts) == 2
|
|
|
|
|
+ assert contents[0]["triage"]["escalated"] is False
|
|
|
|
|
+ assert contents[1]["triage"]["escalated"] is True
|
|
|
|
|
+ assert contents[1]["triage"]["content"] == triage.parse_extraction("x")
|
|
|
|
|
+ assert service.last_triage == contents[1]["triage"]
|
|
|
|
|
+ assert service.status()["triage"] == contents[1]["triage"]
|
|
|
|
|
|
|
|
service.clear()
|
|
service.clear()
|
|
|
|
|
|
|
@@ -1131,6 +1175,7 @@ def test_triage_end_to_end_signals_content_cleared():
|
|
|
"signals",
|
|
"signals",
|
|
|
"signals",
|
|
"signals",
|
|
|
"content",
|
|
"content",
|
|
|
|
|
+ "content",
|
|
|
"cleared",
|
|
"cleared",
|
|
|
]
|
|
]
|
|
|
|
|
|