1 line
30 KiB
JSON
1 line
30 KiB
JSON
{"repo": "caridle/tais", "files": {"src/main.rs": {"226123fa0a9088071d94b13deb662573883afa5d": {"t": 1785745852.5623467, "n": 13826, "h": "1cd6e24b62c9ecfa", "c": "// TAIS Core Engine — entry point\n//\n// Starts the axum HTTP/WebSocket server with all subsystems:\n// - MCP Gateway (tool registration + dispatch)\n// - Orchestrator (workflow DAG generation + execution)\n// - Evolution Engine (TextGrad-style self-optimization)\n// - Skills Bus (TAIS skill dispatch)\n// - Gene Gateway (persona injection at decision points)\n// - LlmRouter (OpenAI / Anthropic / Ollama unified LLM layer)\n// - Dashboard (system status HTML page)\n//\n// Usage:\n// cargo run # Start server on 0.0.0.0:9527\n// cargo run -- --reset-password caridle1 newpass # Reset user password\n// TAIS_PORT=8080 cargo run # Custom port\n// TAIS_AUTO_DEPLOY=true cargo run # Enable auto-deploy (DANGER)\n\nuse argon2::{PasswordHasher, password_hash::SaltString, password_hash::rand_core::OsRng};\nuse std::sync::Arc;\nuse std::sync::atomic::AtomicU32;\nuse tokio::net::TcpListener;\nuse tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};\n\n#[tokio::main]\nasync fn main() -> anyhow::Result<()> {\n // ── CLI: --reset-password <username> <newpassword> ──────────────\n let args: Vec<String> = std::env::args().collect();\n if args.len() >= 4 && args[1] == \"--reset-password\" {\n let username = &args[2];\n let new_password = &args[3];\n // Hash the new password\n let salt = SaltString::generate(&mut OsRng);\n let hash = argon2::Argon2::default()\n .hash_password(new_password.as_bytes(), &salt)\n .map(|h| h.to_string())\n .map_err(|e| anyhow::anyhow!(\"Hash error: {e}\"))?;\n // Update SQLite\n let config = tais_core::config::Config::load();\n if let Some(pool) = tais_core::data::init_db(&config.database).await {\n let result = sqlx::query(\n \"INSERT OR REPLACE INTO users (id, display_name, password_hash, first_seen, last_active)\n VALUES (?1, ?1, ?2, datetime('now'), datetime('now'))\"\n ).bind(username).bind(&hash).execute(&pool).await;\n match result {\n Ok(_) => println!(\"✅ Password reset for '{}' — new password: {}\", username, new_password),\n Err(e) => eprintln!(\"❌ Failed: {e}\"),\n }\n } else {\n eprintln!(\"❌ Database not available. Ensure tais.db exists (start server once first).\");\n }\n return Ok(());\n }\n\n // Initialize tracing\n tracing_subscriber::registry()\n .with(tracing_subscriber::EnvFilter::try_from_default_env()\n .unwrap_or_else(|_| \"tais_core=info,tower_http=info\".into()))\n .with(tracing_subscriber::fmt::layer())\n .init();\n\n tracing::info!(\"🧬 TAIS Core Engine v0.2.0 starting...\");\n\n // Load configuration\n let config = tais_core::config::Config::load();\n\n // ── Database initialization ──\n let db_pool = tais_core::data::init_db(&config.database).await;\n let db_pool = match db_pool {\n Some(ref pool) => {\n tracing::info!(\"Database initialized (max {} connections)\", config.database.max_connections);\n Some(pool.clone())\n }\n None => {\n tracing::info!(\"Running in memory-only mode (no database)\");\n None\n }\n };\n\n // ── Initialize subsystems ──\n\n // MCP Gateway\n let mcp_gateway = Arc::new(tais_core::mcp::Gateway::new());\n for (name, desc) in all_capsule_tools() {\n mcp_gateway.register_skill_tool(tais_core::McpTool {\n name,\n description: desc,\n parameters: serde_json::json!({\"type\": \"object\"}),\n }).await;\n }\n\n // Orchestrator\n let orchestrator = Arc::new(\n tais_core::orchestrator::Orchestrator::new().with_mcp(mcp_gateway.clone())\n );\n\n // Evolution Engine\n let evolution_engine = Arc::new(tais_core::evolution::EvolutionEngine::new(\n config.evolution.threshold,\n config.evolution.min_sessions,\n ));\n\n // Skills Bus\n let skills_bus = Arc::new(tais_core::skills::SkillsBus::new());\n\n // LLM Router\n let llm_router = Arc::new(tais_core::llm::LlmRouter::new());\n tracing::info!(\"LLM Router initialized (0 configs — use POST /api/llm/configs to add)\");\n\n // Register all 7 built-in TAIS skills\n {\n let count = tais_core::skills::implementations::all_tais_skills(llm_router.clone()).len();\n for skill in tais_core::skills::implementations::all_tais_skills(llm_router.clone()) {\n let name = skill.name().to_string();\n let def = skill.definition().clone();\n // Install definition first\n if let Err(e) = skills_bus.install(def).await {\n tracing::warn!(\"Failed to install skill {name}: {e}\");\n continue;\n }\n // Then register\n if let Err(e) = skills_bus.register(skill).await {\n tracing::warn!(\"Failed to register skill {name}: {e}\");\n } else {\n tracing::info!(\"✓ Registered: {name}\");\n }\n }\n tracing::info!(\"TAIS skills loaded: {count} installed & registered\");\n }\n\n // Auto-configure LLM from environment (only if explicitly set)\n // Disabled by default — use Dashboard or `llm add` command instead\n if std::env::var(\"TAIS_AUTO_LLM\").is_ok() {\n if let Ok(key) = std::env::var(\"DEEPSEEK_API_KEY\") {\n if !key.is_empty() {\n let _ = llm_router.create_config(tais_core::llm::LlmConfigRequest {\n name: \"DeepSeek\".into(), provider: tais_core::llm::ProviderType::OpenAI,\n base_url: \"https://api.deepseek.com/v1\".into(), api_key: key,\n model: \"deepseek-chat\".into(), params: tais_core::llm::LlmParams::default(),\n is_default: true, is_active: true,\n }).await;\n }\n }\n }\n\n // WeChat Bot\n let wechat_token = std::env::var(\"WECHAT_TOKEN\").unwrap_or_else(|_| \"tais_wechat_token\".into());\n let wechat_bot = Arc::new(tokio::sync::Mutex::new(\n tais_core::wechat::WechatBot::new(&wechat_token, None, None)\n ));\n tracing::info!(\"WeChat Bot initialized (token={}...)\", &wechat_token[..8.min(wechat_token.len())]);\n\n // ── Habit Engine ──\n let habit_engine = Arc::new(tais_core::habit::HabitEngine::new());\n for rule in tais_core::habit::rules::all_habit_rules() {\n let name = rule.name.clone();\n let id = rule.id.clone();\n match habit_engine.register(rule).await {\n Ok(()) => tracing::info!(\"✓ Habit registered: {id} — {name}\"),\n Err(e) => tracing::warn!(\"Failed to register habit {id}: {e}\"),\n }\n }\n if let Some(ref pool) = db_pool {\n habit_engine.with_db(pool.clone()).await;\n }\n tracing::info!(\"Habit Engine initialized with 7 capsules\");\n\n // Start periodic scheduler for H01 daily review (runs in background)\n let he = habit_engine.clone();\n tokio::spawn(async move {\n he.start_scheduler().await;\n });\n tracing::info!(\"Habit scheduler started (checks every 60s)\");\n\n // Memory (with optional DB persistence)\n let memory = if let Some(ref pool) = db_pool {\n Arc::new(tais_core::memory::SessionMemory::new().with_db(pool.clone()))\n } else {\n Arc::new(tais_core::memory::SessionMemory::new())\n };\n tracing::info!(\"Conversation memory initialized\");\n\n // Auth\n let jwt_secret = std::env::var(\"TAIS_JWT_SECRET\")\n .unwrap_or_else(|_| uuid::Uuid::new_v4().to_string());\n let token_expiry = std::env::var(\"TAIS_TOKEN_EXPIRY_HOURS\")\n .ok()\n .and_then(|s| s.parse().ok())\n .unwrap_or(24);\n let auth_state = Arc::new(tais_core::auth::AuthState::new(&jwt_secret, token_expiry));\n tracing::info!(\"Auth system initialized (JWT expiry={token_expiry}h)\");\n\n tracing::info!(\n \"Total capsules registered: 35 (14 OO + 7 Gene + 7 TAIS + 7 Habit)\",\n );\n\n let tm = Arc::new(tais_core::orchestrator::task::TaskManager::new());\n let task_dispatcher = Arc::new(tais_core::orchestrator::task::TaskDispatcher::new(\n tm.clone(),\n skills_bus.clone(),\n ));\n\n // ── Build AgentLoop ──\n let agent_loop = Arc::new(tais_core::agent::AgentLoop::new(\n Arc::new(tais_core::agent::Proposer::new(llm_router.clone())),\n Arc::new(tais_core::agent::Consumer::new(skills_bus.clone())),\n Arc::new(tais_core::agent::Rater::new(llm_router.clone())),\n Arc::new(tais_core::agent::Deployer::new(evolution_engine.clone())),\n habit_engine.clone(),\n ));\n\n // ── Build app state ──\n let state = Arc::new(tais_core::api::AppState {\n orchestrator,\n mcp_gateway,\n evolution_engine,\n skills_bus,\n llm_router,\n wechat_bot,\n memory,\n task_manager: tm,\n task_dispatcher,\n agent_loop,\n auth_state,\n habit_engine,\n db_pool,\n active_ws_count: AtomicU32::new(0),\n });\n\n // ── Start server ──\n let router = tais_core::api::build_router(state);\n let addr = format!(\"{}:{}\", config.server.host, config.server.port);\n let listener = TcpListener::bind(&addr).await?;\n\n tracing::info!(\"🚀 TAIS server listening on http://{addr}\");\n tracing::info!(\" GET / — Dashboard 首页\");\n tracing::info!(\" POST /api/workflow/generate — Generate teaching workflow\");\n tracing::info!(\" POST /api/workflow/execute — Execute workflow\");\n tracing::info!(\" GET /api/evolution/metrics — View evolution metrics\");\n tracing::info!(\" POST /api/evolution/review — Teacher review evolution\");\n tracing::info!(\" GET /api/skills/list — List TAIS skills\");\n tracing::info!(\" GET /api/mcp/tools — List MCP tools\");\n tracing::info!(\" GET /api/llm/configs — List LLM configs\");\n tracing::info!(\" POST /api/llm/configs — Create LLM config\");\n tracing::info!(\" PUT /api/llm/configs/:id — Update LLM config\");\n tracing::info!(\" DEL /api/llm/configs/:id — Delete LLM config\");\n tracing::info!(\" POST /api/llm/configs/:id/test — Test LLM connection\");\n tracing::info!(\" GET /login — Login / Register page\");\n tracing::info!(\" GET /chat — Web Chat UI\");\n tracing::info!(\" POST /api/auth/register — User registration\");\n tracing::info!(\" POST /api/auth/login — User login (JWT)\");\n tracing::info!(\" POST /api/auth/qr/request — QR login: request token\");\n tracing::info!(\" GET /api/auth/qr/status/:token — QR login: poll status\");\n tracing::info!(\" POST /api/auth/qr/confirm — QR login: confirm\");\n tracing::info!(\" POST /api/auth/wechat/bind — Request WeChat binding code\");\n tracing::info!(\" GET /api/auth/wechat/bind-status — Poll binding status\");\n tracing::info!(\" GET /api/auth/me — Current user info\");\n tracing::info!(\" WS /api/session/:id — Student real-time session\");\n\n axum::serve(listener, router).await?;\n\n Ok(())\n}\n\n/// Register all 35 capsules as MCP tools\nfn all_capsule_tools() -> Vec<(String, String)> {\n vec![\n // OO Capability Capsules (14)\n (\"oo-prd-generator\".into(), \"PRD生成器:一句话需求→8节结构化PRD\".into()),\n (\"oo-user-story\".into(), \"User Story拆解:PRD→14条INVEST Story\".into()),\n (\"oo-use-case\".into(), \"Use Case建模:Story→PlantUML用例图+规约\".into()),\n (\"oo-domain-model\".into(), \"领域模型:Use Case→DDD战术设计\".into()),\n (\"oo-class-diagram\".into(), \"类图:领域模型→OO类图+SOLID检查\".into()),\n (\"oo-sequence-diagram\".into(), \"时序图:Use Case→PlantUML时序图\".into()),\n (\"oo-state-diagram\".into(), \"状态图:类图→UML状态机\".into()),\n (\"oo-activity-diagram\".into(), \"活动图:Use Case→泳道活动图\".into()),\n (\"oo-component-diagram\".into(), \"组件图:类图→组件图+接口+技术栈\".into()),\n (\"oo-ui-prototype\".into(), \"UI原型:Story→HTML原型+页面清单\".into()),\n (\"oo-api-spec\".into(), \"API规范:时序图→OpenAPI 3.0 YAML\".into()),\n (\"oo-db-schema\".into(), \"DB Schema:领域模型→DDL+ER图\".into()),\n (\"oo-design-pattern\".into(), \"设计模式:类图→GoF 23模式推荐\".into()),\n (\"oo-code-scaffold\".into(), \"代码骨架:设计产出→DDD分层项目骨架\".into()),\n // Gene Capsules (7)\n (\"gene-personality\".into(), \"人格基因:Big Five性格模板\".into()),\n (\"gene-thinking\".into(), \"思维基因:第一性原理/类比/系统思维\".into()),\n (\"gene-decision\".into(), \"决策基因:ρ风险/τ阈值/α精度\".into()),\n (\"gene-behavior\".into(), \"行为基因:δ直白/σ简洁/γ主动\".into()),\n (\"gene-risk-control\".into(), \"风控基因:安全红线/合规底线\".into()),\n (\"gene-evolution\".into(), \"进化基因:成功模式/教训库\".into()),\n (\"gene-heredity\".into(), \"遗传基因:交叉/突变/选择算子\".into()),\n // TAIS Teaching Capsules (7)\n (\"tais-workflow\".into(), \"教学工作流编排器\".into()),\n (\"tais-learning-analyst\".into(), \"学情分析师\".into()),\n (\"tais-socratic-tutor\".into(), \"苏格拉底式导师\".into()),\n (\"tais-resource-pusher\".into(), \"个性化资源推送员\".into()),\n (\"tais-skill-coach\".into(), \"技能教练\".into()),\n (\"tais-feedback-collector\".into(), \"反馈采集器\".into()),\n (\"tais-evolution\".into(), \"自进化引擎\".into()),\n // Habit Capsules (7)\n (\"habit-review\".into(), \"复盘习惯:每日定时总结\".into()),\n (\"habit-error-handling\".into(), \"容错习惯:错误模式识别+策略切换\".into()),\n (\"habit-communication\".into(), \"沟通习惯:确认理解+总结共识\".into()),\n (\"habit-documentation\".into(), \"文档习惯:自动更新日志\".into()),\n (\"habit-optimization\".into(), \"优化习惯:自我审查+对比历史\".into()),\n (\"habit-security\".into(), \"安全习惯:高风险操作检查清单\".into()),\n (\"habit-collaboration\".into(), \"协作习惯:握手协议+任务拆解\".into()),\n // Auto-Evolution Tools (GenericAgent-inspired)\n (\"crystallize_skill\".into(), \"技能结晶:成功教学→可复用SOP文件\".into()),\n (\"update_working_checkpoint\".into(), \"工作记忆:短记事本<200 tokens\".into()),\n ]\n}\n"}, "e588e5cb5d2ad00e8fe9b61a148e2d1a4c54a07c": {"t": 1785757264.9813566, "n": 13826, "h": "1cd6e24b62c9ecfa", "c": "// TAIS Core Engine — entry point\n//\n// Starts the axum HTTP/WebSocket server with all subsystems:\n// - MCP Gateway (tool registration + dispatch)\n// - Orchestrator (workflow DAG generation + execution)\n// - Evolution Engine (TextGrad-style self-optimization)\n// - Skills Bus (TAIS skill dispatch)\n// - Gene Gateway (persona injection at decision points)\n// - LlmRouter (OpenAI / Anthropic / Ollama unified LLM layer)\n// - Dashboard (system status HTML page)\n//\n// Usage:\n// cargo run # Start server on 0.0.0.0:9527\n// cargo run -- --reset-password caridle1 newpass # Reset user password\n// TAIS_PORT=8080 cargo run # Custom port\n// TAIS_AUTO_DEPLOY=true cargo run # Enable auto-deploy (DANGER)\n\nuse argon2::{PasswordHasher, password_hash::SaltString, password_hash::rand_core::OsRng};\nuse std::sync::Arc;\nuse std::sync::atomic::AtomicU32;\nuse tokio::net::TcpListener;\nuse tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};\n\n#[tokio::main]\nasync fn main() -> anyhow::Result<()> {\n // ── CLI: --reset-password <username> <newpassword> ──────────────\n let args: Vec<String> = std::env::args().collect();\n if args.len() >= 4 && args[1] == \"--reset-password\" {\n let username = &args[2];\n let new_password = &args[3];\n // Hash the new password\n let salt = SaltString::generate(&mut OsRng);\n let hash = argon2::Argon2::default()\n .hash_password(new_password.as_bytes(), &salt)\n .map(|h| h.to_string())\n .map_err(|e| anyhow::anyhow!(\"Hash error: {e}\"))?;\n // Update SQLite\n let config = tais_core::config::Config::load();\n if let Some(pool) = tais_core::data::init_db(&config.database).await {\n let result = sqlx::query(\n \"INSERT OR REPLACE INTO users (id, display_name, password_hash, first_seen, last_active)\n VALUES (?1, ?1, ?2, datetime('now'), datetime('now'))\"\n ).bind(username).bind(&hash).execute(&pool).await;\n match result {\n Ok(_) => println!(\"✅ Password reset for '{}' — new password: {}\", username, new_password),\n Err(e) => eprintln!(\"❌ Failed: {e}\"),\n }\n } else {\n eprintln!(\"❌ Database not available. Ensure tais.db exists (start server once first).\");\n }\n return Ok(());\n }\n\n // Initialize tracing\n tracing_subscriber::registry()\n .with(tracing_subscriber::EnvFilter::try_from_default_env()\n .unwrap_or_else(|_| \"tais_core=info,tower_http=info\".into()))\n .with(tracing_subscriber::fmt::layer())\n .init();\n\n tracing::info!(\"🧬 TAIS Core Engine v0.2.0 starting...\");\n\n // Load configuration\n let config = tais_core::config::Config::load();\n\n // ── Database initialization ──\n let db_pool = tais_core::data::init_db(&config.database).await;\n let db_pool = match db_pool {\n Some(ref pool) => {\n tracing::info!(\"Database initialized (max {} connections)\", config.database.max_connections);\n Some(pool.clone())\n }\n None => {\n tracing::info!(\"Running in memory-only mode (no database)\");\n None\n }\n };\n\n // ── Initialize subsystems ──\n\n // MCP Gateway\n let mcp_gateway = Arc::new(tais_core::mcp::Gateway::new());\n for (name, desc) in all_capsule_tools() {\n mcp_gateway.register_skill_tool(tais_core::McpTool {\n name,\n description: desc,\n parameters: serde_json::json!({\"type\": \"object\"}),\n }).await;\n }\n\n // Orchestrator\n let orchestrator = Arc::new(\n tais_core::orchestrator::Orchestrator::new().with_mcp(mcp_gateway.clone())\n );\n\n // Evolution Engine\n let evolution_engine = Arc::new(tais_core::evolution::EvolutionEngine::new(\n config.evolution.threshold,\n config.evolution.min_sessions,\n ));\n\n // Skills Bus\n let skills_bus = Arc::new(tais_core::skills::SkillsBus::new());\n\n // LLM Router\n let llm_router = Arc::new(tais_core::llm::LlmRouter::new());\n tracing::info!(\"LLM Router initialized (0 configs — use POST /api/llm/configs to add)\");\n\n // Register all 7 built-in TAIS skills\n {\n let count = tais_core::skills::implementations::all_tais_skills(llm_router.clone()).len();\n for skill in tais_core::skills::implementations::all_tais_skills(llm_router.clone()) {\n let name = skill.name().to_string();\n let def = skill.definition().clone();\n // Install definition first\n if let Err(e) = skills_bus.install(def).await {\n tracing::warn!(\"Failed to install skill {name}: {e}\");\n continue;\n }\n // Then register\n if let Err(e) = skills_bus.register(skill).await {\n tracing::warn!(\"Failed to register skill {name}: {e}\");\n } else {\n tracing::info!(\"✓ Registered: {name}\");\n }\n }\n tracing::info!(\"TAIS skills loaded: {count} installed & registered\");\n }\n\n // Auto-configure LLM from environment (only if explicitly set)\n // Disabled by default — use Dashboard or `llm add` command instead\n if std::env::var(\"TAIS_AUTO_LLM\").is_ok() {\n if let Ok(key) = std::env::var(\"DEEPSEEK_API_KEY\") {\n if !key.is_empty() {\n let _ = llm_router.create_config(tais_core::llm::LlmConfigRequest {\n name: \"DeepSeek\".into(), provider: tais_core::llm::ProviderType::OpenAI,\n base_url: \"https://api.deepseek.com/v1\".into(), api_key: key,\n model: \"deepseek-chat\".into(), params: tais_core::llm::LlmParams::default(),\n is_default: true, is_active: true,\n }).await;\n }\n }\n }\n\n // WeChat Bot\n let wechat_token = std::env::var(\"WECHAT_TOKEN\").unwrap_or_else(|_| \"tais_wechat_token\".into());\n let wechat_bot = Arc::new(tokio::sync::Mutex::new(\n tais_core::wechat::WechatBot::new(&wechat_token, None, None)\n ));\n tracing::info!(\"WeChat Bot initialized (token={}...)\", &wechat_token[..8.min(wechat_token.len())]);\n\n // ── Habit Engine ──\n let habit_engine = Arc::new(tais_core::habit::HabitEngine::new());\n for rule in tais_core::habit::rules::all_habit_rules() {\n let name = rule.name.clone();\n let id = rule.id.clone();\n match habit_engine.register(rule).await {\n Ok(()) => tracing::info!(\"✓ Habit registered: {id} — {name}\"),\n Err(e) => tracing::warn!(\"Failed to register habit {id}: {e}\"),\n }\n }\n if let Some(ref pool) = db_pool {\n habit_engine.with_db(pool.clone()).await;\n }\n tracing::info!(\"Habit Engine initialized with 7 capsules\");\n\n // Start periodic scheduler for H01 daily review (runs in background)\n let he = habit_engine.clone();\n tokio::spawn(async move {\n he.start_scheduler().await;\n });\n tracing::info!(\"Habit scheduler started (checks every 60s)\");\n\n // Memory (with optional DB persistence)\n let memory = if let Some(ref pool) = db_pool {\n Arc::new(tais_core::memory::SessionMemory::new().with_db(pool.clone()))\n } else {\n Arc::new(tais_core::memory::SessionMemory::new())\n };\n tracing::info!(\"Conversation memory initialized\");\n\n // Auth\n let jwt_secret = std::env::var(\"TAIS_JWT_SECRET\")\n .unwrap_or_else(|_| uuid::Uuid::new_v4().to_string());\n let token_expiry = std::env::var(\"TAIS_TOKEN_EXPIRY_HOURS\")\n .ok()\n .and_then(|s| s.parse().ok())\n .unwrap_or(24);\n let auth_state = Arc::new(tais_core::auth::AuthState::new(&jwt_secret, token_expiry));\n tracing::info!(\"Auth system initialized (JWT expiry={token_expiry}h)\");\n\n tracing::info!(\n \"Total capsules registered: 35 (14 OO + 7 Gene + 7 TAIS + 7 Habit)\",\n );\n\n let tm = Arc::new(tais_core::orchestrator::task::TaskManager::new());\n let task_dispatcher = Arc::new(tais_core::orchestrator::task::TaskDispatcher::new(\n tm.clone(),\n skills_bus.clone(),\n ));\n\n // ── Build AgentLoop ──\n let agent_loop = Arc::new(tais_core::agent::AgentLoop::new(\n Arc::new(tais_core::agent::Proposer::new(llm_router.clone())),\n Arc::new(tais_core::agent::Consumer::new(skills_bus.clone())),\n Arc::new(tais_core::agent::Rater::new(llm_router.clone())),\n Arc::new(tais_core::agent::Deployer::new(evolution_engine.clone())),\n habit_engine.clone(),\n ));\n\n // ── Build app state ──\n let state = Arc::new(tais_core::api::AppState {\n orchestrator,\n mcp_gateway,\n evolution_engine,\n skills_bus,\n llm_router,\n wechat_bot,\n memory,\n task_manager: tm,\n task_dispatcher,\n agent_loop,\n auth_state,\n habit_engine,\n db_pool,\n active_ws_count: AtomicU32::new(0),\n });\n\n // ── Start server ──\n let router = tais_core::api::build_router(state);\n let addr = format!(\"{}:{}\", config.server.host, config.server.port);\n let listener = TcpListener::bind(&addr).await?;\n\n tracing::info!(\"🚀 TAIS server listening on http://{addr}\");\n tracing::info!(\" GET / — Dashboard 首页\");\n tracing::info!(\" POST /api/workflow/generate — Generate teaching workflow\");\n tracing::info!(\" POST /api/workflow/execute — Execute workflow\");\n tracing::info!(\" GET /api/evolution/metrics — View evolution metrics\");\n tracing::info!(\" POST /api/evolution/review — Teacher review evolution\");\n tracing::info!(\" GET /api/skills/list — List TAIS skills\");\n tracing::info!(\" GET /api/mcp/tools — List MCP tools\");\n tracing::info!(\" GET /api/llm/configs — List LLM configs\");\n tracing::info!(\" POST /api/llm/configs — Create LLM config\");\n tracing::info!(\" PUT /api/llm/configs/:id — Update LLM config\");\n tracing::info!(\" DEL /api/llm/configs/:id — Delete LLM config\");\n tracing::info!(\" POST /api/llm/configs/:id/test — Test LLM connection\");\n tracing::info!(\" GET /login — Login / Register page\");\n tracing::info!(\" GET /chat — Web Chat UI\");\n tracing::info!(\" POST /api/auth/register — User registration\");\n tracing::info!(\" POST /api/auth/login — User login (JWT)\");\n tracing::info!(\" POST /api/auth/qr/request — QR login: request token\");\n tracing::info!(\" GET /api/auth/qr/status/:token — QR login: poll status\");\n tracing::info!(\" POST /api/auth/qr/confirm — QR login: confirm\");\n tracing::info!(\" POST /api/auth/wechat/bind — Request WeChat binding code\");\n tracing::info!(\" GET /api/auth/wechat/bind-status — Poll binding status\");\n tracing::info!(\" GET /api/auth/me — Current user info\");\n tracing::info!(\" WS /api/session/:id — Student real-time session\");\n\n axum::serve(listener, router).await?;\n\n Ok(())\n}\n\n/// Register all 35 capsules as MCP tools\nfn all_capsule_tools() -> Vec<(String, String)> {\n vec![\n // OO Capability Capsules (14)\n (\"oo-prd-generator\".into(), \"PRD生成器:一句话需求→8节结构化PRD\".into()),\n (\"oo-user-story\".into(), \"User Story拆解:PRD→14条INVEST Story\".into()),\n (\"oo-use-case\".into(), \"Use Case建模:Story→PlantUML用例图+规约\".into()),\n (\"oo-domain-model\".into(), \"领域模型:Use Case→DDD战术设计\".into()),\n (\"oo-class-diagram\".into(), \"类图:领域模型→OO类图+SOLID检查\".into()),\n (\"oo-sequence-diagram\".into(), \"时序图:Use Case→PlantUML时序图\".into()),\n (\"oo-state-diagram\".into(), \"状态图:类图→UML状态机\".into()),\n (\"oo-activity-diagram\".into(), \"活动图:Use Case→泳道活动图\".into()),\n (\"oo-component-diagram\".into(), \"组件图:类图→组件图+接口+技术栈\".into()),\n (\"oo-ui-prototype\".into(), \"UI原型:Story→HTML原型+页面清单\".into()),\n (\"oo-api-spec\".into(), \"API规范:时序图→OpenAPI 3.0 YAML\".into()),\n (\"oo-db-schema\".into(), \"DB Schema:领域模型→DDL+ER图\".into()),\n (\"oo-design-pattern\".into(), \"设计模式:类图→GoF 23模式推荐\".into()),\n (\"oo-code-scaffold\".into(), \"代码骨架:设计产出→DDD分层项目骨架\".into()),\n // Gene Capsules (7)\n (\"gene-personality\".into(), \"人格基因:Big Five性格模板\".into()),\n (\"gene-thinking\".into(), \"思维基因:第一性原理/类比/系统思维\".into()),\n (\"gene-decision\".into(), \"决策基因:ρ风险/τ阈值/α精度\".into()),\n (\"gene-behavior\".into(), \"行为基因:δ直白/σ简洁/γ主动\".into()),\n (\"gene-risk-control\".into(), \"风控基因:安全红线/合规底线\".into()),\n (\"gene-evolution\".into(), \"进化基因:成功模式/教训库\".into()),\n (\"gene-heredity\".into(), \"遗传基因:交叉/突变/选择算子\".into()),\n // TAIS Teaching Capsules (7)\n (\"tais-workflow\".into(), \"教学工作流编排器\".into()),\n (\"tais-learning-analyst\".into(), \"学情分析师\".into()),\n (\"tais-socratic-tutor\".into(), \"苏格拉底式导师\".into()),\n (\"tais-resource-pusher\".into(), \"个性化资源推送员\".into()),\n (\"tais-skill-coach\".into(), \"技能教练\".into()),\n (\"tais-feedback-collector\".into(), \"反馈采集器\".into()),\n (\"tais-evolution\".into(), \"自进化引擎\".into()),\n // Habit Capsules (7)\n (\"habit-review\".into(), \"复盘习惯:每日定时总结\".into()),\n (\"habit-error-handling\".into(), \"容错习惯:错误模式识别+策略切换\".into()),\n (\"habit-communication\".into(), \"沟通习惯:确认理解+总结共识\".into()),\n (\"habit-documentation\".into(), \"文档习惯:自动更新日志\".into()),\n (\"habit-optimization\".into(), \"优化习惯:自我审查+对比历史\".into()),\n (\"habit-security\".into(), \"安全习惯:高风险操作检查清单\".into()),\n (\"habit-collaboration\".into(), \"协作习惯:握手协议+任务拆解\".into()),\n // Auto-Evolution Tools (GenericAgent-inspired)\n (\"crystallize_skill\".into(), \"技能结晶:成功教学→可复用SOP文件\".into()),\n (\"update_working_checkpoint\".into(), \"工作记忆:短记事本<200 tokens\".into()),\n ]\n}\n"}}}} |