refactor: remove worker capability summary flags

This commit is contained in:
2026-09-30 13:11:28 +09:00
parent eb222c8d62
commit c0fd476d8b
26 changed files with 281 additions and 248 deletions
+2 -3
View File
@@ -5,7 +5,6 @@ pub use server_api::{
CreateWorkspaceWorkerRequest as BackendCreateWorkerRequest, Diagnostic as BackendDiagnostic, CreateWorkspaceWorkerRequest as BackendCreateWorkerRequest, Diagnostic as BackendDiagnostic,
DiagnosticSeverity as BackendDiagnosticSeverity, ListResponse as BackendRuntimeListResponse, DiagnosticSeverity as BackendDiagnosticSeverity, ListResponse as BackendRuntimeListResponse,
RuntimeSummary as BackendRuntimeSummary, RuntimeSummary as BackendRuntimeSummary,
WorkerCapabilitySummary as BackendWorkerCapabilitySummary,
WorkerImplementationSummary as BackendWorkerImplementationSummary, WorkerImplementationSummary as BackendWorkerImplementationSummary,
WorkerLaunchOptionsResponse as BackendWorkerLaunchOptions, WorkerLaunchOptionsResponse as BackendWorkerLaunchOptions,
WorkerLaunchProfileCandidate as BackendWorkerLaunchProfileCandidate, WorkerLaunchProfileCandidate as BackendWorkerLaunchProfileCandidate,
@@ -869,7 +868,6 @@ mod tests {
"pinned": false, "pinned": false,
"retention_state": "resident", "retention_state": "resident",
"implementation": {"kind": "embedded", "display_hint": "Embedded"}, "implementation": {"kind": "embedded", "display_hint": "Embedded"},
"capabilities": {"can_stop": true, "can_spawn_followup": false},
"diagnostics": [] "diagnostics": []
}, },
"diagnostics": [] "diagnostics": []
@@ -952,10 +950,11 @@ mod tests {
"label": "Coder", "label": "Coder",
"workspace": {"visibility": "workspace", "identity": "workspace"}, "workspace": {"visibility": "workspace", "identity": "workspace"},
"state": "idle", "state": "idle",
"availability": "observed",
"implementation": {"kind": "worker", "display_hint": "Coder"}, "implementation": {"kind": "worker", "display_hint": "Coder"},
"capabilities": {"can_stop": true, "can_spawn_followup": false},
"workdir_attachments": [{ "workdir_attachments": [{
"alias": "checkout", "alias": "checkout",
"effective_permissions": {"read": true, "write": true, "command": true},
"working_directory": { "working_directory": {
"working_directory_id": "wd-1", "working_directory_id": "wd-1",
"source": {"kind": "repository", "repository_key": "main"}, "source": {"kind": "repository", "repository_key": "main"},
+1 -1
View File
@@ -24,7 +24,7 @@ pub use backend_runtime::{
BackendCreateWorkerRequest, BackendCreateWorkerResponse, BackendDiagnostic, BackendCreateWorkerRequest, BackendCreateWorkerResponse, BackendDiagnostic,
BackendDiagnosticSeverity, BackendRuntimeClientError, BackendRuntimeListResponse, BackendDiagnosticSeverity, BackendRuntimeClientError, BackendRuntimeListResponse,
BackendRuntimeListTarget, BackendRuntimeSummary, BackendRuntimeTarget, BackendRuntimeListTarget, BackendRuntimeSummary, BackendRuntimeTarget,
BackendWorkerCapabilitySummary, BackendWorkerImplementationSummary, BackendWorkerLaunchOptions, BackendWorkerImplementationSummary, BackendWorkerLaunchOptions,
BackendWorkerLaunchProfileCandidate, BackendWorkerLaunchRuntimeOption, BackendWorkerLaunchProfileCandidate, BackendWorkerLaunchRuntimeOption,
BackendWorkerLaunchTarget, BackendWorkerOperationState, BackendWorkerRestoreResponse, BackendWorkerLaunchTarget, BackendWorkerOperationState, BackendWorkerRestoreResponse,
BackendWorkerRestoreResult, BackendWorkerRestoreState, BackendWorkerSummary, BackendWorkerRestoreResult, BackendWorkerRestoreState, BackendWorkerSummary,
+2 -2
View File
@@ -1029,7 +1029,7 @@ mod tests {
), ),
( (
"200 OK", "200 OK",
r#"{"workspace_id":"workspace-a","runtime_id":"embedded","worker_id":"worker-1","console_href":"/w/workspace-a/workers/worker-1","worker":{"runtime_id":"embedded","worker_id":"worker-1","host_id":"embedded","display_name":"Intake","label":"worker-1","profile":"builtin:intake","singleton_key":null,"tags":[],"workspace":{"visibility":"workspace","identity":"workspace-a","workspace_id":"workspace-a"},"state":"idle","last_seen_at":null,"pinned":false,"retention_state":"active","implementation":{"kind":"runtime","display_hint":"Runtime Worker"},"capabilities":{"can_stop":true,"can_spawn_followup":false},"diagnostics":[]},"diagnostics":[]}"#, r#"{"workspace_id":"workspace-a","runtime_id":"embedded","worker_id":"worker-1","console_href":"/w/workspace-a/workers/worker-1","worker":{"runtime_id":"embedded","worker_id":"worker-1","host_id":"embedded","display_name":"Intake","label":"worker-1","profile":"builtin:intake","singleton_key":null,"tags":[],"workspace":{"visibility":"workspace","identity":"workspace-a","workspace_id":"workspace-a"},"state":"idle","last_seen_at":null,"pinned":false,"retention_state":"active","implementation":{"kind":"runtime","display_hint":"Runtime Worker"},"diagnostics":[]},"diagnostics":[]}"#,
), ),
]); ]);
let client = BackendWorkspaceProductClient::new_with_access_token( let client = BackendWorkspaceProductClient::new_with_access_token(
@@ -1057,7 +1057,7 @@ mod tests {
#[test] #[test]
fn workspace_orchestrator_launch_uses_scoped_backend_route() { fn workspace_orchestrator_launch_uses_scoped_backend_route() {
let body = r#"{"workspace_id":"workspace-a","online":true,"disposition":"created","worker":{"runtime_id":"embedded","worker_id":"worker-2","host_id":"embedded","display_name":"Orchestrator","label":"worker-2","profile":"builtin:orchestrator","singleton_key":"workspace-orchestrator","tags":[],"workspace":{"visibility":"workspace","identity":"workspace-a","workspace_id":"workspace-a"},"state":"idle","last_seen_at":null,"pinned":true,"retention_state":"active","implementation":{"kind":"runtime","display_hint":"Runtime Worker"},"capabilities":{"can_stop":true,"can_spawn_followup":false},"diagnostics":[]},"diagnostics":[]}"#; let body = r#"{"workspace_id":"workspace-a","online":true,"disposition":"created","worker":{"runtime_id":"embedded","worker_id":"worker-2","host_id":"embedded","display_name":"Orchestrator","label":"worker-2","profile":"builtin:orchestrator","singleton_key":"workspace-orchestrator","tags":[],"workspace":{"visibility":"workspace","identity":"workspace-a","workspace_id":"workspace-a"},"state":"idle","last_seen_at":null,"pinned":true,"retention_state":"active","implementation":{"kind":"runtime","display_hint":"Runtime Worker"},"diagnostics":[]},"diagnostics":[]}"#;
let (base_url, request, handle) = one_response_server("200 OK", body); let (base_url, request, handle) = one_response_server("200 OK", body);
let client = BackendWorkspaceProductClient::new_with_access_token( let client = BackendWorkspaceProductClient::new_with_access_token(
base_url, base_url,
-16
View File
@@ -6892,7 +6892,6 @@ pub struct RuntimeWorkerSummary {
#[serde(default)] #[serde(default)]
pub retention_state: String, pub retention_state: String,
pub implementation: WorkerImplementationSummary, pub implementation: WorkerImplementationSummary,
pub capabilities: WorkerCapabilitySummary,
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "Vec::is_empty")]
pub workdir_attachments: Vec<serde_json::Value>, pub workdir_attachments: Vec<serde_json::Value>,
#[serde(default)] #[serde(default)]
@@ -7888,13 +7887,6 @@ pub struct WorkerImplementationSummary {
pub display_hint: String, pub display_hint: String,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
pub struct WorkerCapabilitySummary {
pub can_stop: bool,
pub can_spawn_followup: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))] #[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)] #[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)]
@@ -8120,7 +8112,6 @@ pub struct WorkerSummary {
#[serde(default)] #[serde(default)]
pub retention_state: String, pub retention_state: String,
pub implementation: WorkerImplementationSummary, pub implementation: WorkerImplementationSummary,
pub capabilities: WorkerCapabilitySummary,
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "Vec::is_empty")]
pub workdir_attachments: Vec<WorkerWorkdirAttachmentSummary>, pub workdir_attachments: Vec<WorkerWorkdirAttachmentSummary>,
#[serde(default)] #[serde(default)]
@@ -8163,7 +8154,6 @@ pub struct WorkerLaunchWorkerSummary {
pub pinned: bool, pub pinned: bool,
pub retention_state: String, pub retention_state: String,
pub implementation: WorkerImplementationSummary, pub implementation: WorkerImplementationSummary,
pub capabilities: WorkerCapabilitySummary,
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "Vec::is_empty")]
pub workdir_attachments: Vec<RuntimeWorkerWorkdirAttachmentSummary>, pub workdir_attachments: Vec<RuntimeWorkerWorkdirAttachmentSummary>,
#[serde(default)] #[serde(default)]
@@ -9339,7 +9329,6 @@ pub fn worker_launch_api_typescript() -> String {
WorkingDirectorySummary::decl(&config), WorkingDirectorySummary::decl(&config),
WorkerWorkspaceSummary::decl(&config), WorkerWorkspaceSummary::decl(&config),
WorkerImplementationSummary::decl(&config), WorkerImplementationSummary::decl(&config),
WorkerCapabilitySummary::decl(&config),
RuntimeWorkerWorkdirAttachmentSummary::decl(&config), RuntimeWorkerWorkdirAttachmentSummary::decl(&config),
WorkerLaunchWorkerSummary::decl(&config), WorkerLaunchWorkerSummary::decl(&config),
WorkerLaunchRuntimeOption::decl(&config), WorkerLaunchRuntimeOption::decl(&config),
@@ -10308,10 +10297,6 @@ mod tests {
kind: "runtime".to_string(), kind: "runtime".to_string(),
display_hint: "Runtime Worker".to_string(), display_hint: "Runtime Worker".to_string(),
}, },
capabilities: WorkerCapabilitySummary {
can_stop: true,
can_spawn_followup: false,
},
workdir_attachments: Vec::new(), workdir_attachments: Vec::new(),
diagnostics: Vec::new(), diagnostics: Vec::new(),
} }
@@ -10791,7 +10776,6 @@ mod tests {
}, },
"state": "idle", "state": "idle",
"implementation": {"kind": "worker", "display_hint": "Coder"}, "implementation": {"kind": "worker", "display_hint": "Coder"},
"capabilities": {"can_stop": true, "can_spawn_followup": false}
}); });
assert!(serde_json::from_value::<WorkerSummary>(payload).is_err()); assert!(serde_json::from_value::<WorkerSummary>(payload).is_err());
+2 -7
View File
@@ -552,9 +552,8 @@ fn working_directory_text(worker: &BackendWorkerSummary) -> String {
mod tests { mod tests {
use super::*; use super::*;
use client::{ use client::{
BackendDiagnostic, BackendDiagnosticSeverity, BackendWorkerCapabilitySummary, BackendDiagnostic, BackendDiagnosticSeverity, BackendWorkerImplementationSummary,
BackendWorkerImplementationSummary, BackendWorkerRestoreResult, BackendWorkerRestoreResult, BackendWorkerWorkspaceSummary,
BackendWorkerWorkspaceSummary,
}; };
fn worker(runtime_id: &str, worker_id: &str, profile: Option<&str>) -> BackendWorkerSummary { fn worker(runtime_id: &str, worker_id: &str, profile: Option<&str>) -> BackendWorkerSummary {
@@ -588,10 +587,6 @@ mod tests {
kind: "embedded".to_string(), kind: "embedded".to_string(),
display_hint: "embedded".to_string(), display_hint: "embedded".to_string(),
}, },
capabilities: BackendWorkerCapabilitySummary {
can_stop: true,
can_spawn_followup: false,
},
workdir_attachments: Vec::new(), workdir_attachments: Vec::new(),
diagnostics: Vec::new(), diagnostics: Vec::new(),
} }
+3 -1
View File
@@ -1298,7 +1298,9 @@ mod tests {
#[test] #[test]
fn runtime_owned_workspace_client_has_no_fixed_request_timeout() { fn runtime_owned_workspace_client_has_no_fixed_request_timeout() {
let (base_url, server) = delayed_workspace_response(Duration::from_millis(75)); // This must exceed reqwest::blocking::Client's default 30-second timeout.
// A short delay only checks our Option field, not the effective HTTP deadline.
let (base_url, server) = delayed_workspace_response(Duration::from_secs(31));
let client = let client =
RuntimeOwnedWorkspaceClient::new("workspace-a", base_url, "runtime-a", "worker-a"); RuntimeOwnedWorkspaceClient::new("workspace-a", base_url, "runtime-a", "worker-a");
assert_eq!(client.request_timeout, None); assert_eq!(client.request_timeout, None);
+26 -55
View File
@@ -240,12 +240,6 @@ pub struct InternalWorkerImplementationSummary {
pub display_hint: String, pub display_hint: String,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct InternalWorkerCapabilitySummary {
pub can_stop: bool,
pub can_spawn_followup: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct InternalWorkerSummary { pub struct InternalWorkerSummary {
#[serde(flatten)] #[serde(flatten)]
@@ -273,7 +267,6 @@ pub struct InternalWorkerSummary {
#[serde(default)] #[serde(default)]
pub retention_state: String, pub retention_state: String,
pub implementation: InternalWorkerImplementationSummary, pub implementation: InternalWorkerImplementationSummary,
pub capabilities: InternalWorkerCapabilitySummary,
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "Vec::is_empty")]
pub workdir_attachments: Vec<WorkingDirectoryAttachmentStatus>, pub workdir_attachments: Vec<WorkingDirectoryAttachmentStatus>,
pub diagnostics: Vec<RuntimeDiagnostic>, pub diagnostics: Vec<RuntimeDiagnostic>,
@@ -384,10 +377,6 @@ pub(crate) fn workspace_worker_summary(
kind: summary.implementation.kind, kind: summary.implementation.kind,
display_hint: summary.implementation.display_hint, display_hint: summary.implementation.display_hint,
}, },
capabilities: server_api::WorkerCapabilitySummary {
can_stop: summary.capabilities.can_stop,
can_spawn_followup: summary.capabilities.can_spawn_followup,
},
workdir_attachments, workdir_attachments,
diagnostics: summary.diagnostics.into_iter().map(Into::into).collect(), diagnostics: summary.diagnostics.into_iter().map(Into::into).collect(),
} }
@@ -2231,10 +2220,6 @@ impl EmbeddedWorkerRuntime {
Some(EmbeddedWorkerRef::new(EmbeddedWorkerId::parse(worker_id)?)) Some(EmbeddedWorkerRef::new(EmbeddedWorkerId::parse(worker_id)?))
} }
fn can_stop_embedded_worker(&self, status: EmbeddedWorkerStatus) -> bool {
runtime_worker_can_stop(self.execution_enabled, status)
}
fn map_worker_summary( fn map_worker_summary(
&self, &self,
summary: worker_runtime::catalog::WorkerSummary, summary: worker_runtime::catalog::WorkerSummary,
@@ -2274,11 +2259,6 @@ impl EmbeddedWorkerRuntime {
kind: "embedded_worker_runtime".to_string(), kind: "embedded_worker_runtime".to_string(),
display_hint: "backend-internal worker-runtime Worker".to_string(), display_hint: "backend-internal worker-runtime Worker".to_string(),
}, },
capabilities: InternalWorkerCapabilitySummary {
can_stop: summary.execution_metadata_available
&& self.can_stop_embedded_worker(summary.status),
can_spawn_followup: false,
},
workdir_attachments: summary.workdir_attachments, workdir_attachments: summary.workdir_attachments,
diagnostics: embedded_worker_projection_diagnostics( diagnostics: embedded_worker_projection_diagnostics(
summary.execution_metadata_available, summary.execution_metadata_available,
@@ -2319,11 +2299,6 @@ impl EmbeddedWorkerRuntime {
kind: "embedded_worker_runtime".to_string(), kind: "embedded_worker_runtime".to_string(),
display_hint: "backend-internal worker-runtime Worker".to_string(), display_hint: "backend-internal worker-runtime Worker".to_string(),
}, },
capabilities: InternalWorkerCapabilitySummary {
can_stop: detail.execution_metadata_available
&& self.can_stop_embedded_worker(detail.status),
can_spawn_followup: false,
},
workdir_attachments: detail.workdir_attachments, workdir_attachments: detail.workdir_attachments,
diagnostics: embedded_worker_projection_diagnostics( diagnostics: embedded_worker_projection_diagnostics(
detail.execution_metadata_available, detail.execution_metadata_available,
@@ -4127,11 +4102,6 @@ impl RemoteWorkerRuntime {
kind: "remote_worker_runtime".to_string(), kind: "remote_worker_runtime".to_string(),
display_hint: "Backend-proxied remote worker-runtime Worker".to_string(), display_hint: "Backend-proxied remote worker-runtime Worker".to_string(),
}, },
capabilities: InternalWorkerCapabilitySummary {
can_stop: summary.execution_metadata_available
&& runtime_worker_can_stop(true, summary.status),
can_spawn_followup: false,
},
workdir_attachments: summary.workdir_attachments, workdir_attachments: summary.workdir_attachments,
diagnostics: remote_worker_projection_diagnostics(summary.execution_metadata_available), diagnostics: remote_worker_projection_diagnostics(summary.execution_metadata_available),
} }
@@ -4170,11 +4140,6 @@ impl RemoteWorkerRuntime {
kind: "remote_worker_runtime".to_string(), kind: "remote_worker_runtime".to_string(),
display_hint: "Backend-proxied remote worker-runtime Worker".to_string(), display_hint: "Backend-proxied remote worker-runtime Worker".to_string(),
}, },
capabilities: InternalWorkerCapabilitySummary {
can_stop: detail.execution_metadata_available
&& runtime_worker_can_stop(true, detail.status),
can_spawn_followup: false,
},
workdir_attachments: detail.workdir_attachments, workdir_attachments: detail.workdir_attachments,
diagnostics: remote_worker_projection_diagnostics(detail.execution_metadata_available), diagnostics: remote_worker_projection_diagnostics(detail.execution_metadata_available),
} }
@@ -5152,10 +5117,6 @@ fn embedded_runtime_status_label(status: RuntimeStatus) -> &'static str {
} }
} }
fn runtime_worker_can_stop(execution_enabled: bool, status: EmbeddedWorkerStatus) -> bool {
execution_enabled && status.is_active()
}
fn embedded_worker_status_label(status: EmbeddedWorkerStatus) -> &'static str { fn embedded_worker_status_label(status: EmbeddedWorkerStatus) -> &'static str {
match status { match status {
EmbeddedWorkerStatus::Idle => "idle", EmbeddedWorkerStatus::Idle => "idle",
@@ -5963,10 +5924,6 @@ pub fn placeholder_worker(host_id: impl Into<String>) -> InternalWorkerSummary {
kind: "placeholder".to_string(), kind: "placeholder".to_string(),
display_hint: "unsupported".to_string(), display_hint: "unsupported".to_string(),
}, },
capabilities: InternalWorkerCapabilitySummary {
can_stop: false,
can_spawn_followup: false,
},
workdir_attachments: Vec::new(), workdir_attachments: Vec::new(),
diagnostics: vec![diagnostic( diagnostics: vec![diagnostic(
"runtime_capability_unsupported", "runtime_capability_unsupported",
@@ -6621,10 +6578,6 @@ mod tests {
kind: "fixture".to_string(), kind: "fixture".to_string(),
display_hint: "test fixture".to_string(), display_hint: "test fixture".to_string(),
}, },
capabilities: InternalWorkerCapabilitySummary {
can_stop: false,
can_spawn_followup: false,
},
workdir_attachments: Vec::new(), workdir_attachments: Vec::new(),
diagnostics: Vec::new(), diagnostics: Vec::new(),
}], }],
@@ -7123,7 +7076,12 @@ mod tests {
let spawned = runtime.spawn_worker(test_create_binding(), embedded_spawn_request()); let spawned = runtime.spawn_worker(test_create_binding(), embedded_spawn_request());
assert_eq!(spawned.state, InternalWorkerOperationState::Accepted); assert_eq!(spawned.state, InternalWorkerOperationState::Accepted);
let worker = spawned.worker.expect("created embedded worker"); let worker = spawned.worker.expect("created embedded worker");
assert!(worker.capabilities.can_stop); assert!(
serde_json::to_value(&worker)
.unwrap()
.get("capabilities")
.is_none()
);
let input = runtime.send_input( let input = runtime.send_input(
&worker.worker.worker_id, &worker.worker.worker_id,
@@ -7496,7 +7454,12 @@ mod tests {
workers.items[0].workspace.identity, workers.items[0].workspace.identity,
"runtime_registry_worker" "runtime_registry_worker"
); );
assert!(workers.items[0].capabilities.can_stop); assert!(
serde_json::to_value(&workers.items[0])
.unwrap()
.get("capabilities")
.is_none()
);
let input = registry let input = registry
.send_input( .send_input(
@@ -7581,11 +7544,14 @@ mod tests {
let workers = registry.list_workers(10); let workers = registry.list_workers(10);
assert_eq!(workers.items.len(), 5); assert_eq!(workers.items.len(), 5);
assert!(!workers.items[0].capabilities.can_stop); for worker in &workers.items {
assert!(workers.items[1].capabilities.can_stop); assert!(
assert!(workers.items[2].capabilities.can_stop); serde_json::to_value(worker)
assert!(workers.items[3].capabilities.can_stop); .unwrap()
assert!(!workers.items[4].capabilities.can_stop); .get("capabilities")
.is_none()
);
}
assert_eq!(workers.items[0].state, "stopped"); assert_eq!(workers.items[0].state, "stopped");
assert_eq!(workers.items[1].state, "running"); assert_eq!(workers.items[1].state, "running");
assert_eq!(workers.items[2].state, "paused"); assert_eq!(workers.items[2].state, "paused");
@@ -7601,7 +7567,12 @@ mod tests {
let stopped_detail = registry let stopped_detail = registry
.worker(&RuntimeWorkerRef::new("remote:primary", &worker_id)) .worker(&RuntimeWorkerRef::new("remote:primary", &worker_id))
.unwrap(); .unwrap();
assert!(!stopped_detail.capabilities.can_stop); assert!(
serde_json::to_value(&stopped_detail)
.unwrap()
.get("capabilities")
.is_none()
);
assert_eq!(stopped_detail.state, "stopped"); assert_eq!(stopped_detail.state, "stopped");
server.join().expect("mock remote server finished"); server.join().expect("mock remote server finished");
+22 -39
View File
@@ -152,17 +152,16 @@ use crate::companion::{
use crate::config_source::ConfigCommitRequest; use crate::config_source::ConfigCommitRequest;
use crate::hosts::{ use crate::hosts::{
EMBEDDED_RUNTIME_ID, EmbeddedWorkerRuntime, HostDiagnosticSeverity, InternalHostSummary, EMBEDDED_RUNTIME_ID, EmbeddedWorkerRuntime, HostDiagnosticSeverity, InternalHostSummary,
InternalWorkerCapabilitySummary, InternalWorkerImplementationSummary, InternalWorkerImplementationSummary, InternalWorkerOperationState, InternalWorkerRestoreResult,
InternalWorkerOperationState, InternalWorkerRestoreResult, InternalWorkerSummary, InternalWorkerSummary, InternalWorkerWorkspaceSummary, RemoteRuntimeConfig,
InternalWorkerWorkspaceSummary, RemoteRuntimeConfig, RemoteWorkerRuntime, RuntimeDiagnostic, RemoteWorkerRuntime, RuntimeDiagnostic, RuntimePingFailureKind, RuntimeRegistry,
RuntimePingFailureKind, RuntimeRegistry, RuntimeRegistryError, RuntimeRegistryUnregisterResult, RuntimeRegistryError, RuntimeRegistryUnregisterResult, TicketWorkerRole,
TicketWorkerRole, WorkerCompletionsRequest, WorkerCompletionsResult, WorkerControlOperation, WorkerCompletionsRequest, WorkerCompletionsResult, WorkerControlOperation, WorkerCreateBinding,
WorkerCreateBinding, WorkerInputKind, WorkerInputRequest, WorkerInputResult, WorkerInputKind, WorkerInputRequest, WorkerInputResult, WorkerLifecycleRequest,
WorkerLifecycleRequest, WorkerLifecycleResult, WorkerSpawnAcceptanceRequirement, WorkerLifecycleResult, WorkerSpawnAcceptanceRequirement, WorkerSpawnIntent, WorkerSpawnRequest,
WorkerSpawnIntent, WorkerSpawnRequest, WorkerSpawnResult, WorkerSpawnWorkingDirectoryRequest, WorkerSpawnResult, WorkerSpawnWorkingDirectoryRequest, WorkerTicketAssignmentRequest,
WorkerTicketAssignmentRequest, WorkspaceRuntimeAuthorization, WorkspaceRuntimeAuthorization, is_disallowed_remote_runtime_address,
is_disallowed_remote_runtime_address, is_loopback_runtime_origin, is_loopback_runtime_origin, worker_spawn_create_fingerprint, workspace_worker_summary,
worker_spawn_create_fingerprint, workspace_worker_summary,
}; };
use crate::memory_backend::execute_memory_backend_operation_with_authority; use crate::memory_backend::execute_memory_backend_operation_with_authority;
use crate::memory_staging::{ use crate::memory_staging::{
@@ -5175,10 +5174,6 @@ fn runtime_worker_summary_to_api(
kind: worker.implementation.kind, kind: worker.implementation.kind,
display_hint: worker.implementation.display_hint, display_hint: worker.implementation.display_hint,
}, },
capabilities: server_api::WorkerCapabilitySummary {
can_stop: worker.capabilities.can_stop,
can_spawn_followup: worker.capabilities.can_spawn_followup,
},
workdir_attachments: worker workdir_attachments: worker
.workdir_attachments .workdir_attachments
.into_iter() .into_iter()
@@ -16956,10 +16951,6 @@ fn worker_launch_worker_summary(worker: InternalWorkerSummary) -> WorkerLaunchWo
kind: worker.implementation.kind, kind: worker.implementation.kind,
display_hint: worker.implementation.display_hint, display_hint: worker.implementation.display_hint,
}, },
capabilities: server_api::WorkerCapabilitySummary {
can_stop: worker.capabilities.can_stop,
can_spawn_followup: worker.capabilities.can_spawn_followup,
},
workdir_attachments: worker workdir_attachments: worker
.workdir_attachments .workdir_attachments
.into_iter() .into_iter()
@@ -24806,10 +24797,6 @@ fn worker_summary_from_registry(record: &WorkerRegistryRecord) -> InternalWorker
last_seen_at: Some(record.updated_at.clone()), last_seen_at: Some(record.updated_at.clone()),
pinned: record.retention_state == "pinned", pinned: record.retention_state == "pinned",
retention_state: record.retention_state.clone(), retention_state: record.retention_state.clone(),
capabilities: InternalWorkerCapabilitySummary {
can_stop: false,
can_spawn_followup: false,
},
workspace: InternalWorkerWorkspaceSummary { workspace: InternalWorkerWorkspaceSummary {
visibility: "backend_registry".to_string(), visibility: "backend_registry".to_string(),
identity: record.workspace_id.clone(), identity: record.workspace_id.clone(),
@@ -24855,8 +24842,6 @@ fn worker_summary_from_projection(
.then(|| observation.worker.worker_state.clone()) .then(|| observation.worker.worker_state.clone())
.flatten(); .flatten();
summary.last_seen_at = Some(observation.observed_at.clone()); summary.last_seen_at = Some(observation.observed_at.clone());
summary.capabilities.can_stop = observed
&& observation.worker.state != protocol::subscription::SubscriptionWorkerState::Stopped;
summary.implementation.display_hint = if observed { summary.implementation.display_hint = if observed {
"Runtime-backed Worker".to_string() "Runtime-backed Worker".to_string()
} else { } else {
@@ -26709,7 +26694,12 @@ mod tests {
assert_eq!(unavailable.availability, availability); assert_eq!(unavailable.availability, availability);
assert_eq!(unavailable.state, "unavailable"); assert_eq!(unavailable.state, "unavailable");
assert_eq!(unavailable.worker_state, None); assert_eq!(unavailable.worker_state, None);
assert!(!unavailable.capabilities.can_stop); assert!(
serde_json::to_value(&unavailable)
.unwrap()
.get("capabilities")
.is_none()
);
let mut observed_stopped = projection; let mut observed_stopped = projection;
let observation = observed_stopped.observation.as_mut().unwrap(); let observation = observed_stopped.observation.as_mut().unwrap();
@@ -28645,10 +28635,6 @@ mod tests {
kind: "fixture".to_string(), kind: "fixture".to_string(),
display_hint: "Workdirless fixture".to_string(), display_hint: "Workdirless fixture".to_string(),
}, },
capabilities: InternalWorkerCapabilitySummary {
can_stop: true,
can_spawn_followup: false,
},
workdir_attachments: Vec::new(), workdir_attachments: Vec::new(),
diagnostics: Vec::new(), diagnostics: Vec::new(),
} }
@@ -40983,10 +40969,6 @@ mod tests {
kind: "remote".to_string(), kind: "remote".to_string(),
display_hint: "remote".to_string(), display_hint: "remote".to_string(),
}, },
capabilities: server_api::WorkerCapabilitySummary {
can_stop: true,
can_spawn_followup: false,
},
workdir_attachments: Vec::new(), workdir_attachments: Vec::new(),
diagnostics: Vec::new(), diagnostics: Vec::new(),
} }
@@ -41081,10 +41063,6 @@ mod tests {
kind: "remote".to_string(), kind: "remote".to_string(),
display_hint: "remote".to_string(), display_hint: "remote".to_string(),
}, },
capabilities: server_api::WorkerCapabilitySummary {
can_stop: true,
can_spawn_followup: false,
},
workdir_attachments: Vec::new(), workdir_attachments: Vec::new(),
diagnostics: Vec::new(), diagnostics: Vec::new(),
}], }],
@@ -43445,7 +43423,12 @@ mod tests {
// catalog remains controllable while its failed execution is represented in // catalog remains controllable while its failed execution is represented in
// `worker_state` rather than by removing the catalog Worker. // `worker_state` rather than by removing the catalog Worker.
assert_eq!(restored_worker.state, "idle"); assert_eq!(restored_worker.state, "idle");
assert!(restored_worker.capabilities.can_stop); assert!(
serde_json::to_value(&restored_worker)
.unwrap()
.get("capabilities")
.is_none()
);
let bundles = restored let bundles = restored
.runtime .runtime
+4 -35
View File
@@ -7448,9 +7448,6 @@
"$ref": "#/components/schemas/SubscriptionWorkerAvailability", "$ref": "#/components/schemas/SubscriptionWorkerAvailability",
"description": "Freshness of the Runtime observation used to construct `worker_state`.\n`Unavailable` means no current controller snapshot is being asserted." "description": "Freshness of the Runtime observation used to construct `worker_state`.\n`Unavailable` means no current controller snapshot is being asserted."
}, },
"capabilities": {
"$ref": "#/components/schemas/WorkerCapabilitySummary"
},
"diagnostics": { "diagnostics": {
"default": [], "default": [],
"items": { "items": {
@@ -7550,7 +7547,6 @@
"availability", "availability",
"state", "state",
"implementation", "implementation",
"capabilities",
"updated_at" "updated_at"
], ],
"type": "object" "type": "object"
@@ -7791,9 +7787,6 @@
"RuntimeWorkerSummary": { "RuntimeWorkerSummary": {
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"capabilities": {
"$ref": "#/components/schemas/WorkerCapabilitySummary"
},
"diagnostics": { "diagnostics": {
"default": [], "default": [],
"items": { "items": {
@@ -7872,8 +7865,7 @@
"label", "label",
"workspace", "workspace",
"state", "state",
"implementation", "implementation"
"capabilities"
], ],
"type": "object" "type": "object"
}, },
@@ -11254,21 +11246,6 @@
} }
] ]
}, },
"WorkerCapabilitySummary": {
"properties": {
"can_spawn_followup": {
"type": "boolean"
},
"can_stop": {
"type": "boolean"
}
},
"required": [
"can_stop",
"can_spawn_followup"
],
"type": "object"
},
"WorkerFileDeleteResponse": { "WorkerFileDeleteResponse": {
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
@@ -11447,9 +11424,6 @@
"additionalProperties": false, "additionalProperties": false,
"description": "Runtime-owned Worker summary embedded in Worker launch responses.\n\nThis preserves the existing launch wire shape. Workspace-owned Worker list\nand detail responses use [`WorkerSummary`] instead.", "description": "Runtime-owned Worker summary embedded in Worker launch responses.\n\nThis preserves the existing launch wire shape. Workspace-owned Worker list\nand detail responses use [`WorkerSummary`] instead.",
"properties": { "properties": {
"capabilities": {
"$ref": "#/components/schemas/WorkerCapabilitySummary"
},
"diagnostics": { "diagnostics": {
"default": [], "default": [],
"items": { "items": {
@@ -11529,8 +11503,7 @@
"state", "state",
"pinned", "pinned",
"retention_state", "retention_state",
"implementation", "implementation"
"capabilities"
], ],
"type": "object" "type": "object"
}, },
@@ -11830,9 +11803,6 @@
"$ref": "#/components/schemas/SubscriptionWorkerAvailability", "$ref": "#/components/schemas/SubscriptionWorkerAvailability",
"description": "Freshness of the Runtime observation used to construct `worker_state`.\n`Unavailable` means no current controller snapshot is being asserted." "description": "Freshness of the Runtime observation used to construct `worker_state`.\n`Unavailable` means no current controller snapshot is being asserted."
}, },
"capabilities": {
"$ref": "#/components/schemas/WorkerCapabilitySummary"
},
"diagnostics": { "diagnostics": {
"default": [], "default": [],
"items": { "items": {
@@ -11928,8 +11898,7 @@
"workspace", "workspace",
"availability", "availability",
"state", "state",
"implementation", "implementation"
"capabilities"
], ],
"type": "object" "type": "object"
}, },
@@ -14020,7 +13989,7 @@
"info": { "info": {
"title": "Yoi Server API", "title": "Yoi Server API",
"version": "0.1.0", "version": "0.1.0",
"x-yoi-source-digest": "sha256:49856606e4a16d138cc04a62a6096fd40fff213587b1cbf7f0594f28994a45b0" "x-yoi-source-digest": "sha256:ae559492220ec118f04c2c0c9593e8b3cb44c3cb857be3ae85715ace26da8043"
}, },
"openapi": "3.1.0", "openapi": "3.1.0",
"paths": { "paths": {
@@ -31,7 +31,6 @@ const worker = {
profile: "default", profile: "default",
tags: [], tags: [],
diagnostics: [], diagnostics: [],
capabilities: { can_stop: false, can_spawn_followup: false },
workspace: { workspace: {
workspace_id: workspaceId, workspace_id: workspaceId,
visibility: "workspace", visibility: "workspace",
@@ -1,6 +1,6 @@
// @generated by yoi-companion-openapi-typescript@1. Do not edit. // @generated by yoi-companion-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json // Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:49856606e4a16d138cc04a62a6096fd40fff213587b1cbf7f0594f28994a45b0) // Input contract: 0.1.0 (sha256:ae559492220ec118f04c2c0c9593e8b3cb44c3cb857be3ae85715ace26da8043)
// Options: companion-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output // Options: companion-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/companion-api.ts // Output: web/workspace/src/lib/generated/companion-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_companion_api_types -- --check // Regenerate/check: cargo run -q -p server-api --example generate_companion_api_types -- --check
@@ -1,6 +1,6 @@
// @generated by yoi-repository-openapi-typescript@1. Do not edit. // @generated by yoi-repository-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json // Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:49856606e4a16d138cc04a62a6096fd40fff213587b1cbf7f0594f28994a45b0) // Input contract: 0.1.0 (sha256:ae559492220ec118f04c2c0c9593e8b3cb44c3cb857be3ae85715ace26da8043)
// Options: repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output // Options: repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output
// Output: web/workspace/src/lib/generated/repository-api.ts // Output: web/workspace/src/lib/generated/repository-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_repository_openapi_types -- --check // Regenerate/check: cargo run -q -p server-api --example generate_repository_openapi_types -- --check
@@ -61,8 +61,6 @@ export type SubscriptionWorkerAvailability = "observed" | "unavailable";
export type WorkerBusyState = { kind: "run"; state: WorkerRunState; } | { kind: "maintenance"; state: WorkerMaintenanceState; }; export type WorkerBusyState = { kind: "run"; state: WorkerRunState; } | { kind: "maintenance"; state: WorkerMaintenanceState; };
export type WorkerCapabilitySummary = { can_spawn_followup: boolean; can_stop: boolean; };
export type WorkerImplementationSummary = { display_hint: string; kind: string; }; export type WorkerImplementationSummary = { display_hint: string; kind: string; };
export type WorkerMaintenanceState = "compacting"; export type WorkerMaintenanceState = "compacting";
@@ -73,7 +71,7 @@ export type WorkerState = { kind: "idle"; } | { kind: "busy"; state: WorkerBusyS
export type WorkerStateSnapshot = { last_command_id: number; state: WorkerState; }; export type WorkerStateSnapshot = { last_command_id: number; state: WorkerState; };
export type WorkerSummary = { availability: SubscriptionWorkerAvailability; capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; }; export type WorkerSummary = { availability: SubscriptionWorkerAvailability; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type WorkerWorkdirAttachmentSummary = { alias: string; effective_permissions: ExternalWorkdirPermissions; working_directory: WorkingDirectorySummary; }; export type WorkerWorkdirAttachmentSummary = { alias: string; effective_permissions: ExternalWorkdirPermissions; working_directory: WorkingDirectorySummary; };
@@ -1,6 +1,6 @@
// @generated by yoi-runtime-openapi-typescript@1. Do not edit. // @generated by yoi-runtime-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json // Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:49856606e4a16d138cc04a62a6096fd40fff213587b1cbf7f0594f28994a45b0) // Input contract: 0.1.0 (sha256:ae559492220ec118f04c2c0c9593e8b3cb44c3cb857be3ae85715ace26da8043)
// Options: runtime-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output // Options: runtime-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/runtime-api.ts // Output: web/workspace/src/lib/generated/runtime-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_runtime_api_types -- --check // Regenerate/check: cargo run -q -p server-api --example generate_runtime_api_types -- --check
@@ -107,7 +107,7 @@ export type RuntimeWorkerLifecycleResult = { diagnostics?: Array<Diagnostic>; ru
export type RuntimeWorkerListResponse = { diagnostics?: Array<Diagnostic>; items: Array<WorkerSummary>; limit: number; source: string; workspace_id: string; }; export type RuntimeWorkerListResponse = { diagnostics?: Array<Diagnostic>; items: Array<WorkerSummary>; limit: number; source: string; workspace_id: string; };
export type RuntimeWorkerShowResponse = { availability: SubscriptionWorkerAvailability; capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; updated_at: string; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; }; export type RuntimeWorkerShowResponse = { availability: SubscriptionWorkerAvailability; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; updated_at: string; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type RuntimeWorkerSpawnAcceptanceEvidence = { detail: string; kind: string; }; export type RuntimeWorkerSpawnAcceptanceEvidence = { detail: string; kind: string; };
@@ -123,7 +123,7 @@ export type RuntimeWorkerSpawnWorkingDirectoryAttachmentRequest = { alias: strin
export type RuntimeWorkerSpawnWorkingDirectoryRequest = { repository_key: string; selector?: string | null; }; export type RuntimeWorkerSpawnWorkingDirectoryRequest = { repository_key: string; selector?: string | null; };
export type RuntimeWorkerSummary = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<unknown>; worker_id: string; worker_state?: unknown; workspace: WorkerWorkspaceSummary; }; export type RuntimeWorkerSummary = { diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<unknown>; worker_id: string; worker_state?: unknown; workspace: WorkerWorkspaceSummary; };
export type RuntimeWorkerTicketAssignmentRequest = { operation_id: string; ticket_id: string; }; export type RuntimeWorkerTicketAssignmentRequest = { operation_id: string; ticket_id: string; };
@@ -137,8 +137,6 @@ export type UploadedFileRef = { artifact_id: string; availability: UploadedFileA
export type WorkerBusyState = { kind: "run"; state: WorkerRunState; } | { kind: "maintenance"; state: WorkerMaintenanceState; }; export type WorkerBusyState = { kind: "run"; state: WorkerRunState; } | { kind: "maintenance"; state: WorkerMaintenanceState; };
export type WorkerCapabilitySummary = { can_spawn_followup: boolean; can_stop: boolean; };
export type WorkerFileDeleteResponse = { deleted: boolean; }; export type WorkerFileDeleteResponse = { deleted: boolean; };
export type WorkerFileUploadResponse = { file: UploadedFileRef; }; export type WorkerFileUploadResponse = { file: UploadedFileRef; };
@@ -163,7 +161,7 @@ export type WorkerState = { kind: "idle"; } | { kind: "busy"; state: WorkerBusyS
export type WorkerStateSnapshot = { last_command_id: number; state: WorkerState; }; export type WorkerStateSnapshot = { last_command_id: number; state: WorkerState; };
export type WorkerSummary = { availability: SubscriptionWorkerAvailability; capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; }; export type WorkerSummary = { availability: SubscriptionWorkerAvailability; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type WorkerWorkdirAttachmentSummary = { alias: string; effective_permissions: ExternalWorkdirPermissions; working_directory: WorkingDirectorySummary; }; export type WorkerWorkdirAttachmentSummary = { alias: string; effective_permissions: ExternalWorkdirPermissions; working_directory: WorkingDirectorySummary; };
@@ -1,6 +1,6 @@
// @generated by yoi-ticket-browser-openapi-typescript@1. Do not edit. // @generated by yoi-ticket-browser-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json // Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:49856606e4a16d138cc04a62a6096fd40fff213587b1cbf7f0594f28994a45b0) // Input contract: 0.1.0 (sha256:ae559492220ec118f04c2c0c9593e8b3cb44c3cb857be3ae85715ace26da8043)
// Options: ticket-objective-merge-request-browser-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output // Options: ticket-objective-merge-request-browser-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/ticket-api.ts // Output: web/workspace/src/lib/generated/ticket-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_ticket_api_types -- --check // Regenerate/check: cargo run -q -p server-api --example generate_ticket_api_types -- --check
@@ -1,6 +1,6 @@
// @generated by yoi-worker-openapi-typescript@1. Do not edit. // @generated by yoi-worker-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json // Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:49856606e4a16d138cc04a62a6096fd40fff213587b1cbf7f0594f28994a45b0) // Input contract: 0.1.0 (sha256:ae559492220ec118f04c2c0c9593e8b3cb44c3cb857be3ae85715ace26da8043)
// Options: worker-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output // Options: worker-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/worker-launch-api.ts // Output: web/workspace/src/lib/generated/worker-launch-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_worker_launch_api_types -- --check // Regenerate/check: cargo run -q -p server-api --example generate_worker_launch_api_types -- --check
@@ -45,8 +45,6 @@ export type UploadedFileRef = { artifact_id: string; availability: UploadedFileA
export type WorkerBusyState = { kind: "run"; state: WorkerRunState; } | { kind: "maintenance"; state: WorkerMaintenanceState; }; export type WorkerBusyState = { kind: "run"; state: WorkerRunState; } | { kind: "maintenance"; state: WorkerMaintenanceState; };
export type WorkerCapabilitySummary = { can_spawn_followup: boolean; can_stop: boolean; };
export type WorkerImplementationSummary = { display_hint: string; kind: string; }; export type WorkerImplementationSummary = { display_hint: string; kind: string; };
export type WorkerLaunchOptionsResponse = { default_profile?: string | null; diagnostics: Array<Diagnostic>; profiles: Array<WorkerLaunchProfileCandidate>; repositories: Array<WorkingDirectoryRepositoryOption>; runtimes: Array<WorkerLaunchRuntimeOption>; working_directories: Array<WorkingDirectorySummary>; workspace_id: string; }; export type WorkerLaunchOptionsResponse = { default_profile?: string | null; diagnostics: Array<Diagnostic>; profiles: Array<WorkerLaunchProfileCandidate>; repositories: Array<WorkingDirectoryRepositoryOption>; runtimes: Array<WorkerLaunchRuntimeOption>; working_directories: Array<WorkingDirectorySummary>; workspace_id: string; };
@@ -55,7 +53,7 @@ export type WorkerLaunchProfileCandidate = { description: string; id: string; la
export type WorkerLaunchRuntimeOption = { built_in: boolean; diagnostics: Array<Diagnostic>; display_name: string; runtime_id: string; status: string; worker_creation_available: boolean; working_directory_required: boolean; }; export type WorkerLaunchRuntimeOption = { built_in: boolean; diagnostics: Array<Diagnostic>; display_name: string; runtime_id: string; status: string; worker_creation_available: boolean; working_directory_required: boolean; };
export type WorkerLaunchWorkerSummary = { capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned: boolean; profile?: string | null; retention_state: string; runtime_id: string; singleton_key?: string | null; state: string; tags: Array<string>; workdir_attachments?: Array<RuntimeWorkerWorkdirAttachmentSummary>; worker_id: string; workspace: WorkerWorkspaceSummary; }; export type WorkerLaunchWorkerSummary = { diagnostics?: Array<Diagnostic>; display_name: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned: boolean; profile?: string | null; retention_state: string; runtime_id: string; singleton_key?: string | null; state: string; tags: Array<string>; workdir_attachments?: Array<RuntimeWorkerWorkdirAttachmentSummary>; worker_id: string; workspace: WorkerWorkspaceSummary; };
export type WorkerListResponse = { diagnostics?: Array<Diagnostic>; items: Array<WorkerSummary>; limit: number; source: string; workspace_id: string; }; export type WorkerListResponse = { diagnostics?: Array<Diagnostic>; items: Array<WorkerSummary>; limit: number; source: string; workspace_id: string; };
@@ -67,7 +65,7 @@ export type WorkerState = { kind: "idle"; } | { kind: "busy"; state: WorkerBusyS
export type WorkerStateSnapshot = { last_command_id: number; state: WorkerState; }; export type WorkerStateSnapshot = { last_command_id: number; state: WorkerState; };
export type WorkerSummary = { availability: SubscriptionWorkerAvailability; capabilities: WorkerCapabilitySummary; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; }; export type WorkerSummary = { availability: SubscriptionWorkerAvailability; diagnostics?: Array<Diagnostic>; display_name?: string; host_id: string; implementation: WorkerImplementationSummary; label: string; last_seen_at?: string | null; pinned?: boolean; profile?: string | null; resource_key: string; retention_state?: string; runtime_id: string; singleton_key?: string | null; state: string; tags?: Array<string>; workdir_attachments?: Array<WorkerWorkdirAttachmentSummary>; worker_id: string; worker_state?: WorkerStateSnapshot | null; workspace: WorkerWorkspaceSummary; };
export type WorkerWorkdirAttachmentSummary = { alias: string; effective_permissions: ExternalWorkdirPermissions; working_directory: WorkingDirectorySummary; }; export type WorkerWorkdirAttachmentSummary = { alias: string; effective_permissions: ExternalWorkdirPermissions; working_directory: WorkingDirectorySummary; };
@@ -56,13 +56,28 @@ const worker = {
kind: "runtime", kind: "runtime",
display_hint: "Runtime Worker", display_hint: "Runtime Worker",
}, },
capabilities: {
can_stop: true,
can_spawn_followup: false,
},
diagnostics: [], diagnostics: [],
}; };
Deno.test("Worker summaries omit the removed management capabilities field", () => {
const summary = { ...worker, resource_key: "W-1", availability: "observed" };
assertEquals("capabilities" in parseWorkerSummary(summary), false);
assertThrows(
() => parseWorkerSummary({ ...summary, capabilities: {} }),
Error,
"unknown field capabilities",
);
const created = parseBrowserCreateWorkerResponse({
workspace_id: "workspace-a",
runtime_id: "runtime-a",
worker_id: "worker-a",
console_href: "/w/workspace-a/workers/W-1/console",
worker,
diagnostics: [],
});
assertEquals("capabilities" in created.worker, false);
});
Deno.test("Worker summary parser enforces observation freshness", () => { Deno.test("Worker summary parser enforces observation freshness", () => {
const unavailable = { const unavailable = {
...worker, ...worker,
@@ -10,7 +10,6 @@ import type {
RuntimeWorkerWorkdirAttachmentSummary, RuntimeWorkerWorkdirAttachmentSummary,
RuntimeWorkingDirectoryCleanupTarget, RuntimeWorkingDirectoryCleanupTarget,
RuntimeWorkingDirectorySummary, RuntimeWorkingDirectorySummary,
WorkerCapabilitySummary,
WorkerImplementationSummary, WorkerImplementationSummary,
WorkerLaunchOptionsResponse, WorkerLaunchOptionsResponse,
WorkerLaunchProfileCandidate, WorkerLaunchProfileCandidate,
@@ -251,21 +250,6 @@ function implementationSummary(
}; };
} }
function capabilitySummary(
value: unknown,
label: string,
): WorkerCapabilitySummary {
const item = record(value, label);
exact(item, ["can_stop", "can_spawn_followup"], label);
return {
can_stop: boolean(item.can_stop, `${label}.can_stop`),
can_spawn_followup: boolean(
item.can_spawn_followup,
`${label}.can_spawn_followup`,
),
};
}
function workerStateSnapshot( function workerStateSnapshot(
value: unknown, value: unknown,
label: string, label: string,
@@ -374,7 +358,6 @@ export function parseWorkerSummary(
"pinned", "pinned",
"retention_state", "retention_state",
"implementation", "implementation",
"capabilities",
"workdir_attachments", "workdir_attachments",
"diagnostics", "diagnostics",
], ],
@@ -423,7 +406,6 @@ export function parseWorkerSummary(
item.implementation, item.implementation,
`${label}.implementation`, `${label}.implementation`,
), ),
capabilities: capabilitySummary(item.capabilities, `${label}.capabilities`),
workdir_attachments: item.workdir_attachments === undefined workdir_attachments: item.workdir_attachments === undefined
? undefined ? undefined
: array( : array(
@@ -617,7 +599,6 @@ function workerSummary(
"pinned", "pinned",
"retention_state", "retention_state",
"implementation", "implementation",
"capabilities",
"workdir_attachments", "workdir_attachments",
"diagnostics", "diagnostics",
], ],
@@ -641,7 +622,6 @@ function workerSummary(
item.implementation, item.implementation,
`${label}.implementation`, `${label}.implementation`,
), ),
capabilities: capabilitySummary(item.capabilities, `${label}.capabilities`),
workdir_attachments: item.workdir_attachments === undefined workdir_attachments: item.workdir_attachments === undefined
? undefined ? undefined
: array( : array(
@@ -3,6 +3,7 @@
import { workerConsoleHref } from '$lib/workspace/resource-links'; import { workerConsoleHref } from '$lib/workspace/resource-links';
import { pushWorkspaceAlert } from '$lib/workspace/alerts/store'; import { pushWorkspaceAlert } from '$lib/workspace/alerts/store';
import { import {
canStopSidebarWorker,
canDeleteSidebarWorker, canDeleteSidebarWorker,
deleteSidebarWorker, deleteSidebarWorker,
stopSidebarWorker, stopSidebarWorker,
@@ -91,14 +92,14 @@
} }
async function stopWorker(worker: SidebarWorker) { async function stopWorker(worker: SidebarWorker) {
if (busyAction || !worker.capabilities.can_stop) return; if (busyAction || !canStopSidebarWorker(worker)) return;
closeWorkerMenu(); closeWorkerMenu();
busyAction = { workerKey: workerKey(worker), kind: 'stop' }; busyAction = { workerKey: workerKey(worker), kind: 'stop' };
try { try {
await stopSidebarWorker(workspaceId, worker); await stopSidebarWorker(workspaceId, worker);
workers = workers.map((item) => workers = workers.map((item) =>
workerKey(item) === workerKey(worker) workerKey(item) === workerKey(worker)
? { ...item, state: 'stopped', capabilities: { ...item.capabilities, can_stop: false } } ? { ...item, state: 'stopped', lifecycleState: 'stopped' }
: item : item
); );
pushWorkspaceAlert('info', `${worker.display_name || worker.label} stopped`, { pushWorkspaceAlert('info', `${worker.display_name || worker.label} stopped`, {
@@ -226,7 +227,7 @@
<button <button
type="button" type="button"
role="menuitem" role="menuitem"
disabled={busyAction !== null || !worker.capabilities.can_stop} disabled={busyAction !== null || !canStopSidebarWorker(worker)}
onclick={() => stopWorker(worker)} onclick={() => stopWorker(worker)}
> >
{isBusy(worker, 'stop') ? 'Stopping…' : 'Stop'} {isBusy(worker, 'stop') ? 'Stopping…' : 'Stop'}
@@ -10,7 +10,6 @@ import type {
BrowserWorkerWorkingDirectorySelection BrowserWorkerWorkingDirectorySelection
as SharedBrowserWorkerWorkingDirectorySelection, as SharedBrowserWorkerWorkingDirectorySelection,
Diagnostic as SharedDiagnostic, Diagnostic as SharedDiagnostic,
WorkerCapabilitySummary as SharedWorkerCapabilitySummary,
WorkerLaunchOptionsResponse as SharedWorkerLaunchOptionsResponse, WorkerLaunchOptionsResponse as SharedWorkerLaunchOptionsResponse,
WorkerLaunchProfileCandidate as SharedWorkerLaunchProfileCandidate, WorkerLaunchProfileCandidate as SharedWorkerLaunchProfileCandidate,
WorkerLaunchRuntimeOption as SharedWorkerLaunchRuntimeOption, WorkerLaunchRuntimeOption as SharedWorkerLaunchRuntimeOption,
@@ -78,8 +77,6 @@ export type Runtime = {
}; };
}; };
export type WorkerCapabilities = SharedWorkerCapabilitySummary;
export type WorkerWorkdirAttachment = SharedWorkerWorkdirAttachmentSummary; export type WorkerWorkdirAttachment = SharedWorkerWorkdirAttachmentSummary;
export type Worker = export type Worker =
@@ -4,10 +4,7 @@ import {
parseRuntimeCleanupPlan, parseRuntimeCleanupPlan,
parseRuntimeWorkerLifecycleResult, parseRuntimeWorkerLifecycleResult,
} from "$lib/workspace/api/runtime-workers"; } from "$lib/workspace/api/runtime-workers";
import type { import type { Diagnostic, Worker } from "./types";
Diagnostic,
Worker,
} from "./types";
type FetchFn = typeof fetch; type FetchFn = typeof fetch;
type WorkerActionTarget = Pick<Worker, "runtime_id" | "worker_id" | "state">; type WorkerActionTarget = Pick<Worker, "runtime_id" | "worker_id" | "state">;
@@ -25,13 +22,17 @@ async function responseError(response: Response): Promise<string> {
const fallback = `${response.status} ${response.statusText}`.trim(); const fallback = `${response.status} ${response.statusText}`.trim();
try { try {
const payload: unknown = await response.json(); const payload: unknown = await response.json();
if (typeof payload !== "object" || payload === null || Array.isArray(payload)) { if (
typeof payload !== "object" || payload === null || Array.isArray(payload)
) {
return fallback; return fallback;
} }
const record = payload as Record<string, unknown>; const record = payload as Record<string, unknown>;
if (typeof record.message === "string") return record.message.slice(0, 512); if (typeof record.message === "string") return record.message.slice(0, 512);
const nested = record.error; const nested = record.error;
if (typeof nested === "object" && nested !== null && !Array.isArray(nested)) { if (
typeof nested === "object" && nested !== null && !Array.isArray(nested)
) {
const message = (nested as Record<string, unknown>).message; const message = (nested as Record<string, unknown>).message;
if (typeof message === "string") return message.slice(0, 512); if (typeof message === "string") return message.slice(0, 512);
} }
@@ -51,6 +52,14 @@ function diagnosticMessage(
fallback; fallback;
} }
export function canStopSidebarWorker(worker: {
availability: Worker["availability"];
lifecycleState: string;
}): boolean {
return worker.availability === "observed" &&
["idle", "running", "paused"].includes(worker.lifecycleState);
}
export function canDeleteSidebarWorker(worker: WorkerActionTarget): boolean { export function canDeleteSidebarWorker(worker: WorkerActionTarget): boolean {
return worker.state === "stopped"; return worker.state === "stopped";
} }
@@ -112,7 +121,9 @@ export async function deleteSidebarWorker(
throw new Error(await responseError(executionResponse)); throw new Error(await responseError(executionResponse));
} }
const execution = parseRuntimeCleanupExecution(await executionResponse.json()); const execution = parseRuntimeCleanupExecution(
await executionResponse.json(),
);
const outcome = execution.results.find((result) => const outcome = execution.results.find((result) =>
result.target_id === candidate.target_id result.target_id === candidate.target_id
); );
@@ -0,0 +1,136 @@
// @vitest-environment happy-dom
import {
cleanup,
fireEvent,
render,
screen,
waitFor,
} from "@testing-library/svelte";
import { afterEach, expect, test, vi } from "vitest";
import type {
SubscriptionFrame,
SubscriptionWorker,
} from "$lib/generated/protocol";
import WorkersNavSection from "./WorkersNavSection.svelte";
import { disposeWorkspaceWorkersStore } from "./worker-subscription";
const transport = vi.hoisted(() => ({
listener: null as { onFrame(frame: SubscriptionFrame): void } | null,
close: vi.fn(),
}));
vi.mock("$lib/workspace/multiplexer", () => ({
workspaceMultiplexer: () => ({
subscribe: (
_selector: unknown,
listener: NonNullable<typeof transport.listener>,
) => {
transport.listener = listener;
return { close: transport.close };
},
}),
}));
afterEach(() => {
cleanup();
disposeWorkspaceWorkersStore("stop-test");
transport.listener = null;
vi.unstubAllGlobals();
});
function snapshot(
state: SubscriptionWorker["state"],
availability: SubscriptionWorker["availability"],
): SubscriptionFrame {
return {
protocol_version: 1,
frame: "response",
message: {
result: "subscribed",
payload: {
request_id: "request-1",
subscription_id: "subscription-1",
selector: { topic: "workspace_workers" },
snapshot_revision: 1,
snapshot: {
topic: "workers",
data: {
workers: [{
worker_id: "worker-a",
runtime_id: "runtime-a",
resource_key: "W-1",
availability,
subject_revision: 1,
state,
// An absent foreground snapshot must not prevent stopping an active catalog Worker.
worker_state: null,
has_running_internal_workers: false,
display_name: "Test worker",
workspace_id: "stop-test",
workdir_attachments: [],
}],
},
},
},
},
};
}
test.each(["idle", "running", "paused", "stopped"] as const)(
"Stop uses observed catalog state without capabilities (%s)",
async (state) => {
const request = vi.fn(async (input: RequestInfo | URL) =>
String(input).endsWith("/stop")
? Response.json({
state: "accepted",
runtime_id: "runtime-a",
worker_id: "worker-a",
diagnostics: [],
})
: new Response(null, { status: 404 })
);
vi.stubGlobal("fetch", request);
render(WorkersNavSection, { workspaceId: "stop-test" });
await waitFor(() => expect(transport.listener).not.toBeNull());
transport.listener!.onFrame(snapshot(state, "observed"));
await fireEvent.click(
await screen.findByRole("button", { name: "Actions for Test worker" }),
);
const stop = screen.getByRole("menuitem", {
name: "Stop",
}) as HTMLButtonElement;
expect(stop.disabled).toBe(state === "stopped");
if (state === "stopped") return;
await fireEvent.click(stop);
await waitFor(() =>
expect(request.mock.calls.some(([url]) => String(url).endsWith("/stop")))
.toBe(true)
);
await fireEvent.click(
screen.getByRole("button", { name: "Actions for Test worker" }),
);
await waitFor(() =>
expect(
(screen.getByRole("menuitem", { name: "Stop" }) as HTMLButtonElement)
.disabled,
).toBe(true)
);
},
);
test("Unavailable observation disables Stop even when catalog state is running", async () => {
vi.stubGlobal(
"fetch",
vi.fn(async () => new Response(null, { status: 404 })),
);
render(WorkersNavSection, { workspaceId: "stop-test" });
await waitFor(() => expect(transport.listener).not.toBeNull());
transport.listener!.onFrame(snapshot("running", "unavailable"));
await fireEvent.click(
await screen.findByRole("button", { name: "Actions for Test worker" }),
);
expect(
(screen.getByRole("menuitem", { name: "Stop" }) as HTMLButtonElement)
.disabled,
).toBe(true);
});
@@ -16,6 +16,8 @@ import type { Worker } from "./types";
export type SidebarWorker = Omit<Worker, "workdir_attachments"> & { export type SidebarWorker = Omit<Worker, "workdir_attachments"> & {
workdir_attachments: SidebarWorkdirAttachment[]; workdir_attachments: SidebarWorkdirAttachment[];
has_running_internal_workers: boolean; has_running_internal_workers: boolean;
/** Catalog lifecycle, independent of the possibly unknown foreground display state. */
lifecycleState: SubscriptionWorker["state"];
}; };
export type WorkspaceWorkersState = { export type WorkspaceWorkersState = {
@@ -148,6 +150,7 @@ function projectWorker(
}, },
availability: worker.availability, availability: worker.availability,
state: liveWorkerState(worker), state: liveWorkerState(worker),
lifecycleState: worker.state,
worker_state: worker.worker_state, worker_state: worker.worker_state,
pinned: false, pinned: false,
retention_state: "transient", retention_state: "transient",
@@ -155,11 +158,6 @@ function projectWorker(
kind: "runtime_subscription_worker", kind: "runtime_subscription_worker",
display_hint: "Workspace-authorized Runtime Worker", display_hint: "Workspace-authorized Runtime Worker",
}, },
capabilities: {
can_stop: worker.availability !== "unavailable" &&
worker.state !== "stopped",
can_spawn_followup: false,
},
workdir_attachments: (worker.workdir_attachments ?? []).map(( workdir_attachments: (worker.workdir_attachments ?? []).map((
attachment, attachment,
) => ({ ) => ({
@@ -38,10 +38,6 @@ function worker(overrides: Partial<Worker>): Worker {
kind: "runtime_worker", kind: "runtime_worker",
display_hint: "Runtime Worker", display_hint: "Runtime Worker",
}, },
capabilities: {
can_stop: true,
can_spawn_followup: false,
},
workdir_attachments: [], workdir_attachments: [],
diagnostics: [], diagnostics: [],
...overrides, ...overrides,
@@ -56,10 +52,6 @@ Deno.test("registry-only workers are not sidebar targets or console targets", ()
kind: "backend_worker_registry", kind: "backend_worker_registry",
display_hint: "Missing Worker", display_hint: "Missing Worker",
}, },
capabilities: {
can_stop: false,
can_spawn_followup: false,
},
}); });
assertEquals(canShowWorkerInSidebar(registryOnly), false); assertEquals(canShowWorkerInSidebar(registryOnly), false);
assertEquals(canOpenWorkerConsole(registryOnly), false); assertEquals(canOpenWorkerConsole(registryOnly), false);
@@ -1935,22 +1935,6 @@
</dd> </dd>
</div> </div>
</dl> </dl>
<details class="metadata-details">
<summary>Capabilities</summary>
<ul>
<li>
stop: {worker.capabilities.can_stop
? "available"
: "unsupported"}
</li>
<li>
follow-up spawn: {worker.capabilities
.can_spawn_followup
? "available"
: "unsupported"}
</li>
</ul>
</details>
{:else if !workerError} {:else if !workerError}
<p>Loading Worker detail…</p> <p>Loading Worker detail…</p>
{/if} {/if}
@@ -62,10 +62,6 @@ function worker(workerId = "worker-a", runtimeId = "runtime-a"): Worker {
profile: "default", profile: "default",
tags: [], tags: [],
diagnostics: [], diagnostics: [],
capabilities: {
can_stop: true,
can_spawn_followup: true,
},
workspace: { visibility: "workspace", identity: "workspace-a" }, workspace: { visibility: "workspace", identity: "workspace-a" },
implementation: { kind: "builtin", display_hint: "test" }, implementation: { kind: "builtin", display_hint: "test" },
workdir_attachments: [], workdir_attachments: [],
@@ -1,5 +1,6 @@
import { import {
canDeleteSidebarWorker, canDeleteSidebarWorker,
canStopSidebarWorker,
deleteSidebarWorker, deleteSidebarWorker,
stopSidebarWorker, stopSidebarWorker,
} from "../../src/lib/workspace/sidebar/worker-actions.ts"; } from "../../src/lib/workspace/sidebar/worker-actions.ts";
@@ -41,7 +42,6 @@ const worker = {
runtime_id: "runtime /", runtime_id: "runtime /",
worker_id: "worker /", worker_id: "worker /",
state: "running", state: "running",
capabilities: { can_stop: true },
} as Worker; } as Worker;
function jsonResponse(payload: unknown, status = 200): Response { function jsonResponse(payload: unknown, status = 200): Response {
@@ -51,6 +51,33 @@ function jsonResponse(payload: unknown, status = 200): Response {
}); });
} }
Deno.test("sidebar Stop follows observed catalog lifecycle, not foreground display state", () => {
for (const lifecycleState of ["idle", "running", "paused"]) {
const target = {
availability: "observed" as const,
lifecycleState,
state: "unknown",
};
assert(canStopSidebarWorker(target));
assert(!canStopSidebarWorker({ ...target, availability: "unavailable" }));
}
for (
const lifecycleState of [
"stopped",
"missing",
"execution_unavailable",
"unknown",
]
) {
const target = {
availability: "observed" as const,
lifecycleState,
state: "running",
};
assert(!canStopSidebarWorker(target));
}
});
Deno.test("sidebar Stop uses the workspace-scoped Worker lifecycle endpoint", async () => { Deno.test("sidebar Stop uses the workspace-scoped Worker lifecycle endpoint", async () => {
const requests: Array<{ url: string; init?: RequestInit }> = []; const requests: Array<{ url: string; init?: RequestInit }> = [];
const fetchFn = (async (input: RequestInfo | URL, init?: RequestInit) => { const fetchFn = (async (input: RequestInfo | URL, init?: RequestInit) => {