feat: migrate workspace worker and companion domains to ServerApi

This commit is contained in:
2026-09-23 10:00:56 +09:00
parent ad12d77ad4
commit 89024d3b01
28 changed files with 7471 additions and 819 deletions
+21 -33
View File
@@ -393,15 +393,16 @@ async fn get_backend_worker_launch_options_with_client(
target: &BackendWorkerLaunchTarget,
api: &BackendApiClient,
) -> Result<BackendWorkerLaunchOptions, BackendRuntimeClientError> {
let path = backend_workspace_workers_launch_options_path(
target
.workspace_id
.as_deref()
.expect("validated Backend Workspace scope"),
);
let response = api.request(HttpMethod::GET, &path)?.send().await?;
let response = api.require_success(response).await?;
Ok(response.json::<BackendWorkerLaunchOptions>().await?)
runtime_server_api_client(&target.base_url, api)?
.workspace_worker_launch_options(
target
.workspace_id
.as_deref()
.expect("validated Backend Workspace scope")
.to_string(),
)
.await
.map_err(Into::into)
}
pub async fn create_backend_worker(
@@ -418,19 +419,17 @@ async fn create_backend_worker_with_client(
request: &BackendCreateWorkerRequest,
api: &BackendApiClient,
) -> Result<BackendCreateWorkerResponse, BackendRuntimeClientError> {
let path = backend_workspace_workers_path(
target
.workspace_id
.as_deref()
.expect("validated Backend Workspace scope"),
);
let response = api
.request(HttpMethod::POST, &path)?
.json(request)
.send()
.await?;
let response = api.require_success(response).await?;
Ok(response.json::<BackendCreateWorkerResponse>().await?)
runtime_server_api_client(&target.base_url, api)?
.workspace_worker_create(
target
.workspace_id
.as_deref()
.expect("validated Backend Workspace scope")
.to_string(),
request.clone(),
)
.await
.map_err(Into::into)
}
pub async fn list_backend_workers(
@@ -680,17 +679,6 @@ fn validate_list_target(
Ok(())
}
fn backend_workspace_workers_path(workspace_id: &str) -> String {
format!("/api/w/{}/workers", path_segment_encode(workspace_id))
}
fn backend_workspace_workers_launch_options_path(workspace_id: &str) -> String {
format!(
"{}/launch-options",
backend_workspace_workers_path(workspace_id)
)
}
fn protocol_ws_request(
target: &BackendRuntimeTarget,
api: &BackendApiClient,
+13 -40
View File
@@ -1,6 +1,3 @@
use reqwest::Method;
use serde::Serialize;
use serde::de::DeserializeOwned;
use server_api::{
BrowserCreateWorkerResponse, BrowserWorkspaceOrchestratorResponse,
CreateWorkspaceWorkerRequest, ListResponse, MemoryDocumentResponse, MemoryStagingListResponse,
@@ -417,7 +414,10 @@ impl BackendWorkspaceProductClient {
&self,
ticket_id: &str,
) -> Result<String, BackendWorkspaceClientError> {
let options: WorkerLaunchOptionsResponse = self.get_json("/workers/launch-options")?;
let workspace_id = self.workspace_id.clone();
let options: WorkerLaunchOptionsResponse = self.generated(move |client| async move {
client.workspace_worker_launch_options(workspace_id).await
})?;
let runtime = options
.runtimes
.iter()
@@ -439,8 +439,10 @@ impl BackendWorkspaceProductClient {
workdir_attachments: Vec::new(),
control_operation_id: None,
};
let response: BrowserCreateWorkerResponse =
self.send_json(Method::POST, "/workers", Some(&request))?;
let workspace_id = self.workspace_id.clone();
let response: BrowserCreateWorkerResponse = self.generated(move |client| async move {
client.workspace_worker_create(workspace_id, request).await
})?;
Ok(format!(
"Started Intake Worker {}/{} for Ticket {ticket_id}",
response.runtime_id, response.worker_id
@@ -448,8 +450,11 @@ impl BackendWorkspaceProductClient {
}
pub fn start_workspace_orchestrator(&self) -> Result<String, BackendWorkspaceClientError> {
let workspace_id = self.workspace_id.clone();
let response: BrowserWorkspaceOrchestratorResponse =
self.send_json::<(), _>(Method::POST, "/orchestrator", None)?;
self.generated(move |client| async move {
client.workspace_orchestrator_start(workspace_id).await
})?;
let worker = response.worker.ok_or_else(|| {
BackendWorkspaceClientError::InvalidTarget(
"Backend accepted the Orchestrator request without returning a Worker".to_string(),
@@ -464,39 +469,6 @@ impl BackendWorkspaceProductClient {
pub fn default_product_list_limit() -> usize {
DEFAULT_PRODUCT_LIST_LIMIT
}
fn get_json<R: DeserializeOwned>(&self, path: &str) -> Result<R, BackendWorkspaceClientError> {
self.send_json::<(), R>(Method::GET, path, None)
}
fn send_json<B: Serialize + ?Sized, R: DeserializeOwned>(
&self,
method: Method,
path: &str,
body: Option<&B>,
) -> Result<R, BackendWorkspaceClientError> {
let response = self.request(method, path, body)?.send()?;
self.api.check_status(response.status())?;
response.json().map_err(BackendWorkspaceClientError::Http)
}
fn request<B: Serialize + ?Sized>(
&self,
method: Method,
path: &str,
body: Option<&B>,
) -> Result<reqwest::blocking::RequestBuilder, BackendWorkspaceClientError> {
let path = format!(
"/api/w/{}/{}",
encode_path_segment(&self.workspace_id),
path.trim_start_matches('/')
);
let request = self.api.blocking_request(method, &path)?;
Ok(match body {
Some(body) => request.json(body),
None => request,
})
}
}
impl TicketBackend for BackendWorkspaceProductClient {
@@ -785,6 +757,7 @@ fn ticket_list_state_query(query: &TicketListQuery) -> String {
}
}
#[cfg(test)]
fn encode_path_segment(value: &str) -> String {
let mut encoded = String::with_capacity(value.len());
for byte in value.bytes() {