Commit Graph

83 Commits

Author SHA1 Message Date
rcourtman 7d772acff3 feat(assistant): mid-turn steering of the running response
A follow-up sent during an active run now offers itself to the running
agentic loop via POST /api/ai/sessions/{id}/steer. Accepted steers join
the loop at its next turn boundary (the abort-check site) as plain user
messages, are announced with a steer_applied stream event so the drawer
settles the pending row, and persist through the end-of-run save. A
steer carries prompt text only: no route, control-level, or autonomy
changes, no turn-budget extension, system sessions rejected, and the
per-session inbox is bounded (steer_backlog overflow). Delivery is not
guaranteed by acceptance: a run that ends first discards the inbox and
the row drains as an ordinary queued turn, so pre-steering queue
semantics remain the fallback. Steering rows lose edit/remove once
accepted.
2026-07-12 23:01:40 +01:00
rcourtman 60ce8924bb feat(assistant): retry re-runs the turn in place and the last answer gains regenerate
Retrying a failed turn re-sent the prompt without removing the persisted
turn, so session history double-recorded the prompt. Session undo now
accepts an expected-prompt guard (a stale retry can never remove a
different turn); retry drops the replaced turn server-side before
re-sending. The latest settled assistant answer gains a hover-revealed
Regenerate button that reuses the same path.
2026-07-12 20:58:20 +01:00
rcourtman ffd1ea8127 Enforce Assistant read-only scope integrity 2026-07-11 12:43:55 +01:00
rcourtman 4edf5f8265 fix: close chat command authority boundary 2026-07-11 11:54:56 +01:00
rcourtman ee8a24e14a backend and governance: MCP contract, agent capabilities, API, and release-control
Manifest-backed MCP tools, prompts, and resources with surface affordance contracts; agent capability manifest and governance projection; API contract tests and capability route projection; operations-loop and intelligence-funnel telemetry; release-control subsystem documentation, registry, and tooling; licensing and configuration.
2026-06-23 17:26:15 +01:00
rcourtman 738fc4eb13 Reject unsupported Assistant session diff/revert 2026-06-07 18:01:55 +01:00
rcourtman 3c74fe2ca0 Start Assistant runtime in mock mode 2026-06-06 21:39:39 +01:00
rcourtman e4ac092876 Add Assistant stream idle progress 2026-06-06 19:59:34 +01:00
rcourtman 44e8a1b2bd Add Assistant turn undo and redo 2026-06-06 19:42:27 +01:00
rcourtman 5503e15d23 Add Assistant session rename
Add persisted session rename support across the chat store, API contract, and Assistant session picker.
2026-06-06 18:32:21 +01:00
rcourtman 49c23d6bed Search Assistant session history 2026-06-06 09:14:06 +01:00
rcourtman 0ad040bdf0 Resolve Assistant plain-text resource context
Attach backend-resolved current_resource context for live Assistant read prompts.
2026-06-06 07:13:05 +01:00
rcourtman 2ab0a60e99 Speed up Assistant stream startup 2026-06-05 22:54:44 +01:00
rcourtman 0d2f2a3cc8 Anchor Assistant stream and OpenRouter default 2026-06-05 22:02:47 +01:00
rcourtman a648afaff0 Avoid duplicate Assistant stream errors 2026-06-05 19:29:07 +01:00
rcourtman dae5daf6ac Fix Assistant provider route validation 2026-06-05 18:48:57 +01:00
rcourtman 5ea51b4b25 Harden Assistant stream output and OpenRouter token budget 2026-06-05 16:30:07 +01:00
rcourtman 064cd4bc80 Hide Assistant reasoning from message history 2026-06-05 15:43:06 +01:00
rcourtman 91528f5a07 Fix Assistant resource context and model route labels 2026-06-04 23:45:15 +01:00
rcourtman a6b773a85f Reuse the loaded AI config when restarting the service
Back-port v5 fix 716340dcd to v6. Extracts startWithConfig from Start so
Restart passes the config it already loaded down to the start path, instead
of Start re-reading loadAIConfig a second time. Avoids starting the AI
service with a stale/inconsistent config if it changed between Restart's
load and the start. Both Restart start paths now use startWithConfig.
2026-06-04 10:30:45 +01:00
rcourtman 303a8e2fe8 Remove Assistant handoff decision guidance 2026-05-15 16:57:25 +01:00
rcourtman 14d3284233 Remove Assistant prompt routing heuristics 2026-05-15 16:10:58 +01:00
rcourtman a0b3bc7ed3 Record user-chat token usage to the cost ledger
chat.Service.ExecuteStream was a long-standing cost-ledger gap: the
agentic loop accumulated token counts via stream callbacks (see
GetTotalInputTokens / GetTotalOutputTokens in agentic_control.go)
and surfaced them in the SSE done envelope to the frontend, but
nothing on the server side recorded a cost.UsageEvent. Patrol,
discovery, QuickAnalysis, and the report narrators all record; only
chat — the bulk of AI token spend — did not. The operator's AI
usage dashboard was therefore understating cost dramatically.

