refactor: LLM Typen und Traits nach nazarick-core verschoben, BaseAgent extrahiert
This commit is contained in:
Generated
+1
@@ -760,6 +760,7 @@ dependencies = [
|
|||||||
name = "nazarick-core"
|
name = "nazarick-core"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|||||||
+9
-1
@@ -15,5 +15,13 @@ bot_token = "k1RMRh0NbcROtVlPbUg2GNgtGzb3AKmiHzgIt0E1VcmtWkZFAic7Sv6s
|
|||||||
incoming_webhook_url = "https://sithies-tb.de6.quickconnect.to/direct/webapi/entry.cgi?api=SYNO.Chat.External&method=chatbot&version=2&token=%22k1RMRh0NbcROtVlPbUg2GNgtGzb3AKmiHzgIt0E1VcmtWkZFAic7Sv6sS3ZPHO1D%22"
|
incoming_webhook_url = "https://sithies-tb.de6.quickconnect.to/direct/webapi/entry.cgi?api=SYNO.Chat.External&method=chatbot&version=2&token=%22k1RMRh0NbcROtVlPbUg2GNgtGzb3AKmiHzgIt0E1VcmtWkZFAic7Sv6sS3ZPHO1D%22"
|
||||||
allowed_user_ids = [5]
|
allowed_user_ids = [5]
|
||||||
|
|
||||||
|
agent_id = "lyra"
|
||||||
|
bot_token = "e8Hg50YgD1YcfmfaKCr1B3lgAE3c2s8QyJOTXyfkPJulKzcqgqq7EBrT4MNw1gUy"
|
||||||
|
incoming_webhook_url = "https://sithies-tb.de6.quickconnect.to/direct/webapi/entry.cgi?api=SYNO.Chat.External&method=chatbot&version=2&token=%22e8Hg50YgD1YcfmfaKCr1B3lgAE3c2s8QyJOTXyfkPJulKzcqgqq7EBrT4MNw1gUy%22"
|
||||||
|
allowed_user_ids = [5]
|
||||||
|
|
||||||
[agents.sebas_tian]
|
[agents.sebas_tian]
|
||||||
# Sebas-spezifisches
|
# Sebas-spezifisches
|
||||||
|
|
||||||
|
[agents.lyra]
|
||||||
|
# Lyra-spezifisches
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
/// Abstraktionsschicht für alle LLM-Provider.
|
/// Abstraktionsschicht für alle LLM-Provider.
|
||||||
/// Neue Provider (Ollama, Mistral) werden hier als weitere Submodule ergänzt.
|
/// Neue Provider (Ollama, Mistral) werden hier als weitere Submodule ergänzt.
|
||||||
pub mod provider;
|
|
||||||
pub mod lmstudio;
|
pub mod lmstudio;
|
||||||
|
|
||||||
// Re-export der wichtigsten Typen damit Nutzer nur `api::llm::X` schreiben müssen
|
// Re-export aus nazarick-core damit bestehende Importe `api::llm::X` weiter funktionieren
|
||||||
pub use provider::{LlmProvider, LlmRequest, LlmResponse, Message};
|
pub use nazarick_core::llm::{LlmProvider, LlmRequest, LlmResponse, Message};
|
||||||
@@ -3,7 +3,7 @@ use reqwest::Client;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use nazarick_core::types::Result;
|
use nazarick_core::types::Result;
|
||||||
use nazarick_core::error::NazarickError;
|
use nazarick_core::error::NazarickError;
|
||||||
use crate::llm::provider::{LlmProvider, LlmRequest, LlmResponse, Message};
|
use nazarick_core::llm::{LlmProvider, LlmRequest, LlmResponse, Message};
|
||||||
|
|
||||||
/// LM Studio Provider — für lokale Entwicklung auf dem Entwicklungsrechner.
|
/// LM Studio Provider — für lokale Entwicklung auf dem Entwicklungsrechner.
|
||||||
/// LM Studio emuliert die OpenAI Chat Completions API, daher nutzen
|
/// LM Studio emuliert die OpenAI Chat Completions API, daher nutzen
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ edition = "2024"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
thiserror = "2.0.18"
|
thiserror = "2.0.18"
|
||||||
uuid = { version = "1.22.0", features = ["v4"] }
|
uuid = { version = "1.22.0", features = ["v4"] }
|
||||||
|
async-trait = "0.1.89"
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
// nazarick-core/src/agent.rs
|
||||||
|
//
|
||||||
|
// BaseAgent — gemeinsame Logik für alle Agenten.
|
||||||
|
// Sebas, Lyra und zukünftige Agenten sind nur noch dünne Wrapper darum.
|
||||||
|
|
||||||
|
use crate::prompt::PromptBuilder;
|
||||||
|
use crate::types::{AgentId, Result};
|
||||||
|
use crate::llm::{LlmProvider, LlmRequest, Message};
|
||||||
|
|
||||||
|
pub struct BaseAgent {
|
||||||
|
/// Eindeutige ID dieser Agent-Instanz
|
||||||
|
pub id: AgentId,
|
||||||
|
/// Baut den System-Prompt aus soul_core + soul_personality
|
||||||
|
prompt_builder: PromptBuilder,
|
||||||
|
/// Das LLM-Backend (LmStudio, Ollama, Mistral)
|
||||||
|
llm: Box<dyn LlmProvider>,
|
||||||
|
/// Konversationsverlauf — damit der Agent den Kontext behält
|
||||||
|
history: Vec<Message>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BaseAgent {
|
||||||
|
/// Erstellt eine neue BaseAgent-Instanz.
|
||||||
|
/// Wird von jedem Agenten in seinem new() aufgerufen.
|
||||||
|
pub fn new(
|
||||||
|
soul_core_path: impl Into<String>,
|
||||||
|
soul_personality_path: impl Into<String>,
|
||||||
|
llm: Box<dyn LlmProvider>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
id: AgentId::new_v4(),
|
||||||
|
prompt_builder: PromptBuilder::new(soul_core_path, soul_personality_path),
|
||||||
|
llm,
|
||||||
|
history: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sendet eine Nachricht und gibt die Antwort zurück.
|
||||||
|
/// Konversationsverlauf wird automatisch mitgeführt.
|
||||||
|
pub async fn chat(&mut self, user_message: &str) -> Result<String> {
|
||||||
|
let system_prompt = self.prompt_builder.build()?;
|
||||||
|
|
||||||
|
self.history.push(Message::user(user_message));
|
||||||
|
|
||||||
|
let mut messages = vec![Message::system(system_prompt)];
|
||||||
|
messages.extend(self.history.clone());
|
||||||
|
|
||||||
|
let request = LlmRequest {
|
||||||
|
messages,
|
||||||
|
max_tokens: 4096,
|
||||||
|
temperature: 0.7,
|
||||||
|
};
|
||||||
|
|
||||||
|
let response = self.llm.complete(request).await?;
|
||||||
|
|
||||||
|
self.history.push(Message::assistant(&response.content));
|
||||||
|
|
||||||
|
Ok(response.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Löscht den Konversationsverlauf.
|
||||||
|
/// Nützlich wenn ein neues Gespräch beginnen soll.
|
||||||
|
pub fn clear_history(&mut self) {
|
||||||
|
self.history.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,4 +9,6 @@ pub mod usage;
|
|||||||
/// Persönlichkeit basiert auf zwei Dateien:
|
/// Persönlichkeit basiert auf zwei Dateien:
|
||||||
/// - soul_core.md → unveränderlicher Kern (Regeln, Sicherheit)
|
/// - soul_core.md → unveränderlicher Kern (Regeln, Sicherheit)
|
||||||
/// - soul_personality.md → entwickelbarer Teil (Ton, Präferenzen)
|
/// - soul_personality.md → entwickelbarer Teil (Ton, Präferenzen)
|
||||||
pub mod prompt;
|
pub mod prompt;
|
||||||
|
pub mod llm;
|
||||||
|
pub mod agent;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// nazarick-core/src/llm/mod.rs
|
||||||
|
//
|
||||||
|
// LLM-Modul — Typen und Traits für alle LLM-Provider.
|
||||||
|
// Re-exportiert alles damit Nutzer nur `nazarick_core::llm::X` schreiben müssen.
|
||||||
|
|
||||||
|
mod types;
|
||||||
|
mod traits;
|
||||||
|
|
||||||
|
pub use types::{Message, LlmRequest, LlmResponse};
|
||||||
|
pub use traits::LlmProvider;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// nazarick-core/src/llm/traits.rs
|
||||||
|
//
|
||||||
|
// LlmProvider Trait — gemeinsame Schnittstelle für alle LLM-Backends.
|
||||||
|
// Neue Provider (Ollama, Mistral) implementieren diesen Trait.
|
||||||
|
|
||||||
|
use crate::types::Result;
|
||||||
|
use crate::llm::types::{LlmRequest, LlmResponse};
|
||||||
|
|
||||||
|
/// Zentraler Trait für alle LLM-Provider.
|
||||||
|
/// Jeder Provider (LmStudio, Ollama, Mistral) implementiert diesen Trait.
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
pub trait LlmProvider: Send + Sync {
|
||||||
|
/// Sendet eine Anfrage an das LLM und gibt die Antwort zurück.
|
||||||
|
async fn complete(&self, request: LlmRequest) -> Result<LlmResponse>;
|
||||||
|
|
||||||
|
/// Gibt den Namen des Providers zurück.
|
||||||
|
/// Wird für Logging und Usage-Tracking verwendet.
|
||||||
|
fn name(&self) -> &str;
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
use nazarick_core::types::Result;
|
// nazarick-core/src/llm/types.rs
|
||||||
|
//
|
||||||
|
// Gemeinsame Datentypen für alle LLM-Provider.
|
||||||
|
// Jeder Provider (LmStudio, Ollama, Mistral) nutzt diese Typen.
|
||||||
|
|
||||||
/// Repräsentiert eine einzelne Nachricht in einem Gespräch.
|
/// Repräsentiert eine einzelne Nachricht in einem Gespräch.
|
||||||
/// Entspricht dem Message-Format das alle gängigen LLM APIs verwenden.
|
/// Entspricht dem Message-Format das alle gängigen LLM APIs verwenden.
|
||||||
@@ -47,15 +50,4 @@ pub struct LlmResponse {
|
|||||||
pub tokens_input: u64,
|
pub tokens_input: u64,
|
||||||
/// Anzahl der Output-Token (für Usage-Tracking)
|
/// Anzahl der Output-Token (für Usage-Tracking)
|
||||||
pub tokens_output: u64,
|
pub tokens_output: u64,
|
||||||
}
|
|
||||||
|
|
||||||
/// Zentraler Trait für alle LLM-Provider.
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
pub trait LlmProvider: Send + Sync {
|
|
||||||
/// Sendet eine Anfrage an das LLM und gibt die Antwort zurück.
|
|
||||||
async fn complete(&self, request: LlmRequest) -> Result<LlmResponse>;
|
|
||||||
|
|
||||||
/// Gibt den Namen des Providers zurück.
|
|
||||||
/// Wird für Logging und Usage-Tracking verwendet.
|
|
||||||
fn name(&self) -> &str;
|
|
||||||
}
|
}
|
||||||
@@ -1,74 +1,38 @@
|
|||||||
/// Sebas Tian — Haupt-Butler-Agent von Nazarick.
|
// crates/sebas-tian/src/lib.rs
|
||||||
/// Implementiert den Agent-Trait und orchestriert
|
//
|
||||||
/// LLM-Kommunikation, Prompt-Aufbau und Konversationsverlauf.
|
// Sebas Tian — Haupt-Butler-Agent.
|
||||||
|
// Dünner Wrapper um BaseAgent — nur name() ist Sebas-spezifisch.
|
||||||
|
|
||||||
|
use nazarick_core::agent::BaseAgent;
|
||||||
use nazarick_core::traits::Agent;
|
use nazarick_core::traits::Agent;
|
||||||
use nazarick_core::types::AgentId;
|
use nazarick_core::types::AgentId;
|
||||||
use nazarick_core::prompt::PromptBuilder;
|
use nazarick_core::llm::LlmProvider;
|
||||||
use api::llm::{LlmProvider, LlmRequest, Message};
|
|
||||||
|
|
||||||
pub struct Sebas {
|
pub struct Sebas {
|
||||||
/// Eindeutige ID dieser Agent-Instanz
|
base: BaseAgent,
|
||||||
id: AgentId,
|
|
||||||
/// Baut den System-Prompt aus soul_core + soul_personality
|
|
||||||
prompt_builder: PromptBuilder,
|
|
||||||
/// Das LLM-Backend (LmStudio, Ollama, Mistral)
|
|
||||||
llm: Box<dyn LlmProvider>,
|
|
||||||
/// Konversationsverlauf — damit Sebas den Kontext behält
|
|
||||||
history: Vec<Message>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sebas {
|
impl Sebas {
|
||||||
/// Erstellt eine neue Sebas-Instanz.
|
/// Erstellt eine neue Sebas-Instanz.
|
||||||
/// `soul_core_path` → Pfad zu soul_core.md
|
|
||||||
/// `soul_personality_path` → Pfad zu soul_personality.md
|
|
||||||
/// `llm` → LLM-Provider (z.B. LmStudioProvider)
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
soul_core_path: impl Into<String>,
|
soul_core_path: impl Into<String>,
|
||||||
soul_personality_path: impl Into<String>,
|
soul_personality_path: impl Into<String>,
|
||||||
llm: Box<dyn LlmProvider>,
|
llm: Box<dyn LlmProvider>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: AgentId::new_v4(),
|
base: BaseAgent::new(soul_core_path, soul_personality_path, llm),
|
||||||
prompt_builder: PromptBuilder::new(soul_core_path, soul_personality_path),
|
|
||||||
llm,
|
|
||||||
history: Vec::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sendet eine Nachricht an Sebas und gibt seine Antwort zurück.
|
/// Delegiert chat() an BaseAgent.
|
||||||
/// Der Konversationsverlauf wird automatisch mitgeführt.
|
|
||||||
pub async fn chat(&mut self, user_message: &str) -> nazarick_core::types::Result<String> {
|
pub async fn chat(&mut self, user_message: &str) -> nazarick_core::types::Result<String> {
|
||||||
// System-Prompt aus soul-Dateien aufbauen
|
self.base.chat(user_message).await
|
||||||
let system_prompt = self.prompt_builder.build()?;
|
|
||||||
|
|
||||||
// User-Nachricht zum Verlauf hinzufügen
|
|
||||||
self.history.push(Message::user(user_message));
|
|
||||||
|
|
||||||
// Vollständige Nachrichtenliste aufbauen:
|
|
||||||
// System-Prompt + gesamter bisheriger Verlauf
|
|
||||||
let mut messages = vec![Message::system(system_prompt)];
|
|
||||||
messages.extend(self.history.clone());
|
|
||||||
|
|
||||||
// LLM anfragen
|
|
||||||
let request = LlmRequest {
|
|
||||||
messages,
|
|
||||||
max_tokens: 4096, // ← erhöht damit Thinking + Antwort reinpassen
|
|
||||||
temperature: 0.7,
|
|
||||||
};
|
|
||||||
|
|
||||||
let response = self.llm.complete(request).await?;
|
|
||||||
|
|
||||||
// Antwort zum Verlauf hinzufügen damit Sebas sich erinnert
|
|
||||||
self.history.push(Message::assistant(&response.content));
|
|
||||||
|
|
||||||
Ok(response.content)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Agent for Sebas {
|
impl Agent for Sebas {
|
||||||
fn id(&self) -> AgentId {
|
fn id(&self) -> AgentId {
|
||||||
self.id
|
self.base.id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
|
|||||||
Reference in New Issue
Block a user