Documentation
¶
Index ¶
- func NewArtifactGzipWriter(w io.Writer) *gzip.Writer
- func WriteArtifactHeaders(w http.ResponseWriter, kind, ext, contentType string, at time.Time, ...)
- type ConversationTracker
- type Server
- func (s *Server) AttachPausePersist(p pausePersist)
- func (s *Server) DebugSnapshot() map[string]any
- func (s *Server) HandleDebug(w http.ResponseWriter, r *http.Request)
- func (s *Server) HandleDebugCapture(w http.ResponseWriter, r *http.Request)
- func (s *Server) HandlePause(w http.ResponseWriter, r *http.Request)
- func (s *Server) HandleQuotaPause(w http.ResponseWriter, r *http.Request)
- func (s *Server) HandleThrottle(w http.ResponseWriter, r *http.Request)
- func (s *Server) PauseSnapshot() map[string]any
- func (s *Server) Reload(cfg *config.Config)
- func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (s *Server) StormSnapshot() map[string]any
- func (s *Server) ThrottleSnapshot() map[string]any
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NewArtifactGzipWriter ¶ added in v0.3.13
NewArtifactGzipWriter wraps any writer in the one gzip codec for saved artifacts. The caller owns Close on the normal path so the deflate trailer flushes; an abandoned stream is a correct truncated artifact.
func WriteArtifactHeaders ¶ added in v0.3.13
func WriteArtifactHeaders(w http.ResponseWriter, kind, ext, contentType string, at time.Time, fallback string)
WriteArtifactHeaders is THE owner of a downloaded artifact's response headers, shared by the backup, logs export and capture download surfaces: it composes the millivolt-<kind>-<stamp>.<ext> attachment name - the stamp is the artifact's moment in artifactStampLayout, always rendered UTC, one naming policy for every surface - and stages Content-Disposition, the surface's content type and Cache-Control: no-store, so no shared cache retains a downloaded artifact. fallback replaces the stamp segment when the artifact's moment is unknown (the capture route's damaged-payload row names the record id); a surface whose moment is always known passes the empty string beside a non-zero moment. Precondition: at must be non-zero or fallback non-empty - a zero moment with an empty fallback would publish a name with an empty stamp segment - and fallback must be quote-safe (no double quote or backslash): the name is spliced inside a quoted Content-Disposition, and a quote-bearing fallback would break the header. Unreachable today: every surface passes a real moment (the backup and export pass time.Now(), the capture passes the document's decoded moment or the record-id fallback, and the only realizable fallback is the minted request id, which is quote-safe).
Types ¶
type ConversationTracker ¶
type ConversationTracker struct {
// contains filtered or unexported fields
}
ConversationTracker assigns a stable conversation id to each request. It is safe for concurrent use and bounds memory by expiring idle sessions lazily.
func NewConversationTracker ¶
func NewConversationTracker(idleGap time.Duration, maxOpen int) *ConversationTracker
NewConversationTracker creates a tracker. idleGap is the inactivity window after which a request is treated as a new conversation; maxOpen caps concurrently-open conversations per partition (oldest evicted past it).
func (*ConversationTracker) Assign ¶
func (t *ConversationTracker) Assign(client, keyHash, explicitID, trackedID string, totalTurns int, now time.Time) string
Assign returns the conversation id for a request. explicitID (from X-Proxy-Session) wins when present, then trackedID (a sub_conversations body-param value); each is namespaced by its own owner so neither identity can collide with the other or with an auto id. Otherwise the request is auto-grouped by turn count. totalTurns is turns_user+turns_assistant+turns_tool.
func (*ConversationTracker) UpdateLimits ¶
func (t *ConversationTracker) UpdateLimits(idleGap time.Duration, maxOpen int)
UpdateLimits hot-applies new idleGap/maxOpen on a live tracker (config reload). Existing sessions are unaffected; the new limits govern subsequent matching, eviction, and sweeps.
type Server ¶
type Server struct {
// ModelObserver is wired before serving. Debug state uses the same Go
// canonical-name metadata provider as all other dashboard observers.
ModelObserver func([]string) any
// contains filtered or unexported fields
}
Server is the transparent reverse proxy. A single Server shares one http.Transport so upstream connections are pooled across all requests.
func New ¶
New builds a Server. rec may be nil (uses a Noop recorder). All tunables come from cfg (see internal/config); nothing is hardcoded here.
func (*Server) AttachPausePersist ¶
func (s *Server) AttachPausePersist(p pausePersist)
AttachPausePersist restores the hold from durable storage and seeds the known-client / known-provider lists. Call once after New when a store is open.
func (*Server) DebugSnapshot ¶
DebugSnapshot builds the GET /admin/debug state document - the single owner of that shape, shared by the HTTP handler and the dashboard bootstrap payload (so the two can never disagree).
func (*Server) HandleDebug ¶
func (s *Server) HandleDebug(w http.ResponseWriter, r *http.Request)
HandleDebug is GET/POST /admin/debug. GET returns current sessions; POST applies {"enabled": bool} (required - deny by default). enabled:true adds one session (clients/providers/models AND, duration). enabled:true with id updates that session in place. A replace that omits scope / duration keeps the previous values. enabled:false clears everything, or just {"id"} when set. Overlapping filters return 409.
func (*Server) HandleDebugCapture ¶
func (s *Server) HandleDebugCapture(w http.ResponseWriter, r *http.Request)
HandleDebugCapture is GET /admin/debug/capture?id= - the drawer fetch for one sidecar document. 404 when missing/expired. Never on the live SSE path. The plain response is the drawer's render JSON; download=1 serves the same document as a saved gzip artifact. The query is parsed from the raw string through the shared strict owner (adminjson.StrictQuery) so no malformed pair is silently dropped: an unparsable query, a repeated flag or id, or a flag outside the standing 0/1 grammar is a 400, never first-wins; an empty download value means the render mode. The kinship with the export owner stops at unknown keys, a deliberate split in the three-class route taxonomy: a filter grammar (the export) rejects unknown keys, an idempotent fetch like this one ignores them - only the consumed id and download are validated - and a mutating closed-set route (the backup and restore plane) rejects every key outside its consumed set. The method, id, no-store and 404 semantics are identical in both modes.
func (*Server) HandlePause ¶
func (s *Server) HandlePause(w http.ResponseWriter, r *http.Request)
HandlePause is GET/POST /admin/pause. GET returns current state; POST applies {"paused": bool} (required - deny by default). paused:true adds one hold (all/new/clients/providers/duration/max_queued). paused:true with id updates that hold in place (queued waiters stay parked). A replace that omits scope / duration keeps the previous values - {"paused":true,"id"} is not a global hold. Compat {"paused":true} with no id and no scope still is. paused:false clears everything, or just {"id"} when set. In-flight requests are never cancelled.
func (*Server) HandleQuotaPause ¶ added in v0.3.13
func (s *Server) HandleQuotaPause(w http.ResponseWriter, r *http.Request)
HandleQuotaPause serves GET /admin/quota (the shared storm snapshot, which includes open quota gates) and POST {"provider": string, "resume": true}, the operator action that closes a provider's open retry-mode quota gate without waiting for the next recovery probe; parked sends resume immediately. Resuming a provider without an open gate is a no-op state report (the pause may have recovered between banner and click). Manual-mode quota holds are ordinary operator holds and resume through the pause surface, not here.
func (*Server) HandleThrottle ¶
func (s *Server) HandleThrottle(w http.ResponseWriter, r *http.Request)
HandleThrottle is GET/POST /admin/throttle. GET returns every active cap plus known providers (history ∪ current caps) so the dashboard can set a limit on a seen provider. POST requires {"provider"} (deny by default). clear:true drops the cap. Otherwise any supplied dimension merges; omitted dimensions keep their current value; 0 / empty window turns that dimension off.
func (*Server) PauseSnapshot ¶
PauseSnapshot builds the GET /admin/pause state document - the single owner of that shape, shared by the HTTP handler and the dashboard bootstrap payload (so the two can never disagree).
func (*Server) Reload ¶
Reload hot-applies a freshly-loaded config with ZERO dropped requests: the listener and HTTP server are never touched, so no connection can be dropped. It swaps the config snapshot (per-request reads pick it up atomically), rebuilds the upstream transport (new pool sizes + header timeout apply to new connections; in-flight streams keep the transport they started on), and re-applies the scheduler/conversation tunables. Fields that are bound at process startup and cannot move (listen address, db path, storage pipeline, HTTP server timeouts, history size) are NOT re-applied - they require a restart and are the caller's responsibility to flag.
func (*Server) ServeHTTP ¶
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler.
func (*Server) StormSnapshot ¶ added in v0.3.0
StormSnapshot shares scheduler-authoritative status with embedded bootstrap and ordinary dashboard refreshes. It does no history or storage work.
func (*Server) ThrottleSnapshot ¶
ThrottleSnapshot builds the GET /admin/throttle state document - the single owner of that shape, shared by the HTTP handler and the dashboard bootstrap payload (so the two can never disagree).