added Tokens, openrouter, memory system
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
// crates/skills/src/lib.rs
|
||||
pub mod skills;
|
||||
|
||||
// Stellt sicher dass alle inventory::submit! ausgeführt werden.
|
||||
// Ohne diesen Import würden Skills nie eingesammelt.
|
||||
pub use skills::personality;
|
||||
pub mod skills;
|
||||
pub use skills::personality;
|
||||
pub use skills::remember;
|
||||
@@ -1 +1,2 @@
|
||||
pub mod personality;
|
||||
pub mod personality;
|
||||
pub mod remember;
|
||||
@@ -77,40 +77,62 @@ impl PersonalitySkill {
|
||||
#[async_trait]
|
||||
impl Skill for PersonalitySkill {
|
||||
fn summary(&self) -> &str {
|
||||
"Liest und schreibt den PERSONALITY [MUTABLE] Block — speichert dauerhaft Eigenschaften wie Ton, Stil oder Präferenzen des Herrn die das Verhalten des Agenten beeinflussen"
|
||||
"Liest und schreibt den PERSONALITY [MUTABLE] Block — speichert dauerhaft Eigenschaften wie Ton, Stil oder Präferenzen des Herrn"
|
||||
}
|
||||
|
||||
fn details(&self) -> &str {
|
||||
"Verwaltet Persönlichkeitswerte in soul_personality.md.
|
||||
|
||||
## update
|
||||
Setzt oder überschreibt einen Wert:
|
||||
<skill name=\"personality\">
|
||||
<action>update</action>
|
||||
<field>Ton</field>
|
||||
<value>kurz und direkt</value>
|
||||
</skill>
|
||||
## update — Wert setzen oder überschreiben
|
||||
action: update, field: <name>, value: <wert>
|
||||
|
||||
## remove
|
||||
Entfernt einen Wert:
|
||||
<skill name=\"personality\">
|
||||
<action>remove</action>
|
||||
<field>Ton</field>
|
||||
</skill>"
|
||||
## remove — Wert entfernen
|
||||
action: remove, field: <name>"
|
||||
}
|
||||
|
||||
fn tool_definition(&self) -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "personality",
|
||||
"description": self.summary(),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"enum": ["update", "remove"],
|
||||
"description": "update = setzen/überschreiben, remove = entfernen"
|
||||
},
|
||||
"field": {
|
||||
"type": "string",
|
||||
"description": "Name des Persönlichkeitswerts, z.B. 'Ton', 'Stil'"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Neuer Wert — nur bei action=update nötig"
|
||||
}
|
||||
},
|
||||
"required": ["action", "field"]
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async fn execute(&self, input: SkillInput, ctx: AgentContext) -> Result<SkillOutput> {
|
||||
let path = Self::path(&ctx.agent_id);
|
||||
let field = input.require("field")?;
|
||||
|
||||
// action ist optional — fehlt es, wird aus value abgeleitet
|
||||
let action = input.get("action").unwrap_or_else(|| {
|
||||
if input.get("value").is_some() { "update" } else { "remove" }
|
||||
});
|
||||
let action = input.get("action").unwrap_or("update");
|
||||
let field = match input.get("field") {
|
||||
Some(f) => f,
|
||||
None => return Ok(SkillOutput::err("Parameter 'field' fehlt")),
|
||||
};
|
||||
|
||||
match action {
|
||||
"update" => {
|
||||
let value = input.require("value")?;
|
||||
let value = match input.get("value") {
|
||||
Some(v) => v,
|
||||
None => return Ok(SkillOutput::err("Parameter 'value' fehlt bei action=update")),
|
||||
};
|
||||
Self::do_update(&path, field, value)?;
|
||||
Ok(SkillOutput::ok(format!("'{}' gesetzt auf '{}'", field, value)))
|
||||
}
|
||||
@@ -118,7 +140,9 @@ impl Skill for PersonalitySkill {
|
||||
Self::do_remove(&path, field)?;
|
||||
Ok(SkillOutput::ok(format!("'{}' entfernt", field)))
|
||||
}
|
||||
unknown => Ok(SkillOutput::err(format!("Unbekannte Action '{}'", unknown)))
|
||||
unknown => Ok(SkillOutput::err(format!(
|
||||
"Unbekannte Action '{}'. Erlaubt: update, remove", unknown
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
use std::sync::Arc;
|
||||
use async_trait::async_trait;
|
||||
use anyhow::Result;
|
||||
use tracing::info;
|
||||
use nazarick_core::agent::traits::{Skill, SkillInput, SkillOutput};
|
||||
use nazarick_core::agent::context::AgentContext;
|
||||
use nazarick_core::agent::skill_registry::SkillMeta;
|
||||
|
||||
pub struct RememberSkill;
|
||||
|
||||
#[async_trait]
|
||||
impl Skill for RememberSkill {
|
||||
fn summary(&self) -> &str {
|
||||
"Speichert, aktualisiert, löscht oder liest dauerhaft Fakten über den User"
|
||||
}
|
||||
|
||||
fn details(&self) -> &str {
|
||||
"Verwaltet Fakten über den User in kategorisierten Einträgen.
|
||||
|
||||
## Vordefinierte Kategorien
|
||||
persönlich, präferenzen, gewohnheiten, beziehungen, arbeit
|
||||
|
||||
## update
|
||||
action: update, category: <kategorie>, key: <schlüssel>, value: <wert>
|
||||
|
||||
## delete
|
||||
action: delete, category: <kategorie>, key: <schlüssel>
|
||||
|
||||
## get
|
||||
action: get, category: <kategorie>"
|
||||
}
|
||||
|
||||
fn tool_definition(&self) -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "remember",
|
||||
"description": self.summary(),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"enum": ["update", "delete", "get"]
|
||||
},
|
||||
"category": {
|
||||
"type": "string",
|
||||
"description": "persönlich, präferenzen, gewohnheiten, beziehungen, arbeit"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["action", "category"]
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async fn execute(&self, input: SkillInput, ctx: AgentContext) -> Result<SkillOutput> {
|
||||
let action = input.get("action").unwrap_or("update");
|
||||
let category = input.get("category").unwrap_or("persönlich");
|
||||
|
||||
match action {
|
||||
"update" => {
|
||||
let key = match input.get("key") {
|
||||
Some(k) => k,
|
||||
None => return Ok(SkillOutput::err("Parameter 'key' fehlt")),
|
||||
};
|
||||
let value = match input.get("value") {
|
||||
Some(v) => v,
|
||||
None => return Ok(SkillOutput::err("Parameter 'value' fehlt")),
|
||||
};
|
||||
ctx.memory.upsert_fact(category, key, value).await
|
||||
.map_err(|e| anyhow::anyhow!(e.to_string()))?;
|
||||
info!(category = %category, key = %key, "Fakt gespeichert");
|
||||
Ok(SkillOutput::ok(format!("[{}] '{}' = '{}' gespeichert", category, key, value)))
|
||||
}
|
||||
"delete" => {
|
||||
let key = match input.get("key") {
|
||||
Some(k) => k,
|
||||
None => return Ok(SkillOutput::err("Parameter 'key' fehlt")),
|
||||
};
|
||||
ctx.memory.delete_fact(category, key).await
|
||||
.map_err(|e| anyhow::anyhow!(e.to_string()))?;
|
||||
info!(category = %category, key = %key, "Fakt gelöscht");
|
||||
Ok(SkillOutput::ok(format!("[{}] '{}' gelöscht", category, key)))
|
||||
}
|
||||
"get" => {
|
||||
let facts = ctx.memory.get_category(category).await
|
||||
.map_err(|e| anyhow::anyhow!(e.to_string()))?;
|
||||
|
||||
if facts.is_empty() {
|
||||
return Ok(SkillOutput::ok_with_feedback(
|
||||
format!("Keine Fakten in '{}'", category),
|
||||
format!("Kategorie '{}' ist leer.", category),
|
||||
));
|
||||
}
|
||||
|
||||
let list = facts.iter()
|
||||
.map(|f| format!("- {}: {}", f.key, f.value))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
Ok(SkillOutput::ok_with_feedback(
|
||||
format!("Fakten aus '{}' geladen", category),
|
||||
format!("## Fakten: {}\n{}", category, list),
|
||||
))
|
||||
}
|
||||
unknown => Ok(SkillOutput::err(format!(
|
||||
"Unbekannte Action '{}'. Erlaubt: update, delete, get", unknown
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inventory::submit!(SkillMeta {
|
||||
name: "remember",
|
||||
allowed: &["all"],
|
||||
awaits_result: true,
|
||||
skill: || Arc::new(RememberSkill),
|
||||
});
|
||||
Reference in New Issue
Block a user