Topology P-zc 1A: ZeroClawDriveExecutor — real role-agents over /ws/chat
cm-orchestrator owns the topology graph; each turn now drives a real ZeroClaw
role-agent in a container via the proven gateway drive recipe, instead of a
tool-free cm-llm call.
- crates/cm-api/src/topology_exec.rs: ZeroClawDriveExecutor impl TurnExecutor —
pair (POST /pair + X-Pairing-Code, token cached) -> ws /ws/chat?agent=<alias>
-> send {type:message,content} -> drain chunk/done/approval_request/error.
approval_request is recorded as a BLOCKED GatedAction, never auto-approved (§15).
Role->alias via ZEROCLAW_AGENT_MAP, fallback ZEROCLAW_DEFAULT_AGENT (scout).
- POST /api/topologies/run {task,graph} -> execute() -> RunRecord, persisted
best-effort to the existing topology_runs table (no migration). compare stays
tool-free. from_env() is read in-handler so cm-api still boots unset.
- deploy/clawmates-runtime: example config now declares a tool-free multi-agent
role-cast; README documents the ZEROCLAW_* knobs + run endpoint.
tokio-tungstenite 0.26 (already in lock) + dev axum `ws` for the hermetic test.
3 lib tests green, clippy clean, SQLX_OFFLINE build clean.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
7baf2082d0
commit
6d77a0acc1
@@ -5,7 +5,7 @@
|
||||
|
||||
use axum::extract::{Path, State};
|
||||
use axum::Json;
|
||||
use cm_orchestrator::{compare, Comparison, JudgeScorer, ProviderExecutor};
|
||||
use cm_orchestrator::{compare, execute, Comparison, JudgeScorer, ProviderExecutor, RunRecord};
|
||||
use cm_topology::{build, classify, heuristics, Classification, TopologyGraph, TopologyKind};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::format_description::well_known::Rfc3339;
|
||||
@@ -113,6 +113,42 @@ pub async fn compare_topologies(
|
||||
Ok(Json(cmp))
|
||||
}
|
||||
|
||||
/// Request body for executing a single topology on a real agent container.
|
||||
#[derive(Deserialize)]
|
||||
pub struct RunRequest {
|
||||
pub task: String,
|
||||
pub graph: TopologyGraph,
|
||||
}
|
||||
|
||||
/// `POST /api/topologies/run` — execute one topology by driving real ZeroClaw
|
||||
/// role-agents (in a container) for each turn, returning the run journal. The
|
||||
/// orchestrator owns the graph; agents are tool-free behind the Clawmates MCP
|
||||
/// door, so §15 holds by construction. Result is persisted best-effort to the
|
||||
/// existing `topology_runs` table.
|
||||
pub async fn run_topology(
|
||||
State(state): State<AppState>,
|
||||
Authed(user): Authed,
|
||||
Json(req): Json<RunRequest>,
|
||||
) -> Result<Json<RunRecord>, ApiError> {
|
||||
let executor =
|
||||
crate::topology_exec::ZeroClawDriveExecutor::from_env().map_err(|_| ApiError::Internal)?;
|
||||
let record = execute(&req.graph, &req.task, &executor)
|
||||
.await
|
||||
.map_err(|_| ApiError::Internal)?;
|
||||
|
||||
if let Ok(value) = serde_json::to_value(&record) {
|
||||
let _ = cm_db::repo::topology_runs::insert(
|
||||
&state.pool,
|
||||
Uuid::now_v7(),
|
||||
user.workspace_id,
|
||||
&req.task,
|
||||
&value,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
Ok(Json(record))
|
||||
}
|
||||
|
||||
/// A saved comparison run, summarized.
|
||||
#[derive(Serialize)]
|
||||
pub struct RunSummary {
|
||||
|
||||
Reference in New Issue
Block a user