Skip to content

🏗️ RFC: One-Shot Integration — декомпозиция crates + дефолтный протокол связи агентов #107

@gHashTag

Description

@gHashTag

Проблема

Сейчас 31 крейт workspace'а растут органически без единого протокола связи. Агенты общаются через ad-hoc serde_json::Value, нет типизированного шины сообщений, нет стандартного способа подключить новый крейт в one-shot без знания всей системы.


Цель

One-shot integration: любой новый агент/крейт подключается через единый trios-bus trait за ≤ 10 строк кода. Коммуникация между агентами — типизированная, async, через Tokio-каналы с phi-приоритетами.


Текущая карта crates (6 слоёв)

L0 Kernel  — trios-core, trios-golden-float, trios-ternary, trios-physics, trios-sacred, trios-crypto
L1 Engine  — trios-vm, trios-vsa, trios-hdc, trios-kg, trios-model, trios-data
L2 Agent   — trios-llm, trios-agents, trios-zig-agents, zig-agents, zig-knowledge-graph, trios-ca-mask, trios-phi-schedule
L3 Learn   — trios-training, trios-training-ffi, trios-train-cpu, trios-trinity-init
L4 Infra   — trios-git, trios-gb, precision-router, trios-hybrid, trios-bridge, trios-tri
L5 Public  — trios-sdk, trios-server, trinity-brain

Диагноз: AgentMessage в trios-agents содержит только content: String + agent_id. Нет msg_type, нет priority, нет correlation_id, нет reply_to. Агенты слепые — не знают кто им пишет и зачем.


🧩 ПЛАН ДЕКОМПОЗИЦИИ

Шаг 1 — trios-proto: единый протокол сообщений (L0)

Новый микро-крейт, 0 бизнес-логики, только типы:

// crates/trios-proto/src/lib.rs

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Envelope<T> {
    pub id: Ulid,              // уникальный ID сообщения
    pub correlation_id: Option<Ulid>, // для request/reply
    pub from: AgentId,
    pub to:   Routing,         // Direct(AgentId) | Broadcast | Topic(String)
    pub priority: PhiPriority, // φ-based: P0..P8 (Fibonacci)
    pub payload: T,
    pub ts: u64,               // unix millis
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Routing {
    Direct(AgentId),
    Broadcast,
    Topic(String),
}

#[repr(u8)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum PhiPriority {
    P0 = 1, P1 = 1, P2 = 2, P3 = 3,
    P4 = 5, P5 = 8, P6 = 13, P7 = 21, P8 = 34,
    // Fibonacci = φ-sequence приоритеты
}

Зависимости: только serde, ulid. Никаких tokio/axum в proto.


Шаг 2 — trios-bus: шина сообщений (L1)

// crates/trios-bus/src/lib.rs

/// Trait, который реализует любой агент для one-shot интеграции
#[async_trait]
pub trait TriosAgent: Send + Sync + 'static {
    fn agent_id(&self) -> AgentId;
    fn subscriptions(&self) -> Vec<String>; // topics
    async fn handle(&self, env: Envelope<serde_json::Value>) -> Option<Envelope<serde_json::Value>>;
}

/// Центральная шина — регистр агентов + роутинг
pub struct Bus {
    agents: DashMap<AgentId, Arc<dyn TriosAgent>>,
    topics: DashMap<String, Vec<AgentId>>,
    tx:     broadcast::Sender<Envelope<serde_json::Value>>,
}

impl Bus {
    pub fn new(capacity: usize) -> Self { ... }
    
    /// One-shot регистрация агента
    pub fn register(&self, agent: Arc<dyn TriosAgent>) {
        for topic in agent.subscriptions() {
            self.topics.entry(topic).or_default().push(agent.agent_id());
        }
        self.agents.insert(agent.agent_id(), agent);
    }
    
    pub async fn publish(&self, env: Envelope<serde_json::Value>) { ... }
    pub async fn request(&self, env: Envelope<serde_json::Value>) 
        -> Result<Envelope<serde_json::Value>> { ... }
}

Паттерн: Actor Model через Tokio broadcast + DashMap (lock-free registry). Ref: Actix Architecture, [Bastion paper 2020].


Шаг 3 — Мигрировать trios-agents на новый протокол

