Commit Graph

18 Commits

Author SHA1 Message Date
258b14dcbc feat(web): ontology-driven fleet treegrid, relations grouping, dev auto-config
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
ci / web (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled
Knowledge Base / Fleet browsing:
- EntityTable renders as a treegrid (arbitrary depth, expand/collapse,
  ARIA row/level/expanded), grouped by parent-child relationships
  derived entirely from the live ontology graph (cardinality ->
  direction; typeDepth specificity for ties) rather than a hardcoded
  relationship list — see loadFleetGrouping in KnowledgeBase.svelte.
- Fold Services and Storage categories into Fleet (services/pools/
  volumes/datasets now nest under the compute entity or pool that
  provides/contains them instead of having their own browsing tabs).
- Drop `cluster` entities from Fleet browsing so a host's `located-at`
  (site) relationship wins the tree-parent slot without needing a
  hardcoded priority override — member-of simply has no valid target
  left to point at.
- Add a "show destroyed/inactive" Switch (default off) filtering on
  entity.state, replacing an always-on checkbox.

Entity detail panel:
- Split the Relations section into Outgoing/Incoming groups (relative
  to the viewed entity), and scope the section's count to edges
  actually incident to it rather than the whole depth-1 neighborhood.

Dev experience:
- Auto-fill the SPA's token from the dev server's own OIKOS_API_TOKEN
  (vite.config.ts define + main.ts, dev-only, only when unconfigured)
  so the "Connect to Oikos" prompt doesn't reappear on every reload.
- .claude/launch.json: autoPort, since port 5173 is often already
  claimed by another worktree's dev server.

Adds ui/checkbox and ui/switch (bits-ui primitives, following the
existing shadcn-svelte wrapper pattern) and fetchOntology()/
RelationshipTypeDef to api.ts. Also fixes a missing types.ts import
in api.ts (ChatEvent/MessageContent) that predates this branch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-17 23:26:04 +02:00
6806fac5fd feat(web): define ChatEvent discriminated union, eliminate all any sites (R9)
Created web/src/lib/types.ts with discriminated unions for SSE event
payloads: ChatEvent (7 variants: session, tool_use, tool_result,
text_delta, text, done, error), ToolCallResult, MessageContent, and
typed data shapes for live events (PlanProposedData, PlanStepEventData,
QuestionRaisedData, QuestionAnsweredData, EntityTouchedData,
HealthChangedData) plus WailsGlobal for the desktop bridge.

Replaced all ~15 `any` sites across 7 files:
- api.ts: Message.content any -> MessageContent | string; removed local
  ChatEvent interface (now imported from types.ts as a discriminated
  union); JSON.parse cast to ChatEvent.
- stores/chat.ts: removed local ToolCallResult interface (imported from
  types.ts, re-exported for backward compat); extractApprovals accesses
  args with typeof guards instead of implicit any access; toChatMessages
  handles string|object Message.content cleanly.
- stores/activity.ts: update_plan_step seq/status extracted via typeof
  guards instead of `as any` casts; toolActivityLabel uses a str() helper
  for safe string extraction from unknown args.
- stores/workspace.ts: applyPlanStepEvent takes PlanStepEventData;
  applyEvent casts data to Record<string, unknown>; switch cases cast to
  typed interfaces (PlanProposedData, QuestionRaisedData, etc.) instead
  of `as any`; applyHealthChanged uses HealthChangedData.
- Config.svelte: (window as any).wails -> typed WailsGlobal cast;
  catch (e: any) -> catch (e: unknown) with instanceof Error check.
- utils.ts: WithoutChild/WithoutChildren `any` -> `unknown`.
- vite.config.ts: authProxy proxy/proxyReq `any` -> ProxyOptions type.

Result: eslint no-explicit-any warnings dropped 12 -> 0. Tests (6/6) and
build pass. VERSION 0.7.10 -> 0.7.11. Plan R9 marked done.
2026-07-17 23:08:35 +02:00
0a3654b08f refactor(web): delete dead code (R2) — 1736 lines removed
Tool-renderer registry (21 files, ~1.5k lines):
- src/lib/tool-renderers.ts — registry + getToolRenderer (exported, never
  imported anywhere)
- src/lib/renderers/index.ts + 10 .ts registrars + 10 .svelte components
- main.ts: removed the requestAnimationFrame(() => import('./lib/renderers'))
  that was the only thing keeping the dead subsystem alive

Dead components (never imported):
- ToolCallGroup, PlanProgress, GoalHeader, InlineApproval, SessionDigest

Dead store exports (written, never read):
- context.ts: pendingApprovals writable (+ Approval type import)
- events.ts: connectionState writable (+ its .set() calls)

Dead API surface:
- api.ts: SessionDigest interface + fetchSessionDigest (only caller was the
  dead SessionDigest.svelte)

Dead npm deps:
- mode-watcher (0 imports; superseded by stores/theme.svelte.ts)
- @internationalized/date (0 imports)

Also: fix stale comments referencing deleted symbols, update plan R1/R2
status. Build clean (4683 modules, down from 4706; one Svelte 5 warning
gone — the dead HealthSummary.svelte was emitting state_referenced_locally).
2026-07-17 22:10:27 +02:00
60effcb2fe session reliability: reconnect, knowledge loop, retire request_execution
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled
Phase 1 — crash recovery: SSE auto-reconnect + backoff, polling gate
during disconnect, connection banner with retry button, empty-response
retry 3x, non-terminal resume on empty response, persistent error cards.

Phase 2/4 — visibility + continuation: custom ExecutionStatus renderer,
approvals extracted on every tool_result (not just done), activity bar
with status/goal, SessionDigest live polling, Continue button.

Phase 3 — cleanup: complete_task auto-cancels orphaned approvals,
deletes assent/destructive window keys, propose_plan marks pending
steps as replaced, plan step seq-order enforcement.

Phase 5 — knowledge loop: list_lxcs state filter (active/destroyed),
SOUL.md unmissable writeback section, propose_plan validation nudge,
complete_task writeback check, upsert_knowledge about array support,
plan generation grouping in frontend, session approval count badge.

Retire request_execution — all mutations now route through run.
Updated SOUL.md, AGENTS.md, CLIENTS.md, skills, and agent system notes.

Migration 020: plan step generation column, audit_log session_id index,
nomos_plan_executions pending-approval index.
2026-07-14 11:03:23 +02:00
61ad785fef fix(web): render full document content, keep graph connected under categories
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
Two fixes to the new category taxonomy:

- Knowledge Base couldn't show a document/investigation/runbook's own
  markdown body — knowledge_entities.content was never exposed by any
  endpoint (GetEntityKnowledge answers "what knowledge references this
  entity", not "what is this entity's content"). Add GET
  /api/v1/knowledge/content/{id} and render it with the existing
  marked+DOMPurify pipeline in a new Content section.

- The graph hid any edge whose other endpoint wasn't in the active
  category, so nodes with only cross-category neighbors rendered as
  disconnected dots. Queried the real relationship table: ~70% of infra
  edges cross Fleet/Network/Services/Storage lines (compute+network+
  software+storage+physical used to be one "infrastructure" layer).
  EntityGraph now keeps 1-hop neighbors visible but dimmed instead of
  hiding them, so the edges — and what they connect to — stay visible.

- categories.ts: `cognition` domain conflated true knowledge (document/
  investigation/runbook, 58 entities) with operational telemetry
  (execution/check/task/signal/approval/pattern/skill/classification/
  feedback, 300+ entities with their own Operations/Signals/Learning
  pages). Mapping the whole domain to Knowledge pulled in 245 execution
  entities fanning out from ~17 compute nodes via `targets` edges — the
  single biggest source of graph clutter. Knowledge now maps by type
  (document/investigation/runbook only); the rest of cognition is
  excluded from Knowledge Base browsing entirely.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 10:17:13 +02:00
35c54ceef5 feat(web): browse Knowledge Base by mixed Network/Fleet/Services/Storage/Identity/Knowledge categories
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
Replace the layer-based (Infrastructure/Governance/Cognition) browsing tabs
with a synthesized category taxonomy built from the ontology's finer-grained
`domain` field, since layer lumped unrelated entity types (an LXC and a DNS
record and a storage volume) into one bucket. Network and Fleet each span
two domains, so the table view now fans out per-domain fetches and merges,
while the graph view maps domain->category client-side. Also carries over
several detail-panel polish items (Tasks-not-raw-executions, slug URL
encoding, MultiSelectFilter) from earlier in this session.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 09:53:15 +02:00
94c94c0758 feat(web): merge Entities + Graph into a single Knowledge Base page
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
Replaces the separate Entities/Graph nav items with one Knowledge Base
page that browses all entities as either a table or a force-graph,
scoped by ontology layer (Infrastructure/Governance/Cognition), with a
resizable browse/detail split instead of a slide-over sheet.

- New KnowledgeBase.svelte: layer tabs, view toggle, resizable
  browse/detail split (pattern from Chat.svelte's rail).
- EntityTable/EntityGraph extracted as presentational sub-components;
  their search/filter/root/depth toolbars live in the shared page
  toolbar (not the resizable pane) so they don't truncate when the
  divider is dragged narrow, and both views start flush with the
  detail pane for consistent height.
- EntityTable columns are sortable (slug/type/name/state/health).
- EntityDetailContent redesigned as a single-column list of
  collapsible sections (DetailSection.svelte), collapsed by default
  when empty; relation entries are clickable and select the entity in
  the browse pane + detail pane (and drill in-place in EntitySheet
  wherever it's used elsewhere in the app).
- api.ts: add layer filter to fetchEntities, add fetchEntityTypes for
  client-side graph layer scoping (the graph endpoint has no layer
  param).

Old hash routes (#/entities, #/graph) redirect to #/kb.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-12 22:21:29 +02:00
0c0f35a3a9 feat(web): split SPA from oikos binary, require auth on every route
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
Phase 0 of plans/2026-07-12-wails-desktop-app.md. The control-room SPA
is no longer embedded (web/embed.go deleted); it's a standalone static
build served separately (make ui / make deploy-ui). The api process
adds CORS and drops the dev-open auth bypass — every route now needs a
real bearer token, including SSE (?token= query param, EventSource
can't set headers) and api's own /agent proxy to nomos (previously
unauthenticated by omission).

nomos was an unauthenticated client of api's /mcp and approval-decision
endpoints; closing dev-open would have broken it, so it now sends
Authorization: Bearer $OIKOS_MCP_BEARER_TOKEN on every call back to api.

SPA gets a runtime config module (config.ts) and a Config.svelte
first-launch/reconfigure page, reachable afterwards via a "Connection"
entry in the sidebar footer. Every fetch() in api.ts routes through
fetchWithAuth so the same build works same-origin (browser prod, Vite
dev proxy) or cross-origin (future Wails webview, remote access).

Six gaps found against the plan and the live Caddy topology while
implementing — documented in the plan's "Plan review" section, most
notably: api's own /agent mount was never behind combinedAuth (fixed),
and production's Authentik forward-auth needs a bearer-token bypass for
API routes that this repo's Caddyfile.oikos reference copy now has, but
the real dtoro/caddy-conf deploy does not yet.

Verified live: cross-origin static SPA + API, CORS, bearer auth, SSE
query-token auth, and localStorage persistence all confirmed working
in-browser. Full Go test suite and npm run build pass with no
regressions against the pre-change baseline.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 15:49:42 +02:00
991e7d0900 feat(tasks): phase 6 — live TaskContextPanel (goal, plan, question, entities)
Replaces the chat right rail's ad-hoc Digest+Graph stack with a single
TaskContextPanel that renders the task's live working state, driven by the
always-on events stream (not the per-turn chat SSE) so it keeps updating
during server-side auto-continuation/resume:

- GoalHeader: goal + status pill (planning/executing/awaiting_input/done/
  failed), sourced from the sessions list.
- PlanProgress: ordered steps with live status icons + progress bar, hydrated
  via new GET /sessions/{id}/plan; clicking a step with a target opens its
  EntitySheet (no fake "jump to transcript" — bits-ui Collapsible content
  isn't force-mounted, so a DOM-scroll jump would silently no-op for
  collapsed tool groups).
- OperatorQuestion: the pinned structured question card (prompt/why/entity
  chips/option buttons/free-text), hydrated via new GET /sessions/{id}/
  questions; answering POSTs to the existing answer endpoint.
- SessionGraph upgraded to a live entity panel: entity.touched pulses the
  node (animated ring) and shows "Now touching <slug>"; health.changed shows
  a transient diff badge for touched entities.
- SessionDigest gains a success/failure/partial outcome banner and now also
  refetches when the task's status changes, not just on session switch.

Two bugs found and fixed while wiring this up:
- workspace.ts's status-refresh trigger only covered goal.set/task.status;
  question.raised/answered didn't refresh the sessions list, so GoalHeader's
  pill went stale after answering via the panel (resumeSession runs entirely
  server-side — no client 'done' event to piggyback a refresh on). Now every
  status-affecting event triggers the (debounced) refetch.
- Forgot to rebuild the nomos container after adding the /plan and
  /questions endpoints, so they silently fell through to the old default GET
  handler — caught via a live curl diff against the running container,
  not a code read.

Verified end-to-end against the live stack: goal/plan/question all update
without a reload as the agent works; answering a question via the panel
resumes the agent and the header pill correctly flips to Executing;
entity.touched pulses the live graph.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 13:52:36 +02:00
413bf54daf feat(tasks): task board UI — chat window becomes Tasks + card grid
Reframes the chat surface as tasks:
- New Tasks.svelte: a card grid of tasks, each showing status (Running /
  Needs input / Done / Failed), the goal as title, the outcome summary, and
  relative time; filterable by status with live counts; delete on hover;
  "New task" and per-card click open the conversation.
- Board updates LIVE off the events stream (goal.set / task.status /
  question.*) via an explicit liveEvents.subscribe with a debounced refetch —
  scanning all events newer than the last seen, since entity.touched bursts
  bury task events below index 0.
- App shell: primary nav "Chat" → "Tasks" (board is now the home route),
  "New chat" → "New task", conversation header gets a Tasks / Conversation
  breadcrumb. Removed the superseded Sessions page.
- api.ts Session type carries the task fields (goal/status/outcome/summary).

Also fixes a pre-existing SSE bug that blocked ALL live updates app-wide:
writeSSE emitted `event: <type>`, which EventSource only delivers to
addEventListener(type) handlers — but stores/events.ts (and every page reading
liveEvents) consumes via onmessage, which never fires for named events. So the
live stream delivered nothing to the UI. Dropped the event-name line; the type
is already in the JSON payload, and new event types now need zero client
changes. SSE test still green (it parses data: lines).

Verified in the browser against the live stack: the board renders 50 tasks
with correct status buckets; a goal-driven task appears and flips to a Done
card with its summary in real time without a reload; Events page confirms the
stream now delivers to onmessage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 13:22:27 +02:00
52e16e04ca feat: Learning page — capability timeline + trend, built on real data
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
The plan's "learning view" (runbook success-rate trends, promoted
skills, capability timeline) assumes the patterns/skills/feedback
pipeline is populated. It isn't: all three tables are empty in
production and nothing in the codebase ever writes to feedback, so
building the UI against them today would ship a permanently-empty
page. Scoped instead around data that's real and growing —
executions — while still wiring up /patterns and /skills so the page
needs no rework once that pipeline exists.

New /api/v1/learning/timeline (per-verb first-success date + success
rate, parsed via the existing splitAction helper) and
/api/v1/learning/trend (30-day daily success/fail counts), both
read-only queries against executions. Patterns and skills sections
call the existing (untouched) ListPatterns/ListSkills endpoints and
render an explanatory empty state instead of nothing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 21:28:19 +02:00
ac48390796 feat: global activity feed + session digest
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
Ops "Executions" tab showed raw target UUIDs, alphabetical (not
recency) order, and a stale status vocabulary from an earlier schema
iteration — never actually usable as a live "what's happening" view.
Replaced with a new recency-ordered /api/v1/activity/recent endpoint
and matching table (human-readable action summaries, risk/status
badges, duration, inline error preview).

Also added /api/v1/activity/session/{id} + a collapsible SessionDigest
panel in the chat rail, answering "what did this session actually do"
(executions by status, entities touched, knowledge written) — the
missing piece for proactive outcome reporting to be visible in the UI,
not just in the chat transcript.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 20:09:09 +02:00
ec41c0b828 feat: learning view — make the growing knowledge base visible
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
First slice of the observability/learning UI (the "see the system come alive
and learn" ask). The Knowledge page was search-only — blank until you typed —
so the knowledge Nomos now writes via upsert_knowledge was invisible unless
you knew to search for it. Now the page LEADS with what the system knows and
is learning:

- internal/httpapi/knowledge.go: GET /api/v1/knowledge/recent — recency-ordered
  knowledge + a stats header (total, agent-authored, learned-this-week,
  by-kind). Custom route (not OpenAPI-generated), same auth as the rest.
- web Knowledge page rewrite: stat cards up top (Total / Written by Nomos /
  Learned this week / runbooks-investigations), then a "Recently learned" feed
  with agent-authored notes highlighted and badged "learned by Nomos", tags,
  and relative timestamps. A toggle filters to Nomos-only. Search still works,
  now as a mode you enter/clear rather than the whole page.

This turns "the system is getting smarter" from a claim into something you
watch fill up: every gotcha the agent records shows here within seconds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 19:22:35 +02:00
f248508919 feat: robust provisioning (DNS self-heal) + live execution feedback in chat
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
Production session provisioned the container but the service never installed:
apt failed with "Temporary failure resolving deb.debian.org" — a static-IP LXC
whose assigned nameserver couldn't resolve. The operator also got zero feedback:
the approval banner just sat there with no running/complete/failed status.

Backend robustness (provisionScript):
- Wait for real DNS/connectivity inside the container before apt, and self-heal
  /etc/resolv.conf to a public resolver (1.1.1.1/8.8.8.8) if the assigned one
  is dead. `set -e` after the gate so apt/post_install failures surface.
- apt-get update/install with Acquire::Retries=3.

Frontend feedback (InlineApproval):
- After approve, poll GET /executions/{id} and show live phase: submitting →
  provisioning… → provisioned successfully / execution failed (with the error).
- add getExecution() to api.ts.

Agent guidance (SOUL.md):
- omit vmid (auto-assigned), prefer dhcp, docker-compose-plugin is not in Debian
  (use docker.io + get.docker.com), end post_install with a health check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 01:15:21 +02:00
49c37fe8b1 fix: chat session reliability, cost, and hygiene (empty-response guard, tool truncation, delete, titles)
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
- Empty/refusal responses retried once, then surfaced as errors instead of silent blanks
- Chinese refusal boilerplate detected via denylist + non-ASCII heuristic
- Bulk-tool preference added to SOUL.md (list_lxcs over per-entity get_lxc_state)
- Tool results truncated to 4KB on persist; get_state_snapshot filters null-state entities
- Session delete (DELETE /sessions/{id} + confirm-on-second-click UI)
- Session titles auto-generated from assistant answer instead of raw user message
2026-07-09 10:18:06 +02:00
851b5dce67 feat: master-detail entity sheet, freshness in Entities table, live logo
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
Problem: the web UI felt dead and hard to navigate — the Entities table
had no health/freshness signal (just a meaningless row-mutation
timestamp), no way to see what was actually monitoring an entity,
sessions couldn't be reopened, and every drill-down was a full page
navigation that lost the list.

Change:
- Entities table: Updated column replaced with a health dot + relative
  "checked Xm ago", sourced from the backend's new health/last_check_at
  fields.
- New EntityDetailContent.svelte extracted from EntityDetail.svelte and
  shared between the full #/entity/:slug page and a new EntitySheet.svelte
  opened from the Entities table (master-detail, row click opens a panel
  instead of navigating away). Adds a Monitoring card listing the
  entity's check_defs (kind, interval, enabled/disabled with
  click-to-toggle via the existing PatchCheck endpoint) and renders
  attributes as key/value pairs instead of raw JSON.
- Sessions: fixed a bug where clicking a session loaded it into the
  chat store but never navigated to the chat page, so nothing appeared
  to happen. Added a SessionRail inside Chat so switching sessions
  never leaves the chat surface.
- Fixed the local dev proxy (vite.config.ts): production Caddy strips
  the /agent prefix before forwarding to nomos; the dev proxy didn't,
  so every session/chat fetch 404'd locally while working in prod.
- Found and fixed a real latent bug while testing the session fix:
  chat.ts's loadSessionMessages passed the persisted tool_calls array
  straight through, but nomos stores the tool_use and tool_result as
  two entries sharing one id. Chat.svelte's keyed {#each tool (tool.id)}
  throws on the duplicate key, which silently blanked the entire
  message list — invisible until sessions were actually clickable.
  Fixed by merging tool_calls by id before rendering, matching the
  shape the live-streaming path already produces.
- UI polish: sidebar logo is now just the omicron mark in white (was
  icon+text in the accent color); removed the sheet overlay's
  backdrop-blur (distracting per feedback); the Attributes/Relations/
  Signals grids used viewport-based lg:/3xl: breakpoints, which forced
  multi-column layouts based on browser width regardless of the sheet's
  actual rendered width — switched to Tailwind v4 container queries
  (@lg:/@2xl:/@3xl:) so layout responds to the real available width in
  both the full page and the narrower sheet.

Risk: reversible_low (UI-only; no destructive operations; the tool_calls
merge and dev-proxy fix are corrections to broken paths, not behavior
changes to working ones).

Verification: npx tsc --noEmit clean (excluding pre-existing unrelated
.svelte type-resolution warnings). Manually verified in the browser
preview against the live dev API: Entities table health column renders
correctly; clicking a row opens the EntitySheet with a populated
Monitoring card (16 checks for host:hubris, verified via psql that
check_defs.target_id links them correctly); clicking a session now
loads its full transcript inline (was blank before the tool_calls fix);
sheet has no blur and lays out single/multi-column correctly at the
sheet's actual width.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-09 00:26:37 +02:00
2908b0a377 feat(ui): M4 — agent activity, knowledge search, audit, correlation grouping
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
Add three new pages completing the control-room web UI:
- Agent activity: polls /agent-activity every 5s, filterable by type/agent
- Knowledge search: FTS over /knowledge/search with snippet + entity links
- Audit trail: browseable audit log with actor/action/entity filters

Enhanced live events page with correlation-id clustering (Groups toggle).
Added fetchAgentActivity/searchKnowledge/fetchAudit to the API client.
11 nav items now cover all planned control-room views.
2026-07-08 17:02:09 +02:00
e8e230b4a5 nomos+web: streaming, provider routing, event gap-fill, embedded UI; fix approval FK & session context
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
Agent (cmd/nomos):
- Stream LLM tokens via NewStreaming; emit text_delta then final text.
- OpenRouter provider routing: data_collection=deny (ZDR) + require_parameters;
  NOMOS_PROVIDER_SORT opt-in; Exacto via model suffix.
- Multi-turn: reload session history into context; UI passes session id.
- Fix agent_activity logging (agent_id/session_id) and mcpClient data race.

Events (live control-room feed):
- approval.created (mcp), approval.decided (api), execution.completed/failed
  (approved-action path), signal.raised/resolved + health.changed (scheduler,
  transition-gated).

Fixes:
- createApproval FK violation (reuse execution entity) — the agent's only
  write path; log the previously-swallowed errors.

Web UI:
- Embed web/dist via //go:embed (single binary); Dockerfile builds SPA into
  the Go stage; committed .gitkeep placeholder keeps backend-only builds green.
- Caddy: Authentik-gated /agent/* -> nomos so the UI reaches the agent
  same-origin in production.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 15:22:27 +02:00