SpacetimeDB er nå helt fjernet fra Synops. Sanntid håndteres av PG LISTEN/NOTIFY + WebSocket i portvokteren (maskinrommet). Kode fjernet: - spacetimedb/ Rust-modul og spacetime.json - maskinrommet/src/stdb.rs (HTTP-klient for STDB-reducers) - frontend module_bindings/ (23 auto-genererte filer) - spacetimedb npm-avhengighet fra package.json - scripts/test-sanntid.sh (testet STDB-flyt) Infrastruktur: - Docker-container stoppet og fjernet fra docker-compose.yml - Caddy: fjernet /spacetime/* reverse proxy - maskinrommet-env.sh: fjernet STDB_IP og SPACETIMEDB_*-variabler - .env.example: fjernet SpacetimeDB-seksjoner Dokumentasjon oppdatert: - CLAUDE.md: stack, lagmodell, kjerneprinsipper, driftsmodell - docs/arkitektur.md: skrivestien, lesestien, datalag, teknologivalg - docs/retninger/datalaget.md: migrasjonshistorikk, status "fjernet" - 37 andre docs oppdatert (features, concepts, infra, ops, retninger) - Alle kode-kommentarer med STDB-referanser oppdatert Verifisert: maskinrommet bygger og starter OK, frontend bygger OK, helsesjekk returnerer 200. Caddy reloadet.
290 lines
11 KiB
Markdown
290 lines
11 KiB
Markdown
# Feature: AI-verktøy (Drag-and-drop tekstbehandling)
|
||
**Filsti:** `docs/features/ai_verktoy.md`
|
||
|
||
## 1. Konsept
|
||
Et frittstående verktøy-panel på arbeidsflaten for AI-drevet
|
||
tekstbehandling. I stedet for en ✨-knapp inne i editoren er AI-et
|
||
et eget verktøy som lever side ved side med chat, artikkelverktøy,
|
||
kanban og andre paneler. Brukeren konfigurerer verktøyet med en prompt
|
||
og drar innhold til/fra det.
|
||
|
||
Inspirert av fysiske verktøy: du har en maskin på arbeidsbenken,
|
||
konfigurert til å gjøre én ting godt. Du mater inn materiale, og
|
||
får bearbeidet materiale tilbake. Maskinen står der klar mellom bruk.
|
||
|
||
## 2. Brukeropplevelse
|
||
|
||
### 2.1 Åpne og konfigurere
|
||
1. Brukeren trekker AI-verktøyet inn på arbeidsflaten (fra verktøy-paletten).
|
||
2. Verktøyet åpner seg med:
|
||
- En **prompt-velger** med gjennomarbeidede standardprompter
|
||
- Et **fritekst-felt** for egendefinert prompt
|
||
- En **modell-indikator** (viser hvilken modell som brukes — styrt av server)
|
||
3. Brukeren velger prompt og verktøyet er klart.
|
||
4. Verktøyet *husker* konfigurasjonen — det står klart til bruk uten
|
||
å rekonfigurere hver gang.
|
||
|
||
### 2.2 To retninger — to semantikker
|
||
|
||
| Retning | Metafor | Handling | Resultat |
|
||
|---|---|---|---|
|
||
| **Verktøy → Node** | "Penselen" | Dra AI-verktøyet og slipp på en tekstnode | In-place revisjon: teksten modifiseres, originalen versjoneres |
|
||
| **Node → Verktøy** | "Kverna" | Dra en tekstnode og slipp på AI-verktøyet | Ny node opprettes med `derived_from`-edge til kilden |
|
||
|
||
**Penselen** — du bruker verktøyet *på* teksten. Passer for korrektur,
|
||
språkvask, rensing av innlimt rot. Teksten oppgraderes, originalen
|
||
bevares som revisjon.
|
||
|
||
**Kverna** — du sender teksten *gjennom* verktøyet. Passer for
|
||
oppsummering, oversettelse, uttrekk av fakta. Output er et nytt
|
||
objekt som kan tas med videre til andre verktøy på flaten.
|
||
|
||
### 2.3 Typisk bruksscenario
|
||
```
|
||
Vegard sitter på bussen, leser en artikkel i VG på mobilen.
|
||
Ctrl+A → kopierer alt (artikkel + ingresser + annonser + navigasjon).
|
||
Limer inn i en ny node i Synops.
|
||
|
||
Drar AI-verktøyet (konfigurert med "Rens tekst") → noden.
|
||
AI-et vasker bort alt som ikke er artikkelen, strukturerer teksten,
|
||
forkorter, og oppgir kilde. Originalen er bevart som revisjon.
|
||
|
||
Ferdig. Ren, lesbar tekst. Ingen rot.
|
||
```
|
||
|
||
## 3. Standardprompter
|
||
|
||
Gjennomarbeidede, klare til bruk uten konfigurasjon:
|
||
|
||
| Prompt | Hva den gjør | Typisk retning |
|
||
|---|---|---|
|
||
| **Rens tekst** | Fjerner støy fra innlimt webinnhold, fikser skrivefeil, strukturerer, oppgir kilde | Verktøy → Node |
|
||
| **Korrektør** | Fikser grammatikk og skrivefeil, beholder innhold intakt | Verktøy → Node |
|
||
| **Oppsummering** | Kondenserer til 2–5 setninger med det viktigste | Node → Verktøy |
|
||
| **Oversett** | Oversetter til/fra norsk/engelsk | Begge |
|
||
| **Skriv om for publisering** | Omskriver til artikkelformat med tittel, ingress, brødtekst | Node → Verktøy |
|
||
| **Trekk ut fakta** | Identifiserer påstander, tall, sitater som separate punkter | Node → Verktøy |
|
||
| **Forenkle** | Omskriver til klarere, enklere språk | Verktøy → Node |
|
||
| **Endre tone** | Formell ↔ uformell, saklig ↔ engasjert | Verktøy → Node |
|
||
|
||
Brukere kan lage egne prompter og lagre dem. Egendefinerte prompter
|
||
lagres som noder (`node_kind: 'ai_preset'`) som kan deles via edges.
|
||
|
||
## 4. Modellstyring
|
||
|
||
**Modell bestemmes av serveren, ikke brukeren.**
|
||
|
||
Hvert AI-verktøy (standardprompt eller egendefinert) har en
|
||
server-tildelt modellprofil. Brukeren ser hvilken modell som brukes
|
||
(transparens), men kan ikke endre den.
|
||
|
||
| Prompt-kategori | Modellprofil | Begrunnelse |
|
||
|---|---|---|
|
||
| Rens tekst, korrektør, forenkle | Flash (billig, rask) | Enkle transformasjoner |
|
||
| Oppsummering, oversettelse | Flash (billig, rask) | Rutineoppgaver |
|
||
| Skriv om for publisering | Standard | Krever mer resonering |
|
||
| Trekk ut fakta | Standard | Nøyaktighet viktigere |
|
||
| Egendefinert (default) | Flash | Kan oppgraderes av admin |
|
||
|
||
Modellprofiler konfigureres i maskinrommet og mappes til LiteLLM-aliaser.
|
||
Admin kan justere modellprofil per prompt via Prompt Lab.
|
||
|
||
**Kostnadskontroll:** Serveren styrer modellvalg for å hindre at brukere
|
||
velger den dyreste modellen for alt. AI-forbruk logges per bruker/samling
|
||
i `ai_usage_log`.
|
||
|
||
## 5. AI-verktøyet som node
|
||
|
||
AI-verktøyet er selv en node i grafen (`node_kind: 'ai_preset'`):
|
||
|
||
```jsonc
|
||
{
|
||
"node_kind": "ai_preset",
|
||
"title": "Rens tekst",
|
||
"metadata": {
|
||
"prompt": "Fiks denne teksten. Output på norsk...",
|
||
"model_profile": "flash",
|
||
"category": "standard", // "standard" | "custom"
|
||
"default_direction": "tool_to_node", // hint for UI
|
||
"icon": "sparkles",
|
||
"color": "#8B5CF6"
|
||
}
|
||
}
|
||
```
|
||
|
||
Fordeler:
|
||
- **Delbart:** Edge til samling/team → alle i teamet har tilgang
|
||
- **Versjonerbart:** Promptjustering over tid med revisjonshistorikk
|
||
- **Sporbart:** `derived_from`-edge fra output til kilde + `processed_by`-edge
|
||
til AI-preset → full provenance i kunnskapsgrafen
|
||
- **Gjenbrukbart:** Flere instanser av samme verktøy med ulik konfigurasjon
|
||
|
||
## 6. Teknisk arkitektur
|
||
|
||
### 6.1 Signalflyt
|
||
```
|
||
Bruker drar node → AI-verktøy (eller omvendt)
|
||
│
|
||
▼
|
||
Frontend sender intention til maskinrommet:
|
||
POST /intentions/ai_process
|
||
{
|
||
source_node_id: "...",
|
||
ai_preset_id: "...",
|
||
direction: "node_to_tool" | "tool_to_node"
|
||
}
|
||
│
|
||
▼
|
||
Maskinrommet:
|
||
1. Hent kilde-node content
|
||
2. Hent AI-preset prompt + modellprofil
|
||
3. Map modellprofil → LiteLLM-alias
|
||
4. Send til AI Gateway (LiteLLM)
|
||
5a. direction = tool_to_node:
|
||
→ Lagre original som revisjon
|
||
→ Oppdater node content med AI-output
|
||
5b. direction = node_to_tool:
|
||
→ Opprett ny node med AI-output
|
||
→ Opprett derived_from-edge til kilde
|
||
→ Opprett processed_by-edge til AI-preset
|
||
6. Logg forbruk i ai_usage_log
|
||
│
|
||
▼
|
||
Frontend mottar oppdatering via WebSocket (PG LISTEN/NOTIFY)
|
||
```
|
||
|
||
### 6.2 Drag-and-drop integrasjon
|
||
|
||
AI-verktøyet følger arbeidsflate-konvensjonene fra
|
||
`docs/retninger/arbeidsflaten.md`:
|
||
|
||
**Som mål (node → verktøy):**
|
||
- Aksepterer: alle noder med `content`-felt (tekst, chatmeldinger, notater)
|
||
- Drop-sone lyser opp med verktøyets farge under drag
|
||
- Ved drop: opprett ny node, vis den ved siden av verktøyet
|
||
|
||
**Som kilde (verktøy → node):**
|
||
- Verktøyet kan "dras" til en tekstnode
|
||
- Drop-sone på tekstnoden lyser opp
|
||
- Ved drop: modifiser noden in-place
|
||
|
||
**Inkompatibilitet:**
|
||
- Lydfiler, bilder, mediefiler → "AI-verktøyet behandler kun tekst"
|
||
- Tomme noder → "Noden har ikke innhold å behandle"
|
||
|
||
### 6.3 Oppdatering av kompatibilitetsmatrisen
|
||
|
||
Legges til i `docs/retninger/arbeidsflaten.md`:
|
||
|
||
| Kilde → Mål | AI-verktøy |
|
||
|---|---|
|
||
| **Chatboble** | Ny node med AI-output + `derived_from` |
|
||
| **Tekst/notat** | Ny node med AI-output + `derived_from` |
|
||
| **Lydfil** | Inkompatibel: "AI-verktøyet behandler kun tekst" |
|
||
| **Transkripsjon** | Ny node med AI-output + `derived_from` |
|
||
| **Bilde** | Inkompatibel |
|
||
|
||
| Kilde → Mål | Tekstnode (fra AI-verktøy) |
|
||
|---|---|
|
||
| **AI-verktøy** | In-place revisjon av tekstnoden |
|
||
|
||
## 7. Forhold til eksisterende AI-design
|
||
|
||
### Erstatter ✨-knappen i editoren
|
||
Editor-proposalen (`docs/proposals/editor.md`) beskriver en ✨-knapp
|
||
inne i editoren. Med spatial workspace-retningen erstattes denne av
|
||
AI-verktøyet som eget panel. Fordeler:
|
||
|
||
- **Separat konfigurasjonsflate:** Prompt og parametere lever i sitt
|
||
eget panel, ikke gjemt bak en meny i editoren
|
||
- **Persistent:** Verktøyet står konfigurert og klart. ✨-knappen
|
||
krever prompt-valg hver gang
|
||
- **Konsistent drag-and-drop:** Samme interaksjonsmønster som mellom
|
||
alle andre verktøy på flaten
|
||
- **Flere samtidige:** Du kan ha "Rens tekst" og "Oppsummer" som to
|
||
separate paneler, begge klare
|
||
|
||
### Bygger på Prompt Lab
|
||
Egendefinerte prompter kan opprettes og testes i Prompt Lab
|
||
(`docs/features/prompt_lab.md`) før de deployes som AI-preset-noder.
|
||
|
||
### Fremtidig: kjeding
|
||
Flere AI-verktøy i serie: dra output fra "Oversett" videre til
|
||
"Forenkle". Grafen sporer hele transformasjonskjeden via
|
||
`derived_from`-edges. Ikke i scope for v1.
|
||
|
||
## 8. Avgrensning
|
||
- Opererer på **hele noden** (hele `content`-feltet), ikke markert utvalg
|
||
- Brukeren kan **ikke** velge modell — kun server-tildelt modellprofil
|
||
- Ingen sanntids-streaming av AI-output (synkron respons via jobbkø)
|
||
- Støtter kun tekst — ikke bilder, lyd eller video
|
||
- Kjeding av verktøy er fremtidig funksjonalitet
|
||
|
||
## 9. Utviklingsfaser
|
||
|
||
### Fase A: Grunnleggende verktøy-panel
|
||
- [x] AI-preset node-type (`node_kind: 'ai_preset'`) + metadata-skjema
|
||
- [x] Standard-presets som seed-data (rens tekst, korrektør, oppsummering osv.)
|
||
- [x] `POST /intentions/ai_process` endepunkt i maskinrommet
|
||
- [x] Verktøy-panel UI med prompt-velger og modell-indikator
|
||
- [x] Jobbkø-integrasjon med AI Gateway
|
||
|
||
### Fase B: Drag-and-drop
|
||
- [x] Node → verktøy: opprett ny node med `derived_from`-edge
|
||
- [x] Verktøy → node: in-place revisjon med versjonering
|
||
- [x] Drop-sone feedback (farge, inkompatibilitet)
|
||
- [ ] Visuell output: ny node animeres inn ved siden av verktøyet
|
||
|
||
### Fase C: Egendefinerte prompter
|
||
- [x] Opprett egne AI-preset-noder (`POST /intentions/create_ai_preset`)
|
||
- [x] Del via edges (samling/team) — `shared_with`-edge til samling
|
||
- [x] Rediger og slett egne presets (via update_node/delete_node)
|
||
- [x] Modellprofil-beskyttelse: kun admin kan endre model_profile
|
||
- [ ] Prompt Lab-integrasjon for testing
|
||
|
||
## 10. Egendefinerte presets (oppgave 18.6)
|
||
|
||
### 10.1 Opprett egne AI-presets
|
||
Brukere kan opprette egne AI-preset-noder via `POST /intentions/create_ai_preset`:
|
||
|
||
```json
|
||
{
|
||
"title": "Lag ingress",
|
||
"prompt": "Skriv en kort, fengende ingress for denne teksten...",
|
||
"default_direction": "node_to_tool",
|
||
"icon": "pencil_square",
|
||
"color": "#10B981",
|
||
"share_with_collection_id": "<uuid>" // valgfri
|
||
}
|
||
```
|
||
|
||
Egendefinerte presets får alltid:
|
||
- `category: "custom"` (kan ikke endres til "standard")
|
||
- `model_profile: "flash"` (kan kun oppgraderes av admin)
|
||
- `visibility: "discoverable"` (synlig for brukere med tilgang)
|
||
|
||
### 10.2 Deling via edges
|
||
Presets kan deles med samlinger/team via `shared_with`-edge:
|
||
- Enten direkte i `create_ai_preset` via `share_with_collection_id`
|
||
- Eller via `create_edge` med `edge_type: "shared_with"`
|
||
|
||
### 10.3 Modellprofil-beskyttelse
|
||
- Vanlige brukere kan **ikke** endre `model_profile` — det er alltid "flash" for egne presets
|
||
- Admin (owner/admin-edge til en samling) kan oppgradere til "standard" via `update_node`
|
||
- Kategori "standard" er reservert for systempresets og kan ikke velges av brukere
|
||
|
||
### 10.4 Frontend
|
||
AiToolPanel har:
|
||
- "+ Nytt preset"-knapp for å opprette egne presets
|
||
- Rediger/slett/del-knapper for egne custom presets
|
||
- Egendefinerte presets markert med "egn." i preset-velgeren
|
||
- Delingsdialog for å dele med samling via UUID
|
||
|
||
## 11. Instruks for Claude Code
|
||
- AI-behandling skjer **alltid** via maskinrommet, aldri direkte fra frontend
|
||
- Modellprofil → LiteLLM-alias-mapping konfigureres i maskinrommet
|
||
- Brukeren kan **ikke** velge modell — dette er en server-side beslutning
|
||
- Standardprompter er seed-data som opprettes ved deploy, ikke hardkodet i frontend
|
||
- `derived_from`-edge og `processed_by`-edge gir sporbarhet i grafen
|
||
- AI-forbruk logges alltid i `ai_usage_log` per bruker, samling og preset
|
||
- Hele noden prosesseres — ingen "markert utvalg"-støtte
|