Текущий AgentMessage { agent_id, content, timestamp } → заменить на Envelope<AgentPayload>:

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum AgentPayload {
    Task    { description: String, params: serde_json::Value },
    Result  { task_id: Ulid, data: serde_json::Value },
    Status  { state: AgentState },
    Ping,
    Pong    { latency_ms: u64 },
}

Шаг 4 — trios-orchestrator: заменяет ручной spawn (L2)

pub struct Orchestrator {
    bus: Arc<Bus>,
    phi_scheduler: Arc<PhiScheduler>, // из trios-phi-schedule
}

impl Orchestrator {
    /// One-shot запуск всей системы агентов
    pub async fn boot(config: TriosConfig) -> Result<Self> {
        let bus = Arc::new(Bus::new(1024));
        
        // Автодискавери агентов через inventory pattern
        for agent in config.agents {
            bus.register(agent);
        }
        
        Ok(Self { bus, phi_scheduler: ... })
    }
    
    /// Отправить задачу в систему, получить результат
    pub async fn run_task(&self, task: AgentTask) -> Result<TaskResult> {
        let env = Envelope::new(task.into(), PhiPriority::P5);
        let result = self.bus.request(env).await?;
        Ok(result.payload.try_into()?)
    }
}

Шаг 5 — trios-sdk обёртка (один import)

// После рефакторинга — всё в одном:
use trios_sdk::prelude::*;

#[tokio::main]
async fn main() -> Result<()> {
    let trios = Trios::boot(TriosConfig::default()).await?;
    let result = trios.run("analyze physics constants").await?;
    println!("{result:?}");
    Ok(())
}

📐 Граф зависимостей (после рефакторинга)

trios-proto (L0, no-std compatible)
    ↑
trios-bus (L1, tokio)
    ↑
trios-agents / trios-llm / trios-phi-schedule ... (L2, implements TriosAgent)
    ↑
trios-orchestrator (L2, координирует)
    ↑
trios-sdk (L5, public API)

Правило: зависимости только вниз по слоям. L0 не знает о L1+.


📋 Чеклист задач

Фаза 1: Протокол (≈2 дня)

  • Создать crates/trios-proto с Envelope<T>, Routing, PhiPriority, AgentId
  • Добавить ulid в workspace dependencies
  • Unit тесты: сериализация envelope, phi-priority ordering

Фаза 2: Шина (≈3 дня)

  • Создать crates/trios-bus с трейтом TriosAgent + Bus
  • Добавить dashmap в workspace dependencies
  • Тест: 3 агента, broadcast, direct routing, request/reply

Фаза 3: Миграция агентов (≈2 дня)

  • Мигрировать trios-agents: AgentMessageEnvelope<AgentPayload>
  • Мигрировать trios-llm: добавить impl TriosAgent
  • Мигрировать trios-phi-schedule: подключить к Bus

Фаза 4: Оркестратор (≈2 дня)

  • Создать crates/trios-orchestrator
  • Реализовать Orchestrator::boot() с autodiscovery
  • Интегрировать precision-router как middleware шины

Фаза 5: SDK one-shot (≈1 день)

  • Обновить trios-sdk prelude::*
  • Добавить Trios::boot() + Trios::run()
  • Пример: examples/one_shot.rs

Фаза 6: CI

  • Добавить cargo deny check для граф зависимостей
  • Integration test: boot → task → result за ≤ 100ms

🔬 Научные основы

Паттерн Источник
Actor Model + typed mailbox Hewitt 1973, адаптация Actix/Bastion
Phi-priority scheduling Fibonacci heap scheduling, Fredman & Tarjan 1987
Hexagonal Architecture Alistair Cockburn 2005 — ports & adapters
Lock-free registry DashMap — Porcupine 2020 (Rust lock-free HashMap)
Envelope pattern EIP — Gregor Hohpe "Enterprise Integration Patterns" 2003
One-shot integration Unix philosophy + Cargo workspace resolver v2

Workspace изменения

# Cargo.toml — добавить:
[workspace.dependencies]
ulid = "1"
dashmap = "6"

# Новые members:
"crates/trios-proto",
"crates/trios-bus",
"crates/trios-orchestrator",

Метрики успеха

  • cargo build --workspace за < 60s (cold)
  • Новый агент = impl TriosAgent за ≤ 10 строк
  • Trios::boot() поднимает всю систему за ≤ 500ms
  • Нет serde_json::Value в публичных API (только в payload envelope)
  • 0 unwrap() в bus/orchestrator

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions