Skip to content

Commit f8388a0

Browse files
fix(lcm): default transcript reads to all providers
1 parent 180e29d commit f8388a0

6 files changed

Lines changed: 118 additions & 48 deletions

File tree

src/agents/hermes/templates/plugin_init.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,18 @@ def _resolve_auxiliary_client(agent=None):
296296
"tracedecay_lcm_preflight",
297297
))
298298

299+
STANDARD_HERMES_LCM_PROVIDER = "cursor"
300+
301+
LCM_PROVIDER_LOCAL_TOOL_NAMES = frozenset((
302+
"tracedecay_lcm_compress",
303+
"tracedecay_lcm_describe",
304+
"tracedecay_lcm_doctor",
305+
"tracedecay_lcm_expand",
306+
"tracedecay_lcm_expand_query",
307+
"tracedecay_lcm_preflight",
308+
"tracedecay_lcm_session_boundary",
309+
))
310+
299311
# Direct duplicates of the memory provider's own tool surface
300312
# (fact_store / fact_feedback / memory_status). Skipped at register() time
301313
# when tracedecay is the active memory.provider so the same store is not
@@ -1858,7 +1870,9 @@ def _synthesize_expand_query_payload(retrieval, agent=None, **kwargs):
18581870
def _handle_lcm_expand_query(args, **kwargs) -> str:
18591871
kwargs = dict(kwargs)
18601872
agent = kwargs.pop("agent", None)
1861-
retrieval = call_tracedecay_json("tracedecay_lcm_expand_query", args or {}, **kwargs)
1873+
args = dict(args or {})
1874+
args.setdefault("provider", STANDARD_HERMES_LCM_PROVIDER)
1875+
retrieval = call_tracedecay_json("tracedecay_lcm_expand_query", args, **kwargs)
18621876
payload = _synthesize_expand_query_payload(retrieval, agent=agent, **kwargs)
18631877
return json.dumps(payload)
18641878