Found while extending the cost-recording mindset across subpackages
after fixing QuickAnalysis (08491b9f4). Initially spawned as a
separate task but the right shape and scope became clear, so landing
it directly here.

Pipeline:
- Service.CostStore() exposes the per-tenant cost store handle.
- chat.Config gains optional CostStore *cost.Store field, threaded
  into chat.Service.costStore at NewService time.
- chat.Service.recordChatTurnCost records a UsageEvent with
  UseCase="chat" after every loop.ExecuteWithTools return (success
  OR error — operator was billed regardless of clean response).
  Skips when costStore is nil or zero tokens accumulated.
- ai_handler.go's two chatCfg construction sites populate CostStore
  via h.resolveCostStore(ctx).
- router wires the resolver to AISettingsHandler.GetAIService(ctx).CostStore()
  with no Enabled gate — even brief chat usage while AI was being
  configured should appear in the dashboard.

ExecutePatrolStream is deliberately not changed. It creates a
separate tempLoop and its caller (patrol_ai.go) records cost via
its own helper at line 887. Recording in ExecuteStream only avoids
double-counting on the patrol-via-chat path.

Tests in chat/cost_recording_test.go cover: recording when store
configured, no-op when store nil, no-op on zero tokens (early
failures), graceful handling of model strings missing the
provider prefix.
2026-05-10 23:15:53 +01:00
rcourtman 03463c1bfe Thread per-tenant AI narrators into pulse_summarize via chat session
v1 of pulse_summarize (1fe5d6853) shipped with heuristic narrative
only. The follow-up wiring promised in that commit now lands: the
chat session carries optional report-narration providers that the
tool's handler reads when building requests, so AI-narrated synthesis
flows into chat using the same provider, sanitizer, model selection,
cost ledger, and budget gate the report PDF endpoint already uses.

Pipeline:
- pkg/reporting Narrator / FleetNarrator / FindingsProvider interfaces
  are already implemented by internal/ai.Service. No new
  implementations.
- tools.ExecutorConfig + PulseToolExecutor gain three optional fields
  (ReportNarrator, ReportFleetNarrator, ReportFindingsProvider).
  Clone() copies them so per-session executors inherit the wiring.
- chat.Config gains the same three fields; NewService threads them
  into ExecutorConfig.
- tools_summarize.go reads e.reportNarrator/FleetNarrator/
  FindingsProvider and populates MetricReportRequest /
  MultiReportRequest. The engine already accepts these on the request
  and falls back to heuristic when they are nil — no engine changes
  needed.
- AIHandler gains SetReportNarratorResolver(ctx -> narrators); both
  per-tenant and default chat.Config construction sites invoke the
  resolver. Router wires the resolver to AISettingsHandler.GetAIService
  with the same Enabled-gate the reporting handler uses.

Unconfigured tenants are unchanged: the resolver returns nil, the
tool returns heuristic narrative — identical to today. Configured
tenants get AI synthesis in chat that matches what their report PDF
already carries, billed and budget-gated the same way.
2026-05-10 22:50:17 +01:00
rcourtman 52669128e6 Drop redundant policy gates in resource-link routing
Tail of the operator-local-UI redaction sweep (abdde303a, a17f879a1).

resolveKubernetesContextForResource gated on requiresGovernedResourceDisplay
to choose between getPreferredInfrastructureDisplayName and a manual
displayName-or-name fallback. Both branches produce a raw infra name
once we trust that displayName never carries a redacted summary in
local rendering, so the gate is dead complexity. Collapse to a single
call and drop the now-unused requiresGovernedResourceDisplay import.

problemResourcePresentation.getProblemResourceDisplayName has no
production consumers today, but it still routes through the governed
helper. Reclassify it now (same as every other operator-local helper)
so the rule is consistent across the codebase if the surface ever gets
adopted.
2026-05-09 21:31:45 +01:00
rcourtman b5c8e00859 Preserve previous successful fix across regressions
Capture the prior InvestigationRecord.ProposedFix.Description into a
new Finding.PreviousResolvedFixSummary field at regression time, before
the InvestigationRecord is cleared. Without this capture the next
investigation starts from blank context whenever a finding regresses,
and operational memory of "what worked last time" is lost.

