initial commit

This commit is contained in:
2026-03-25 00:05:57 +01:00
commit 25c7d598ca
63 changed files with 5257 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
# Control Plane
#sympozium #architektura #control-plane
## Komponenty
Control Plane Sympozium składa się z następujących komponentów:
### Controller Manager
Serce systemu. Zawiera **6 [[Controller i Reconciler|reconcilerów]]** + 2 routery:
| Reconciler | CRD | Odpowiedzialność |
|------------|-----|------------------|
| `AgentRunReconciler` | AgentRun | Tworzy Job/Sandbox CR, monitoruje lifecycle, zbiera wyniki |
| `SympoziumInstanceReconciler` | SympoziumInstance | Zarządza kanałami, memory, web endpoints |
| `PersonaPackReconciler` | PersonaPack | Stampuje instancje, schedules, memory z packów |
| `SkillPackReconciler` | SkillPack | Generuje ConfigMapy ze skilli |
| `SympoziumPolicyReconciler` | SympoziumPolicy | Zarządza politykami |
| `SympoziumScheduleReconciler` | SympoziumSchedule | Tworzy AgentRuns wg harmonogramu cron |
| `MCPServerReconciler` | MCPServer | Deployuje i probeuje MCP serwery |
**Routery** (reagują na eventy NATS):
- `ChannelRouter` - przetwarza wiadomości z kanałów → tworzy AgentRun
- `ScheduleRouter` - obsługuje `schedule.upsert` z agentów → tworzy/aktualizuje SympoziumSchedule
### API Server
- HTTP + WebSocket API
- Serwuje embedded web UI (React)
- Czyta annotacje node'ów (inference discovery)
- Sesje i historia w PostgreSQL
### [[Admission Webhook]]
- Enforces `SympoziumPolicy` przy tworzeniu AgentRun
- Waliduje sandbox requirements, tool gating, feature gates
- Działa at admission time, nie at runtime
### [[NATS JetStream]]
- Durable pub/sub event bus
- Decouples kanały od control plane
- Replay capability dla niezawodności
## Warstwa danych
| Magazyn | Zastosowanie |
|---------|-------------|
| **etcd** | [[CRD - Custom Resource Definition|CRD]] state (via K8s API) |
| **PostgreSQL** | Sesje, historia konwersacji |
| **SQLite + FTS5** | Persistent memory agentów (na PVC) |
| **[[ConfigMap i Secret\|ConfigMaps]]** | Skills, legacy memory |
| **[[ConfigMap i Secret\|Secrets]]** | Klucze API providerów |
## Przepływ reconciliation
```
User/Channel → Wiadomość
Channel Pod → NATS (channel.message.received)
Channel Router → Tworzy AgentRun CR
AgentRun Reconciler:
1. Walidacja polityki (SympoziumPolicy)
2. Tworzenie input ConfigMap (task + system prompt)
3. Rozwiązywanie skill sidecars (SkillPack CRDs)
4. Rozwiązywanie MCP serverów
5. Tworzenie Job/Sandbox CR z:
- Agent container
- IPC bridge sidecar
- Skill sidecars (z auto-provisioned RBAC)
- MCP bridge sidecar (opcjonalnie)
- Sandbox sidecar (opcjonalnie)
6. Monitorowanie faz: Pending → Running → Succeeded/Failed
7. Zbieranie wyników z logów poda
8. Ekstrakcja memory updates
9. Czyszczenie RBAC i zasobów
```
## Metryki OTel
Controller eksportuje metryki OpenTelemetry:
- `sympozium.agent.runs` - counter zakończonych runów
- `sympozium.agent.duration_ms` - histogram czasu trwania
- `sympozium.errors` - counter błędów
- `sympozium.web_endpoint.serving` - aktywne deployments server-mode
---
Powiązane: [[Cykl życia Agent Pod]] | [[NATS JetStream - Event Bus]] | [[Orchestrator - PodBuilder i Spawner]]

View File

