Lyra Agent hinzugefügt, Multi-Agent Routing, BaseAgent refactoring

This commit is contained in:
Sithies
2026-03-16 23:30:42 +01:00
parent 6fc1648939
commit 750fe1f5f6
22 changed files with 454 additions and 111 deletions
+43 -4
View File
@@ -186,16 +186,26 @@ async fn process(state: Arc<AppState>, payload: SynologyIncoming, agent: AgentCh
// ─── HTTP Sender ──────────────────────────────────────────────────────────────
//
// Sendet eine Nachricht an einen Synology Chat User.
// Synology erwartet Form-encoded payload mit JSON — kein reines JSON.
// user_id wird dynamisch angehängt — Basis-URL bleibt sauber in config.toml.
// Lange Nachrichten werden automatisch in Chunks aufgeteilt.
// Synology erlaubt max. ~2000 Zeichen pro Nachricht.
const MAX_CHUNK_SIZE: usize = 1800; // Puffer unter dem Limit
async fn send(client: &Client, base_url: &str, user_id: u64, text: &str) {
let chunks = split_message(text);
for chunk in chunks {
send_chunk(client, base_url, user_id, &chunk).await;
}
}
/// Sendet einen einzelnen Chunk.
async fn send_chunk(client: &Client, base_url: &str, user_id: u64, text: &str) {
let body = SynologyOutgoing {
text: text.to_string(),
user_ids: vec![user_id],
};
// JSON serialisieren und als Form-Parameter verpacken
let payload = serde_json::to_string(&body).unwrap_or_default();
match client
@@ -206,9 +216,38 @@ async fn send(client: &Client, base_url: &str, user_id: u64, text: &str) {
{
Ok(r) if r.status().is_success() => {
let response_body = r.text().await.unwrap_or_default();
info!("Nachricht gesendet an user_id={} body={}", user_id, response_body);
info!("Chunk gesendet an user_id={} body={}", user_id, response_body);
}
Ok(r) => error!(status = %r.status(), "Synology hat abgelehnt"),
Err(e) => error!(error = %e, "Senden fehlgeschlagen"),
}
}
/// Teilt einen Text in Chunks auf die Synology verarbeiten kann.
/// Schneidet an Zeilenumbrüchen oder Satzenden — nie mitten im Wort.
fn split_message(text: &str) -> Vec<String> {
if text.len() <= MAX_CHUNK_SIZE {
return vec![text.to_string()];
}
let mut chunks = Vec::new();
let mut remaining = text;
while remaining.len() > MAX_CHUNK_SIZE {
// Schnittpunkt suchen — bevorzugt Zeilenumbruch, dann Leerzeichen
let cut = remaining[..MAX_CHUNK_SIZE]
.rfind('\n')
.or_else(|| remaining[..MAX_CHUNK_SIZE].rfind(". "))
.or_else(|| remaining[..MAX_CHUNK_SIZE].rfind(' '))
.unwrap_or(MAX_CHUNK_SIZE);
chunks.push(remaining[..cut].trim().to_string());
remaining = remaining[cut..].trim_start();
}
if !remaining.is_empty() {
chunks.push(remaining.to_string());
}
chunks
}