Files
jbergner a6bc71fb3a
Some checks failed
release-tag / Resolve release metadata (push) Successful in 30s
release-tag / Build knowledge (push) Failing after 4m51s
release-tag / Build control (push) Failing after 5m0s
release-tag / Build agent (push) Failing after 5m0s
release-tag / Build agent-data-init (push) Failing after 5m5s
release-tag / Build neuroforge-worker (push) Failing after 5m7s
release-tag / Build neuroforge (push) Failing after 5m9s
Init
2026-08-26 18:34:41 +02:00

50 lines
1.4 KiB
Go

package httpapi
import (
"net/http"
"strconv"
)
func (s *Server) goalResearchLive(w http.ResponseWriter, r *http.Request) {
goalID := r.PathValue("id")
run, ok := s.store.LatestResearchRun(goalID)
if !ok {
s.json(w, http.StatusOK, map[string]any{"run": nil, "events": []any{}, "reset": false})
return
}
after, _ := strconv.ParseUint(r.URL.Query().Get("after"), 10, 64)
clientRunID := r.URL.Query().Get("run_id")
reset := clientRunID != "" && clientRunID != run.ID
if reset {
after = 0
}
events := run.Events
if after > 0 {
filtered := events[:0:0]
for _, ev := range events {
if ev.Seq > after {
filtered = append(filtered, ev)
}
}
events = filtered
}
// Return metadata separately from the event delta so a 1s UI poll stays
// bounded even when the persisted run keeps a larger audit tail.
run.Events = nil
s.json(w, http.StatusOK, map[string]any{"run": run, "events": events, "reset": reset})
}
func (s *Server) goalResearchHistory(w http.ResponseWriter, r *http.Request) {
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
if limit <= 0 || limit > 50 {
limit = 10
}
runs := s.store.ResearchRunsSnapshot(r.PathValue("id"), limit)
for i := range runs {
// History cards need summary/stats, not hundreds of event rows. The live
// endpoint exposes the latest run's detailed trace on demand.
runs[i].Events = nil
}
s.json(w, http.StatusOK, runs)
}