返回 CodeWhale
operate.rs
根目录 / crates / tui / src / tui / setup / operate.rs
1 use crate::config::Config;
2 use crate::tui::app::App;
3
4 #[derive(Debug, Clone, PartialEq, Eq)]
5 pub(super) struct SetupOperateFacts {
6 pub(super) runtime_ready: bool,
7 pub(super) runtime_result: String,
8 pub(super) roster_ready: bool,
9 pub(super) roster_result: String,
10 pub(super) concurrency_result: String,
11 pub(super) result: String,
12 }
13
14 impl Default for SetupOperateFacts {
15 fn default() -> Self {
16 Self {
17 runtime_ready: false,
18 runtime_result: "worker runtime not loaded".to_string(),
19 roster_ready: false,
20 roster_result: "Team roster not loaded".to_string(),
21 concurrency_result: "concurrency not loaded".to_string(),
22 result: "operate readiness not loaded".to_string(),
23 }
24 }
25 }
26
27 impl SetupOperateFacts {
28 pub(super) fn from_app_config(app: &App, config: &Config, provider_ready: bool) -> Self {
29 let provider_identity = app.provider_identity_for_persistence();
30 let subagents_enabled = config.subagents_enabled_for_provider(app.api_provider);
31 let max_subagents = config.max_subagents_for_provider(app.api_provider);
32 let launch_concurrency = config.launch_concurrency_for_provider(app.api_provider);
33 let max_admitted = config.max_admitted_subagents_for_provider(app.api_provider);
34 let runtime_disabled_reason = if subagents_enabled {
35 None
36 } else {
37 Some(
38 config
39 .subagents_disabled_reason()
40 .unwrap_or("disabled for active provider"),
41 )
42 };
43 let max_spawn_depth = config.subagent_max_spawn_depth_for_provider(app.api_provider);
44 let runtime_configured =
45 subagents_enabled && max_subagents > 0 && launch_concurrency > 0 && max_spawn_depth > 0;
46 // Conversation and read-only discovery do not require a worker. This
47 // readiness fact describes whether Operate can also dispatch executable
48 // work in the background and report its lifecycle accurately.
49 let runtime_ready = runtime_configured && provider_ready;
50 let runtime_result = if let Some(reason) = runtime_disabled_reason {
51 format!("worker runtime disabled ({reason})")
52 } else if runtime_ready {
53 format!(
54 "worker runtime ready for {}; max_subagents={}, launch_concurrency={}, admission={}, max_spawn_depth={}; background dispatch and completion receipts are available",
55 provider_identity, max_subagents, launch_concurrency, max_admitted, max_spawn_depth
56 )
57 } else if runtime_configured {
58 format!(
59 "worker runtime configured for {}, but the active provider route is not ready; max_subagents={}, launch_concurrency={}, admission={}, max_spawn_depth={}",
60 provider_identity, max_subagents, launch_concurrency, max_admitted, max_spawn_depth
61 )
62 } else {
63 format!(
64 "worker runtime has no launch capacity for {}; max_subagents={}, launch_concurrency={}, admission={}, max_spawn_depth={}",
65 provider_identity, max_subagents, launch_concurrency, max_admitted, max_spawn_depth
66 )
67 };
68
69 let roster = crate::fleet::identity::load_effective_roster(
70 &config.fleet_config(),
71 &app.workspace,
72 Some(app.plugin_registry.as_ref()),
73 );
74 let roster_members = roster.members().len();
75 let origin_count = |origin| {
76 roster
77 .members()
78 .iter()
79 .filter(|member| member.origin == origin)
80 .count()
81 };
82 let config_members = origin_count(crate::fleet::roster::ProfileOrigin::Config);
83 let personal_members = origin_count(crate::fleet::roster::ProfileOrigin::Personal);
84 let project_members = origin_count(crate::fleet::roster::ProfileOrigin::Workspace);
85 let custom_roster_members = config_members + personal_members + project_members;
86 let roster_ready = roster.load_error().is_none() && roster_members > 0;
87 let roster_result = if let Some(error) = roster.load_error() {
88 error.to_string()
89 } else if custom_roster_members > 0 {
90 let origins = [
91 ("config", config_members),
92 ("personal", personal_members),
93 ("project", project_members),
94 ]
95 .into_iter()
96 .filter(|(_, count)| *count > 0)
97 .map(|(label, count)| format!("{label}={count}"))
98 .collect::<Vec<_>>()
99 .join(", ");
100 format!("{roster_members} team members (custom: {origins})")
101 } else {
102 format!("{roster_members} built-in team members; starter roster available")
103 };
104
105 let concurrency_result = format!(
106 "configured launch_concurrency={launch_concurrency}; max_subagents={max_subagents}; admission={max_admitted}; plan limit not probed"
107 );
108 let result = format!(
109 "provider={}, runtime={}, roster={}, concurrency={}",
110 if provider_ready {
111 "ready"
112 } else {
113 "needs_action"
114 },
115 if runtime_ready {
116 "ready"
117 } else {
118 "needs_action"
119 },
120 if roster_ready {
121 "ready"
122 } else {
123 "needs_action"
124 },
125 concurrency_result
126 );
127
128 Self {
129 runtime_ready,
130 runtime_result,
131 roster_ready,
132 roster_result,
133 concurrency_result,
134 result,
135 }
136 }
137 }
138
138 lines RUST