The summary propagates through:
- FindingsStore.Add regression branch (capture before clear)
- Finding.MarshalJSON / UnmarshalJSON (wire shape)
- Both Finding to UnifiedFinding conversion sites in router.go
- UnifiedFinding (struct + JSON shadow + Marshal/Unmarshal)
- UnifiedStore.AddFromAI update branch (non-empty overwrite)
- Assistant chat context as a "Previous Resolved Fix" line so the LLM
  sees what worked previously rather than blank-slate diagnosing each
  regression.

Adds a unit test that walks the full lifecycle (detect, resolve via
UpdateInvestigationRecord + ResolveWithReason, re-detect) and asserts
PreviousResolvedFixSummary is preserved while InvestigationRecord is
cleared, plus two chat-context tests covering the surfaces-when-set and
omits-when-empty cases. Adds a contract test pinning the canonical
"previous_resolved_fix_summary" JSON key. Updates the api-contracts,
ai-runtime, and the dependent agent-lifecycle, performance-and-
scalability, and storage-recovery contracts to pin the operational
memory propagation rule and its scope boundary.
2026-05-08 19:45:44 +01:00
rcourtman dd15d23a35 Hydrate Patrol requester in Assistant handoffs
- hydrate approval requester identity into backend handoff actions
- include requester provenance in refreshed finding action context
- document the backend requester authority boundary
2026-05-08 00:26:04 +01:00
rcourtman bbaa6c0a6c Cover Patrol handoff approval mode
- force non-empty Patrol finding handoffs into approval-required mode

- add direct helper coverage for finding, scoped, resource, action, and metadata handoffs

- align subsystem contracts with the backend-owned clamp
2026-05-07 23:08:56 +01:00
rcourtman d9331d39e4 Move Patrol run Assistant handoffs server-side
- rehydrate Patrol run context from Patrol history for chat requests and follow-up sessions
- send only browser-safe run metadata from the frontend
- classify and redact provider runtime failures in handoff prompts and briefings
2026-05-07 21:58:06 +01:00
rcourtman ff9cb5c133 Restore Patrol run Assistant session identity
Refs #1463
2026-05-07 15:53:59 +01:00
rcourtman 6b4e4d7fe6 Merge Patrol handoff context into Assistant requests 2026-05-07 11:58:02 +01:00
rcourtman a66b80ceb9 Carry structured Patrol actions into Assistant handoffs 2026-05-07 10:48:15 +01:00
rcourtman 7aaf76d03c Carry live approval lifecycle into Assistant handoffs 2026-05-07 10:25:14 +01:00
rcourtman 812c86692d Route Assistant handoffs through model context 2026-05-07 03:00:58 +01:00
rcourtman 2c913fac8e Clamp Patrol finding chat handoffs to approval mode 2026-05-07 01:31:45 +01:00
rcourtman bf0e4e16ac Align Assistant briefings with handoff actions 2026-05-07 00:38:42 +01:00
rcourtman b8bad16d80 Recover live Patrol approvals for Assistant handoffs 2026-05-07 00:31:44 +01:00
rcourtman 1fc66cf0cb Add attention reasons to Assistant briefings 2026-05-06 23:39:33 +01:00
rcourtman 6b51a15dfe Frame Assistant operator decisions 2026-05-06 23:30:11 +01:00
rcourtman eb88119a29 Add evidence cues to Assistant briefings 2026-05-06 23:17:33 +01:00
rcourtman c50f051e13 Add evidence cues to Assistant briefings 2026-05-06 23:10:32 +01:00
rcourtman 2fd85f62d3 Add related finding recency to Assistant handoffs 2026-05-06 22:50:18 +01:00
rcourtman 1f424523da Surface Assistant finding lifecycle context 2026-05-06 21:21:35 +01:00
rcourtman 6269bc2afa Enrich Assistant related finding handoffs 2026-05-06 21:14:09 +01:00
rcourtman 67974f2ada Add Assistant operator briefing handoff 2026-05-06 20:48:25 +01:00
rcourtman 2e85079263 Hydrate Assistant finding lifecycle context 2026-05-06 19:54:04 +01:00
rcourtman 2832bd321e Invalidate stale Assistant handoff context 2026-05-06 19:36:05 +01:00
rcourtman 50fee63c9e Refresh Assistant handoff finding context 2026-05-06 19:16:57 +01:00
rcourtman 5c8070c582 Persist Assistant handoff action references 2026-05-06 18:26:21 +01:00
rcourtman aeede4fb2f Hydrate Assistant handoff resource scope 2026-05-06 17:59:55 +01:00