@@ -0,0 +1,114 @@
# Cykl życia Agent Pod
#sympozium #architektura #agent-pod
## Anatomia Agent Pod
Każdy agent run tworzy pod z następującymi kontenerami:
```
┌─────────────────────────────────────────────────────┐
│ Agent Pod (Job) │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌──────────────┐ │
│ │ Agent │ │ IPC Bridge │ │ Skill Sidecar│ │
│ │ Container │ │ Sidecar │ │ (kubectl, │ │
│ │ │ │ │ │ helm, etc.) │ │
│ │ - LLM loop │ │ - fsnotify │ │ │ │
│ │ - Tool exec │ │ - NATS pub │ │ - /workspace │ │
│ │ - /skills │ │ - /ipc │ │ - RBAC scope │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬───────┘ │
│ │ │ │ │
│ /workspace /ipc (tmpfs) /workspace │
│ /skills (ro) (RAM-backed) │
│ /ipc │
│ /tmp │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ MCP Bridge │ │ Sandbox │ │
│ │ (opcjonalny) │ │ (opcjonalny) │ │
│ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────┘
```
## Woluminy
| Wolumin | Typ | Rozmiar | Cel |
|---------|-----|---------|-----|
| `workspace` | emptyDir | 1Gi | Współdzielone pliki robocze agent ↔ sidecary |
| `ipc` | emptyDir (RAM) | 64Mi | JSON IPC: agent → bridge → NATS |
| `skills` | Projected ConfigMap | - | Markdown instrukcje ze SkillPacks (read-only) |
| `tmp` | emptyDir | 256Mi | Tymczasowe pliki (read-only root FS) |
## [[SecurityContext]] agenta
Hardened security context - patrz [[SecurityContext]] dla wyjaśnienia poszczególnych pól:
```go
SecurityContext: &corev1.SecurityContext{
ReadOnlyRootFilesystem: &readOnly, // true - root FS read-only
AllowPrivilegeEscalation: &noPrivEsc, // false - blokuje setuid
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{"ALL"}, // Drop ALL Linux capabilities
},
}
```
## Zasoby
| Kontener | CPU Request | CPU Limit | Memory Request | Memory Limit |
|----------|-------------|-----------|----------------|--------------|
| Agent | 250m | 1 | 512Mi | 1Gi |
| IPC Bridge | 50m | 100m | 64Mi | 128Mi |
| Sandbox | 100m | 500m | 256Mi | 512Mi |
## Fazy lifecycle
```
Pending → Running → Succeeded
→ Failed
→ Serving (tryb server)
```
### Pending
1. Walidacja polityki
2. Tworzenie ServiceAccount `sympozium-agent`
3. Tworzenie input ConfigMap (task, system prompt, memory)
4. Rozwiązywanie sidecars i RBAC
5. Tworzenie Job/Sandbox CR
### Running
- Polling statusu poda co 10 sekund
- Monitorowanie completion/failure
### Succeeded/Failed
1. Zbieranie logów poda (wynik agenta)
2. Ekstrakcja memory markers z outputu
3. Aktualizacja memory ConfigMap
4. Usuwanie efemerycznego RBAC
5. Pruning historii (domyślnie 50 runów per instancja)
6. Usuwanie finalizera
### Serving (tryb server)
- Deployment zamiast Job
- Service dla routowania
- Używany dla web-endpoint
- Długo żyjący, nie jest garbage-collectowany po zakończeniu
## Zmienne środowiskowe agenta
| Zmienna | Wartość |
|---------|---------|
| `AGENT_RUN_ID` | Nazwa AgentRun CR |
| `AGENT_ID` | ID konfiguracji agenta |
| `SESSION_KEY` | Klucz sesji |
| `INSTANCE_NAME` | Nazwa SympoziumInstance |
| `MODEL_PROVIDER` | openai/anthropic/azure/ollama |
| `MODEL_NAME` | Identyfikator modelu |
| `THINKING_MODE` | off/low/medium/high |
| `SPAWN_DEPTH` | Głębokość zagnieżdżenia sub-agenta |
| `TRACEPARENT` | W3C traceparent (OTel) |
---
Powiązane: [[Control Plane]] | [[Orchestrator - PodBuilder i Spawner]] | [[Skill Sidecars i auto-RBAC]]

View File

@@ -0,0 +1,59 @@
# NATS JetStream - Event Bus
#sympozium #architektura #nats #messaging
## Rola w systemie
NATS JetStream pełni rolę **centralnego event bus** łączącego wszystkie komponenty Sympozium. Jest deployowany jako StatefulSet w namespace `sympozium-system`.
## Dlaczego NATS?
| Cecha | Wartość dla Sympozium |
|-------|----------------------|
| **Durable pub/sub** | Wiadomości nie są tracone przy restartach podów |
| **Replay** | Kanały mogą odtworzyć niezrealizowane wiadomości |
| **Lightweight** | Minimalne zasoby vs Kafka/RabbitMQ |
| **Cloud-native** | Natywne wsparcie K8s |
| **Decoupling** | Kanały i agenty nie muszą wiedzieć o sobie |
## Topologia
```
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Channel Pods │ │ NATS │ │ Controller │
│ (Telegram, │────►│ JetStream │◄────│ Manager │
│ Slack, etc.)│◄────│ │────►│ │
└──────────────┘ │ StatefulSet │ └──────────────┘
│ sympozium- │
┌──────────────┐ │ system │ ┌──────────────┐
│ IPC Bridge │────►│ │ │ Schedule │
│ (sidecars) │◄────│ │ │ Router │
└──────────────┘ └──────────────┘ └──────────────┘
```
## Połączenie
Wszystkie komponenty łączą się pod adresem:
```
nats://nats.sympozium-system.svc:4222
```
Zmienna środowiskowa: `EVENT_BUS_URL`
## Wzorzec komunikacji
1. **Request/Reply** - tool execution (request → sidecar → result)
2. **Pub/Sub** - lifecycle events (run.started, run.completed)
3. **Queue Groups** - channel messages (load-balanced between consumers)
## Dlaczego nie bezpośrednia komunikacja?
Agent pod nie ma dostępu sieciowego (NetworkPolicy deny-all). Jedyny komponent z dostępem do NATS to **IPC Bridge sidecar**. To zapewnia:
- Agent nie może bezpośrednio komunikować się z innymi podami
- Całość komunikacji przechodzi przez kontrolowany kanał
- Łatwe auditowanie (jeden punkt wejścia/wyjścia)
---
Powiązane: [[Przepływ danych i IPC]] | [[Control Plane]] | [[NetworkPolicy i izolacja sieciowa]]

