personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: migrate speaker_attribution pre-hook to template_vars

Return Layer 4 unmatched speaker context through template_vars instead of rewriting the transcript in the pre hook.

Update the speaker attribution prompt to render unmatched_context inline and add coverage for the Layer 4 pre_process path.

+57 -4
+3 -1
talent/speaker_attribution.md
··· 14 14 15 15 $segment_preamble 16 16 17 + $unmatched_context 18 + 17 19 # Speaker Attribution — Contextual Identification (Layer 4) 18 20 19 21 ## Context ··· 23 25 - **Layer 2** used structural heuristics (speaker count, meeting metadata) to label non-owner sentences 24 26 - **Layer 3** matched remaining sentences against known voiceprints 25 27 26 - The sentences listed above under "Unmatched sentences" could not be resolved by these methods. Your task is to identify the speaker for each unmatched sentence using contextual clues from the transcript. 28 + The unmatched sentences shown above could not be resolved by these methods. Your task is to identify the speaker for each unmatched sentence using contextual clues from the transcript. 27 29 28 30 ## Identification Strategies 29 31
+2 -3
talent/speaker_attribution.py
··· 116 116 lines.append(f'- Sentence {sid}: "{text}"') 117 117 lines.append("") 118 118 119 - original_transcript = context.get("transcript", "") 120 - modified_transcript = "\n".join(lines) + "\n" + original_transcript 119 + unmatched_block = "\n".join(lines) 121 120 122 - return {"meta": meta, "transcript": modified_transcript} 121 + return {"meta": meta, "template_vars": {"unmatched_context": unmatched_block}} 123 122 124 123 125 124 def post_process(result: str, context: dict) -> str | None:
+52
tests/test_speaker_attribution_hook.py
··· 88 88 stub_path = tmp_path / "agents" / "speaker_labels.json" 89 89 assert not stub_path.exists() 90 90 assert result == {"skip_reason": "no_segment_context"} 91 + 92 + def test_layer4_returns_template_vars(self): 93 + """Unmatched sentences return template vars without changing transcript.""" 94 + result = _run_pre_process( 95 + { 96 + **CONTEXT, 97 + "transcript": "some transcript", 98 + "meta": {}, 99 + }, 100 + None, 101 + { 102 + "labels": [ 103 + { 104 + "sentence_id": 0, 105 + "speaker": "owner", 106 + "confidence": "high", 107 + "method": "embedding", 108 + }, 109 + { 110 + "sentence_id": 1, 111 + "speaker": None, 112 + "confidence": None, 113 + "method": None, 114 + }, 115 + { 116 + "sentence_id": 2, 117 + "speaker": None, 118 + "confidence": None, 119 + "method": None, 120 + }, 121 + ], 122 + "unmatched": [1, 2], 123 + "unmatched_texts": {1: "Hello everyone", 2: "Let me explain"}, 124 + "candidates": ["Alice Johnson", "Bob Smith"], 125 + "metadata": {"total": 3, "resolved": 1}, 126 + "source": "audio", 127 + }, 128 + ) 129 + 130 + assert "meta" in result 131 + assert "attribution_result" in result["meta"] 132 + assert "template_vars" in result 133 + assert "unmatched_context" in result["template_vars"] 134 + assert "transcript" not in result 135 + 136 + unmatched_context = result["template_vars"]["unmatched_context"] 137 + assert "Alice Johnson" in unmatched_context 138 + assert "Bob Smith" in unmatched_context 139 + assert "Hello everyone" in unmatched_context 140 + assert "Let me explain" in unmatched_context 141 + assert "Sentence 1" in unmatched_context 142 + assert "Sentence 2" in unmatched_context