Orkestrering restrukturert med deklarativt script som primærnivå:
- Nivå 1: eksakte CLI-kall med {event.*}-variabler, ingen AI
- Nivå 2: fritekst tolket av bot med function calling
- Nivå 3: drømmemodus — bruker skriver fritt, mangler→work_items
- Auto-eskalering: script→bot ved uventet feil
Rename portvokter→vaktmester i alle docs — bedre navn for en
tjeneste som gjør ting, ikke bare sjekker legitimasjon.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
353 lines
11 KiB
Markdown
353 lines
11 KiB
Markdown
# Konsept: Orkestrering
|
||
**Filsti:** `docs/concepts/orkestrering.md`
|
||
|
||
## 1. Konsept
|
||
|
||
Orkestreringer er noder som *gjør* ting. De er oppskrifter —
|
||
sekvenser av CLI-verktøy som utføres automatisk når en trigger
|
||
aktiveres. Tre nivåer: deklarativt script (ingen AI),
|
||
fritekst med AI-tolkning, og full drømmemodus.
|
||
|
||
## 2. Hvorfor
|
||
|
||
Synops har mange automatiseringer hardkodet i vaktmesteren:
|
||
podcast-pipeline, AI-beriking, publisering. De er usynlige,
|
||
uendrelige og umulige å tilpasse for brukere.
|
||
|
||
Orkestreringer gjør automatisering til førsteklasses graf-
|
||
primitiver — synlige, redigerbare, delbare, versjonerbare.
|
||
|
||
## 3. Nodemodell
|
||
|
||
```
|
||
node_kind: 'orchestration'
|
||
title: "Podcast: opptak → publisering"
|
||
content: <script eller fritekst>
|
||
metadata: {
|
||
"trigger": {
|
||
"event": "communication.ended",
|
||
"conditions": {
|
||
"has_trait": "podcast",
|
||
"has_media": "audio"
|
||
}
|
||
},
|
||
"executor": "script" | "bot" | "dream",
|
||
"intelligence": 2,
|
||
"effort": 2
|
||
}
|
||
```
|
||
|
||
### Tre typer noder som gjør
|
||
|
||
| node_kind | Ikon | Aktivering | Eksempel |
|
||
|-----------|------|------------|----------|
|
||
| `cli_tool` | 🔧 | Kalles av andre | synops-transcribe |
|
||
| `ai_preset` | 🔧 | Kalles av AI-verktøy | "Rens tekst"-prompt |
|
||
| `orchestration` | ⚡ | **Trigger-drevet, utfører seg selv** | Podcast-pipeline |
|
||
|
||
⚡ signaliserer: "denne noden gjør noe av seg selv."
|
||
|
||
## 4. Tre utførelsesnivåer
|
||
|
||
### Nivå 1: Deklarativt script (ingen AI)
|
||
|
||
Eksakte CLI-kall med variabler fra trigger-konteksten.
|
||
Vaktmesteren parser og eksekverer direkte — ingen LLM.
|
||
|
||
```
|
||
NÅR innspilling.avsluttet
|
||
HVIS samling.har_trait("podcast")
|
||
|
||
1. synops-transcribe --cas-hash {event.cas_hash} --model large
|
||
VED_FEIL: synops-transcribe --cas-hash {event.cas_hash} --model medium
|
||
2. synops-summarize --communication-id {event.communication_id}
|
||
3. synops-rss --collection-id {event.collection_id}
|
||
|
||
VED_FEIL: work_item "Podcast-pipeline feilet" --tag bug
|
||
```
|
||
|
||
**Grammatikk:**
|
||
|
||
```
|
||
TRIGGER NÅR <event> [HVIS <betingelse>]
|
||
STEP <N>. <tool> <args...>
|
||
FALLBACK VED_FEIL: <tool> <args...> | work_item <title> [--tag <tag>]
|
||
VARIABLE {event.<felt>} — substitueres fra trigger-konteksten
|
||
```
|
||
|
||
Enkelt nok til å parse med en liten Rust-parser i vaktmesteren.
|
||
Deterministisk, gratis, raskt. **De fleste produksjons-
|
||
orkestreringer vil være på dette nivået.**
|
||
|
||
### Nivå 2: Fritekst med AI-tolkning
|
||
|
||
Naturlig språk som boten tolker og utfører steg for steg
|
||
med function calling. For orkestreringer der stegene ikke
|
||
er helt forutsigbare.
|
||
|
||
```
|
||
Når en innspilling i en samling med podcast-trait avsluttes:
|
||
|
||
1. Transkriber lydfilen med stor modell
|
||
2. Generer oppsummering
|
||
3. Foreslå kapitler basert på transkripsjonen
|
||
4. Generer show notes
|
||
5. Oppdater RSS-feed
|
||
|
||
Hvis transkribering feiler, prøv igjen med medium modell.
|
||
Hvis RSS feiler, opprett en oppgave.
|
||
```
|
||
|
||
Boten mapper "transkriber lydfilen" → `synops-transcribe`,
|
||
"oppsummer" → `synops-summarize`, osv. Krever LLM-kall
|
||
per kjøring (Haiku er nok for de fleste).
|
||
|
||
### Nivå 3: Drømmemodus
|
||
|
||
Brukeren skriver hva de *ønsker*, uten å vite hvilke verktøy
|
||
som finnes. Boten prøver, og mangler som oppdages blir
|
||
feature requests.
|
||
|
||
```
|
||
Gjør episoden klar for publisering. Lag en lydfil med
|
||
sammendrag og send den til alle deltakere.
|
||
```
|
||
|
||
Boten sjekker tilgjengelige verktøy, gjør det den kan,
|
||
og oppretter work_items for det som mangler.
|
||
|
||
### Naturlig progresjon
|
||
|
||
```
|
||
Drømmemodus → Bruker beskriver ønsket resultat
|
||
↓ AI foreslår
|
||
Fritekst → Bruker justerer steg i naturlig språk
|
||
↓ AI foreslår kompilering etter N kjøringer
|
||
Script → Deklarative CLI-kall, ingen AI
|
||
↓ manuelt
|
||
Kode → Eget CLI-verktøy (synops-<verb>)
|
||
```
|
||
|
||
Hvert nivå kan fryses til nivået under. AI foreslår
|
||
kompilering, bruker godkjenner. Scriptet kan alltid
|
||
redigeres manuelt.
|
||
|
||
## 5. Strukturert trigger
|
||
|
||
Triggeren er alltid strukturert — vaktmesteren evaluerer
|
||
den effektivt uten LLM, uavhengig av utførelsesnivå:
|
||
|
||
```jsonc
|
||
{
|
||
"trigger": {
|
||
"event": "communication.ended",
|
||
"conditions": {
|
||
"has_trait": "podcast",
|
||
"has_media": "audio"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### Kjente trigger-events
|
||
|
||
| Event | Beskrivelse |
|
||
|-------|-------------|
|
||
| `node.created` | Ny node opprettet |
|
||
| `edge.created` | Ny edge opprettet |
|
||
| `communication.ended` | Samtale/innspilling avsluttet |
|
||
| `node.published` | Node publisert (belongs_to med slot) |
|
||
| `scheduled.due` | Planlagt tidspunkt nådd |
|
||
| `manual` | Bruker trykker "Kjør" |
|
||
|
||
### Betingelser
|
||
|
||
Filtrerer triggeren ytterligere:
|
||
- `has_trait` — noden/samlingen har denne traiten
|
||
- `has_media` — noden har media-edge av denne typen
|
||
- `has_tag` — noden har tagged-edge med denne verdien
|
||
- `node_kind` — noden er av denne typen
|
||
|
||
## 6. Utførelse
|
||
|
||
### Script-modus (nivå 1)
|
||
|
||
```
|
||
Trigger aktiveres
|
||
→ Vaktmesteren finner matchende orchestration-node
|
||
→ Parser scriptet
|
||
→ Substituerer {event.*}-variabler fra trigger-kontekst
|
||
→ Utfører steg sekvensielt via generisk dispatch
|
||
(synops-{tool} --payload-json)
|
||
→ Ved feil: kjør VED_FEIL-steg eller opprett work_item
|
||
→ Logger i orchestration_log
|
||
```
|
||
|
||
Ingen LLM. Deterministisk. Raskt.
|
||
|
||
### Bot-modus (nivå 2)
|
||
|
||
```
|
||
Trigger aktiveres
|
||
→ Vaktmesteren finner matchende orchestration-node
|
||
→ Sender til bot med function calling:
|
||
- Trigger-kontekst (hvilken node, hvilken event)
|
||
- Instruksjonene fra orchestration.content
|
||
- Tilgjengelige verktøy (cli_tool-noder)
|
||
→ Boten utfører steg for steg
|
||
→ Logger hvert steg i orchestration_log
|
||
→ Ved feil: resonnerer og prøver alternativ
|
||
```
|
||
|
||
### Drømmemodus (nivå 3)
|
||
|
||
Som bot-modus, men med høyere intelligens (Sonnet+) og
|
||
instruks om å opprette work_items for manglende verktøy.
|
||
|
||
### Auto-eskalering
|
||
|
||
Script-modus faller tilbake til bot-modus ved uventet feil:
|
||
|
||
```
|
||
Script kjører steg 2
|
||
→ synops-summarize returnerer exit 1
|
||
→ VED_FEIL er definert → prøv alternativ
|
||
→ Alternativ feiler også
|
||
→ Eskalér til bot-modus for dette steget
|
||
→ Boten resonnerer om feilen og prøver å løse det
|
||
```
|
||
|
||
## 7. Koblinger mellom orkestreringer
|
||
|
||
Orkestreringer er noder med edges:
|
||
|
||
```
|
||
"Podcast: opptak → publisering"
|
||
──triggers──→ "Varsle redaksjonen om ny episode"
|
||
──triggers──→ "Post til sosiale medier"
|
||
```
|
||
|
||
Output fra én orkestrering kan trigge neste via `triggers`-edge.
|
||
Kaskade via edges, ikke hardkodet.
|
||
|
||
## 8. Brukergrensesnitt
|
||
|
||
```
|
||
┌─ Podcastorkestrering ⚡ ──────────────────┐
|
||
│ │
|
||
│ Trigger: [Innspilling avsluttet ▼] │
|
||
│ Betingelse: [Samling har podcast-trait ▼] │
|
||
│ Modus: [Script ▼] │
|
||
│ │
|
||
│ ┌─────────────────────────────────────┐ │
|
||
│ │ NÅR innspilling.avsluttet │ │
|
||
│ │ HVIS samling.har_trait("podcast") │ │
|
||
│ │ │ │
|
||
│ │ 1. synops-transcribe │ │
|
||
│ │ --cas-hash {event.cas_hash} │ │
|
||
│ │ --model large │ │
|
||
│ │ VED_FEIL: ... --model medium │ │
|
||
│ │ 2. synops-summarize │ │
|
||
│ │ --communication-id {event.id} │ │
|
||
│ │ 3. synops-rss │ │
|
||
│ │ --collection-id {event.coll_id} │ │
|
||
│ └─────────────────────────────────────┘ │
|
||
│ │
|
||
│ [▶ Test kjøring] [↑ Konverter til AI] │
|
||
│ │
|
||
│ Status: Aktiv Kjørt: 47 ganger │
|
||
│ Sist: 2026-03-18 12:30 (OK) │
|
||
│ │
|
||
│ ℹ Tilgjengelig: synops-transcribe, │
|
||
│ synops-rss, synops-render... │
|
||
│ (12 verktøy) │
|
||
└───────────────────────────────────────────┘
|
||
```
|
||
|
||
Modusvelger: Script / Fritekst / Drømmemodus.
|
||
"Test kjøring" utfører med dry-run.
|
||
"Konverter til AI" løfter scriptet til fritekst-modus.
|
||
|
||
## 9. Edge-modell
|
||
|
||
| Edge | Source → Target | Betydning |
|
||
|------|----------------|-----------|
|
||
| `belongs_to` | orchestration → collection | Tilhører denne samlingen |
|
||
| `observes` | orchestration → any node | Overvåker denne noden for trigger-events |
|
||
| `triggers` | orchestration → orchestration | Kaskade-kobling |
|
||
| `uses` | orchestration → cli_tool | Bruker dette verktøyet |
|
||
| `mentions` | orchestration → any | Refererer til denne noden |
|
||
|
||
### `observes`-edge: eksplisitt kobling
|
||
|
||
Orkestreringen peker på det den observerer:
|
||
|
||
```
|
||
"Auto-clip URL-er" (orchestration)
|
||
──observes──→ #Redaksjonen (communication)
|
||
──observes──→ #Research (communication)
|
||
```
|
||
|
||
Legg til `observes`-edge → aktivert for den noden.
|
||
Fjern edge → deaktivert. Opprettet via drag-and-drop
|
||
(se `docs/retninger/interaksjonsmodell.md`).
|
||
|
||
### Implisitt vs eksplisitt
|
||
|
||
- **`observes`-edge:** Eksplisitt. "Denne orkestreringen overvåker
|
||
denne noden."
|
||
- **Trigger-betingelser:** Implisitt. "Overvåk alt som matcher."
|
||
- `observes` overtrumfer: fjernet `observes`-edge betyr "ikke her",
|
||
selv om betingelsene matcher. Brukeren har kontroll.
|
||
|
||
## 10. Drømmemodus: brukeren skriver hva de vil
|
||
|
||
Brukeren begrenses ikke til kjente verktøy. De skriver fritt
|
||
— boten prøver, og mangler som oppdages blir feature requests.
|
||
|
||
```
|
||
Bruker skriver: "Lag en lydfil med sammendrag og send til deltakerne"
|
||
|
||
Boten sjekker:
|
||
✓ synops-summarize finnes → oppsummerer
|
||
✗ synops-tts finnes ikke → kan ikke lage lyd
|
||
|
||
Boten svarer:
|
||
"Jeg oppsummerte møtet, men Synops har ikke tekst-til-tale
|
||
ennå. Jeg oppretter en forespørsel?"
|
||
|
||
→ work_item i innboks:
|
||
title: "TTS for møteoppsummeringer"
|
||
tagged: "feature"
|
||
source_material → orkestreringsnoden
|
||
```
|
||
|
||
Systemet lærer hva brukerne vil ha fra det som ikke lykkes.
|
||
|
||
## 11. Avgrensning
|
||
|
||
- Orkestreringer er **ikke** en generell workflow-engine.
|
||
De er oppskrifter — deklarative eller AI-tolkede.
|
||
- Deklarativt script er primær for produksjon. AI er for
|
||
oppretting, feilhåndtering og drømmemodus.
|
||
- Triggere evalueres av vaktmesteren, utførelse av
|
||
vaktmesteren (script) eller bot (fritekst/drøm).
|
||
- Brukeren begrenses aldri til kjente verktøy. Manglende
|
||
funksjonalitet fanges opp som feature requests.
|
||
|
||
## 12. Komponenter
|
||
|
||
| Feature | Rolle |
|
||
|---------|-------|
|
||
| Vaktmesteren | Evaluerer triggere, parser/utfører scripts, dispatcher til bot |
|
||
| @bot | Tolker fritekst-instruksjoner, utfører med function calling |
|
||
| CLI-verktøy | Gjør det faktiske arbeidet |
|
||
| Arbeidstavlen | Work items opprettes ved feil |
|
||
| Responskvalitet | Intelligence/effort per orkestrering |
|
||
|
||
## 13. Bygger på
|
||
- `docs/retninger/unix_filosofi.md` — CLI-verktøy som byggeklosser
|
||
- `docs/retninger/interaksjonsmodell.md` — drag-and-drop for observes-edge
|
||
- `docs/concepts/arbeidstavlen.md` — @bot, work items ved feil
|
||
- `docs/infra/robusthet.md` — function calling, fallback
|
||
- `docs/features/responskvalitet.md` — intelligence/effort-nivåer
|