pub struct EngineState {Show 17 fields
pub tasks: HashMap<StepId, TaskState>,
pub sessions: HashMap<SessionId, OperatorSession>,
pub prompts: HashMap<(StepId, u32), Value>,
pub systems: HashMap<(StepId, u32), Option<String>>,
pub agent_render_sizes: HashMap<String, usize>,
pub agent_ctx: HashMap<(StepId, u32), AgentCtxEntry>,
pub step_namings: HashMap<StepId, Arc<StepNaming>>,
pub projection_placements: HashMap<StepId, Arc<ProjectionPlacement>>,
pub tokens: HashMap<String, CapTokenRecord>,
pub worker_handles: HashMap<String, String>,
pub pending_resumes: HashMap<ResumeKey, ResumePending>,
pub task_notifies: HashMap<StepId, Arc<Notify>>,
pub resources: HashMap<String, Value>,
pub output_store: HashMap<(StepId, u32), Vec<OutputEvent>>,
pub worker_artifact_names: HashMap<(StepId, u32), Vec<String>>,
pub event_log_tail: Vec<Event>,
pub event_log_max: usize,
}Expand description
The single Mutex-guarded blob of engine flow state, accessed only
through Engine::with_state (see the R1-R4 discipline documented
there).
Fields§
§tasks: HashMap<StepId, TaskState>All known tasks, keyed by StepId.
sessions: HashMap<SessionId, OperatorSession>All attached/detached sessions, keyed by SessionId.
prompts: HashMap<(StepId, u32), Value>Per-(task_id, attempt) prompt/directive value, seeded from
TaskSpec.initial_directive and fetched via fetch_prompt. Held
as serde_json::Value end-to-end (issue #18): the render down to
String (strings verbatim, anything else serde-stringified)
happens only at the two consumer boundaries — the Worker HTTP
path (Engine::fetch_worker_payload* → WorkerPayload.prompt: String) and the WS Spawn frame text render
(operator_ws::session::default_spawn_directive_with_task_directive).
Engine-internal storage and Engine::fetch_prompt keep the
Value end-to-end, so Step.in Object / Array seeds are not
prematurely flattened.
systems: HashMap<(StepId, u32), Option<String>>Per-attempt system_prompt: AgentDef.profile.system_prompt is
baked at compile time, rendered inside OperatorSpawner::spawn,
and stashed here for the SubAgent to fetch alongside its prompt via
HTTP /v1/worker/prompt. The value is Option<String> so a missing
profile can be distinguished: an absent key means “not yet baked”,
while Some(None) means “baked and profile is explicitly absent”.
agent_render_sizes: HashMap<String, usize>GH #31: per-agent-name “most-recently-baked system_prompt size”
bookkeeping, updated by Engine::bake_worker_system_prompt
whenever system.is_some() (keyed by TaskState.spec.agent, the
same lookup fetch_worker_payload uses). Last-write-wins is the
deliberate semantics — “most-recently-observed”, not “largest” or
“per-attempt” — since this exists only to let bp_doctor-style
tooling ask “how big does this agent’s rendered system prompt
currently run” without plumbing the live Engine into
BlueprintsState. Read via Engine::agent_last_rendered_size.
agent_ctx: HashMap<(StepId, u32), AgentCtxEntry>Per-attempt materialized crate::core::agent_context::AgentContextView
(Contract C, GH #20) paired with the effective
mlua_swarm_schema::ContextPolicy AgentContextMiddleware already
applied to that same view — the Worker axis’s read-back source.
Written by crate::middleware::agent_context::AgentContextMiddleware
(innermost spawner layer) at dispatch time via one insert (GH #23:
folded from two separately-keyed maps — see below); read by
Engine::fetch_worker_payload{,_trusted} / Engine::agent_context_for
(the AgentCtxEntry::view half, threaded into WorkerPayload.context)
and Engine::context_policy_for (the AgentCtxEntry::policy half,
read by crates/mlua-swarm-server/src/worker.rs’s GET /v1/worker/prompt handler to filter WorkerPayload.context.steps via
ContextPolicy::allows_step without re-deriving the policy from the
Blueprint at fetch time). Keyed the same way as prompts / systems
— Ctx itself is not stored, so the entry has to be snapshotted here
to still be servable at fetch time. An absent entry (pre-ST5 spawns,
or a spawner stack that never layered AgentContextMiddleware) means
no materialized view and a pass-all policy
(mlua_swarm_schema::ContextPolicy::default()) for that key.
GH #23: this map used to be two separately-keyed maps
(agent_contexts: HashMap<_, AgentContextView> /
context_policies: HashMap<_, ContextPolicy>) sharing a key and kept
in sync only by convention (the single insert site in
AgentContextMiddleware writing both in the same with_state call).
Folding both values into one map of an AgentCtxEntry struct makes
that pairing structural — the two values can no longer drift apart
key-by-key. TODO(GH #23): this map (nor prompts / systems) still
has no removal path — entries accumulate for the process lifetime; a
long-running server needs a task-completion sweep (tracked
separately from this fold).
step_namings: HashMap<StepId, Arc<StepNaming>>GH #23: per-dispatch snapshot of the Blueprint-wide
crate::core::step_naming::StepNaming addressing-space table —
built once by blueprint::compiler::Compiler::compile and stashed
here, per StepId, by crate::blueprint::EngineDispatcher::dispatch
(its single insert site; the same Arc is shared across every
Step dispatched from the same Blueprint launch). Engine::step_naming_for
reads it back so later consumers (GH #23 subtask-2/3 —
ContextPolicy.allows_step, StepPointer/StepSummary assembly,
the REST :step resolver, FileProjectionAdapter) do not have to
re-derive the table from the Blueprint at read time. An absent
entry means the dispatcher was never given a StepNaming (e.g. a
direct EngineDispatcher::with_spawner caller that skipped
with_step_naming) — callers fall back to the pre-GH-#23 runtime
union rule in that case.
projection_placements: HashMap<StepId, Arc<ProjectionPlacement>>GH #27 (follow-up to #23): per-dispatch snapshot of the
Blueprint-wide crate::core::projection_placement::ProjectionPlacement
resolver — built once by blueprint::compiler::Compiler::compile
and stashed here, per StepId, by
crate::blueprint::EngineDispatcher::dispatch (the same insert
site, and the same “construct once, read many” contract, as
Self::step_namings). Engine::projection_placement_for reads
it back so every one of the 3 materialize call sites (submit-time
sink, server read-back, spawn-time pointer) resolves the SAME root
preference / directory template. An absent entry means the
dispatcher was never given a ProjectionPlacement (e.g. a direct
EngineDispatcher::with_spawner caller that skipped
with_projection_placement) — callers fall back to
ProjectionPlacement::default() (byte-compat with the pre-#27
hardcoded layout) in that case.
tokens: HashMap<String, CapTokenRecord>All minted CapToken records, keyed by token fingerprint
(CapToken::fingerprint = SHA-256 of the nonce; issue #14 — the
key is loggable, the nonce is not).
worker_handles: HashMap<String, String>Short worker handle (wh-XXXXXXXX, 12 chars) → token-fingerprint
lookup map. Resolves the worker_handle field a SubAgent receives
with its prompt. There is no signature verification: task_id is
resolved by a plain HashMap lookup — deliberately thin for the
local running over WebSocket, and adopted specifically to remove
the base64 copy-paste failure mode.
pending_resumes: HashMap<ResumeKey, ResumePending>Outstanding query_senior suspensions awaiting resume.
task_notifies: HashMap<StepId, Arc<Notify>>Per-task notifier — notify_waiters fires on every task-status
change. Used by poll_task on the caller side, and by callers that
need to await again after detach/reattach.
resources: HashMap<String, Value>Arbitrary named resources set via set_resource and read via
fetch_data.
output_store: HashMap<(StepId, u32), Vec<OutputEvent>>Per-attempt output-event log. The SpawnerAdapter appends via
submit_output; the dispatch path pulls the terminal
OutputEvent::Final off the tail and decides Pass / Blocked.
worker_artifact_names: HashMap<(StepId, u32), Vec<String>>GH #36 ST1 (named multi-part worker output): the set of Artifact
names staged via Engine::stage_worker_artifact_trusted (= POST /v1/worker/artifact) for (task_id, attempt), in staging order.
output_store is a SHARED per-attempt tail — besides a worker’s own
staged parts, other producers append OutputEvent::Artifact events
to the SAME tail too (e.g. AfterRunAuditMiddleware’s
"audit:<step_ref>" sidecar finding, an intentionally
BP-chain-invisible observation — see Engine::submit_output’s doc,
“Artifact dual-write” section). Engine::dispatch_attempt_with’s
Final-pull assembly must fold ONLY a worker’s own named parts into
"parts", not every Artifact that happens to land on the tail —
this set is that distinguishing signal, so a step under audit keeps
its BP-chain value byte-identical to pre-GH-#36 unless the WORKER
itself opted in via /v1/worker/artifact.
event_log_tail: Vec<Event>Bounded in-process tail of recent Events (most recent last),
trimmed to event_log_max by push_event.
event_log_max: usizeMaximum length of event_log_tail before older entries are
dropped.
Implementations§
Source§impl EngineState
impl EngineState
Sourcepub fn ensure_task_notify(&mut self, task_id: &StepId) -> Arc<Notify> ⓘ
pub fn ensure_task_notify(&mut self, task_id: &StepId) -> Arc<Notify> ⓘ
Ensure a per-task Notify exists; return the existing one if any.
Sourcepub fn push_event(&mut self, ev: Event)
pub fn push_event(&mut self, ev: Event)
Append ev to event_log_tail, trimming the oldest entries once
event_log_max is exceeded.
Trait Implementations§
Source§impl Debug for EngineState
impl Debug for EngineState
Auto Trait Implementations§
impl Freeze for EngineState
impl RefUnwindSafe for EngineState
impl Send for EngineState
impl Sync for EngineState
impl Unpin for EngineState
impl UnsafeUnpin for EngineState
impl UnwindSafe for EngineState
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more