Skip to main content

Module projection

Module projection 

Source
Expand description

GET /v1/tasks/:id/runs/:run/steps* (the metadata + content debug plane over a Run’s step OUTPUT — McpQueryAdapter, a server-side mlua_swarm::core::projection::ProjectionAdapter impl reading through the Data-plane OutputStore with a persisted RunRecord.result_ref fallback). See the module doc for how this relates to operator_ws::session’s in-flight FileProjectionAdapter hook and worker’s Worker-axis context.steps pointer assembly. McpQueryAdapter — server-side [ProjectionAdapter], and the REST hierarchy that serves a Run’s step OUTPUT as metadata + content (projection-adapter ST5’s HTTP debug plane — replaces the ST2/ST4 GET /v1/tasks/:id/ctx single-value endpoint / ProjectionResponse).

§Two consumers, two roles (ST5)

  • Worker axis (crates/mlua-swarm-server/src/worker.rs’s GET /v1/worker/prompt handler) — the primary supply path. A worker’s fetch payload carries context.steps: Vec<StepPointer>, a ContextPolicy.steps-filtered pointer list assembled automatically at fetch time; no separate tool call needed.
  • HTTP debug plane (this module’s GET /v1/tasks/:id/runs/:run/steps* routes) — the content the above pointers’ content_url addresses, plus an unfiltered metadata/content view for operators / humans debugging a run.

Both consumers share McpQueryAdapter::list_steps’s enumeration: every distinct step_ref name in RunRecord.step_entries, resolved through the Data-plane OutputStore (in-flight-safe — see below), union RunRecord.result_ref’s top-level object keys (the finalized-Run fallback) — a name present in both wins on the Data-plane side (same rule McpQueryAdapter::resolve_run’s single-key sibling, McpQueryAdapter::resolve_async, already applies). Name-namespace unification (Data-plane producer names vs. flow.ir ctx-path segments) is tracked separately (see the KNOWN LIMITATION note below); this module does not resolve it.

§Architecture (subtask-4 rework, carried into ST5)

McpQueryAdapter reads through two backings, tried in order:

  1. Data-plane, in-flight-safe (subtask-4’s whole reason for being): when key.step is Some(producer_agent) and no explicit run_id pins an older Run, McpQueryAdapter::resolve_async first tries OutputStore::get_latest_by_name(producer_agent) — the same store Engine::submit_output’s submit-time projection sink dual-writes into (see mlua_swarm::core::engine::Engine::submit_output’s doc). A hit here can be a not-yet-finalized Run’s already-submitted step — the in-flight case this rework exists for.
  2. Persisted RunRecord.result_ref fallback (the pre-rework path, unchanged): used whenever (1) is skipped (key.step is None, or an explicit run_id was given) or comes back empty (no Data-plane record under that producer name yet — e.g. a Run that predates the engine having an OutputStore wired, or key.step names a flow.ir ctx-path segment rather than an agent ref — see the KNOWN LIMITATION note below).

Unlike crate::operator_ws::session‘s spawn-time mlua_swarm::core::projection::FileProjectionAdapter hook (which materializes the spawning agent’s own AgentContextView), this adapter’s Data-plane path serves prior steps’ submitted OUTPUT — the pull-supply counterpart to Engine’s submit-time file sink.

§KNOWN LIMITATION

OutputStore::get_latest_by_name is producer-name-scoped, not Run-scoped (see mlua_swarm::store::output’s module doc) — it returns the single newest Final submitted anywhere under that producer name, across every Run / Task. This adapter narrows the blast radius by only taking this path when an explicit run_id did NOT pin an older Run (an explicit pin always uses the Run-scoped result_ref fallback instead), but two concurrent Runs whose flow.ir happens to dispatch an agent of the identical name can still race each other on this path. This is an accepted, pre-existing characteristic of the Data-plane store (not a new race introduced here) — see mlua_swarm::store::output::OutputStore::get_latest_by_name’s doc.

[ProjectionAdapter::fetch] is a synchronous trait method, but this adapter’s backing stores are async. McpQueryAdapter::resolve_async is the real, native-async implementation; [step_content] (the content-plane HTTP handler) calls McpQueryAdapter::list_steps directly. [ProjectionAdapter::fetch] instead bridges to McpQueryAdapter::resolve_async via tokio::task::block_in_place + Handle::block_on purely for trait conformance (dependency inversion — this adapter implements the same core::projection::ProjectionAdapter trait mlua_swarm::core::projection::FileProjectionAdapter does, so a caller holding a dyn ProjectionAdapter can use either polymorphically); the hot HTTP path never takes that bridge.

Structs§

McpQueryAdapter
Server-side ProjectionAdapter backed by an OutputStore (in-flight-safe, subtask-4) with a RunStore-backed result_ref fallback (see the module doc for the full narrative).
StepList
Response body for GET /v1/tasks/:id/runs/:run/steps.
StepPathQuery
Query params shared by the metadata and content routes: narrows a single step’s value via $.a.b dot-path form (the leading $. is optional) — same syntax mlua_swarm::core::projection::ProjectionKey already establishes.
StepSummary
One step’s metadata (operator / debug plane) — GET /v1/tasks/:id/runs/:run/steps/:step, and each entry of StepList::steps.

Enums§

ProjectionSource
Which backing produced a StepSummary / a Worker-axis StepPointer — Data-plane wins a name collision (module doc’s “Architecture” section).

Functions§

step_content
GET /v1/tasks/:id/runs/:run/steps/:step/content?path=$.a.b — the raw body: full bytes, no envelope, no Range support. Content-Type and ETag follow StepSummary::content_type / StepSummary::sha256’s same rules (module doc).
step_get
GET /v1/tasks/:id/runs/:run/steps/:step?path=$.a.b — one step’s metadata, optionally narrowed.
steps_list
GET /v1/tasks/:id/runs/:run/steps — every step visible for the addressed Run, unfiltered (see the module doc’s role split).