upgrade Skill system auf regitry
This commit is contained in:
@@ -8,6 +8,9 @@ edition = "2024"
|
||||
sebas-tian = { path = "../sebas-tian" }
|
||||
lyra = { path = "../lyra" }
|
||||
|
||||
# Kern
|
||||
nazarick-core = { path = "../nazarick-core" }
|
||||
|
||||
# Skills
|
||||
skills = { path = "../skills" }
|
||||
|
||||
|
||||
@@ -234,15 +234,23 @@ fn split_message(text: &str) -> Vec<String> {
|
||||
let mut remaining = text;
|
||||
|
||||
while remaining.len() > MAX_CHUNK_SIZE {
|
||||
// Schnittpunkt suchen — bevorzugt Zeilenumbruch, dann Leerzeichen
|
||||
let cut = remaining[..MAX_CHUNK_SIZE]
|
||||
// Sicherstellen dass wir auf einer char-Grenze starten
|
||||
let safe_max = {
|
||||
let mut idx = MAX_CHUNK_SIZE;
|
||||
while !remaining.is_char_boundary(idx) {
|
||||
idx -= 1;
|
||||
}
|
||||
idx
|
||||
};
|
||||
|
||||
let cut = remaining[..safe_max]
|
||||
.rfind('\n')
|
||||
.or_else(|| remaining[..MAX_CHUNK_SIZE].rfind(". "))
|
||||
.or_else(|| remaining[..MAX_CHUNK_SIZE].rfind(' '))
|
||||
.unwrap_or(MAX_CHUNK_SIZE);
|
||||
.or_else(|| remaining[..safe_max].rfind(". "))
|
||||
.or_else(|| remaining[..safe_max].rfind(' '))
|
||||
.unwrap_or(safe_max);
|
||||
|
||||
chunks.push(remaining[..cut].trim().to_string());
|
||||
remaining = remaining[cut..].trim_start();
|
||||
remaining = &remaining[cut..].trim_start();
|
||||
}
|
||||
|
||||
if !remaining.is_empty() {
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
// crates/nazarick/src/chat/types.rs
|
||||
//
|
||||
// Gemeinsame Typen für alle Chat-Kanäle.
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
// ─── Auth ────────────────────────────────────────────────────────────────────
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AuthResult {
|
||||
Allowed,
|
||||
Denied { user_id: u64, username: String },
|
||||
}
|
||||
|
||||
// ─── Agent-Config ─────────────────────────────────────────────────────────────
|
||||
//
|
||||
// Wird aus config.toml geladen.
|
||||
// Jeder Agent hat seinen eigenen Bot-Token und Webhook-URL.
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct AgentChatConfig {
|
||||
pub agent_id: String,
|
||||
pub max_tokens: u32,
|
||||
pub max_loops: u32,
|
||||
pub bot_token: String,
|
||||
pub incoming_webhook_url: String,
|
||||
pub allowed_user_ids: Vec<u64>,
|
||||
|
||||
@@ -3,33 +3,19 @@
|
||||
use serde::Deserialize;
|
||||
use crate::chat::types::AgentChatConfig;
|
||||
|
||||
/// Wurzel der gesamten Nazarick-Konfiguration.
|
||||
/// Entspricht dem obersten Level in config.toml.
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct NazarickConfig {
|
||||
/// Alles unter [chat] in config.toml
|
||||
pub chat: ChatConfig,
|
||||
}
|
||||
|
||||
/// Konfiguration für den Chat-Connector.
|
||||
/// Entspricht dem [chat]-Block in config.toml.
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ChatConfig {
|
||||
/// Port auf dem Nazarick auf eingehende Webhooks lauscht
|
||||
pub listen_port: u16,
|
||||
|
||||
/// Synology User-ID des Admins — bekommt System-Benachrichtigungen
|
||||
pub admin_user_id: u64,
|
||||
|
||||
/// Basis Webhook URL für Admin-Benachrichtigungen — ohne user_ids Parameter
|
||||
pub admin_webhook_url: String,
|
||||
|
||||
/// Liste aller konfigurierten Bot-Agenten
|
||||
pub agents: Vec<AgentChatConfig>,
|
||||
}
|
||||
|
||||
/// Lädt die Konfiguration aus config.toml im Arbeitsverzeichnis.
|
||||
/// Gibt einen Fehler zurück wenn die Datei fehlt oder ungültig ist.
|
||||
pub fn load() -> anyhow::Result<NazarickConfig> {
|
||||
let content = std::fs::read_to_string("config/config.toml")?;
|
||||
let config = toml::from_str(&content)?;
|
||||
|
||||
+24
-26
@@ -1,8 +1,3 @@
|
||||
// crates/nazarick/src/main.rs
|
||||
//
|
||||
// Nazarick — Einstiegspunkt.
|
||||
// Initialisiert alle Komponenten und startet den HTTP-Server.
|
||||
|
||||
mod chat;
|
||||
mod config;
|
||||
|
||||
@@ -14,68 +9,73 @@ use tower_http::trace::TraceLayer;
|
||||
use tracing::info;
|
||||
|
||||
use api::llm::lmstudio::LmStudioProvider;
|
||||
use nazarick_core::agent::skill_registry::SkillRegistry;
|
||||
use sebas_tian::Sebas;
|
||||
use lyra::Lyra;
|
||||
use skills::personality::PersonalitySkill;
|
||||
use chat::synology::{handle_incoming, AppState};
|
||||
use skills as _;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
// Logging initialisieren
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter("nazarick=info,tower_http=debug,api=debug")
|
||||
.init();
|
||||
|
||||
info!("Nazarick erwacht...");
|
||||
|
||||
// Arbeitsverzeichnis auf Workspace-Root setzen
|
||||
// Damit relative Pfade wie "config/shared_core.md" immer funktionieren
|
||||
let exe_path = std::env::current_exe()?;
|
||||
let workspace_root = exe_path
|
||||
.parent() // debug/
|
||||
.and_then(|p| p.parent()) // target/
|
||||
.and_then(|p| p.parent()) // workspace root
|
||||
.parent()
|
||||
.and_then(|p| p.parent())
|
||||
.and_then(|p| p.parent())
|
||||
.ok_or_else(|| anyhow::anyhow!("Workspace-Root nicht gefunden"))?;
|
||||
std::env::set_current_dir(workspace_root)?;
|
||||
|
||||
info!("Arbeitsverzeichnis: {}", workspace_root.display());
|
||||
|
||||
// Config laden
|
||||
let cfg = config::load().map_err(|e| {
|
||||
eprintln!("Config Fehler: {}", e);
|
||||
e
|
||||
})?;
|
||||
let port = cfg.chat.listen_port;
|
||||
|
||||
// Sebas Tian — Butler Agent
|
||||
let registry = Arc::new(SkillRegistry::collect());
|
||||
info!("Skills geladen: {:?}", registry.all_names());
|
||||
|
||||
let sebas_cfg = cfg.chat.agents.iter()
|
||||
.find(|a| a.agent_id == "sebas_tian")
|
||||
.ok_or_else(|| anyhow::anyhow!("sebas_tian nicht in config"))?;
|
||||
|
||||
let lyra_cfg = cfg.chat.agents.iter()
|
||||
.find(|a| a.agent_id == "lyra")
|
||||
.ok_or_else(|| anyhow::anyhow!("lyra nicht in config"))?;
|
||||
|
||||
let sebas = Sebas::new(
|
||||
"sebas_tian",
|
||||
"config/shared_core.md",
|
||||
"crates/sebas-tian/config/soul_core.md",
|
||||
"crates/sebas-tian/config/soul_personality.md",
|
||||
Box::new(LmStudioProvider::new(
|
||||
"http://localhost:1234",
|
||||
"qwen/qwen3.5-9b",
|
||||
)),
|
||||
Arc::new(PersonalitySkill::new(
|
||||
"crates/sebas-tian/config/soul_personality.md",
|
||||
)),
|
||||
registry.clone(),
|
||||
sebas_cfg.max_tokens,
|
||||
sebas_cfg.max_loops,
|
||||
);
|
||||
|
||||
// Lyra — Companion Agent
|
||||
let lyra = Lyra::new(
|
||||
"lyra",
|
||||
"config/shared_core.md",
|
||||
"crates/lyra/config/soul_core.md",
|
||||
"crates/lyra/config/soul_personality.md",
|
||||
Box::new(LmStudioProvider::new(
|
||||
"http://localhost:1234",
|
||||
"qwen/qwen3.5-9b",
|
||||
)),
|
||||
Arc::new(PersonalitySkill::new(
|
||||
"crates/lyra/config/soul_personality.md",
|
||||
)),
|
||||
registry.clone(),
|
||||
lyra_cfg.max_tokens,
|
||||
lyra_cfg.max_loops,
|
||||
);
|
||||
|
||||
// Shared State aufbauen
|
||||
let state = Arc::new(AppState {
|
||||
agents: cfg.chat.agents,
|
||||
admin_user_id: cfg.chat.admin_user_id,
|
||||
@@ -85,13 +85,11 @@ async fn main() -> anyhow::Result<()> {
|
||||
lyra: Mutex::new(lyra),
|
||||
});
|
||||
|
||||
// Routes registrieren
|
||||
let app = Router::new()
|
||||
.route("/chat/synology", post(handle_incoming))
|
||||
.with_state(state)
|
||||
.layer(TraceLayer::new_for_http());
|
||||
|
||||
// Server starten
|
||||
let addr = format!("0.0.0.0:{}", port);
|
||||
let listener = tokio::net::TcpListener::bind(&addr).await?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user