lash_core/plugin/session_obj/
tools.rs1use std::collections::{BTreeMap, BTreeSet};
2use std::sync::Arc;
3
4use super::*;
5
6impl PluginSession {
7 pub fn resolved_tool_catalog(
8 &self,
9 session_id: &str,
10 ) -> Result<Arc<crate::ToolCatalog>, PluginError> {
11 let tools = self.tools.tool_manifests();
12 let contract_provider = Arc::clone(&self.tools);
13 let resolve_contract: lash_sansio::ToolContractResolver =
14 Arc::new(move |name: &str| contract_provider.resolve_contract(name));
15 Ok(Arc::new(self.resolve_tool_catalog(ToolCatalogContext {
16 session_id: session_id.to_string(),
17 tools,
18 resolve_contract: Some(Arc::clone(&resolve_contract)),
19 tool_access: self.tool_access.clone(),
20 subagent: self.subagent.clone(),
21 extensions: self.extensions.clone(),
22 })?))
23 }
24
25 pub fn tool_catalog(&self, session_id: &str) -> Result<Vec<serde_json::Value>, PluginError> {
28 let catalog = self.resolved_tool_catalog(session_id)?;
29 Ok(crate::tool_registry::project_tool_catalog(
30 catalog.tools.iter().cloned(),
31 ))
32 }
33
34 pub fn resolve_tool_catalog(
35 &self,
36 ctx: ToolCatalogContext,
37 ) -> Result<crate::ToolCatalog, PluginError> {
38 let mut contributions = collect_owned_sync(
39 &self.contributions.tool_catalog_contributors,
40 ToolCatalogContext {
41 session_id: ctx.session_id.clone(),
42 tools: ctx.tools.clone(),
43 resolve_contract: ctx.resolve_contract.clone(),
44 tool_access: ctx.tool_access.clone(),
45 subagent: ctx.subagent.clone(),
46 extensions: ctx.extensions.clone(),
47 },
48 |hook, ctx| hook(ctx),
49 )?
50 .into_iter()
51 .map(|owned| owned.value)
52 .collect::<Vec<_>>();
53 contributions.push(self.tool_catalog_overlay.clone());
54 let (tools, resolve_contract) = if ctx.tool_access.tools.is_empty() {
55 (ctx.tools, ctx.resolve_contract)
56 } else {
57 let contracts = ctx
58 .tool_access
59 .tools
60 .iter()
61 .map(|tool| (tool.name().to_string(), Arc::new(tool.contract())))
62 .collect::<BTreeMap<_, _>>();
63 (
64 ctx.tool_access
65 .tools
66 .iter()
67 .map(|tool| tool.manifest())
68 .collect(),
69 Some(Arc::new(move |name: &str| contracts.get(name).cloned())
70 as lash_sansio::ToolContractResolver),
71 )
72 };
73 let authority_hidden_tools = tools
74 .iter()
75 .filter(|tool| ctx.tool_access.hides(&tool.name))
76 .map(|tool| tool.name.clone())
77 .collect::<BTreeSet<_>>();
78 if !authority_hidden_tools.is_empty() {
79 contributions.push(ToolCatalogContribution {
80 remove: authority_hidden_tools.into_iter().collect(),
81 });
82 }
83 Ok(crate::build_tool_catalog(crate::ToolCatalogBuildInput {
84 tools,
85 resolve_contract,
86 contributions,
87 }))
88 }
89}