feat: implement orchestrator core (Rust)

Task 1.1:  Cargo.toml with axum, rusqlite, matrix-sdk, serde, etc.
Task 1.2:  Directory structure: src/core, src/adapters, src/integrations, src/api
Task 1.5:  config.example.toml with full schema
Task 2.1:  Data models: Agent, Task, Receipt, Artifact, TaskEvent
Task 2.2:  Event Store: SQLite append-only with task/agent tables
Task 2.3:  Task state machine: created→assigned→running→completed/failed
Task 2.4:  Global task queue with priority ordering
Task 2.5:  Background timeout checker
Task 2.6:  Retry policy with configurable max_retries

Compiles clean (warnings only, no errors).
API handler stubs in place for Phase 2.
This commit is contained in:
Zer4tul 2026-05-11 14:57:23 +08:00
parent e983955036
commit 4e01728a67
15 changed files with 5220 additions and 3 deletions

58
src/core/task_queue.rs Normal file
View file

@ -0,0 +1,58 @@
use std::sync::Arc;
use tokio::sync::Mutex;
use super::event_store::EventStore;
use super::models::*;
use super::state_machine::{StateError, StateMachine};
/// Global task queue ordered by priority.
pub struct TaskQueue {
sm: Arc<StateMachine>,
store: Arc<Mutex<EventStore>>,
}
impl TaskQueue {
pub fn new(sm: Arc<StateMachine>, store: Arc<Mutex<EventStore>>) -> Self {
Self { sm, store }
}
/// Enqueue a new task (status = created).
pub async fn enqueue(&self, task: Task) -> Result<Task, StateError> {
self.sm.create_task(&task).await
}
/// Dequeue the highest-priority task matching the given capabilities.
pub async fn dequeue(
&self,
required_capabilities: &[String],
) -> Result<Option<Task>, StateError> {
let tasks = {
let store = self.store.lock().await;
store.query_queued_tasks()?
};
if required_capabilities.is_empty() {
return Ok(tasks.into_iter().next());
}
for task in tasks {
let all_match = required_capabilities
.iter()
.all(|cap| {
task.labels.iter().any(|l| l == cap) || &task.task_type == cap
});
if all_match {
return Ok(Some(task));
}
}
Ok(None)
}
/// Re-queue a failed/agent_lost task (increment retry_count).
pub async fn requeue(&self, task_id: &str) -> Result<Task, StateError> {
self.sm
.transition(task_id, TaskStatus::Assigned, None, "re-queued after failure")
.await
}
}