2025-12-05 16:43:14 -03:00
|
|
|
use crate::core::bot::channels::{ChannelAdapter, VoiceAdapter, WebChannelAdapter};
|
2026-01-04 08:48:27 -03:00
|
|
|
use crate::core::bot_database::BotDatabaseManager;
|
2025-12-05 16:43:14 -03:00
|
|
|
use crate::core::config::AppConfig;
|
|
|
|
|
use crate::core::session::SessionManager;
|
|
|
|
|
use crate::core::shared::analytics::MetricsCollector;
|
|
|
|
|
use crate::core::shared::state::{AppState, Extensions};
|
|
|
|
|
#[cfg(feature = "directory")]
|
2026-01-18 19:53:34 -03:00
|
|
|
use crate::core::directory::client::ZitadelConfig;
|
2025-12-05 16:43:14 -03:00
|
|
|
#[cfg(feature = "directory")]
|
2026-01-18 19:53:34 -03:00
|
|
|
use crate::core::directory::AuthService;
|
2025-12-05 16:43:14 -03:00
|
|
|
#[cfg(feature = "llm")]
|
|
|
|
|
use crate::llm::LLMProvider;
|
|
|
|
|
use crate::shared::models::BotResponse;
|
2025-12-07 02:13:28 -03:00
|
|
|
use crate::shared::utils::{get_database_url_sync, DbPool};
|
2025-12-05 16:43:14 -03:00
|
|
|
use crate::tasks::TaskEngine;
|
|
|
|
|
use async_trait::async_trait;
|
|
|
|
|
use diesel::r2d2::{ConnectionManager, Pool};
|
|
|
|
|
use diesel::PgConnection;
|
|
|
|
|
use serde_json::Value;
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
use tokio::sync::{broadcast, mpsc, Mutex};
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "llm")]
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct MockLLMProvider {
|
|
|
|
|
pub response: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "llm")]
|
|
|
|
|
impl MockLLMProvider {
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
response: "Mock LLM response".to_string(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn with_response(response: &str) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
response: response.to_string(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "llm")]
|
|
|
|
|
impl Default for MockLLMProvider {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self::new()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "llm")]
|
|
|
|
|
#[async_trait]
|
|
|
|
|
impl LLMProvider for MockLLMProvider {
|
|
|
|
|
async fn generate(
|
|
|
|
|
&self,
|
|
|
|
|
_prompt: &str,
|
|
|
|
|
_config: &Value,
|
|
|
|
|
_model: &str,
|
|
|
|
|
_key: &str,
|
|
|
|
|
) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
Ok(self.response.clone())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn generate_stream(
|
|
|
|
|
&self,
|
|
|
|
|
_prompt: &str,
|
|
|
|
|
_config: &Value,
|
|
|
|
|
tx: mpsc::Sender<String>,
|
|
|
|
|
_model: &str,
|
|
|
|
|
_key: &str,
|
|
|
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
tx.send(self.response.clone()).await?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn cancel_job(
|
|
|
|
|
&self,
|
|
|
|
|
_session_id: &str,
|
|
|
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct MockChannelAdapter {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub messages: Arc<Mutex<Vec<BotResponse>>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl MockChannelAdapter {
|
|
|
|
|
pub fn new(name: &str) -> Self {
|
|
|
|
|
Self {
|
2025-12-26 08:59:25 -03:00
|
|
|
name: name.into(),
|
2025-12-05 16:43:14 -03:00
|
|
|
messages: Arc::new(Mutex::new(Vec::new())),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn get_sent_messages(&self) -> Vec<BotResponse> {
|
|
|
|
|
self.messages.lock().await.clone()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[async_trait]
|
|
|
|
|
impl ChannelAdapter for MockChannelAdapter {
|
2025-12-26 08:59:25 -03:00
|
|
|
fn name(&self) -> &'static str {
|
|
|
|
|
"Mock"
|
2025-12-05 16:43:14 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn is_configured(&self) -> bool {
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn send_message(
|
|
|
|
|
&self,
|
|
|
|
|
response: BotResponse,
|
|
|
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
self.messages.lock().await.push(response);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn receive_message(
|
|
|
|
|
&self,
|
|
|
|
|
_payload: Value,
|
|
|
|
|
) -> Result<Option<String>, Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
Ok(Some("mock_message".to_string()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn get_user_info(
|
|
|
|
|
&self,
|
|
|
|
|
user_id: &str,
|
|
|
|
|
) -> Result<Value, Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
Ok(serde_json::json!({
|
|
|
|
|
"id": user_id,
|
|
|
|
|
"platform": self.name,
|
|
|
|
|
"name": "Mock User"
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct TestAppStateBuilder {
|
|
|
|
|
database_url: Option<String>,
|
|
|
|
|
bucket_name: String,
|
|
|
|
|
config: Option<AppConfig>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TestAppStateBuilder {
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
database_url: None,
|
|
|
|
|
bucket_name: "test-bucket".to_string(),
|
|
|
|
|
config: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn with_database_url(mut self, url: &str) -> Self {
|
|
|
|
|
self.database_url = Some(url.to_string());
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn with_bucket_name(mut self, name: &str) -> Self {
|
|
|
|
|
self.bucket_name = name.to_string();
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn with_config(mut self, config: AppConfig) -> Self {
|
|
|
|
|
self.config = Some(config);
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn build(self) -> Result<AppState, Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
let database_url = self
|
|
|
|
|
.database_url
|
2025-12-07 02:13:28 -03:00
|
|
|
.or_else(|| get_database_url_sync().ok())
|
2025-12-05 16:43:14 -03:00
|
|
|
.unwrap_or_else(|| "postgres://test:test@localhost:5432/test".to_string());
|
|
|
|
|
|
|
|
|
|
let manager = ConnectionManager::<PgConnection>::new(&database_url);
|
|
|
|
|
let pool = Pool::builder()
|
|
|
|
|
.max_size(1)
|
|
|
|
|
.test_on_check_out(false)
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
.connection_timeout(std::time::Duration::from_secs(5))
|
2025-12-05 16:43:14 -03:00
|
|
|
.build(manager)?;
|
|
|
|
|
|
|
|
|
|
let conn = pool.get()?;
|
|
|
|
|
let session_manager = SessionManager::new(conn, None);
|
|
|
|
|
|
|
|
|
|
let (attendant_tx, _) = broadcast::channel(100);
|
|
|
|
|
|
2025-12-31 23:45:29 -03:00
|
|
|
let (task_progress_tx, _) = broadcast::channel(100);
|
|
|
|
|
|
2026-01-04 08:48:27 -03:00
|
|
|
let bot_database_manager = Arc::new(BotDatabaseManager::new(pool.clone(), &database_url));
|
|
|
|
|
|
2025-12-05 16:43:14 -03:00
|
|
|
Ok(AppState {
|
|
|
|
|
#[cfg(feature = "drive")]
|
|
|
|
|
drive: None,
|
|
|
|
|
s3_client: None,
|
|
|
|
|
#[cfg(feature = "cache")]
|
|
|
|
|
cache: None,
|
|
|
|
|
bucket_name: self.bucket_name,
|
|
|
|
|
config: self.config,
|
|
|
|
|
conn: pool.clone(),
|
|
|
|
|
database_url,
|
2026-01-04 08:48:27 -03:00
|
|
|
bot_database_manager,
|
2025-12-05 16:43:14 -03:00
|
|
|
session_manager: Arc::new(tokio::sync::Mutex::new(session_manager)),
|
|
|
|
|
metrics_collector: MetricsCollector::new(),
|
|
|
|
|
task_scheduler: None,
|
|
|
|
|
#[cfg(feature = "llm")]
|
|
|
|
|
llm_provider: Arc::new(MockLLMProvider::new()),
|
|
|
|
|
#[cfg(feature = "directory")]
|
|
|
|
|
auth_service: Arc::new(tokio::sync::Mutex::new(create_mock_auth_service())),
|
|
|
|
|
channels: Arc::new(tokio::sync::Mutex::new(HashMap::new())),
|
|
|
|
|
response_channels: Arc::new(tokio::sync::Mutex::new(HashMap::new())),
|
|
|
|
|
web_adapter: Arc::new(WebChannelAdapter::new()),
|
|
|
|
|
voice_adapter: Arc::new(VoiceAdapter::new()),
|
|
|
|
|
kb_manager: None,
|
|
|
|
|
task_engine: Arc::new(TaskEngine::new(pool)),
|
|
|
|
|
extensions: Extensions::new(),
|
|
|
|
|
attendant_broadcast: Some(attendant_tx),
|
2025-12-31 23:45:29 -03:00
|
|
|
task_progress_broadcast: Some(task_progress_tx),
|
|
|
|
|
task_manifests: Arc::new(std::sync::RwLock::new(HashMap::new())),
|
Add video module, RBAC, security features, billing, contacts, dashboards, learn, social, and multiple new modules
Major additions:
- Video editing engine with AI features (transcription, captions, TTS, scene detection)
- RBAC middleware and organization management
- Security enhancements (MFA, passkey, DLP, encryption, audit)
- Billing and subscription management
- Contacts management
- Dashboards module
- Learn/LMS module
- Social features
- Compliance (SOC2, SOP middleware, vulnerability scanner)
- New migrations for RBAC, learn, and video tables
2026-01-08 13:16:17 -03:00
|
|
|
project_service: Arc::new(tokio::sync::RwLock::new(crate::project::ProjectService::new())),
|
|
|
|
|
legal_service: Arc::new(tokio::sync::RwLock::new(crate::legal::LegalService::new())),
|
2025-12-05 16:43:14 -03:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for TestAppStateBuilder {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self::new()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "directory")]
|
2025-12-17 17:41:37 -03:00
|
|
|
pub fn create_mock_auth_service() -> AuthService {
|
2025-12-05 16:43:14 -03:00
|
|
|
let config = ZitadelConfig {
|
|
|
|
|
issuer_url: "http://localhost:8080".to_string(),
|
|
|
|
|
issuer: "http://localhost:8080".to_string(),
|
|
|
|
|
client_id: "mock_client_id".to_string(),
|
|
|
|
|
client_secret: "mock_client_secret".to_string(),
|
|
|
|
|
redirect_uri: "http://localhost:3000/callback".to_string(),
|
|
|
|
|
project_id: "mock_project_id".to_string(),
|
|
|
|
|
api_url: "http://localhost:8080".to_string(),
|
|
|
|
|
service_account_key: None,
|
|
|
|
|
};
|
|
|
|
|
|
feat(autotask): Implement AutoTask system with intent classification and app generation
- Add IntentClassifier with 7 intent types (APP_CREATE, TODO, MONITOR, ACTION, SCHEDULE, GOAL, TOOL)
- Add AppGenerator with LLM-powered app structure analysis
- Add DesignerAI for modifying apps through conversation
- Add app_server for serving generated apps with clean URLs
- Add db_api for CRUD operations on bot database tables
- Add ask_later keyword for pending info collection
- Add migration 6.1.1 with tables: pending_info, auto_tasks, execution_plans, task_approvals, task_decisions, safety_audit_log, generated_apps, intent_classifications, designer_changes
- Write apps to S3 drive and sync to SITE_ROOT for serving
- Clean URL structure: /apps/{app_name}/
- Integrate with DriveMonitor for file sync
Based on Chapter 17 - Autonomous Tasks specification
2025-12-27 21:10:09 -03:00
|
|
|
AuthService::new(config).expect("Failed to create mock AuthService")
|
2025-12-05 16:43:14 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn create_test_db_pool() -> Result<DbPool, Box<dyn std::error::Error + Send + Sync>> {
|
2025-12-07 02:13:28 -03:00
|
|
|
let database_url = get_database_url_sync()
|
2025-12-05 16:43:14 -03:00
|
|
|
.unwrap_or_else(|_| "postgres://test:test@localhost:5432/test".to_string());
|
|
|
|
|
let manager = ConnectionManager::<PgConnection>::new(&database_url);
|
Fix tasks UI, WebSocket progress, memory monitoring, and app generator
Tasks UI fixes:
- Fix task list to query auto_tasks table instead of tasks table
- Fix task detail endpoint to use UUID binding for auto_tasks query
- Add proper filter handling: complete, active, awaiting, paused, blocked
- Add TaskStats fields: awaiting, paused, blocked, time_saved
- Add /api/tasks/time-saved endpoint
- Add count-all to stats HTML response
App generator improvements:
- Add AgentActivity struct for detailed terminal-style progress
- Add emit_activity method for rich progress events
- Add detailed logging for LLM calls with timing
- Track files_written, tables_synced, bytes_generated
Memory and performance:
- Add memory_monitor module for tracking RSS and thread activity
- Skip 0-byte files in drive monitor and document processor
- Change DRIVE_MONITOR checking logs from info to trace
- Remove unused profile_section macro
WebSocket progress:
- Ensure TaskProgressEvent includes activity field
- Add with_activity builder method
2025-12-30 22:42:32 -03:00
|
|
|
let pool = Pool::builder()
|
|
|
|
|
.max_size(1)
|
|
|
|
|
.connection_timeout(std::time::Duration::from_secs(5))
|
|
|
|
|
.build(manager)?;
|
2025-12-05 16:43:14 -03:00
|
|
|
Ok(pool)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn create_mock_metrics_collector() -> MetricsCollector {
|
|
|
|
|
MetricsCollector::new()
|
|
|
|
|
}
|