refactor: migrate monolithic crate to Cargo Workspace with Clean Architecture
Transform the single binary crate into a 9-crate workspace monorepo: - Root Cargo.toml as [workspace] manager with resolver = "2" - zesdex-entities: Domain entity types (session, settings, store, message, etc.) - zesdex-utils: Pure utility functions (error, logger, pagination, slug, clipboard) - zesdex-dto: Data Transfer Objects for LLM provider API communication - zesdex-ipc: Unix-socket IPC layer (client/server/framing/protocol) - zesdex-iam: Identity & Access Management (Clean Architecture: domain/application/infrastructure) - zesdex-cms: Content Management (Clean Architecture: domain/application/infrastructure) - zesdex-middleware: HTTP middleware (Auth, CORS, Rate Limiting) - zesdex-libs: Composition root (AppContext, DB init, JWT, Argon2) - zesdex-backend: Main binary entry point + seed/migrate binaries - DevOps: Dockerfile, docker-compose, Nix (flake/shell/default), CI/CD updates - Remove dead root src/ and src-misc/ directories All crate re-exports maintain backward compatibility with original crate::model::*, crate::dto::*, crate::ipc::* module paths. Feature crates enforce strict layer separation: domain -> application -> infrastructure with generic trait-based dependency injection.
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
//! Per-session runtime state: message history, pending tool queue,
|
||||
//! background bash jobs, lesson/review counters, and the `TurnEvent`
|
||||
//! stream emitted while an agent turn is in flight.
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Cumulative token/latency counters for a session, persisted alongside it.
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
|
||||
pub struct UsageStats {
|
||||
pub tokens_in: u64,
|
||||
pub tokens_out: u64,
|
||||
#[serde(default)]
|
||||
pub last_tokens_in: u64,
|
||||
#[serde(default)]
|
||||
pub last_tokens_out: u64,
|
||||
pub api_calls: u64,
|
||||
pub review_tokens: u64,
|
||||
pub total_ms: u64,
|
||||
}
|
||||
|
||||
/// Mutable, serializable state for one session: chat history, tool
|
||||
/// results, pending tools, background jobs, and lesson/review counters
|
||||
/// shown in the TUI status bar.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SessionRuntime {
|
||||
pub messages: Vec<crate::dto::chat::message::ChatMessage>,
|
||||
pub tool_call_results: Vec<ToolCallResult>,
|
||||
pub pending_tool_queue: Vec<PendingTool>,
|
||||
pub bash_jobs: Vec<BashJobRef>,
|
||||
pub subagent_queue: usize,
|
||||
pub edit_count: u32,
|
||||
pub consecutive_empty_reviews: u32,
|
||||
pub session_start: i64,
|
||||
pub lesson_count: u32,
|
||||
pub lessons_user: u32,
|
||||
pub lessons_feedback: u32,
|
||||
pub lessons_project: u32,
|
||||
pub lessons_reference: u32,
|
||||
pub lessons_active: u32,
|
||||
pub lessons_stale: u32,
|
||||
pub lessons_contradicted: u32,
|
||||
pub lessons_human: u32,
|
||||
pub lessons_verified: u32,
|
||||
pub lessons_unverified: u32,
|
||||
pub review_count: u32,
|
||||
pub session_dir: PathBuf,
|
||||
pub usage: UsageStats,
|
||||
/// Whether a hive-mind convergence has completed at least once in this
|
||||
/// session. Set by the main-thread event loop when it receives a
|
||||
/// `TurnEvent::SystemNote { kind: "hive_mind_converged", .. }` — the
|
||||
/// only reliable way to detect this across turns, since system messages
|
||||
/// pushed mid-turn inside `run_agent_turn` are NOT persisted into
|
||||
/// `rt.messages` (they stay local to that turn's background thread and
|
||||
/// are only archived to `SQLite`).
|
||||
pub hive_mind_converged: bool,
|
||||
}
|
||||
|
||||
/// Record of one completed tool invocation, kept for transcript/history.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ToolCallResult {
|
||||
pub tool_call_id: String,
|
||||
pub tool_name: String,
|
||||
pub output: String,
|
||||
pub is_error: bool,
|
||||
pub duration_ms: u64,
|
||||
}
|
||||
|
||||
/// A tool call awaiting execution, along with which execution model
|
||||
/// (inline, deferred, async) it should run under.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PendingTool {
|
||||
pub tool_name: String,
|
||||
pub args: serde_json::Value,
|
||||
pub execution_model: crate::app::state::types::ExecutionModel,
|
||||
}
|
||||
|
||||
/// Reference to a background bash job tracked in session state (the actual
|
||||
/// process handle lives elsewhere; this is just the display/status record).
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BashJobRef {
|
||||
pub id: String,
|
||||
pub command: String,
|
||||
pub started_at: i64,
|
||||
pub running: bool,
|
||||
}
|
||||
|
||||
/// Events emitted onto the turn-event queue while an agent turn runs,
|
||||
/// consumed by the event loop to update state and drive re-renders.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TurnEvent {
|
||||
AssistantMessage(crate::dto::chat::message::ChatMessage),
|
||||
ToolResult {
|
||||
tool_call_id: String,
|
||||
tool_name: String,
|
||||
output: String,
|
||||
is_error: bool,
|
||||
path: Option<String>,
|
||||
},
|
||||
SystemNote {
|
||||
kind: String,
|
||||
message: String,
|
||||
},
|
||||
StreamStart,
|
||||
StreamToken(String),
|
||||
StreamDone(crate::dto::chat::message::ChatMessage),
|
||||
Usage {
|
||||
tokens_in: u64,
|
||||
tokens_out: u64,
|
||||
},
|
||||
/// Token usage from a subagent (review, test-gen, arch-review, etc.)
|
||||
/// routed to `UsageStats::review_tokens` so the Usage panel can split
|
||||
/// "main" tokens from "self-learning" tokens. Same shape as `Usage` but
|
||||
/// kept as a distinct variant so future subagent-specific metadata
|
||||
/// (origin tag, subagent name) can be attached without breaking the
|
||||
/// main-agent path.
|
||||
ReviewUsage {
|
||||
tokens_in: u64,
|
||||
tokens_out: u64,
|
||||
},
|
||||
Compacted(Vec<crate::dto::chat::message::ChatMessage>),
|
||||
Error(String),
|
||||
Done,
|
||||
/// Real-time update from a workflow subagent: push the new status
|
||||
/// into `AppStateRest::workflow_engine.agents`.
|
||||
WorkflowAgentUpdate {
|
||||
agent_id: String,
|
||||
agent_name: String,
|
||||
status: crate::app::workflow::engine::AgentStatus,
|
||||
},
|
||||
}
|
||||
|
||||
impl SessionRuntime {
|
||||
/// Create fresh runtime state for a session rooted at `session_dir`,
|
||||
/// with all counters zeroed and `session_start` set to now.
|
||||
pub fn new(session_dir: PathBuf) -> Self {
|
||||
SessionRuntime {
|
||||
messages: Vec::new(),
|
||||
tool_call_results: Vec::new(),
|
||||
pending_tool_queue: Vec::new(),
|
||||
bash_jobs: Vec::new(),
|
||||
subagent_queue: 0,
|
||||
edit_count: 0,
|
||||
consecutive_empty_reviews: 0,
|
||||
session_start: chrono::Utc::now().timestamp_millis(),
|
||||
lesson_count: 0,
|
||||
lessons_user: 0,
|
||||
lessons_feedback: 0,
|
||||
lessons_project: 0,
|
||||
lessons_reference: 0,
|
||||
lessons_active: 0,
|
||||
lessons_stale: 0,
|
||||
lessons_contradicted: 0,
|
||||
lessons_human: 0,
|
||||
lessons_verified: 0,
|
||||
lessons_unverified: 0,
|
||||
review_count: 0,
|
||||
session_dir,
|
||||
usage: UsageStats::default(),
|
||||
hive_mind_converged: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Append a message to the session's conversation history.
|
||||
pub fn push_message(&mut self, msg: crate::dto::chat::message::ChatMessage) {
|
||||
self.messages.push(msg);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user