Skip to main content

Module worker

Module worker 

Source
Expand description

/v1/worker/* endpoints (SubAgent self-fetch path). HTTP /v1/worker/* endpoints (SubAgent self-fetch path).

§7-Entry pointer #6 (Output Event design)

This endpoint accesses OutputStore directly and does NOT go through the engine. It is one of the seven entry points enumerated in project CLAUDE.md §“Output Event Design SoT”. For the canonical description, see the crate root doc of mlua-swarm-output-store (cargo doc -p mlua-swarm-output-store).

§Path

A thin-payload path where a SubAgent (= worker process launched by a MainAI) uses the capability token it received via WS Spawn to self-fetch its prompt and submit its result — putting the token in Authorization: Bearer <encoded CapToken>.

§Routes

  • GET /v1/worker/prompt?task_id=<tid> — via engine.fetch_worker_payload, returns {task_id, attempt, agent, system?, prompt, context?}. context.steps (projection-adapter ST5, [assemble_step_pointers]) is assembled fresh on every fetch: a ContextPolicy.steps-filtered pointer list to preceding steps’ OUTPUT, resolved through crate::projection::McpQueryAdapter’s Data-plane + result_ref enumeration — no separate MCP tool call needed to discover a prior step’s OUTPUT.
  • POST /v1/worker/result with body {task_id, value, ok} — appends one Final to the output tail via engine.submit_output(Final) (= the canonical path through which the dispatch layer decides Pass/Blocked) and updates task.last_result via engine.post_result.
  • POST /v1/worker/artifact?name=<name> (GH #36 ST1) — stages one named part per POST via engine.stage_worker_artifact_trusted. Completing the attempt is still POST /v1/worker/submit / /v1/worker/result — this route only stages; the dispatch layer’s Final-pull folds every staged part into {"out": <final>, "parts": {<name>: <value>, ...}}. At staging time the submit-time projection sink also materializes the part raw to <ctx-dir>/<name> (the IN file the next Agent step reads; fail-open skip when no work_dir / project_root resolves).
  • GET /v1/worker/prompt/system?task_id=<tid>&attempt=<n> (GH #31) — raw baked system bytes for (task_id, attempt), the Http-mode fetch target for system_ref.uri. Same Bearer flow as /v1/worker/prompt; body is text/plain, not JSON.
  • GET /v1/agents/:name/render-size (GH #31) — no Bearer required, same trust tier as GET /v1/blueprints/:id/head. Live per-agent most-recently observed render size, backing bp_doctor’s post-render check.
  • POST /v1/worker/degradation (GH #32) — structured JSON {tool, error, fallback, note?}, same Bearer flow as [worker_submit]. An independent channel: entries are appended to RunRecord.degradations via RunStore::append_degradation directly and never touch OutputStore / the fold path (Crux invariant 2 — a degradation must never surface as step OUTPUT). step_ref / attempt / at are server-injected, never trusted from the client. Silent 204 (no append) when the dispatch task carries no Run linkage — same fail-open contract as [reject_if_run_terminal]’s own resolution steps, since a pre-run-tracking dispatch has nowhere to record a degradation and that must not become a client-visible error.

§Bearer authentication

The Bearer value is the string produced by CapToken::encode() (= URL-safe base64 of serde_json). The server decodes it with CapToken::decode and then, inside the engine, verifies HMAC sig + role × verb gate + TTL via verify_token_for_task (= self-contained capability token; no server-side store lookup required).

Tokens are minted during the “2) mint outside the lock” phase of engine.dispatch_attempt (Role::Worker, 600s TTL, scopes=["*"]). The verb gate covers FetchPrompt / EmitOutput / PostResult — the worker leaf capability set (crate::types::WORKER_LEAF_VERBS).

Structs§

AgentRenderSizeResponse
Response body for GET /v1/agents/:name/render-size.
ArtifactQuery
Query params for POST /v1/worker/artifact.
DegradationBody
Body for POST /v1/worker/degradation (GH #32).
PromptQuery
Query params for GET /v1/worker/prompt.
PromptSystemQuery
Query params for GET /v1/worker/prompt/system. Field names are fixed to task_id / attempt — this is the exact shape the engine bakes into system_ref.uri’s query string for Http mode (GH #31), so the names here must match verbatim.
StatsBody
Request body for POST /v1/worker/stats — a worker’s self-reported per-attempt stats (per-step run stats, operator axis). Every field optional; an all-empty body is accepted and dropped.
SubmitQuery
POST /v1/worker/submit. Bearer = encoded CapToken. Body = raw text/octet.
WorkerResultReq
Body for POST /v1/worker/result.

Functions§

agent_render_size
GET /v1/agents/:name/render-size (GH #31). Live per-agent-name lookup of the most-recently-baked system_prompt render size, backing bp_doctor’s post-render size check. No Bearer required — same unauthenticated trust tier as GET /v1/blueprints/:id/head (blueprints::get_head), an operator-diagnostic route.
worker_artifact
POST /v1/worker/artifact?name=<name>. Bearer = same short-handle / full-CapToken forms as worker_submit. Body = raw text/octet.
worker_degradation
POST /v1/worker/degradation (GH #32). Bearer = same short-handle / full-CapToken forms as worker_submit. Body = JSON, not raw bytes — this endpoint carries structured data, unlike its raw-bytes siblings.
worker_prompt
GET /v1/worker/prompt?task_id=<tid>. Bearer = encoded CapToken or short wh- handle. Thin HTTP wrapper over engine.fetch_worker_payload / fetch_worker_payload_trusted. Short-handle path (recommended for SubAgents): handle → task_id cross-check → trusted fetch. Full-CapToken path: token decode → verify → fetch.
worker_prompt_system
GET /v1/worker/prompt/system?task_id=<tid>&attempt=<n> (GH #31). The Http-mode fetch target for system_ref.uri: serves the exact baked system bytes for (task_id, attempt) as a raw text/plain body — not JSON-wrapped, since mse_worker_fetch needs the precise byte sequence to sha256-verify against system_ref.sha256.
worker_result
POST /v1/worker/result. Bearer = encoded CapToken. Fires engine.submit_output(Final) + engine.post_result.
worker_stats
POST /v1/worker/stats. Bearer = same short-handle / full-CapToken forms as worker_submit. Body = JSON (StatsBody).
worker_submit
POST /v1/worker/submit. Simplified counterpart of worker_result: the caller sends only the raw result body, task_id is resolved server-side from the Bearer handle/token, and ok defaults to true unless overridden via SubmitQuery::ok. See the module doc for the short-handle vs full-CapToken Bearer forms.