- SwarmServiceInfo.ports typed as string[]|null, normalised to [] in listSwarmServices()
- SwarmServiceInfo.labels typed as Record|null, normalised to {} in listSwarmServices()
- NodeInfo.labels typed as |null, normalised via .map() in Nodes.tsx before render
- ServiceRow now uses (svc.ports ?? []).length and .map() — no crash when null
- Image display wrapped in IIFE to avoid double-split problem
- agents/nodes arrays normalised with .map() guards before render
- gateway-proxy.ts: listSwarmServices() deserialises and patches null fields server-side
## 1. Fix /nodes Swarm Status Display
- Add SwarmStatusBanner component: clear green/red/loading state
- Shows nodeId, managerAddr, isManager badge
- Error state explains what to check (docker.sock mount)
- Header now shows 'swarm unreachable — check gateway' vs 'active'
- swarmOk now checks nodeId presence, not just data existence
## 2. Autonomous Agent Container
- New docker/Dockerfile.agent — builds Go agent binary from gateway/cmd/agent/
- New gateway/cmd/agent/main.go — standalone HTTP microservice:
* GET /health — liveness probe with idle time info
* POST /task — receives task, forwards to Gateway orchestrator
* GET /info — agent metadata (id, hostname, gateway url)
* Idle watchdog: calls /api/swarm/agents/{name}/stop after IdleTimeoutMinutes
* Connects to Swarm overlay network (goclaw-net) → reaches DB/Gateway by DNS
* Env: AGENT_ID, GATEWAY_URL, DATABASE_URL, IDLE_TIMEOUT_MINUTES
## 3. Swarm Manager Agent (auto-stop after 15min idle)
- New gateway/internal/api/swarm_manager.go:
* SwarmManager goroutine checks every 60s
* Scales idle GoClaw agent services to 0 replicas after 15 min
* Tracks lastActivity from task UpdatedAt timestamps
- New REST endpoints in gateway:
* GET /api/swarm/agents — list agents with idleMinutes
* POST /api/swarm/agents/{name}/start — scale up agent
* POST /api/swarm/agents/{name}/stop — scale to 0
* DELETE /api/swarm/services/{id} — remove service permanently
- SwarmManager started as background goroutine in main.go with context cancel
## 4. Docker Client Enhancements
- Added NetworkAttachment type and Networks field to ServiceSpec
- CreateAgentServiceFull(opts) — supports overlay networks, custom labels
- CreateAgentService() delegates to CreateAgentServiceFull for backward compat
- RemoveService(id) — DELETE /v1.44/services/{id}
- GetServiceLastActivity(id) — finds latest task UpdatedAt for idle detection
## 5. tRPC & Gateway Proxy
- New functions: removeSwarmService, listSwarmAgents, startSwarmAgent, stopSwarmAgent
- SwarmAgentInfo type with idleMinutes, lastActivity, desiredReplicas
- createAgentService now accepts networks[] parameter
- New tRPC endpoints: nodes.removeService, nodes.listAgents, nodes.startAgent, nodes.stopAgent
## 6. Nodes.tsx UI Overhaul
- SwarmStatusBanner component at top — no more silent 'connecting…'
- New 'Agents' tab with AgentManagerRow: idle time, auto-stop warning, start/stop/remove buttons
- IdleColor coding: green < 5m, yellow 5-10m, red 10m+ with countdown to auto-stop
- ServiceRow: added Remove button with confirmation dialog
- RemoveConfirmDialog component
- DeployAgentDialog: added overlay networks field, default env includes GATEWAY_URL
- All queries refetch after agent start/stop/remove
1. AgentDetailModal – fix provider not being pre-selected on edit open:
- Add resolveProviderValue() that does exact → case-insensitive → partial
match between stored provider string and connectedProviders list
- Re-resolve provider in a second useEffect once providers load from API
- Add safety-net SelectItem for stored value not found in providers list
2. AgentCreateModal – refactor Deploy Agent form:
- Fix Provider + Model fields layout (grid-cols-2 with w-full truncate to
prevent overflow/merging)
- Add Wand2 'Auto-fill' button next to Agent Name field that calls
agentCompiler.compile (existing LLM endpoint) with name+description as
spec — fills role, model, temperature, systemPrompt automatically
- Add Sparkles hint text explaining the magic wand functionality
- Auto-select first provider/model when data loads
- All fields use font-mono + proper label spacing
3. Both modals – MaxTokens auto-fill from Ollama API:
- Add getOllamaModelInfo() in gateway-proxy.ts: calls Ollama /api/show,
extracts {arch}.context_length from model_info, returns contextLength +
parameterSize, family, quantization, capabilities
- Add ollama.modelInfo tRPC query endpoint in routers.ts (input: modelId)
- Both modals query trpc.ollama.modelInfo on model selection change
- Auto-set maxTokens to context_length from API (262144 for kimi-k2.5 etc.)
- Show 'max N from API' hint + clickable link to set full context window
- Loading spinner while fetching model info
- AgentDetailModal: load real models from API with loading indicator;
fallback to current agent model when API unavailable; show count badge
- AgentCreateModal: remove broken provider-filter on models list;
add loading indicator and disabled state during fetch; show count badge
- gateway/orchestrator: add resolveModel() — validates desired model
against LLM API before use; auto-fallback to first available model
to prevent 401/404 errors (fixes glm-5 unauthorized in chat)
- gateway/orchestrator: add ModelWarning field to ChatResult struct
- gateway-proxy.ts: add modelWarning field to GatewayChatResult
- Chat.tsx: display modelWarning as amber badge next to model name
- todo.md: add Phase 16 section with bug fixes and tech debt notes
Реализовано:
- gateway/internal/docker/client.go: Docker API клиент через unix socket (/var/run/docker.sock)
- IsSwarmActive(), GetSwarmInfo(), ListNodes(), ListContainers(), GetContainerStats()
- CalcCPUPercent() для расчёта CPU%
- gateway/internal/api/handlers.go: новые endpoints
- GET /api/nodes: список Swarm нод или standalone Docker хост
- GET /api/nodes/stats: live CPU/RAM статистика контейнеров
- POST /api/tools/execute: выполнение инструментов
- gateway/cmd/gateway/main.go: зарегистрированы новые маршруты
- server/gateway-proxy.ts: добавлены getGatewayNodes() и getGatewayNodeStats()
- server/routers.ts: добавлен nodes router (nodes.list, nodes.stats)
- client/src/pages/Nodes.tsx: полностью переписан на реальные данные
- Auto-refresh: 10s для нод, 15s для статистики контейнеров
- Swarm mode: показывает все ноды кластера
- Standalone mode: показывает локальный Docker хост + контейнеры
- CPU/RAM gauges из реальных docker stats
- Error state при недоступном Gateway
- Loading skeleton
- server/nodes.test.ts: 14 новых vitest тестов
- Все 51 тест пройдены