Skip to main content

AgentOrchestrator

Struct AgentOrchestrator 

Source
pub struct AgentOrchestrator { /* private fields */ }
Expand description

The main orchestrator that runs the dark factory.

Implementations§

Source§

impl AgentOrchestrator

Source§

impl AgentOrchestrator

Source

pub fn new(config: OrchestratorConfig) -> Result<Self, OrchestratorError>

Create a new orchestrator from configuration.

Source

pub fn from_config_file( path: impl AsRef<Path>, ) -> Result<Self, OrchestratorError>

Create from a TOML config file path.

Loads the config, resolves include globs, and runs full validation (banned providers, duplicate project ids, unknown project refs, mixed mode). Returns Err if any check fails – does not panic or warn-and- continue.

Source

pub fn config(&self) -> &OrchestratorConfig

Return the validated configuration stored in this orchestrator.

Source

pub fn dispatcher(&self) -> &Dispatcher

Read-only access to the unified dispatcher queue.

Integration tests use this to assert that ROC v1 Step F polling enqueued the expected dispatcher::DispatchTask::AutoMerge work without the test itself holding a reference to the internal dispatcher.

Source

pub fn auto_merge_enqueued(&self) -> &AutoMergeDedupeSet

Read-only access to the in-memory (project, pr_number, head_sha) dedupe set populated by ROC v1 Step F polling and the Step G AutoMerge handler. Integration tests use this to assert that a successful merge leaves the revision recorded so subsequent polls never re-enqueue the same auto-merge.

Source

pub async fn run(&mut self) -> Result<(), OrchestratorError>

Run the orchestrator (blocks until shutdown signal).

  1. Spawns all Safety-layer agents immediately
  2. Enters the select! loop handling schedule events, drift alerts, and periodic tick
Source

pub fn shutdown(&mut self)

Request graceful shutdown of all agents and the orchestrator.

Source

pub fn agent_statuses(&self) -> Vec<AgentStatus>

Get current status of all agents.

Source

pub async fn trigger_compound_review( &mut self, git_ref: &str, base_ref: &str, ) -> Result<CompoundReviewResult, OrchestratorError>

Manually trigger a compound review (outside normal schedule).

Source

pub async fn handoff( &mut self, from_agent: &str, to_agent: &str, context: HandoffContext, ) -> Result<(), OrchestratorError>

Hand off a task from one agent to another.

Source

pub fn latest_handoff_for(&self, to_agent: &str) -> Option<&HandoffContext>

Get the most recent handoff for a specific target agent. Returns the handoff context with the latest timestamp that hasn’t expired.

Source

pub fn router(&self) -> &RoutingEngine

Get a reference to the routing engine.

Source

pub fn router_mut(&mut self) -> &mut RoutingEngine

Get a mutable reference to the routing engine.

Source

pub fn rate_limiter(&self) -> &RateLimitTracker

Get a reference to the rate limiter.

Source

pub fn rate_limiter_mut(&mut self) -> &mut RateLimitTracker

Get a mutable reference to the rate limiter.

Source

pub fn cost_tracker(&self) -> &CostTracker

Get a reference to the cost tracker.

Source

pub fn cost_tracker_mut(&mut self) -> &mut CostTracker

Get a mutable reference to the cost tracker.

Source

pub fn set_quickwit_sink(&mut self, sink: QuickwitFleetSink)

Source

pub fn quickwit_config(&self) -> Option<&QuickwitConfig>

Source

pub fn quickwit_fleet_configs(&self) -> Vec<(String, QuickwitConfig)>

Enumerate per-project Quickwit configurations plus a legacy fallback for the top-level config, so the binary can build a quickwit::QuickwitFleetSink covering every project.

Returns (project_id, QuickwitConfig) pairs. Projects without a per-project Quickwit block inherit the top-level config. The legacy single-project path emits a single entry keyed on crate::dispatcher::LEGACY_PROJECT_ID.

Source

