feat(actor): v0.6.20 — per-user Actor threading + scoped config resolution#286
Merged
Conversation
…onfig cache Repin all v0.1.24 animus-protocol git deps to v0.1.25 and add the new zero-dep `animus-actor` crate. v0.1.25 additively adds `actor: Option<Actor>` to config/control/runner/session request types. control-protocol (v0.1.13 -> v0.1.25), workflow-runner-protocol (v0.5.3 -> v0.1.25) and subject-protocol-wire move with it (wire must share control's subject-protocol rev); queue + subject-protocol-v05 stay on the matched v0.5.10 pair. WU-C: thread `actor: Option<&Actor>` through resolve_plugin_base -> load_via_resident -> config_load_call (serialized into config/load params) and load_workflow_config[_with_metadata]. Re-key the compiled-config cache by (project_root, ActorCacheKey) and fold the actor key into compile_token so one user's compiled config can never be served to another; invalidate_compiled clears every actor partition for a root. ActorCacheKey uses unambiguous JSON (no delimiter-collision between distinct identities). WU-D: relay actor through the control surface (struct passthrough) and populate the runner WorkflowExecuteRequest.actor in execute.rs. The daemon control path spawns a detached runner child that rebuilds its request from the persisted record, so the authenticated actor is relayed to that child via a trusted daemon->child env handoff (WORKFLOW_ACTOR_ENV) carried in the runner overrides. TRUST BOUNDARY: the actor is set ONLY from the authenticated control request; never synthesized from local CLI context, workflow YAML, agent output, or subject content. Tests: per-actor cache isolation (no cross-leak), actor=None == global, invalidate clears all partitions, claim-order independence, delimiter-collision resistance, and the detached-runner actor env round-trip.
… actor to the MCP sidecar TASK 1 (resolve the deferred bootstrap P2): thread the transport-asserted Actor through the workflow run/bootstrap + the phase-plan / config / retry resolution it calls, so a user's PRIVATE workflow (visible only in that actor's config_source partition) resolves at run-time, not from the global view. - `WorkflowServiceApi::run(input, actor: Option<&Actor>)`: actor-scoped default-workflow-ref / phase-plan / skip-guard / retry resolution. actor=None == today's global behavior. Both FileServiceHub + InMemory impls + all callers updated (system/local/test callers pass None; the control-routed detached start passes the run's actor via DetachedRunnerOverrides). - Added actor-aware variants (old fns delegate to None): `resolve_phase_plan_ for_workflow_ref_for_actor`, `load_workflow_config_or_default_for_actor`, `load_agent_runtime_config_*_for_actor`. - Persist the actor on the run so EVERY later lifecycle transition (resume / pause / cancel / complete / fail / mark_* / resolve_merge_conflict) re-resolves from the same partition — otherwise a private workflow starts then fails at the next transition. Stored in a kernel-owned `workflows.actor` SQLite column (NOT the protocol record); `save()` switched from INSERT OR REPLACE to an ON CONFLICT upsert so the column survives every later save. Test seam gains per-(root,actor) base injection. TASK 2 (WU-G): relay the actor to the per-agent `animus mcp serve` sidecar so an agent's MCP tool calls can scope to the user (per-user integrations / subject / queue). The built-in MCP server is spawned PER AGENT SESSION (runtime_contract mcp.stdio.command), so the actor reaches it per-agent-spawn: - `inject_default_stdio_mcp_for_agent(.., actor)` appends `--actor-json` to the default serve args (in-tree ad-hoc callers pass None; the out-of-tree runner passes WorkflowPhaseRunRequest.actor). - `animus mcp serve --actor-json` parses the Actor and pins it on AoMcpServer (`pinned_actor`), exposed via `pinned_actor()`; `run_tool` (the single tool choke point) emits per-user audit. Full per-tool ENFORCEMENT (scoping the underlying subject/queue/integration RPCs) is the consumer-side change tracked separately. TRUST BOUNDARY: the actor is sourced ONLY from the authenticated run/control request, never from workflow YAML, agent output, or subject content. Tests: actor-private workflow resolves for its actor and NOT for None/another actor; run() persists the actor and it survives a lifecycle save; --actor-json clap parse; inject appends/omits --actor-json; actor round-trips through the serve arg.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Threads an opaque per-user
Actor(animus-protocol v0.1.25) through the kernel so config resolution + workflow runs are actor-scoped. Kernel stays user-agnostic (relays the actor, plugins scope).actor=None= byte-for-byte today's global behavior.animus-actor.(PathBuf, ActorCacheKey)) — proven no cross-actor leak.WorkflowServiceApi::runresolves default-ref/phase-plan/skip/retry from the actor's config partition; actor persisted per-run (workflows.actor) so lifecycle transitions re-resolve consistently.animusMCP server (--actor-json→pinned_actor).Verification
build/clippy clean;
cargo test1217 pass / 2 pre-existing fail (decision_gate::workflow_*, confirmed on base); codex 0 P1.Deferred (tracked)
Per-tool MCP enforcement (subject/queue protocol actor fields → TASK-132 consumption);
--actor-jsonargv exposure P2 (low-risk single-tenant; matches--agent-idprecedent).🤖 Generated with Claude Code