1use std::{
2 collections::{HashMap, HashSet},
3 path::PathBuf,
4 sync::Arc,
5};
6
7use murmur_artifact::{
8 ArtifactImplementation, ArtifactRuntime, ContextConfig, HookConfig, InferenceConfig,
9 LifecycleConfig, LifecycleOverride, Registry,
10};
11use wasmtime::{component::Component, Engine};
12
13use crate::{
14 bindings::host::murmur::tool::run::ToolResult,
15 hooks::ShellDispatchInfo,
16 limits::{EpochTicker, ExecutionLimits},
17};
18
19pub(crate) struct DispatchOutcome {
20 pub result: ToolResult,
21 pub shell: Option<ShellDispatchInfo>,
22 pub is_skill: bool,
26}
27
28impl DispatchOutcome {
29 pub(crate) fn tool(result: ToolResult) -> Self {
30 Self {
31 result,
32 shell: None,
33 is_skill: false,
34 }
35 }
36
37 pub(crate) fn skill(result: ToolResult) -> Self {
38 Self {
39 result,
40 shell: None,
41 is_skill: true,
42 }
43 }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
47pub struct ArtifactRequest {
48 pub name: String,
49 pub version: String,
50 pub runtime: ArtifactRuntime,
51 pub source: Option<String>,
55}
56
57#[derive(Debug, Clone, PartialEq, Eq)]
58pub struct LockExpectation {
59 pub name: String,
60 pub resolved_version: String,
61 pub sha256_wasm: String,
62}
63
64#[derive(Debug, Clone, PartialEq, Eq)]
65pub struct ResolvedLockArtifact {
66 pub name: String,
67 pub resolved_version: String,
68 pub sha256_wasm: String,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Default)]
72pub struct CapabilityPolicy {
73 pub network_allow: Vec<String>,
74 pub filesystem_scope: Option<String>,
75 pub shell_allow: Vec<String>,
76 pub spawn_allow: Vec<String>,
77 pub shell_strip_env: Vec<String>,
78 pub shell_baseline_env: Vec<String>,
79 pub env_allow: Vec<String>,
84 pub limits: ExecutionLimits,
89}
90
91#[derive(Debug, Clone, PartialEq, Eq)]
92pub struct InstalledArtifactSummary {
93 pub name: String,
94 pub version: String,
95 pub runtime: ArtifactRuntime,
96 pub implementation: Option<ArtifactImplementation>,
97}
98
99#[derive(Clone)]
100pub(crate) struct StagedHookArtifact {
101 pub name: String,
102 pub version: String,
103 pub component: Component,
104 pub config: HookConfig,
105}
106
107#[derive(Debug, Clone)]
108pub struct StageRequest {
109 pub manifest_dir: PathBuf,
110 pub capsule_name: String,
111 pub capsule_version: String,
112 pub capsule_component_bytes: Vec<u8>,
113 pub artifacts: Vec<ArtifactRequest>,
114 pub allowlisted_tools: HashSet<String>,
115 pub lock_expectations: Option<Vec<LockExpectation>>,
116 pub capability_policy: CapabilityPolicy,
117 pub inference: Option<InferenceConfig>,
118 pub context: Option<ContextConfig>,
119 pub otel_endpoint: Option<String>,
121 pub eval_config_json: Option<String>,
123 pub case_id: Option<String>,
125 pub dataset_id: Option<String>,
127 pub lifecycle: Option<LifecycleConfig>,
129 pub lifecycle_override: Option<LifecycleOverride>,
131 pub trace: Option<murmur_artifact::TraceConfig>,
133 pub workdir: Option<std::path::PathBuf>,
137 pub bind_addr: String,
140 pub internal_port: Option<u16>,
144 pub job_id: Option<String>,
148}
149
150pub struct StagedSession {
151 pub session_id: String,
152 pub workdir: PathBuf,
153 pub accessible_workdir: std::path::PathBuf,
155 pub(crate) manifest_dir: PathBuf,
156 pub(crate) capsule_name: String,
157 pub(crate) capsule_version: String,
158 pub(crate) capsule_url: String,
159 pub resolved_lock_artifacts: Vec<ResolvedLockArtifact>,
160 pub(crate) installed_artifacts: Vec<InstalledArtifactSummary>,
161 pub(crate) inference: Option<InferenceConfig>,
162 pub(crate) context: Option<ContextConfig>,
163 pub(crate) engine: Engine,
164 pub(crate) capsule_component: Option<Component>,
166 pub(crate) tool_components: HashMap<String, Component>,
167 pub(crate) hook_components: Vec<StagedHookArtifact>,
168 pub(crate) allowlisted_tools: HashSet<String>,
169 pub(crate) capability_policy: CapabilityPolicy,
170 pub(crate) otel_endpoint: Option<String>,
171 pub(crate) eval_config_json: Option<String>,
172 pub(crate) case_id: Option<String>,
173 pub(crate) dataset_id: Option<String>,
174 pub(crate) lifecycle: LifecycleConfig,
176 pub(crate) trace_include_tool_output: bool,
178 pub(crate) bind_addr: String,
180 pub(crate) internal_port: Option<u16>,
182 pub(crate) job_id: Option<String>,
184 pub(crate) registry: Arc<dyn Registry>,
187 pub(crate) _epoch_ticker: EpochTicker,
192}
193
194#[derive(Debug, Clone, PartialEq, Eq)]
195pub struct LaunchResult {
196 pub session_id: String,
197 pub workdir: PathBuf,
198}
199
200pub fn capability_policy_from_runtime_manifest(
201 manifest: &murmur_artifact::RuntimeManifest,
202) -> CapabilityPolicy {
203 let caps = manifest.capabilities.as_ref();
204 let network_allow = caps
205 .and_then(|c| c.network.as_ref())
206 .map(|network| network.allow.clone())
207 .unwrap_or_default();
208
209 let filesystem_scope = caps
210 .and_then(|c| c.filesystem.as_ref())
211 .and_then(|filesystem| filesystem.scope.clone());
212
213 let shell_allow = caps
214 .and_then(|c| c.shell.as_ref())
215 .map(|shell| shell.allow.clone())
216 .unwrap_or_default();
217 let shell_strip_env = caps
218 .and_then(|c| c.shell.as_ref())
219 .and_then(|shell| shell.strip_env.clone())
220 .unwrap_or_default();
221 let shell_baseline_env = caps
222 .and_then(|c| c.shell.as_ref())
223 .and_then(|shell| shell.baseline_env.clone())
224 .unwrap_or_default();
225
226 let spawn_allow = caps
227 .and_then(|c| c.spawn.as_ref())
228 .map(|spawn| spawn.allow.clone())
229 .unwrap_or_default();
230
231 let env_allow = caps
232 .and_then(|c| c.env.as_ref())
233 .map(|env| env.allow.clone())
234 .unwrap_or_default();
235
236 let limits = ExecutionLimits::resolve(caps.and_then(|c| c.limits.as_ref()));
237
238 CapabilityPolicy {
239 network_allow,
240 filesystem_scope,
241 shell_allow,
242 spawn_allow,
243 shell_strip_env,
244 shell_baseline_env,
245 env_allow,
246 limits,
247 }
248}