From 73f466f89971ef5f15ecc195c135efc22922d407 Mon Sep 17 00:00:00 2001 From: twentyOne2x Date: Mon, 13 Jul 2026 20:07:51 +0200 Subject: [PATCH] Make broad Leo replies deterministic (#121) --- hermes-agent/leoclean-bin/kb_tool.py | 57 +++++++++++++++++-- .../vps/leo-db-context/__init__.py | 1 + .../test_hermes_leoclean_kb_bridge_source.py | 9 +++ ...st_working_leo_m3taversal_oos_benchmark.py | 1 + 4 files changed, 63 insertions(+), 5 deletions(-) diff --git a/hermes-agent/leoclean-bin/kb_tool.py b/hermes-agent/leoclean-bin/kb_tool.py index 8827f0c..ce0c933 100755 --- a/hermes-agent/leoclean-bin/kb_tool.py +++ b/hermes-agent/leoclean-bin/kb_tool.py @@ -456,6 +456,18 @@ def operational_contracts( identity_question = any(term in lowered for term in ("soul.md", "soul file")) and any( term in lowered for term in ("canonical identity", "canonical", "identity", "source of truth", "database") ) + visible_sender_match = re.search( + r"(?:current visible telegram sender|visible telegram sender|current telegram sender)\s+is\s+@?([a-z0-9_]+)", + query, + re.I, + ) + participant_identity_question = bool( + visible_sender_match + and any( + term in lowered + for term in ("call this participant", "identity sources", "mixing identities", "mix identities") + ) + ) primary_direct_intent = next( ( intent @@ -585,6 +597,27 @@ def operational_contracts( } ) + if participant_identity_question and visible_sender_match: + contracts.append( + { + "id": "telegram_participant_identity", + "current_visible_handle": visible_sender_match.group(1), + "allowed_sources": [ + "the current message sender handle", + "that participant's explicit in-chat correction", + ], + "disallowed_sources": [ + "stale session context", + "environment labels", + "inferred personal names", + "another participant's profile or messages", + ], + "cross_participant_boundary": ( + "re-anchor every reply to that message's visible sender; never transfer or mix identities" + ), + } + ) + mixed_markers = ( "packet", "factual observation", @@ -782,6 +815,19 @@ def compile_operational_response(contracts: list[dict[str, Any]]) -> str | None: """Compile a safe response when a model draft violates live DB contracts.""" by_id = {str(contract.get("id") or ""): contract for contract in contracts} + participant = by_id.get("telegram_participant_identity") + if participant: + handle = str(participant.get("current_visible_handle") or "").lstrip("@") + return ( + f"Call the current Telegram sender {handle}, exactly as their visible handle identifies them.\n" + "Allowed identity sources: the current message sender handle and that participant's explicit in-chat " + "correction.\n" + "Do not use stale session context, environment labels, inferred personal names, or another " + "participant's profile.\n" + "When another user replies, never transfer or mix identities; re-anchor to that message's visible " + "sender handle." + ) + mixed = by_id.get("mixed_packet_composition") if mixed: mapping = mixed.get("map") or {} @@ -953,13 +999,14 @@ def compile_operational_response(contracts: list[dict[str, Any]]) -> str | None: return ( f"Not proven.\nFresh live readback.\n{format_database_count_readback(status_data)}\nProposal states are " f"applied: {states.get('applied', 0)}, approved: {states.get('approved', 0)}, pending_review: " - f"{states.get('pending_review', 0)}. This current snapshot does not establish what changed since " - f"yesterday. Existing receipts identify applied types {applied_types or 'none'}, but not a time-window " - f"delta. Approved is not applied; {approved_needs_payload}/{len(approved_rows)} approved rows are " + f"{states.get('pending_review', 0)}. This current snapshot does not prove what changed since " + f"yesterday, so the demo claim is limited to current readback. Existing receipt artifacts identify " + f"applied types {applied_types or 'none'}, but not a time-window delta. Approved is not applied; " + f"{approved_needs_payload}/{len(approved_rows)} approved rows are " "approved_needs_apply_payload and not directly applyable.\n\n" "Next proof-changing follow-up: build and review a strict apply_payload for the highest-impact approved " - "proposal, then seek explicit apply authorization. Until its applied_at and public.* before/after row " - "IDs or hashes exist, do not claim the canonical database changed." + "proposal, then seek explicit apply authorization. Until its applied_at, public.* before/after row " + "IDs or hashes, and postflight readback exist, do not claim the canonical database changed." ) return ( f"Partly.\nFresh live readback.\n{format_database_count_readback(status_data)}\nProposal states are applied: " diff --git a/hermes-agent/leoclean-plugins/vps/leo-db-context/__init__.py b/hermes-agent/leoclean-plugins/vps/leo-db-context/__init__.py index 7548662..f0369d7 100644 --- a/hermes-agent/leoclean-plugins/vps/leo-db-context/__init__.py +++ b/hermes-agent/leoclean-plugins/vps/leo-db-context/__init__.py @@ -28,6 +28,7 @@ COMPILED_CONTRACT_IDS = frozenset( "source_link_audit", "demo_capability_readback", "identity_canonicality_readback", + "telegram_participant_identity", "runtime_persistence", "shared_claims_agent_positions", "forecast_resolution_schema", diff --git a/tests/test_hermes_leoclean_kb_bridge_source.py b/tests/test_hermes_leoclean_kb_bridge_source.py index b17cea9..55a7677 100644 --- a/tests/test_hermes_leoclean_kb_bridge_source.py +++ b/tests/test_hermes_leoclean_kb_bridge_source.py @@ -251,6 +251,10 @@ def test_vps_bridge_broad_db_questions_select_query_specific_live_contracts() -> "Is the proposal backlog stuck on missing document-to-source links?": "source_link_audit", "Can we demo a real database write from Leo?": "demo_capability_readback", "Does editing the SOUL file alter the source of truth for identity?": "identity_canonicality_readback", + ( + "The current visible Telegram sender is @m3taversal. What should Leo call this participant, which " + "identity sources are allowed, and how should Leo avoid mixing identities?" + ): "telegram_participant_identity", } for query, expected_id in cases.items(): @@ -316,6 +320,11 @@ def test_vps_bridge_oos_intents_preserve_specific_contracts_and_negated_actions( ( "A temporary-profile GatewayRunner answered, but posted nothing to Telegram. Is delivery proven live?" ): {"telegram_delivery_proof"}, + ( + "The current visible Telegram sender is @m3taversal. An earlier answer shortened that handle. What " + "should Leo call this participant, which identity sources are allowed, and how should Leo avoid mixing " + "identities when another user replies? Do not write to memory or the KB." + ): {"telegram_participant_identity"}, } for query, expected_ids in cases.items(): diff --git a/tests/test_working_leo_m3taversal_oos_benchmark.py b/tests/test_working_leo_m3taversal_oos_benchmark.py index b1be2ee..4b2a712 100644 --- a/tests/test_working_leo_m3taversal_oos_benchmark.py +++ b/tests/test_working_leo_m3taversal_oos_benchmark.py @@ -573,6 +573,7 @@ def test_db_compiled_responses_pass_all_database_backed_oos_cases() -> None: "OOS-04", "OOS-05", "OOS-06", + "OOS-09", "OOS-10", "OOS-11", "OOS-12",