SpacetimeDB var brukt som «instant feedback»-lag mellom portvokteren og frontend. Nå som PG NOTIFY-triggere og WebSocket er på plass (oppgave 22.1–22.2), er STDB-skrivestien overflødig. Endringer: - intentions.rs: Alle CRUD-operasjoner (create/update/delete node/edge) skriver nå synkront til PG i stedet for STDB-først + async PG-jobbkø. PG NOTIFY-triggere gir umiddelbar sanntidsoppdatering til klienter. Tilgangsgivende edges (owner/admin/member_of/reader) bruker transaksjon med recompute_access direkte i handleren. - maintenance.rs: Fjernet StdbClient fra alle funksjoner. Varsler opprettes/oppdateres/slettes direkte i PG. - agent.rs, audio.rs, tts.rs, ai_process.rs: Fjernet STDB-synk etter CLI-verktøy-kjøring. PG NOTIFY dekker sanntidsvisning. - pg_writes.rs: Fjernet sync_node_access_to_stdb. access_changed NOTIFY-trigger håndterer dette. - workspace.rs: Synkrone PG-skrivinger med recompute_access. - summarize.rs, ai_edges.rs: Fjernet StdbClient fra signaturer. - jobs.rs: Fjernet StdbClient fra dispatch og start_worker. - main.rs: Fjernet STDB-initialisering, warmup, stdb_monitor. StdbClient fjernet fra AppState. stdb.rs beholdt som død kode (fjernes i oppgave 22.4). - health.rs: Fjernet STDB-helsesjekk fra dashboard. - Slettet warmup.rs og stdb_monitor.rs (PG→STDB-synk ikke lenger relevant). - docs/retninger/datalaget.md: Markert fase M3 som fullført.
118 lines
3.6 KiB
Rust
118 lines
3.6 KiB
Rust
// Oppsummerings-dispatcher — delegerer til synops-summarize CLI.
|
|
//
|
|
// Maskinrommet orkestrerer, CLI-verktøyet gjør jobben.
|
|
// Ref: docs/retninger/unix_filosofi.md
|
|
//
|
|
// Jobbtype: "summarize_communication"
|
|
// Payload: { "communication_id": "<uuid>", "requested_by": "<uuid>" }
|
|
|
|
use std::process::Stdio;
|
|
use uuid::Uuid;
|
|
|
|
use crate::jobs::JobRow;
|
|
|
|
/// Synops-summarize binary path.
|
|
/// Søker i PATH, men kan overrides med SYNOPS_SUMMARIZE_BIN.
|
|
fn summarize_bin() -> String {
|
|
std::env::var("SYNOPS_SUMMARIZE_BIN")
|
|
.unwrap_or_else(|_| "synops-summarize".to_string())
|
|
}
|
|
|
|
/// Handler for summarize_communication-jobber.
|
|
///
|
|
/// Spawner synops-summarize med --write for å gjøre alt arbeidet:
|
|
/// LLM-kall, node-opprettelse, edge-skriving, ressurslogging.
|
|
///
|
|
/// Payload forventer:
|
|
/// - communication_id: UUID — kommunikasjonsnoden som skal oppsummeres
|
|
/// - requested_by: UUID — brukeren som utløste oppsummeringen
|
|
pub async fn handle_summarize_communication(
|
|
job: &JobRow,
|
|
_db: &sqlx::PgPool,
|
|
) -> Result<serde_json::Value, String> {
|
|
let communication_id: Uuid = job
|
|
.payload
|
|
.get("communication_id")
|
|
.and_then(|v| v.as_str())
|
|
.and_then(|s| s.parse().ok())
|
|
.ok_or("Mangler gyldig communication_id i payload")?;
|
|
|
|
let requested_by: Uuid = job
|
|
.payload
|
|
.get("requested_by")
|
|
.and_then(|v| v.as_str())
|
|
.and_then(|s| s.parse().ok())
|
|
.ok_or("Mangler gyldig requested_by i payload")?;
|
|
|
|
// Bygg kommando
|
|
let bin = summarize_bin();
|
|
let mut cmd = tokio::process::Command::new(&bin);
|
|
|
|
cmd.arg("--communication-id")
|
|
.arg(communication_id.to_string())
|
|
.arg("--requested-by")
|
|
.arg(requested_by.to_string())
|
|
.arg("--write");
|
|
|
|
// Sett miljøvariabler CLI-verktøyet trenger
|
|
let db_url = std::env::var("DATABASE_URL")
|
|
.map_err(|_| "DATABASE_URL ikke satt".to_string())?;
|
|
|
|
cmd.env("DATABASE_URL", &db_url);
|
|
|
|
// Videresend AI-relaterte env-variabler hvis satt
|
|
if let Ok(v) = std::env::var("AI_GATEWAY_URL") {
|
|
cmd.env("AI_GATEWAY_URL", v);
|
|
}
|
|
if let Ok(v) = std::env::var("LITELLM_MASTER_KEY") {
|
|
cmd.env("LITELLM_MASTER_KEY", v);
|
|
}
|
|
if let Ok(v) = std::env::var("AI_SUMMARY_MODEL") {
|
|
cmd.env("AI_SUMMARY_MODEL", v);
|
|
}
|
|
|
|
cmd.stdout(Stdio::piped())
|
|
.stderr(Stdio::piped());
|
|
|
|
tracing::info!(
|
|
communication_id = %communication_id,
|
|
requested_by = %requested_by,
|
|
bin = %bin,
|
|
"Starter synops-summarize"
|
|
);
|
|
|
|
// Spawn og vent
|
|
let child = cmd
|
|
.spawn()
|
|
.map_err(|e| format!("Kunne ikke starte {bin}: {e}"))?;
|
|
let output = child
|
|
.wait_with_output()
|
|
.await
|
|
.map_err(|e| format!("Feil ved kjøring av {bin}: {e}"))?;
|
|
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
if !stderr.is_empty() {
|
|
tracing::info!(stderr = %stderr, "synops-summarize stderr");
|
|
}
|
|
|
|
if !output.status.success() {
|
|
let code = output.status.code().unwrap_or(-1);
|
|
return Err(format!(
|
|
"synops-summarize feilet (exit {code}): {stderr}"
|
|
));
|
|
}
|
|
|
|
// Parse stdout som JSON — det er resultatet
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
let result: serde_json::Value = serde_json::from_str(&stdout)
|
|
.map_err(|e| format!("Kunne ikke parse synops-summarize output: {e}"))?;
|
|
|
|
tracing::info!(
|
|
communication_id = %communication_id,
|
|
summary_node_id = result["summary_node_id"].as_str().unwrap_or("n/a"),
|
|
status = result["status"].as_str().unwrap_or("unknown"),
|
|
"synops-summarize fullført"
|
|
);
|
|
|
|
Ok(result)
|
|
}
|