soma_application/provider_registry/
python_operations.rs1use super::*;
2
3impl ProviderRegistry {
4 pub fn resolve_python_provider_path(
6 &self,
7 provider_path: &Path,
8 ) -> Result<PathBuf, ProviderValidationError> {
9 let source = self.file_source.as_ref().ok_or_else(|| {
10 ProviderValidationError::new(
11 "provider_file_source_unavailable",
12 "Python environment operations require a file-backed provider registry",
13 )
14 })?;
15 source
16 .resolve_python_provider_path(provider_path)
17 .map_err(|error| {
18 ProviderValidationError::new("provider_candidate_path_invalid", error.to_string())
19 })
20 }
21
22 pub fn authorize_operator_action(
24 &self,
25 mut call: ProviderCall,
26 ) -> Result<ProviderCall, ProviderError> {
27 let state = self
28 .state
29 .read()
30 .expect("provider registry lock should not be poisoned");
31 let entry = state
32 .snapshot
33 .core_snapshot()
34 .tool(&call.action)
35 .ok_or_else(|| {
36 ProviderError::validation(
37 "registry",
38 call.action.clone(),
39 "unknown_action",
40 format!("unknown provider action `{}`", call.action),
41 )
42 })?;
43 let provider_name = entry.provider_id().as_str();
44 let provider_kind = state
45 .snapshot
46 .catalogs
47 .iter()
48 .find(|catalog| catalog.provider.name == provider_name)
49 .map(|catalog| catalog.provider.kind)
50 .ok_or_else(|| {
51 ProviderError::new(
52 "provider_not_loaded",
53 provider_name,
54 Some(call.action.clone()),
55 "provider is not loaded in the active registry",
56 "Reload providers and retry.",
57 )
58 })?;
59 if !provider_tool_surface_enabled(entry.spec(), call.surface) {
60 return Err(ProviderError::validation(
61 provider_name,
62 call.action.clone(),
63 "surface_disabled",
64 "action is not enabled on this surface",
65 ));
66 }
67 call.provider = provider_name.to_owned();
68 call.snapshot_id = state.snapshot.id.clone();
69 enforce_pre_input(entry.spec(), &call, provider_kind)?;
70 Ok(call)
71 }
72
73 pub fn python_worker_status(&self) -> Value {
75 let state = self
76 .state
77 .read()
78 .expect("provider registry lock should not be poisoned");
79 let workers = state
80 .providers
81 .iter()
82 .filter_map(|(name, provider)| {
83 provider.runtime_status().map(|status| {
84 json!({
85 "provider": name,
86 "status": status,
87 })
88 })
89 })
90 .collect::<Vec<_>>();
91 json!({
92 "snapshot_id": state.snapshot.id,
93 "workers": workers,
94 })
95 }
96
97 pub fn cancel_python_worker(&self, provider_name: &str) -> Result<bool, ProviderError> {
99 let state = self
100 .state
101 .read()
102 .expect("provider registry lock should not be poisoned");
103 let provider = state.providers.get(provider_name).ok_or_else(|| {
104 ProviderError::validation(
105 "registry",
106 "python_worker_cancel",
107 "provider_not_loaded",
108 format!("provider `{provider_name}` is not loaded"),
109 )
110 })?;
111 if provider.runtime_status().is_none() {
112 return Err(ProviderError::validation(
113 provider_name,
114 "python_worker_cancel",
115 "python_worker_unavailable",
116 "provider does not use a persistent Python worker",
117 ));
118 }
119 Ok(provider.cancel_active())
120 }
121
122 pub async fn reset_python_worker_quarantine(
124 &self,
125 provider_name: &str,
126 ) -> Result<(), ProviderError> {
127 let provider = {
128 let state = self
129 .state
130 .read()
131 .expect("provider registry lock should not be poisoned");
132 let provider = state.providers.get(provider_name).cloned().ok_or_else(|| {
133 ProviderError::validation(
134 "registry",
135 "python_worker_reset",
136 "provider_not_loaded",
137 format!("provider `{provider_name}` is not loaded"),
138 )
139 })?;
140 if provider.runtime_status().is_none() {
141 return Err(ProviderError::validation(
142 provider_name,
143 "python_worker_reset",
144 "python_worker_unavailable",
145 "provider does not use a persistent Python worker",
146 ));
147 }
148 provider
149 };
150 provider.reset_quarantine().await;
151 Ok(())
152 }
153}