2025-11-22 22:55:35 -03:00
|
|
|
use crate::core::bot::channels::{ChannelAdapter, VoiceAdapter, WebChannelAdapter};
|
|
|
|
|
use crate::core::config::AppConfig;
|
2025-11-26 22:54:22 -03:00
|
|
|
use crate::core::kb::KnowledgeBaseManager;
|
|
|
|
|
use crate::core::session::SessionManager;
|
2025-11-27 13:53:16 -03:00
|
|
|
use crate::core::shared::analytics::MetricsCollector;
|
2025-11-26 22:54:22 -03:00
|
|
|
#[cfg(feature = "directory")]
|
|
|
|
|
use crate::directory::AuthService;
|
2025-11-22 22:55:35 -03:00
|
|
|
#[cfg(feature = "llm")]
|
|
|
|
|
use crate::llm::LLMProvider;
|
|
|
|
|
use crate::shared::models::BotResponse;
|
|
|
|
|
use crate::shared::utils::DbPool;
|
2025-11-27 13:53:16 -03:00
|
|
|
use crate::tasks::{TaskEngine, TaskScheduler};
|
2025-11-22 22:55:35 -03:00
|
|
|
#[cfg(feature = "drive")]
|
|
|
|
|
use aws_sdk_s3::Client as S3Client;
|
2025-12-05 16:43:14 -03:00
|
|
|
use diesel::r2d2::{ConnectionManager, Pool};
|
|
|
|
|
use diesel::PgConnection;
|
2025-12-05 12:09:02 -03:00
|
|
|
#[cfg(feature = "cache")]
|
2025-11-22 22:55:35 -03:00
|
|
|
use redis::Client as RedisClient;
|
Add Suite app documentation, templates, and Askama config
- Add askama.toml for template configuration (ui/ directory)
- Add Suite app documentation with flow diagrams (SVG)
- App launcher, chat flow, drive flow, tasks flow
- Individual app docs: chat, drive, tasks, mail, etc.
- Add HTML templates for Suite apps
- Base template with header and app launcher
- Auth login page
- Chat, Drive, Mail, Meet, Tasks templates
- Partial templates for messages, sessions, notifications
- Add Extensions type to AppState for type-erased storage
- Add mTLS module for service-to-service authentication
- Update web handlers to use new template paths (suite/)
- Fix auth module to avoid axum-extra TypedHeader dependency
2025-11-30 21:00:48 -03:00
|
|
|
use std::any::{Any, TypeId};
|
2025-11-22 22:55:35 -03:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
use std::sync::Arc;
|
feat(attendance): Add LLM-assisted attendant features
- Real-time tips when customer messages arrive
- Message polishing with one click
- Smart reply generation (3 contextual suggestions)
- Auto-summary when attendant takes conversation
- LLM-powered sentiment analysis with escalation warnings
WhatsApp Attendant Commands:
- /queue, /take, /status, /transfer, /resolve
- /tips, /polish, /replies, /summary, /help
- Portuguese versions: /fila, /pegar, /dicas, /polir, /respostas, /resumo
Config options (config.csv):
- attendant-llm-tips
- attendant-polish-message
- attendant-smart-replies
- attendant-auto-summary
- attendant-sentiment-analysis
API Endpoints:
- POST /api/attendance/llm/tips
- POST /api/attendance/llm/polish
- POST /api/attendance/llm/smart-replies
- GET /api/attendance/llm/summary/{session_id}
- POST /api/attendance/llm/sentiment
- GET /api/attendance/llm/config/{bot_id}
Uses bot's system prompt for consistency between bot and human-assisted responses.
2025-12-05 13:47:15 -03:00
|
|
|
use tokio::sync::{broadcast, mpsc};
|
|
|
|
|
|
|
|
|
|
/// Notification sent to attendants via WebSocket/broadcast
|
|
|
|
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
|
|
|
pub struct AttendantNotification {
|
|
|
|
|
#[serde(rename = "type")]
|
|
|
|
|
pub notification_type: String,
|
|
|
|
|
pub session_id: String,
|
|
|
|
|
pub user_id: String,
|
|
|
|
|
pub user_name: Option<String>,
|
|
|
|
|
pub user_phone: Option<String>,
|
|
|
|
|
pub channel: String,
|
|
|
|
|
pub content: String,
|
|
|
|
|
pub timestamp: String,
|
|
|
|
|
pub assigned_to: Option<String>,
|
|
|
|
|
pub priority: i32,
|
|
|
|
|
}
|
2025-11-22 22:55:35 -03:00
|
|
|
|
Add Suite app documentation, templates, and Askama config
- Add askama.toml for template configuration (ui/ directory)
- Add Suite app documentation with flow diagrams (SVG)
- App launcher, chat flow, drive flow, tasks flow
- Individual app docs: chat, drive, tasks, mail, etc.
- Add HTML templates for Suite apps
- Base template with header and app launcher
- Auth login page
- Chat, Drive, Mail, Meet, Tasks templates
- Partial templates for messages, sessions, notifications
- Add Extensions type to AppState for type-erased storage
- Add mTLS module for service-to-service authentication
- Update web handlers to use new template paths (suite/)
- Fix auth module to avoid axum-extra TypedHeader dependency
2025-11-30 21:00:48 -03:00
|
|
|
/// Type-erased extension storage for AppState
|
|
|
|
|
#[derive(Default)]
|
|
|
|
|
pub struct Extensions {
|
|
|
|
|
map: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Extensions {
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
map: HashMap::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Insert a value into the extensions
|
|
|
|
|
pub fn insert<T: Send + Sync + 'static>(&mut self, value: T) {
|
|
|
|
|
self.map.insert(TypeId::of::<T>(), Box::new(value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get a reference to a value from the extensions
|
|
|
|
|
pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
|
|
|
|
|
self.map
|
|
|
|
|
.get(&TypeId::of::<T>())
|
|
|
|
|
.and_then(|boxed| boxed.downcast_ref::<T>())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get a mutable reference to a value from the extensions
|
|
|
|
|
pub fn get_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
|
|
|
|
|
self.map
|
|
|
|
|
.get_mut(&TypeId::of::<T>())
|
|
|
|
|
.and_then(|boxed| boxed.downcast_mut::<T>())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Check if a value of type T exists
|
|
|
|
|
pub fn contains<T: Send + Sync + 'static>(&self) -> bool {
|
|
|
|
|
self.map.contains_key(&TypeId::of::<T>())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Remove a value from the extensions
|
|
|
|
|
pub fn remove<T: Send + Sync + 'static>(&mut self) -> Option<T> {
|
|
|
|
|
self.map
|
|
|
|
|
.remove(&TypeId::of::<T>())
|
|
|
|
|
.and_then(|boxed| boxed.downcast::<T>().ok())
|
|
|
|
|
.map(|boxed| *boxed)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Clone for Extensions {
|
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
|
// Extensions cannot be cloned deeply, so we create an empty one
|
|
|
|
|
// This is a limitation - extensions should be Arc-wrapped if sharing is needed
|
|
|
|
|
Self::new()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl std::fmt::Debug for Extensions {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
f.debug_struct("Extensions")
|
|
|
|
|
.field("count", &self.map.len())
|
|
|
|
|
.finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-22 22:55:35 -03:00
|
|
|
pub struct AppState {
|
|
|
|
|
#[cfg(feature = "drive")]
|
|
|
|
|
pub drive: Option<S3Client>,
|
2025-11-27 13:53:16 -03:00
|
|
|
pub s3_client: Option<S3Client>,
|
2025-12-05 12:09:02 -03:00
|
|
|
#[cfg(feature = "cache")]
|
2025-11-22 22:55:35 -03:00
|
|
|
pub cache: Option<Arc<RedisClient>>,
|
|
|
|
|
pub bucket_name: String,
|
|
|
|
|
pub config: Option<AppConfig>,
|
|
|
|
|
pub conn: DbPool,
|
2025-11-27 13:53:16 -03:00
|
|
|
pub database_url: String,
|
2025-11-22 22:55:35 -03:00
|
|
|
pub session_manager: Arc<tokio::sync::Mutex<SessionManager>>,
|
2025-11-27 13:53:16 -03:00
|
|
|
pub metrics_collector: MetricsCollector,
|
|
|
|
|
pub task_scheduler: Option<Arc<TaskScheduler>>,
|
2025-11-22 22:55:35 -03:00
|
|
|
#[cfg(feature = "llm")]
|
|
|
|
|
pub llm_provider: Arc<dyn LLMProvider>,
|
|
|
|
|
#[cfg(feature = "directory")]
|
|
|
|
|
pub auth_service: Arc<tokio::sync::Mutex<AuthService>>,
|
|
|
|
|
pub channels: Arc<tokio::sync::Mutex<HashMap<String, Arc<dyn ChannelAdapter>>>>,
|
|
|
|
|
pub response_channels: Arc<tokio::sync::Mutex<HashMap<String, mpsc::Sender<BotResponse>>>>,
|
|
|
|
|
pub web_adapter: Arc<WebChannelAdapter>,
|
|
|
|
|
pub voice_adapter: Arc<VoiceAdapter>,
|
2025-11-26 22:54:22 -03:00
|
|
|
pub kb_manager: Option<Arc<KnowledgeBaseManager>>,
|
2025-11-27 08:34:24 -03:00
|
|
|
pub task_engine: Arc<TaskEngine>,
|
Add Suite app documentation, templates, and Askama config
- Add askama.toml for template configuration (ui/ directory)
- Add Suite app documentation with flow diagrams (SVG)
- App launcher, chat flow, drive flow, tasks flow
- Individual app docs: chat, drive, tasks, mail, etc.
- Add HTML templates for Suite apps
- Base template with header and app launcher
- Auth login page
- Chat, Drive, Mail, Meet, Tasks templates
- Partial templates for messages, sessions, notifications
- Add Extensions type to AppState for type-erased storage
- Add mTLS module for service-to-service authentication
- Update web handlers to use new template paths (suite/)
- Fix auth module to avoid axum-extra TypedHeader dependency
2025-11-30 21:00:48 -03:00
|
|
|
/// Type-erased extension storage for web handlers and other components
|
|
|
|
|
pub extensions: Extensions,
|
feat(attendance): Add LLM-assisted attendant features
- Real-time tips when customer messages arrive
- Message polishing with one click
- Smart reply generation (3 contextual suggestions)
- Auto-summary when attendant takes conversation
- LLM-powered sentiment analysis with escalation warnings
WhatsApp Attendant Commands:
- /queue, /take, /status, /transfer, /resolve
- /tips, /polish, /replies, /summary, /help
- Portuguese versions: /fila, /pegar, /dicas, /polir, /respostas, /resumo
Config options (config.csv):
- attendant-llm-tips
- attendant-polish-message
- attendant-smart-replies
- attendant-auto-summary
- attendant-sentiment-analysis
API Endpoints:
- POST /api/attendance/llm/tips
- POST /api/attendance/llm/polish
- POST /api/attendance/llm/smart-replies
- GET /api/attendance/llm/summary/{session_id}
- POST /api/attendance/llm/sentiment
- GET /api/attendance/llm/config/{bot_id}
Uses bot's system prompt for consistency between bot and human-assisted responses.
2025-12-05 13:47:15 -03:00
|
|
|
/// Broadcast channel for attendant notifications (human handoff)
|
|
|
|
|
/// Used to notify attendants of new messages from customers
|
|
|
|
|
pub attendant_broadcast: Option<broadcast::Sender<AttendantNotification>>,
|
2025-11-22 22:55:35 -03:00
|
|
|
}
|
|
|
|
|
impl Clone for AppState {
|
|
|
|
|
fn clone(&self) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
#[cfg(feature = "drive")]
|
|
|
|
|
drive: self.drive.clone(),
|
2025-11-27 13:53:16 -03:00
|
|
|
s3_client: self.s3_client.clone(),
|
2025-11-22 22:55:35 -03:00
|
|
|
bucket_name: self.bucket_name.clone(),
|
|
|
|
|
config: self.config.clone(),
|
|
|
|
|
conn: self.conn.clone(),
|
2025-11-27 13:53:16 -03:00
|
|
|
database_url: self.database_url.clone(),
|
2025-12-05 12:09:02 -03:00
|
|
|
#[cfg(feature = "cache")]
|
2025-11-22 22:55:35 -03:00
|
|
|
cache: self.cache.clone(),
|
|
|
|
|
session_manager: Arc::clone(&self.session_manager),
|
2025-11-27 13:53:16 -03:00
|
|
|
metrics_collector: self.metrics_collector.clone(),
|
|
|
|
|
task_scheduler: self.task_scheduler.clone(),
|
2025-11-22 22:55:35 -03:00
|
|
|
#[cfg(feature = "llm")]
|
|
|
|
|
llm_provider: Arc::clone(&self.llm_provider),
|
|
|
|
|
#[cfg(feature = "directory")]
|
|
|
|
|
auth_service: Arc::clone(&self.auth_service),
|
2025-11-26 22:54:22 -03:00
|
|
|
kb_manager: self.kb_manager.clone(),
|
2025-11-22 22:55:35 -03:00
|
|
|
channels: Arc::clone(&self.channels),
|
|
|
|
|
response_channels: Arc::clone(&self.response_channels),
|
|
|
|
|
web_adapter: Arc::clone(&self.web_adapter),
|
|
|
|
|
voice_adapter: Arc::clone(&self.voice_adapter),
|
2025-11-27 08:34:24 -03:00
|
|
|
task_engine: Arc::clone(&self.task_engine),
|
Add Suite app documentation, templates, and Askama config
- Add askama.toml for template configuration (ui/ directory)
- Add Suite app documentation with flow diagrams (SVG)
- App launcher, chat flow, drive flow, tasks flow
- Individual app docs: chat, drive, tasks, mail, etc.
- Add HTML templates for Suite apps
- Base template with header and app launcher
- Auth login page
- Chat, Drive, Mail, Meet, Tasks templates
- Partial templates for messages, sessions, notifications
- Add Extensions type to AppState for type-erased storage
- Add mTLS module for service-to-service authentication
- Update web handlers to use new template paths (suite/)
- Fix auth module to avoid axum-extra TypedHeader dependency
2025-11-30 21:00:48 -03:00
|
|
|
extensions: self.extensions.clone(),
|
feat(attendance): Add LLM-assisted attendant features
- Real-time tips when customer messages arrive
- Message polishing with one click
- Smart reply generation (3 contextual suggestions)
- Auto-summary when attendant takes conversation
- LLM-powered sentiment analysis with escalation warnings
WhatsApp Attendant Commands:
- /queue, /take, /status, /transfer, /resolve
- /tips, /polish, /replies, /summary, /help
- Portuguese versions: /fila, /pegar, /dicas, /polir, /respostas, /resumo
Config options (config.csv):
- attendant-llm-tips
- attendant-polish-message
- attendant-smart-replies
- attendant-auto-summary
- attendant-sentiment-analysis
API Endpoints:
- POST /api/attendance/llm/tips
- POST /api/attendance/llm/polish
- POST /api/attendance/llm/smart-replies
- GET /api/attendance/llm/summary/{session_id}
- POST /api/attendance/llm/sentiment
- GET /api/attendance/llm/config/{bot_id}
Uses bot's system prompt for consistency between bot and human-assisted responses.
2025-12-05 13:47:15 -03:00
|
|
|
attendant_broadcast: self.attendant_broadcast.clone(),
|
2025-11-22 22:55:35 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl std::fmt::Debug for AppState {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
let mut debug = f.debug_struct("AppState");
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "drive")]
|
|
|
|
|
debug.field("drive", &self.drive.is_some());
|
|
|
|
|
|
2025-11-27 13:53:16 -03:00
|
|
|
debug.field("s3_client", &self.s3_client.is_some());
|
|
|
|
|
|
2025-12-05 12:09:02 -03:00
|
|
|
#[cfg(feature = "cache")]
|
2025-11-22 22:55:35 -03:00
|
|
|
debug.field("cache", &self.cache.is_some());
|
|
|
|
|
|
2025-11-26 22:54:22 -03:00
|
|
|
debug
|
|
|
|
|
.field("bucket_name", &self.bucket_name)
|
2025-11-22 22:55:35 -03:00
|
|
|
.field("config", &self.config)
|
|
|
|
|
.field("conn", &"DbPool")
|
2025-11-27 13:53:16 -03:00
|
|
|
.field("database_url", &"[REDACTED]")
|
|
|
|
|
.field("session_manager", &"Arc<Mutex<SessionManager>>")
|
|
|
|
|
.field("metrics_collector", &"MetricsCollector")
|
|
|
|
|
.field("task_scheduler", &self.task_scheduler.is_some());
|
2025-11-22 22:55:35 -03:00
|
|
|
|
|
|
|
|
#[cfg(feature = "llm")]
|
|
|
|
|
debug.field("llm_provider", &"Arc<dyn LLMProvider>");
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "directory")]
|
|
|
|
|
debug.field("auth_service", &"Arc<Mutex<AuthService>>");
|
|
|
|
|
|
|
|
|
|
debug
|
|
|
|
|
.field("channels", &"Arc<Mutex<HashMap>>")
|
|
|
|
|
.field("response_channels", &"Arc<Mutex<HashMap>>")
|
|
|
|
|
.field("web_adapter", &self.web_adapter)
|
|
|
|
|
.field("voice_adapter", &self.voice_adapter)
|
Add Suite app documentation, templates, and Askama config
- Add askama.toml for template configuration (ui/ directory)
- Add Suite app documentation with flow diagrams (SVG)
- App launcher, chat flow, drive flow, tasks flow
- Individual app docs: chat, drive, tasks, mail, etc.
- Add HTML templates for Suite apps
- Base template with header and app launcher
- Auth login page
- Chat, Drive, Mail, Meet, Tasks templates
- Partial templates for messages, sessions, notifications
- Add Extensions type to AppState for type-erased storage
- Add mTLS module for service-to-service authentication
- Update web handlers to use new template paths (suite/)
- Fix auth module to avoid axum-extra TypedHeader dependency
2025-11-30 21:00:48 -03:00
|
|
|
.field("extensions", &self.extensions)
|
2025-11-22 22:55:35 -03:00
|
|
|
.finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-05 16:43:14 -03:00
|
|
|
|
|
|
|
|
#[cfg(feature = "llm")]
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
struct MockLLMProvider;
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "llm")]
|
|
|
|
|
#[async_trait::async_trait]
|
|
|
|
|
impl LLMProvider for MockLLMProvider {
|
|
|
|
|
async fn generate(
|
|
|
|
|
&self,
|
|
|
|
|
_prompt: &str,
|
|
|
|
|
_config: &serde_json::Value,
|
|
|
|
|
_model: &str,
|
|
|
|
|
_key: &str,
|
|
|
|
|
) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
Ok("Mock response".to_string())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn generate_stream(
|
|
|
|
|
&self,
|
|
|
|
|
_prompt: &str,
|
|
|
|
|
_config: &serde_json::Value,
|
|
|
|
|
tx: mpsc::Sender<String>,
|
|
|
|
|
_model: &str,
|
|
|
|
|
_key: &str,
|
|
|
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
let _ = tx.send("Mock response".to_string()).await;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn cancel_job(
|
|
|
|
|
&self,
|
|
|
|
|
_session_id: &str,
|
|
|
|
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "directory")]
|
|
|
|
|
fn create_mock_auth_service() -> AuthService {
|
|
|
|
|
use crate::directory::client::ZitadelConfig;
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let rt = tokio::runtime::Handle::try_current()
|
|
|
|
|
.map(|h| h.block_on(AuthService::new(config.clone())))
|
|
|
|
|
.unwrap_or_else(|_| {
|
|
|
|
|
tokio::runtime::Runtime::new()
|
|
|
|
|
.expect("Failed to create runtime")
|
|
|
|
|
.block_on(AuthService::new(config))
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
rt.expect("Failed to create mock AuthService")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for AppState {
|
|
|
|
|
fn default() -> Self {
|
2025-12-07 02:13:28 -03:00
|
|
|
// NO LEGACY FALLBACK - Vault is mandatory
|
|
|
|
|
// This default is only for tests. In production, use the full initialization.
|
|
|
|
|
let database_url = crate::shared::utils::get_database_url_sync()
|
|
|
|
|
.expect("Vault not configured. Set VAULT_ADDR and VAULT_TOKEN in .env");
|
2025-12-05 16:43:14 -03:00
|
|
|
|
|
|
|
|
let manager = ConnectionManager::<PgConnection>::new(&database_url);
|
|
|
|
|
let pool = Pool::builder()
|
|
|
|
|
.max_size(1)
|
|
|
|
|
.test_on_check_out(false)
|
|
|
|
|
.build(manager)
|
|
|
|
|
.expect("Failed to create test database pool");
|
|
|
|
|
|
|
|
|
|
let conn = pool.get().expect("Failed to get test database connection");
|
|
|
|
|
let session_manager = SessionManager::new(conn, None);
|
|
|
|
|
|
|
|
|
|
let (attendant_tx, _) = broadcast::channel(100);
|
|
|
|
|
|
|
|
|
|
Self {
|
|
|
|
|
#[cfg(feature = "drive")]
|
|
|
|
|
drive: None,
|
|
|
|
|
s3_client: None,
|
|
|
|
|
#[cfg(feature = "cache")]
|
|
|
|
|
cache: None,
|
|
|
|
|
bucket_name: "test-bucket".to_string(),
|
|
|
|
|
config: None,
|
|
|
|
|
conn: pool.clone(),
|
|
|
|
|
database_url,
|
|
|
|
|
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),
|
|
|
|
|
#[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),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|