Skip to main content

zagens_runtime/runtime_api/
mod.rs

1//! Runtime HTTP/SSE API for local DeepSeek automation.
2
3use std::path::PathBuf;
4use std::sync::Arc;
5
6use crate::automation_manager::SharedAutomationManager;
7use crate::config::Config;
8use crate::runtime_threads::SharedRuntimeThreadManager;
9use crate::session_manager::SessionManager;
10use crate::task_manager::SharedTaskManager;
11
12pub mod openapi;
13
14mod automations;
15mod blackboards;
16pub(crate) mod kernel_replay;
17mod mcp;
18mod office;
19mod router;
20mod sessions;
21mod skills;
22mod state;
23mod stream;
24mod tasks;
25mod threads;
26mod topic_memory;
27mod usage;
28pub(crate) mod workspace;
29
30pub(crate) use automations::{
31    create_automation, delete_automation, get_automation, list_automation_runs, list_automations,
32    pause_automation, resume_automation, run_automation, update_automation,
33};
34pub(crate) use blackboards::{get_blackboard, list_blackboards};
35pub(crate) use kernel_replay::{get_kernel_thread_replay, get_kernel_turn_replay};
36pub(crate) use mcp::{
37    add_mcp_server, delete_mcp_server, discover_mcp, get_mcp_server, list_mcp_calls,
38    list_mcp_servers, list_mcp_tools, merge_mcp_config_json, reload_mcp_config, update_mcp_server,
39};
40pub(crate) use office::get_office_environment;
41pub(crate) use sessions::{
42    delete_session, get_resume_task, get_session, list_sessions, resume_session_thread,
43};
44pub(crate) use skills::{create_skill, import_skill_local, install_skill_remote, list_skills};
45pub(crate) use tasks::{cancel_task, clear_tasks, create_task, get_task, list_tasks};
46pub(crate) use threads::{
47    browse_thread_workspace, browse_workspace_by_root, compact_thread, create_thread,
48    edit_last_thread_turn, fork_thread, fork_thread_at_user_message, get_thread,
49    get_thread_checklist, get_thread_context, get_thread_harness_cycles,
50    get_thread_harness_task_graph, get_thread_scratchpad_status, init_thread_scratchpad,
51    interrupt_thread_turn, list_thread_snapshots, list_threads, list_threads_summary,
52    persist_thread_session, read_thread_workspace_file, read_workspace_file_by_root,
53    resolve_approval, restore_thread_snapshot, resume_thread, start_thread_turn, steer_thread_turn,
54    update_thread,
55};
56pub(crate) use topic_memory::get_topic_memory;
57pub(crate) use usage::{get_routing_rules, get_usage, rebuild_symbol_index, set_routing_rules};
58pub(crate) use workspace::workspace_status;
59
60pub use router::build_router;
61
62pub(crate) use sessions::ResumeTaskTracker;
63
64#[cfg(test)]
65pub(crate) use zagens_runtime_api::cors_layer;
66
67#[derive(Clone)]
68pub struct RuntimeApiState {
69    config: Config,
70    workspace: PathBuf,
71    task_manager: SharedTaskManager,
72    runtime_threads: SharedRuntimeThreadManager,
73    cors_origins: Vec<String>,
74    mcp_config_path: PathBuf,
75    automations: SharedAutomationManager,
76    runtime_token: Option<String>,
77    process_started_at_ms: u128,
78    token_fingerprint: Arc<String>,
79    shared_session_manager: Arc<SessionManager>,
80    resume_tracker: sessions::ResumeTaskTracker,
81    /// Shared MCP connection pool (hot-reload target for all engines).
82    shared_mcp_pool: std::sync::Arc<tokio::sync::Mutex<crate::mcp::McpPool>>,
83}
84
85impl RuntimeApiState {
86    #[allow(clippy::too_many_arguments)]
87    pub(crate) fn new(
88        config: Config,
89        workspace: PathBuf,
90        task_manager: SharedTaskManager,
91        runtime_threads: SharedRuntimeThreadManager,
92        cors_origins: Vec<String>,
93        mcp_config_path: PathBuf,
94        automations: SharedAutomationManager,
95        runtime_token: Option<String>,
96        process_started_at_ms: u128,
97        token_fingerprint: Arc<String>,
98        shared_session_manager: Arc<SessionManager>,
99        resume_tracker: sessions::ResumeTaskTracker,
100        shared_mcp_pool: std::sync::Arc<tokio::sync::Mutex<crate::mcp::McpPool>>,
101    ) -> Self {
102        Self {
103            config,
104            workspace,
105            task_manager,
106            runtime_threads,
107            cors_origins,
108            mcp_config_path,
109            automations,
110            runtime_token,
111            process_started_at_ms,
112            token_fingerprint,
113            shared_session_manager,
114            resume_tracker,
115            shared_mcp_pool,
116        }
117    }
118}
119
120pub(crate) fn truncate_text(text: &str, max_chars: usize) -> String {
121    let char_count = text.chars().count();
122    if char_count <= max_chars {
123        return text.to_string();
124    }
125    let truncated: String = text.chars().take(max_chars.saturating_sub(3)).collect();
126    format!("{truncated}...")
127}
128
129pub(crate) use zagens_runtime_api::ApiError;
130
131pub(crate) fn map_thread_err(err: anyhow::Error) -> ApiError {
132    let message = err.to_string();
133    if message.contains("not found") {
134        ApiError::not_found(message)
135    } else if message.contains("already has an active turn")
136        || message.contains("No active turn")
137        || message.contains("is not active")
138        || message.contains("no pending approval for")
139        || message.contains("pending approval scope mismatch")
140    {
141        ApiError::conflict(message)
142    } else {
143        ApiError::bad_request(message)
144    }
145}
146
147#[cfg(test)]
148#[path = "tests.rs"]
149mod tests;