starweaver_runtime/
dependency_assembly.rs1use starweaver_context::{
4 AgentContext, AgentContextHandle, ContextMutationHandles, DependencyStore,
5};
6use starweaver_tools::{ToolDependencyProfile, ToolDependencyRequirements};
7
8#[derive(Clone, Debug)]
10pub struct ToolDependencyAssembly {
11 pub dependencies: DependencyStore,
13 pub legacy_context: Option<AgentContextHandle>,
15 pub context_mutations: ContextMutationHandles,
17 pub authorized_context_capabilities: std::collections::BTreeSet<String>,
19}
20
21impl ToolDependencyAssembly {
22 pub fn apply_to(&self, context: &mut AgentContext) {
24 if let Some(handle) = &self.legacy_context {
25 absorb_legacy_context(context, &handle.snapshot());
26 }
27 self.context_mutations
28 .apply_to(context, &self.authorized_context_capabilities);
29 }
30}
31
32#[must_use]
34pub fn assemble_tool_dependencies_for_name(
35 context: &AgentContext,
36 tool_name: &str,
37 requirements: &ToolDependencyRequirements,
38 strict_grant: &starweaver_context::ToolCapabilityGrant,
39) -> ToolDependencyAssembly {
40 let strict_grant = if tool_name.is_empty() {
41 strict_grant.clone()
42 } else {
43 context.tool_capability_grant(tool_name)
44 };
45 let authorized_host_capabilities = if requirements.profile == ToolDependencyProfile::Strict {
46 requirements
47 .host_capabilities
48 .intersection(&strict_grant.host_capabilities)
49 .cloned()
50 .collect()
51 } else {
52 requirements.host_capabilities.clone()
53 };
54 let authorized_context_capabilities = if requirements.profile == ToolDependencyProfile::Strict {
55 requirements
56 .context_capabilities
57 .intersection(&strict_grant.context_capabilities)
58 .cloned()
59 .collect()
60 } else {
61 requirements.context_capabilities.clone()
62 };
63 let shell_environment_authorized = requirements.shell_environment
64 && (requirements.profile != ToolDependencyProfile::Strict
65 || strict_grant.shell_environment);
66 let context_mutations = ContextMutationHandles::from_context(context);
67 let legacy_context = (requirements.profile == ToolDependencyProfile::Legacy)
68 .then(|| AgentContextHandle::new(context.clone()));
69 let mut dependencies = match requirements.profile {
70 ToolDependencyProfile::Legacy => context.tool_dependency_store(),
71 ToolDependencyProfile::Filtered => context.filtered_tool_dependency_store(
72 &authorized_host_capabilities,
73 shell_environment_authorized,
74 ),
75 ToolDependencyProfile::Strict => context.strict_tool_dependency_store(
76 &authorized_host_capabilities,
77 shell_environment_authorized,
78 ),
79 };
80 if let Some(handle) = &legacy_context {
81 dependencies.insert(handle.clone());
82 }
83 context_mutations.insert_grants(&mut dependencies, &authorized_context_capabilities);
84 ToolDependencyAssembly {
85 dependencies,
86 legacy_context,
87 context_mutations,
88 authorized_context_capabilities,
89 }
90}
91
92fn absorb_legacy_context(context: &mut AgentContext, snapshot: &AgentContext) {
93 context.usage.clone_from(&snapshot.usage);
94 context.notes.clone_from(&snapshot.notes);
95 context.state.clone_from(&snapshot.state);
96 context.tools.clone_from(&snapshot.tools);
97 context.events.clone_from(&snapshot.events);
98 context.messages.clone_from(&snapshot.messages);
99 context.metadata.clone_from(&snapshot.metadata);
100 context.agent_registry.clone_from(&snapshot.agent_registry);
101 context
102 .subagent_history
103 .clone_from(&snapshot.subagent_history);
104 context
105 .handoff_message
106 .clone_from(&snapshot.handoff_message);
107 context
108 .runtime
109 .context_manage_tool_names
110 .clone_from(&snapshot.runtime.context_manage_tool_names);
111 context
112 .runtime
113 .tool_tags
114 .clone_from(&snapshot.runtime.tool_tags);
115 context
116 .runtime
117 .wrapper_metadata
118 .clone_from(&snapshot.runtime.wrapper_metadata);
119}