From 6dabdcf8ec421db1f8ac679abf84131662f29773 Mon Sep 17 00:00:00 2001 From: vegard Date: Wed, 18 Mar 2026 16:43:11 +0000 Subject: [PATCH] Legg til orchestration-validering i maskinrommet (oppgave 24.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ny node_kind 'orchestration' med strukturert metadata-validering: - trigger.event valideres mot kjent liste (node.created, edge.created, communication.ended, node.published, scheduled.due, manual) - trigger.conditions må være objekt hvis satt - executor valideres mot script/bot/dream - intelligence og effort valideres som heltall 1-3 - compiled valideres som boolean - pipeline valideres som array Valideringen kjører i både create_node og update_node, identisk mønster som validate_collection_traits og validate_ai_preset_metadata. Ref: docs/concepts/orkestrering.md --- maskinrommet/src/intentions.rs | 116 +++++++++++++++++++++++++++++++++ tasks.md | 3 +- 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/maskinrommet/src/intentions.rs b/maskinrommet/src/intentions.rs index 9a49571..5bea5ec 100644 --- a/maskinrommet/src/intentions.rs +++ b/maskinrommet/src/intentions.rs @@ -102,6 +102,21 @@ fn validate_collection_traits( Ok(()) } +/// Gyldige trigger-events for orchestration-noder. +/// Ref: docs/concepts/orkestrering.md § 5 "Kjente trigger-events" +const VALID_TRIGGER_EVENTS: &[&str] = &[ + "node.created", + "edge.created", + "communication.ended", + "node.published", + "scheduled.due", + "manual", +]; + +/// Gyldige executor-verdier for orchestration-noder. +/// Ref: docs/concepts/orkestrering.md § 4 "Tre utførelsesnivåer" +const VALID_EXECUTORS: &[&str] = &["script", "bot", "dream"]; + /// Gyldige modellprofiler for AI-presets. /// Ref: docs/infra/ai_gateway.md § "Modellprofiler" const VALID_MODEL_PROFILES: &[&str] = &["flash", "standard"]; @@ -188,6 +203,101 @@ fn validate_ai_preset_metadata( Ok(()) } +/// Validerer metadata for `node_kind == "orchestration"`. +/// +/// Påkrevde felter i metadata: +/// - `trigger` (objekt med `event` og valgfri `conditions`) +/// - `trigger.event` (string, må finnes i VALID_TRIGGER_EVENTS) +/// - `executor` (string, må finnes i VALID_EXECUTORS) +/// +/// Valgfrie felter: +/// - `trigger.conditions` (objekt — fri filtrering) +/// - `intelligence` (heltall 1–3) +/// - `effort` (heltall 1–3) +/// - `compiled` (boolean — om scriptet er kompilert fra AI-modus) +/// - `pipeline` (array — sekvens av steg) +/// +/// Ref: docs/concepts/orkestrering.md +fn validate_orchestration_metadata( + node_kind: &str, + metadata: &serde_json::Value, +) -> Result<(), String> { + if node_kind != "orchestration" { + return Ok(()); + } + + // Påkrevd: trigger (objekt) + let trigger = metadata + .get("trigger") + .ok_or("orchestration krever metadata.trigger")?; + let trigger_obj = trigger + .as_object() + .ok_or("metadata.trigger må være et objekt")?; + + // Påkrevd: trigger.event + match trigger_obj.get("event").and_then(|v| v.as_str()) { + None | Some("") => { + return Err("orchestration krever metadata.trigger.event (ikke-tom streng)".into()) + } + Some(ev) if !VALID_TRIGGER_EVENTS.contains(&ev) => { + return Err(format!( + "Ukjent trigger-event: '{ev}'. Gyldige verdier: {VALID_TRIGGER_EVENTS:?}" + )); + } + _ => {} + } + + // Valgfri: trigger.conditions (må være objekt hvis satt) + if let Some(conditions) = trigger_obj.get("conditions") { + if !conditions.is_object() { + return Err("metadata.trigger.conditions må være et objekt".into()); + } + } + + // Påkrevd: executor + match metadata.get("executor").and_then(|v| v.as_str()) { + None => return Err("orchestration krever metadata.executor".into()), + Some(ex) if !VALID_EXECUTORS.contains(&ex) => { + return Err(format!( + "Ugyldig executor: '{ex}'. Gyldige verdier: {VALID_EXECUTORS:?}" + )); + } + _ => {} + } + + // Valgfri: intelligence (1–3) + if let Some(val) = metadata.get("intelligence") { + match val.as_i64() { + Some(n) if (1..=3).contains(&n) => {} + _ => return Err("metadata.intelligence må være et heltall 1–3".into()), + } + } + + // Valgfri: effort (1–3) + if let Some(val) = metadata.get("effort") { + match val.as_i64() { + Some(n) if (1..=3).contains(&n) => {} + _ => return Err("metadata.effort må være et heltall 1–3".into()), + } + } + + // Valgfri: compiled (boolean) + if let Some(val) = metadata.get("compiled") { + if !val.is_boolean() { + return Err("metadata.compiled må være en boolean".into()); + } + } + + // Valgfri: pipeline (array) + if let Some(val) = metadata.get("pipeline") { + if !val.is_array() { + return Err("metadata.pipeline må være et array".into()); + } + } + + Ok(()) +} + #[derive(Serialize)] pub struct ErrorResponse { pub error: String, @@ -517,6 +627,9 @@ pub async fn create_node( // -- Valider metadata for AI-presets (oppgave 18.1) -- validate_ai_preset_metadata(&node_kind, &metadata).map_err(|e| bad_request(&e))?; + // -- Valider metadata for orchestration-noder (oppgave 24.1) -- + validate_orchestration_metadata(&node_kind, &metadata).map_err(|e| bad_request(&e))?; + // -- Kontekstbasert identitet (oppgave 8.2) -- // Hvis context_id er satt, sjekk om brukeren har et alias som er // deltaker i kommunikasjonsnoden. I så fall brukes aliaset som created_by. @@ -1051,6 +1164,9 @@ pub async fn update_node( // -- Valider metadata for AI-presets (oppgave 18.1) -- validate_ai_preset_metadata(&node_kind, &metadata).map_err(|e| bad_request(&e))?; + // -- Valider metadata for orchestration-noder (oppgave 24.1) -- + validate_orchestration_metadata(&node_kind, &metadata).map_err(|e| bad_request(&e))?; + // -- Beskytt model_profile for egendefinerte AI-presets (oppgave 18.6) -- // Kun admin/owner på en samling kan endre model_profile. Vanlige brukere // som eier et custom preset kan redigere alt annet (prompt, icon, farge osv.) diff --git a/tasks.md b/tasks.md index aa01e82..f379560 100644 --- a/tasks.md +++ b/tasks.md @@ -316,8 +316,7 @@ Ref: `docs/concepts/orkestrering.md`. Orkestreringsnoder (`node_kind: 'orchestra med fritekst-instruksjoner som boten utfører via function calling. Strukturerte triggere, automatisk eskalering av intelligens ved feil, kompilering av velprøvde mønstre. -- [~] 24.1 Orchestration node-type: legg til `orchestration` i maskinrommets node-validering. Metadata-skjema: `trigger` (event + conditions), `executor`, `intelligence`, `effort`, `compiled`, `pipeline`. Valider trigger-events mot kjent liste. - > Påbegynt: 2026-03-18T16:35 +- [x] 24.1 Orchestration node-type: legg til `orchestration` i maskinrommets node-validering. Metadata-skjema: `trigger` (event + conditions), `executor`, `intelligence`, `effort`, `compiled`, `pipeline`. Valider trigger-events mot kjent liste. - [ ] 24.2 Trigger-evaluering i portvokteren: ved node/edge-events, sjekk om noen `orchestration`-noder matcher triggeren. Effektiv lookup (indeksert på `metadata.trigger.event`). Ingen LLM-kall for trigger-matching. - [ ] 24.3 Bot-utførelse: utvid `synops-respond` (eller nytt `synops-orchestrate`) til å ta orchestration-node som input. Bygg prompt med trigger-kontekst + instruksjoner + tilgjengelige verktøy. Function calling for hvert steg. Logg i `orchestration_log`. - [ ] 24.4 Auto-eskalering: start med lavt intelligens/effort-nivå. Ved feil (tool_error, ambiguous_instruction) bump automatisk til neste nivå og retry. Maks 3 nivåer.