pub async fn poll_pending_reviews(&mut self) -> Result<(), OrchestratorError>

Poll every project with a Gitea config for open PRs, parse the latest structural-pr-review comment, and enqueue dispatcher::DispatchTask::AutoMerge for any PR that clears every gate in pr_review::AutoMergeCriteria::default.

Called once per reconcile tick after the dispatcher has been drained so AutoMerge tasks enqueued here are serviced on the next tick (deterministic ordering). The method is a no-op when no project has a gitea config.

This is ROC v1 Step F — it enqueues auto-merge but does not actually merge the PR; that lands in Step G. Dedupe is process-local via pr_poller::AutoMergeDedupeSet; durable tracking is Step I.

Source

pub async fn poll_pending_reviews_for_project<T: PrTracker + ?Sized>( &mut self, project_id: &str, tracker: &T, criteria: &AutoMergeCriteria, )

Inner per-project verdict poll. Accepts a generic pr_poller::PrTracker so integration tests can drive it with an in-memory tracker.

Source

pub async fn handle_auto_merge( &mut self, task: DispatchTask, ) -> Result<(), OrchestratorError>

Execute a DispatchTask::AutoMerge task — ROC v1 Step G.

Builds the per-project pr_poller::GiteaPrTracker from config and delegates to AgentOrchestrator::handle_auto_merge_for_project. The task’s project field must match a configured project with a gitea block (or, for legacy configs, the top-level gitea); otherwise the call logs-and-skips so the dispatcher keeps draining.

Source

pub async fn handle_auto_merge_for_project<T: AutoMergeExecutor + ?Sized>( &mut self, task: DispatchTask, tracker: &T, ) -> Result<(), OrchestratorError>

Inner AutoMerge executor. Accepts any pr_poller::AutoMergeExecutor so integration tests can drive the full handler with an in-memory tracker. Real production code funnels through AgentOrchestrator::handle_auto_merge.

Steps:

  1. Defensive re-check: list open PRs on the project. Skip when the PR is absent (already closed/merged) or the HEAD SHA has moved.
  2. Attempt the merge.
  3. On success — enqueue DispatchTask::PostMergeTestGate, record the (pr, head_sha) in the dedupe set so late polls never re-enqueue the same revision.
  4. On failure — open an [ADF] tracking issue with the failure reason via pr_poller::AutoMergeExecutor::open_failure_issue; do not enqueue a post-merge gate.
Source

pub async fn handle_post_merge_test_gate( &mut self, task: DispatchTask, ) -> Result<(), OrchestratorError>

Execute a DispatchTask::PostMergeTestGate task — ROC v1 Step H.

Defers the heavy lifting to post_merge_gate::run_workspace_tests and post_merge_gate::revert_merge so those helpers stay fully testable without orchestrator state. This method resolves the project’s working_dir as repo_root, constructs the post_merge_gate::GateConfig (picking up any overrides from [post_merge_gate] in orchestrator.toml), and funnels the result through the inner handle_post_merge_test_gate_for_project helper which takes a post_merge_gate::CommandRunner so integration tests can drive the full handler with a scripted runner.

Source

pub async fn handle_post_merge_test_gate_with_runner<R>( &mut self, task: DispatchTask, runner: &R, ) -> Result<(), OrchestratorError>
where R: CommandRunner + ?Sized,

Inner handler that accepts any post_merge_gate::CommandRunner. Integration tests use a post_merge_gate::ScriptedRunner here to assert on the exact cargo test / git revert / git push call sequence without spawning real processes.

On green: logs post_merge_gate_verified at info. On red: classifies the failure, runs git revert, pushes to the configured remote, opens an [ADF] post-merge test gate reverted tracking issue on the project’s Gitea repo, and logs post_merge_gate_reverted at warn. Returns Ok(()) in every case the dispatcher should continue draining — only hard I/O errors that prevent even the attempt return Err.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

Source§

impl<T> MaybeSend for T
where T: Send,