View File

@@ -0,0 +1,104 @@
# Orchestrator - PodBuilder i Spawner
#sympozium #architektura #orchestrator
## Lokalizacja
`internal/orchestrator/` - pakiet odpowiedzialny za budowanie specyfikacji podów i spawning Job'ów.
## PodBuilder
`PodBuilder` to struct odpowiedzialny za konstruowanie pod spec'ów. Konfigurowany jest tagiem obrazów:
```go
type PodBuilder struct {
DefaultAgentImage string // agent-runner
DefaultIPCBridgeImage string // ipc-bridge
DefaultSandboxImage string // sandbox
DefaultMCPBridgeImage string // mcp-bridge
EventBusURL string // nats://nats.sympozium-system.svc:4222
ImageTag string // np. "v0.0.25"
}
```
Registry: `ghcr.io/sympozium-ai/sympozium`
## Budowanie kontenerów
### BuildAgentContainer
Główny kontener agenta z:
- Read-only root filesystem
- Drop ALL capabilities
- No privilege escalation
- Woluminy: workspace, skills (ro), ipc, tmp
- EnvFrom: secret z kluczem API
### BuildIPCBridgeContainer
Sidecar IPC bridge z:
- Wolumin ipc (shared z agentem)
- Env: AGENT_RUN_ID, INSTANCE_NAME, EVENT_BUS_URL
- Opcjonalnie: TRACEPARENT, OTEL_* (observability)
### BuildSandboxContainer
Opcjonalny sidecar sandbox z:
- Read-only root filesystem
- Drop ALL capabilities
- Command: `sleep infinity` (czeka na komendy z agenta)
- Woluminy: workspace, tmp
### BuildVolumes
4 woluminy:
- `workspace` - emptyDir 1Gi
- `ipc` - emptyDir (Memory medium) 64Mi - **RAM-backed** dla szybkości
- `tmp` - emptyDir 256Mi
- `skills` - Projected volume z ConfigMapów SkillPacks
## AgentPodConfig
Konfiguracja przekazywana do buildera:
```go
type AgentPodConfig struct {
RunID string
InstanceName string
AgentID string
SessionKey string
ModelProvider string
ModelName string
ThinkingMode string
AuthSecretRef string
SandboxEnabled bool
SandboxImage string
SpawnDepth int
Skills []SkillMount
Traceparent string // W3C traceparent
OTelEndpoint string // OTLP endpoint
}
```
## Proces tworzenia poda (w AgentRunReconciler)
```
1. reconcilePending()
├── validatePolicy() - sprawdza SympoziumPolicy
├── ensureAgentServiceAccount() - ServiceAccount w namespace
├── createInputConfigMap() - task + system prompt
├── resolveSkillSidecars() - SkillPack CRDs → sidecar specs
├── ensureMCPConfigMap() - konfiguracja MCP serwerów
├── buildContainers() - PodBuilder buduje spec
├── createEphemeralRBAC() - Role + RoleBinding per sidecar
└── createJob() / createSandboxCR() - finalne tworzenie zasobu K8s
```
## Relacja z AgentRun Controller
`AgentRunReconciler` (`internal/controller/agentrun_controller.go`) jest "klientem" PodBuilder'a. Reconciler:
1. Obserwuje AgentRun CRDs
2. Używa PodBuilder do budowania spec'ów
3. Tworzy Job/Sandbox CR w Kubernetes
4. Monitoruje lifecycle poda
5. Zbiera wyniki i czyści zasoby
---
Powiązane: [[Cykl życia Agent Pod]] | [[AgentRun]] | [[Cykl życia AgentRun]]

