personal memory agent
0
fork

Configure Feed

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

Merge branch 'hopper-qaby3e2f-entity-brief-flag'

+69 -2
+4 -1
apps/entities/call.py
··· 522 522 def entity_intel( 523 523 entity: str = typer.Argument(help="Entity name or identifier."), 524 524 facet: str | None = typer.Option(None, "--facet", "-f", help="Filter by facet."), 525 + brief: bool = typer.Option( 526 + False, "--brief", "-b", help="Truncate activity and network to 20 items." 527 + ), 525 528 ) -> None: 526 529 """Get a full intelligence briefing for an entity.""" 527 530 import json as _json 528 531 529 - result = get_entity_intelligence(entity, facet=facet) 532 + result = get_entity_intelligence(entity, facet=facet, brief=brief) 530 533 if result is None: 531 534 typer.echo(f"Error: Entity '{entity}' not found.", err=True) 532 535 raise typer.Exit(1)
+47
tests/test_entity_intelligence.py
··· 149 149 result = get_entity_intelligence("Bob Smith") 150 150 assert result is not None 151 151 assert result["identity"]["entity_id"] == "bob_smith" 152 + 153 + 154 + class TestEntityIntelligenceBrief: 155 + def test_brief_has_meta(self): 156 + result = get_entity_intelligence("Alice Johnson", brief=True) 157 + assert result is not None 158 + assert "_meta" in result 159 + assert result["_meta"]["brief"] is True 160 + 161 + def test_brief_has_all_sections(self): 162 + result = get_entity_intelligence("Alice Johnson", brief=True) 163 + for section in ( 164 + "identity", 165 + "relationships", 166 + "observations", 167 + "activity", 168 + "strength", 169 + "network", 170 + "facets", 171 + ): 172 + assert section in result 173 + 174 + def test_brief_truncates_activity(self): 175 + result = get_entity_intelligence("Alice Johnson", brief=True) 176 + assert len(result["activity"]) <= 20 177 + assert result["_meta"]["activity_included"] == len(result["activity"]) 178 + 179 + def test_brief_truncates_network(self): 180 + result = get_entity_intelligence("Alice Johnson", brief=True) 181 + assert len(result["network"]) <= 20 182 + assert result["_meta"]["network_included"] == len(result["network"]) 183 + 184 + def test_brief_meta_counts_consistent(self): 185 + result = get_entity_intelligence("Alice Johnson", brief=True) 186 + meta = result["_meta"] 187 + assert meta["activity_included"] <= meta["activity_total"] 188 + assert meta["network_included"] <= meta["network_total"] 189 + 190 + def test_brief_preserves_other_sections(self): 191 + full = get_entity_intelligence("Alice Johnson") 192 + brief = get_entity_intelligence("Alice Johnson", brief=True) 193 + for key in ("identity", "relationships", "observations", "strength", "facets"): 194 + assert full[key] == brief[key] 195 + 196 + def test_default_no_meta(self): 197 + result = get_entity_intelligence("Alice Johnson") 198 + assert "_meta" not in result
+18 -1
think/indexer/journal.py
··· 2705 2705 def get_entity_intelligence( 2706 2706 entity: str, 2707 2707 facet: str | None = None, 2708 + brief: bool = False, 2708 2709 ) -> dict[str, Any] | None: 2709 2710 """Get a full intelligence briefing for an entity.""" 2710 2711 conn, _ = get_journal_index() ··· 2938 2939 "photo_count": photo_count, 2939 2940 } 2940 2941 2941 - return { 2942 + if brief: 2943 + activity_total = len(activity) 2944 + network_total = len(network) 2945 + activity = activity[:20] 2946 + network = dict(list(network.items())[:20]) 2947 + meta = { 2948 + "brief": True, 2949 + "activity_total": activity_total, 2950 + "activity_included": len(activity), 2951 + "network_total": network_total, 2952 + "network_included": len(network), 2953 + } 2954 + 2955 + result = { 2942 2956 "identity": identity, 2943 2957 "relationships": relationships, 2944 2958 "observations": observations, ··· 2947 2961 "network": network, 2948 2962 "facets": all_facets, 2949 2963 } 2964 + if brief: 2965 + result["_meta"] = meta 2966 + return result 2950 2967 finally: 2951 2968 conn.close()