@@ -2219,6 +2233,7 @@ def _report_compression_boundary(self, session_id, bound_session_id, kwargs):
22192233
return
22202234
args = _storage_args(self.project_root, self.hermes_home)
22212235
args.update({
2236+
"provider": STANDARD_HERMES_LCM_PROVIDER,
22222237
"session_id": session_id,
22232238
"old_session_id": old_session_id,
22242239
"boundary_reason": boundary_reason,
@@ -2261,6 +2276,7 @@ def _preflight_probe(self, messages, current_tokens=None, **kwargs):
22612276
)
22622277
)
22632278
args.update({
2279+
"provider": STANDARD_HERMES_LCM_PROVIDER,
22642280
"session_id": self.active_session_id,
22652281
"messages": messages,
22662282
"current_tokens": current_tokens,
@@ -2469,6 +2485,8 @@ def handle_tool_call(self, name, arguments=None, **kwargs) -> str:
24692485
storage_args = _storage_args(self.project_root, self.hermes_home)
24702486
for key, value in storage_args.items():
24712487
tool_args.setdefault(key, value)
2488+
if tracedecay_name in LCM_PROVIDER_LOCAL_TOOL_NAMES:
2489+
tool_args.setdefault("provider", STANDARD_HERMES_LCM_PROVIDER)
24722490
if tracedecay_name == "tracedecay_lcm_compress" and self.project_root:
24732491
tool_args.setdefault("response_handle_project_root", self.project_root)
24742492
if native_name in ("lcm_status", "lcm_doctor"):
@@ -2485,6 +2503,7 @@ def handle_tool_call(self, name, arguments=None, **kwargs) -> str:
24852503
def expand_query(self, prompt, query=None, node_ids=None, **kwargs):
24862504
kwargs = dict(kwargs)
24872505
args = self._tool_args(kwargs.pop("session_id", None))
2506+
args["provider"] = STANDARD_HERMES_LCM_PROVIDER
24882507
args["prompt"] = prompt
24892508
if query is not None:
24902509
args["query"] = query
@@ -2903,6 +2922,7 @@ def _compress_to_result(self, messages, current_tokens=None, focus_topic=None, *
29032922
)
29042923
)
29052924
args.update({
2925+
"provider": STANDARD_HERMES_LCM_PROVIDER,
29062926
"messages": messages,
29072927
"current_tokens": current_tokens,
29082928
"focus_topic": focus_topic,
@@ -3199,7 +3219,11 @@ def sync_turn(self, user_content, assistant_content, *, session_id="", messages=
31993219
role = str(entry.get("role") or "user")
32003220
entry["id"] = f"tracedecay_sync_{batch_id}_{timestamp_ns}_{idx}_{role}"
32013221
args = _storage_args(self.project_root, self.hermes_home)
3202-
args.update({"session_id": sid, "messages": turn_messages})
3222+
args.update({
3223+
"provider": STANDARD_HERMES_LCM_PROVIDER,
3224+
"session_id": sid,
3225+
"messages": turn_messages,
3226+
})
32033227
try:
32043228
tools.call_tracedecay_tool(
32053229
"tracedecay_lcm_preflight",

src/mcp/tools/definitions.rs

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2392,7 +2392,7 @@ fn def_lcm_status() -> ToolDefinition {
23922392
"properties": {
23932393
"provider": {
23942394
"type": "string",
2395-
"description": "Provider id to inspect (default: cursor)."
2395+
"description": "Optional provider id. Omit or use 'all' to inspect all providers."
23962396
},
23972397
"session_id": {
23982398
"type": "string",
@@ -2420,7 +2420,7 @@ fn def_lcm_doctor() -> ToolDefinition {
24202420
"properties": {
24212421
"provider": {
24222422
"type": "string",
2423-
"description": "Provider id to inspect (default: cursor)."
2423+
"description": "Specific provider id to inspect or repair. Required; 'all' is not accepted for this lifecycle tool."
24242424
},
24252425
"session_id": {
24262426
"type": "string",
@@ -2463,7 +2463,8 @@ fn def_lcm_doctor() -> ToolDefinition {
24632463
"storage_scope": lcm_storage_scope_schema(),
24642464
"hermes_home": lcm_hermes_home_schema()
24652465
},
2466-
"allOf": lcm_storage_scope_requires_hermes_home()
2466+
"allOf": lcm_storage_scope_requires_hermes_home(),
2467+
"required": ["provider"]
24672468
}),
24682469
)
24692470
}
@@ -2478,7 +2479,7 @@ fn def_lcm_load_session() -> ToolDefinition {
24782479
"properties": {
24792480
"provider": {
24802481
"type": "string",
2481-
"description": "Provider id, default cursor."
2482+
"description": "Optional provider id. Omit or use 'all' to load messages for this session id across all providers."
24822483
},
24832484
"session_id": {
24842485
"type": "string",
@@ -2616,7 +2617,7 @@ fn def_lcm_describe() -> ToolDefinition {
26162617
"properties": {
26172618
"provider": {
26182619
"type": "string",
2619-
"description": "Provider id, default cursor."
2620+
"description": "Specific provider id. Required because describe targets are provider-local."
26202621
},
26212622
"session_id": {
26222623
"type": "string",
@@ -2644,7 +2645,7 @@ fn def_lcm_describe() -> ToolDefinition {
26442645
"hermes_home": lcm_hermes_home_schema()
26452646
},
26462647
"allOf": lcm_storage_scope_requires_hermes_home(),
2647-
"required": ["session_id"]
2648+
"required": ["provider", "session_id"]
26482649
}),
26492650
)
26502651
}
@@ -2659,7 +2660,7 @@ fn def_lcm_expand() -> ToolDefinition {
26592660
"properties": {
26602661
"provider": {
26612662
"type": "string",
2662-
"description": "Provider id, default cursor."
2663+
"description": "Specific provider id. Required because expansion targets are provider-local."
26632664
},
26642665
"session_id": {
26652666
"type": "string",
@@ -2714,7 +2715,7 @@ fn def_lcm_expand() -> ToolDefinition {
27142715
"hermes_home": lcm_hermes_home_schema()
27152716
},
27162717
"allOf": lcm_storage_scope_requires_hermes_home(),
2717-
"required": ["session_id", "target"]
2718+
"required": ["provider", "session_id", "target"]
27182719
}),
27192720
)
27202721
}
@@ -2729,7 +2730,7 @@ fn def_lcm_expand_query() -> ToolDefinition {
27292730
"properties": {
27302731
"provider": {
27312732
"type": "string",
2732-
"description": "Provider id, default cursor."
2733+
"description": "Specific provider id. Required because retrieval context is provider-local."
27332734
},
27342735
"session_id": {
27352736
"type": "string",
@@ -2775,7 +2776,7 @@ fn def_lcm_expand_query() -> ToolDefinition {
27752776
"hermes_home": lcm_hermes_home_schema()
27762777
},
27772778
"allOf": lcm_storage_scope_requires_hermes_home(),
2778-
"required": ["session_id", "prompt"]
2779+
"required": ["provider", "session_id", "prompt"]
27792780
}),
27802781
)
27812782
}
@@ -2790,7 +2791,7 @@ fn def_lcm_preflight() -> ToolDefinition {
27902791
"properties": {
27912792
"provider": {
27922793
"type": "string",
2793-
"description": "Provider id, default cursor."
2794+
"description": "Specific provider id. Required for compression lifecycle operations."
27942795
},
27952796
"session_id": {
27962797
"type": "string",
@@ -2865,7 +2866,8 @@ fn def_lcm_preflight() -> ToolDefinition {
28652866
"storage_scope": lcm_storage_scope_schema(),
28662867
"hermes_home": lcm_hermes_home_schema()
28672868
},
2868-
"allOf": lcm_storage_scope_requires_hermes_home()
2869+
"allOf": lcm_storage_scope_requires_hermes_home(),
2870+
"required": ["provider", "session_id"]
28692871
}),
28702872
)
28712873
}
@@ -2880,7 +2882,7 @@ fn def_lcm_compress() -> ToolDefinition {
28802882
"properties": {
28812883
"provider": {
28822884
"type": "string",
2883-
"description": "Provider id, default cursor."
2885+
"description": "Specific provider id. Required for compression lifecycle operations."
28842886
},
28852887
"session_id": {
28862888
"type": "string",
@@ -2978,7 +2980,7 @@ fn def_lcm_compress() -> ToolDefinition {
29782980
"hermes_home": lcm_hermes_home_schema()
29792981
},
29802982
"allOf": lcm_storage_scope_requires_hermes_home(),
2981-
"required": ["session_id"]
2983+
"required": ["provider", "session_id"]
29822984
}),
29832985
)
29842986
}
@@ -2993,7 +2995,7 @@ fn def_lcm_session_boundary() -> ToolDefinition {
29932995
"properties": {
29942996
"provider": {
29952997
"type": "string",
2996-
"description": "Provider id, default cursor."
2998+
"description": "Specific provider id. Required for compression lifecycle operations."
29972999
},
29983000
"session_id": {
29993001
"type": "string",
@@ -3015,7 +3017,7 @@ fn def_lcm_session_boundary() -> ToolDefinition {
30153017
"hermes_home": lcm_hermes_home_schema()
30163018
},
30173019
"allOf": lcm_storage_scope_requires_hermes_home(),
3018-
"required": ["session_id"]
3020+
"required": ["provider", "session_id"]
30193021
}),
30203022
)
30213023
}

src/mcp/tools/handlers/session.rs

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -811,8 +811,18 @@ fn timestamp_argument_error(name: &str) -> TraceDecayError {
811811
))
812812
}
813813

814-
fn provider_arg(args: &Value) -> &str {
815-
string_arg(args, "provider").unwrap_or("cursor")
814+
fn provider_or_all_arg(args: &Value) -> &str {
815+
optional_search_provider_arg(args).unwrap_or("all")
816+
}
817+
818+
fn required_specific_provider_arg(args: &Value) -> Result<&str> {
819+
match string_arg(args, "provider") {
820+
Some("all") => Err(argument_error(
821+
"provider must name a specific provider for this tool",
822+
)),
823+
Some(provider) => Ok(provider),
824+
None => Err(argument_error("provider is required for this tool")),
825+
}
816826
}
817827

818828
fn optional_search_provider_arg(args: &Value) -> Option<&str> {
@@ -1270,15 +1280,10 @@ fn parse_lcm_scope(args: &Value) -> Result<LcmScope> {
12701280
}
12711281
}
12721282

1273-
fn lcm_grep_provider_arg(args: &Value, scope: LcmScope) -> &str {
1283+
fn lcm_grep_provider_arg(args: &Value) -> &str {
12741284
if let Some(provider) = optional_search_provider_arg(args) {
12751285
return provider;
12761286
}
1277-
if matches!(scope, LcmScope::Current | LcmScope::Session)
1278-
&& string_arg(args, "provider").is_none()
1279-
{
1280-
return provider_arg(args);
1281-
}
12821287
"all"
12831288
}
12841289

@@ -1507,7 +1512,7 @@ pub(super) async fn handle_lcm_status(
15071512
context: LcmHandlerContext<'_>,
15081513
args: Value,
15091514
) -> Result<ToolResult> {
1510-
let provider = provider_arg(&args);
1515+
let provider = provider_or_all_arg(&args);
15111516
let session_id = string_arg(&args, "session_id");
15121517
let deep = bool_arg(&args, "deep")?.unwrap_or(false);
15131518
let gc_config = lcm_gc_config(&args)?;
@@ -1534,7 +1539,7 @@ pub(super) async fn handle_lcm_doctor(
15341539
context: LcmHandlerContext<'_>,
15351540
args: Value,
15361541
) -> Result<ToolResult> {
1537-
let provider = provider_arg(&args);
1542+
let provider = required_specific_provider_arg(&args)?;
15381543
let session_id = string_arg(&args, "session_id");
15391544
let mode = lcm_doctor_mode(&args)?;
15401545
let apply = args.get("apply").and_then(Value::as_bool).unwrap_or(false);
@@ -1629,7 +1634,7 @@ pub(super) async fn handle_lcm_load_session(
16291634
context: LcmHandlerContext<'_>,
16301635
args: Value,
16311636
) -> Result<ToolResult> {
1632-
let provider = provider_arg(&args);
1637+
let provider = provider_or_all_arg(&args);
16331638
let session_id = required_string_arg(&args, "session_id")?;
16341639
let (content_slice, content_limit_clamped_from) = lcm_load_content_slice(&args)?;
16351640
let storage = lcm_open_storage_ro!(context, &args);
@@ -1682,7 +1687,7 @@ pub(super) async fn handle_lcm_grep(
16821687
// Validate scope before opening storage so argument errors are reported
16831688
// even when the sessions DB does not exist yet.
16841689
let scope = parse_lcm_scope(&args)?;
1685-
let provider = lcm_grep_provider_arg(&args, scope);
1690+
let provider = lcm_grep_provider_arg(&args);
16861691
let storage = lcm_open_storage_ro!(context, &args);
16871692
let hits = storage
16881693
.db
@@ -1721,7 +1726,7 @@ pub(super) async fn handle_lcm_describe(
17211726
context: LcmHandlerContext<'_>,
17221727
args: Value,
17231728
) -> Result<ToolResult> {
1724-
let provider = provider_arg(&args);
1729+
let provider = required_specific_provider_arg(&args)?;
17251730
let session_id = required_string_arg(&args, "session_id")?;
17261731
// Validate target before opening storage so argument errors are reported
17271732
// even when the sessions DB does not exist yet.
@@ -1751,7 +1756,7 @@ pub(super) async fn handle_lcm_expand(
17511756
context: LcmHandlerContext<'_>,
17521757
args: Value,
17531758
) -> Result<ToolResult> {
1754-
let provider = provider_arg(&args);
1759+
let provider = required_specific_provider_arg(&args)?;
17551760
let session_id = required_string_arg(&args, "session_id")?;
17561761
let target = parse_lcm_expand_target(&args)?;
17571762
let storage = lcm_open_storage_ro!(context, &args);
@@ -1782,7 +1787,7 @@ pub(super) async fn handle_lcm_expand_query(
17821787
context: LcmHandlerContext<'_>,
17831788
args: Value,
17841789
) -> Result<ToolResult> {
1785-
let provider = provider_arg(&args);
1790+
let provider = required_specific_provider_arg(&args)?;
17861791
let session_id = required_string_arg(&args, "session_id")?;
17871792
let prompt = required_string_arg(&args, "prompt")?;
17881793
let max_results =
@@ -1835,7 +1840,7 @@ pub(super) async fn handle_lcm_session_boundary(
18351840
context: LcmHandlerContext<'_>,
18361841
args: Value,
18371842
) -> Result<ToolResult> {
1838-
let provider = provider_arg(&args);
1843+
let provider = required_specific_provider_arg(&args)?;
18391844
let session_id = required_string_arg(&args, "session_id")?;
18401845
let storage = lcm_open_storage!(context, &args);
18411846
let response = storage
@@ -1866,7 +1871,7 @@ pub(super) async fn handle_lcm_preflight(
18661871
context: LcmHandlerContext<'_>,
18671872
args: Value,
18681873
) -> Result<ToolResult> {
1869-
let provider = provider_arg(&args);
1874+
let provider = required_specific_provider_arg(&args)?;
18701875
let session_id = required_string_arg(&args, "session_id")?;
18711876
let storage = lcm_open_storage!(context, &args);
18721877
let response = storage
@@ -1907,7 +1912,7 @@ pub(super) async fn handle_lcm_compress(
19071912
context: LcmHandlerContext<'_>,
19081913
args: Value,
19091914
) -> Result<ToolResult> {
1910-
let provider = provider_arg(&args);
1915+
let provider = required_specific_provider_arg(&args)?;
19111916
let session_id = required_string_arg(&args, "session_id")?;
19121917
let response_handle_root = lcm_response_handle_root(context.project_root, &args);
19131918
let storage = lcm_open_storage!(context, &args);

src/sessions/lcm/query.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ pub(crate) async fn load_session(
9999
let limit = clamp_limit(request.limit);
100100
let fetch_limit = limit.saturating_add(1);
101101
let mut values = vec![
102+
Value::Text(request.provider.clone()),
102103
Value::Text(request.provider.clone()),
103104
Value::Text(request.session_id.clone()),
104105
Value::Integer(request.after_store_id.unwrap_or(0)),
@@ -124,7 +125,7 @@ pub(crate) async fn load_session(
124125
timestamp, content, content_hash, storage_kind, payload_ref,
125126
snippet_text, legacy_source, legacy_truncated, metadata_json
126127
FROM lcm_raw_messages
127-
WHERE provider = ?
128+
WHERE (? = 'all' OR provider = ?)
128129
AND session_id = ?
129130
AND store_id > ?
130131
{role_clause}

tests/hermes_suite/lcm_bridge.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,6 +1231,7 @@ args_index = argv.index("--args")
12311231
args = json.loads(argv[args_index + 1])
12321232
assert args == {
12331233
"project_root": "/tmp/project",
1234+
"provider": "cursor",
12341235
"fresh_tail_count": 64,
12351236
"leaf_chunk_tokens": 20000,
12361237
"dynamic_leaf_chunk_enabled": False,
@@ -1315,6 +1316,7 @@ assert argv[1:6] == ["tool", "--project", "/tmp/project", "tracedecay_lcm_sessio
13151316
args = json.loads(argv[argv.index("--args") + 1])
13161317
assert args == {
13171318
"project_root": "/tmp/project",
1319+
"provider": "cursor",
13181320
"session_id": "session-b",
13191321
"old_session_id": "session-c",
13201322
"boundary_reason": "compression",
@@ -1423,6 +1425,7 @@ else:
14231425
assert args == {
14241426
"project_root": "/tmp/project",
14251427
"response_handle_project_root": "/tmp/project",
1428+
"provider": "cursor",
14261429
"fresh_tail_count": 64,
14271430
"leaf_chunk_tokens": 20000,
14281431
"dynamic_leaf_chunk_enabled": False,

0 commit comments

Comments
 (0)