View File

@@ -0,0 +1,126 @@
# Przepływ danych i IPC
#sympozium #architektura #ipc
## Mechanizm IPC
Sympozium używa **filesystem-based IPC** - agenty komunikują się z control plane przez pliki JSON w woluminie `/ipc/`:
```
Agent tool pisze JSON → /ipc/<dir>/*.json → fsnotify watcher → NATS publish → Controller
```
### Katalogi IPC
| Katalog | Cel | Przykład |
|---------|-----|---------|
| `/ipc/tools/` | Wykonanie komend w sidecarze | `execute_command` |
| `/ipc/messages/` | Wysyłanie wiadomości na kanały | `send_channel_message` |
| `/ipc/schedules/` | Zarządzanie schedulami | `schedule_task` |
## Dlaczego filesystem IPC?
### Zalety
1. **Language-agnostic** - agent mógłby być w Pythonie, Rust, czymkolwiek
2. **Zero zależności** - agent nie potrzebuje klienta NATS ani żadnego SDK
3. **Inspekcja** - pliki JSON w woluminie można łatwo debugować
4. **Prostota** - zapis pliku to najprostsza operacja I/O
5. **Bezpieczeństwo** - agent nie ma dostępu sieciowego, tylko do woluminu
### Jak to działa
```
1. Agent zapisuje /ipc/tools/cmd-12345.json:
{
"command": "kubectl get pods",
"runId": "my-run-123"
}
2. IPC Bridge (sidecar) wykrywa plik via fsnotify
3. Bridge publikuje na NATS:
Topic: tool.exec.request
Payload: {command, runId, instanceName}
4. Skill sidecar (lub controller) odbiera i wykonuje
5. Wynik wraca: NATS → IPC Bridge → /ipc/tools/result-12345.json
6. Agent czyta wynik z pliku
```
## NATS Topics
Kluczowe tematy zdefiniowane w `internal/eventbus/types.go`:
### Lifecycle agenta
- `agent.run.requested` - żądanie nowego runu
- `agent.run.started` - run rozpoczęty
- `agent.run.completed` - run zakończony sukcesem
- `agent.run.failed` - run zakończony błędem
### Wiadomości kanałów
- `channel.message.received` - wiadomość od użytkownika
- `channel.message.send` - wiadomość do użytkownika
### Narzędzia
- `tool.exec.request` - żądanie wykonania komendy w sidecarze
- `tool.exec.result` - wynik wykonania
### Scheduling
- `schedule.upsert` - agent sam tworzy/aktualizuje swój schedule
## Wbudowane narzędzia agenta
Agent-runner ma **7 wbudowanych narzędzi** (`cmd/agent-runner/tools.go`):
| Narzędzie | Kategoria | Opis |
|-----------|-----------|------|
| `execute_command` | IPC (sidecar) | Uruchamia komendy shell w skill sidecarze |
| `read_file` | Native | Czyta zawartość pliku |
| `write_file` | Native | Tworzy/zapisuje pliki |
| `list_directory` | Native | Listuje zawartość katalogu |
| `send_channel_message` | IPC (bridge) | Wysyła wiadomości na kanały |
| `fetch_url` | Native | HTTP GET i zwraca body |
| `schedule_task` | IPC (bridge) | CRUD na SympoziumSchedule CRDs |
### Natywne vs IPC
- **Native** - narzędzia wykonywane bezpośrednio w kontenerze agenta
- **IPC (sidecar)** - narzędzia delegowane do skill sidecara przez IPC bridge
- **IPC (bridge)** - narzędzia delegowane do controllera przez NATS
## Przepływ end-to-end
```
Użytkownik → Telegram
Channel Pod (Telegram) → NATS: channel.message.received
Channel Router → Tworzy AgentRun CR
AgentRun Reconciler → Tworzy Job z kontenerami
Agent Container:
1. Czyta task z /workspace/input/
2. Czyta skills z /skills/
3. Czyta memory z /memory/ lub memory API
4. Wywołuje LLM (OpenAI/Anthropic/etc.)
5. LLM decyduje o użyciu narzędzia
6. Agent pisze do /ipc/tools/
7. IPC Bridge → NATS → Skill Sidecar wykonuje
8. Wynik wraca → Agent kontynuuje dialog z LLM
9. Agent pisze wynik do stdout
Controller zbiera logi poda
Controller → NATS: agent.run.completed
Channel Router → NATS: channel.message.send
Channel Pod (Telegram) → Użytkownik
```
---
Powiązane: [[NATS JetStream - Event Bus]] | [[Cykl życia Agent Pod]] | [[Skill Sidecars i auto-RBAC]]