feat(agent): stream analysis and add incident count windows - #349
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Makes on-demand incident analysis observable while it runs and makes incident
counts describe a deliberate time window instead of an ever-growing all-time
total.
then returns the persisted analysis ID on the terminal event.
happened..." while preserving stable tool identifiers for dispatch and audit.
all, defaulting to 7d.
count_window,so UI labels and numbers come from the same request.
wider shared previews, wrapping for long IDs/payloads, inert table rows with
explicit actions, and one-time recovery from stale lazy-loaded chunks.
Why?
Analysis previously had a long silent wait: operators clicked Run analysis
and saw no evidence that the model was working, which tools it used, or whether
closing the dialog would lose the run. Tool names were implementation identifiers
such as
query_metrics, not readable activity.Incident counts had the opposite problem: they counted the complete history, so
the number only grew and stopped describing current operational load. The UI also
had no contract tying a count to the window used to compute it.
The supporting UI fixes close problems found while exercising these flows:
long metric/pattern IDs forced cards and overlays wider than the viewport,
Decision rows behaved differently from other dense tables, and a deployment
could leave an open browser requesting an obsolete hashed route chunk.
How to test
Automated
Manual: streamed analysis
"I'm checking related logs...") rather than raw snake-case tool names.
horizontal scrollbar.
still finishes and is saved.
AnalysisCardreplaces thetranscript and View full analysis opens the persisted record.
its own error if it also fails.
Manual: incident count window
?tab=tuning).the same windowed count response.
counts over <window>in the left subtitle anddo not duplicate the window beside the right-side AI/Webhook badge.
discoverable; search responses intentionally report
count_window: "all".Manual: UI hardening
alert-fatigue lists, confirm a plain row click is inert and the eye button
opens the shared preview panel.
j/kstill moves the active row and Enter opens its preview.sample. Content must wrap without horizontal page/panel scrolling.
route. A stale dynamic-import chunk should trigger one reload and recover;
repeated failure must show the error boundary rather than reload-loop.
Type of change
counts now default to the last 7 days instead of all time; APIs are
additive and stored incidents are unchanged
Checklist
go test ./...passes locallygo vet ./...is cleangofmt'dsrc/if behavior changes — follow-upneeded for count-window settings and streamed analysis UX
ROADMAP.mdif this closes a roadmap item — N/A; on-demandanalysis and read-only investigation tools were already marked complete
Detailed changes
Streaming analyze
core.AnalyzeEvent, observer context plumbing, and lifecycle kinds forrun, model, and tool activity.
Streamed model output is drained from Eino's per-handler stream copy and
ordered before the terminal event.
POST /api/admin/incidents/:id/analyze/streamwith SSE framing,X-Accel-Buffering: no, detached run lifetime, persistence, and terminalsuccess/failure semantics.
the model. The terminal event gets bounded delivery so failure status and the
persisted analysis ID cannot be silently dropped under backpressure.
tool responses are wrapped safely when stored as JSON.
fetch+ReadableStream(POST and gateway-secretheaders are required), batches events per animation frame, and falls back to
the synchronous endpoint when streaming is unavailable.
Human tool activity
core.AnalyzeToolDisplayerand robust fallback humanization forcustom/legacy tools. Existing
AnalyzeToolimplementations remain sourcecompatible.
tool_displayto live events while keeping persistedToolCallTrace.Nameand model dispatch names stable.and still accepts older events that contain only
tool.Incident count windows
CountSettingswith recognized windows and a 7-daydefault.
storage.IncidentWindowCounterplus implementations forPostgres, file, and memory. Postgres uses one indexed
COUNT/FILTERquerybounded by
created_at; zero time means unbounded.CountSettingsControllerwith authenticated GET/PUT endpoints.count_window; explicit searchstays unbounded and returns
all.optional counter apply the cutoff locally rather than returning unbounded
values under a bounded label.
tuningURLvalue so old deep links continue working.
Shared security and UI consistency
adminGatewayGuard, preserving enterprise-auth short-circuiting and theconstant-time gateway-secret comparison.
inert, explicit links remain links, the eye opens a preview, and Enter opens
the same preview.
reload loops.
explanations, tool data, and evidence.
max-w-lg= 720px list previews,max-w-xl= 960px analysis modal,max-w-2xl= 1200px wide dialogs.Compatibility and intentional behavior
continues to compile and test against this change.
list paging, and historical rows remain unchanged.
find older incidents even when dashboards use a recent window.
tool_errorremains defensive wiring. Normal tool failuresare returned to ReAct as structured results so the model can adapt instead of
aborting the run.
Verification
gofmt,go vet ./...,go test ./...— PASS.go build ./...,go vet ./...,go test ./...— PASS.
git diff --check— PASS.database; memory and file parity run in the normal suite.
Known limitations
src/have not yet been updated for the new countsetting and live-analysis transcript.
to materializing its provider-bounded history before applying the count
cutoff. All shipping OSS storage providers implement the optimized path.
read, not an N+1 query; a short process-local TTL may be worthwhile if polling
volume grows.