research: topology_worker points executor at per-topic gateway (commit 2/3)
Commit 2 of the path-B plan. The container that commit 1 spawns
now actually receives the run's turns — up until now it was
started but unused. This is the payoff commit: research runs are
truly isolated per topic.
Backend
- topology_exec.rs: from_env() refactored to a thin wrapper over a
new from_env_for_gateway(url) helper. Same shape (env-derived
aliases + default + token) but the caller supplies the URL. The
auth token/pairing code still comes from ZEROCLAW_TOKEN /
ZEROCLAW_PAIRING_CODE on the server; research_container's
inherited_env propagates those into the team container so the
same credentials work at both endpoints.
- research_container.rs: new wait_ready(url, deadline) that polls
<url>/health with a 1.5s per-request timeout every 500ms until
it 200s or the deadline passes. reqwest-based so it doesn't need
bollard. Called by the worker after claim, before pair, to bridge
the "container is starting, gateway not yet listening" gap.
- topology_worker.rs run_job:
1. Look up research_topic_id for the claimed run.
2. If Some, load the topic and read zeroclaw_gateway_url.
3. If a URL is present:
- best-effort wait_ready(url, 30s); a timeout logs but
doesn't abort — the pair call below will just fail
faster than pinging forever
- build the leaf via from_env_for_gateway(url)
Else fall back to from_env() (workspace-wide gateway).
4. The rest of run_job is unchanged — the leaf drops into
either SubTopologyExecutor (org/company) or direct drive
(team tier) as before.
What now works end-to-end
Starting a research topic with a bound repo:
1. clone-shallow into per-topic workspace
2. docker create + start the clawmates-runtime container, name
= research-<topic>-team, joined to clawmates_core so the
server reaches it by name
3. persist container name + gateway URL on the topic row
4. enqueue the topology run tagged with research_topic_id
5. worker claims → looks up the topic → waits for the team
gateway's /health → constructs a from_env_for_gateway
executor pointed at http://research-<topic>-team:42617
6. every turn's `/ws/chat?agent=…` hits the isolated container;
agents inside see the repo at /workspace/repo (rw); each
topic's memory/state lives under its own /zeroclaw-data mount
Deploy prereqs (unchanged from commit 1)
- clawmates_server compose service needs a bind-mount of
CLAWMATES_RESEARCH_WORKSPACE_ROOT so the paths spawn() writes to
are visible on the host and the spawned team container mounts
the same underlying data.
- socket-proxy ACL needs POST + DELETE on /containers (prod ✓).
This commit is contained in:
@@ -71,6 +71,18 @@ impl ZeroClawDriveExecutor {
|
||||
pub fn from_env() -> Result<Self, String> {
|
||||
let gateway_url =
|
||||
std::env::var("ZEROCLAW_GATEWAY_URL").map_err(|_| "ZEROCLAW_GATEWAY_URL not set")?;
|
||||
Self::from_env_for_gateway(gateway_url)
|
||||
}
|
||||
|
||||
/// Same as [`from_env`] but with a caller-supplied gateway URL. Used by
|
||||
/// the research pipeline to point the executor at the per-topic team
|
||||
/// container spawned in `research_container::spawn` instead of the
|
||||
/// workspace-wide gateway from `ZEROCLAW_GATEWAY_URL`. The auth token,
|
||||
/// role map, and default alias still come from the parent server's
|
||||
/// env — they're propagated into the team container by
|
||||
/// `research_container::inherited_env` so both endpoints use the same
|
||||
/// credentials.
|
||||
pub fn from_env_for_gateway(gateway_url: String) -> Result<Self, String> {
|
||||
let token = std::env::var("ZEROCLAW_TOKEN")
|
||||
.ok()
|
||||
.filter(|t| !t.is_empty());
|
||||
|
||||
Reference in New Issue
Block a user