Documentation
¶
Index ¶
- Constants
- Variables
- func ParseClientFrame(data []byte) (any, error)
- func ScopesFromRecord(rec *SessionRecord) []string
- func ValidateKeyInput(name string, scopes []string) error
- type APIKeyRecord
- type ActivityFrame
- type ApprovalResponseFrame
- type CancelFrame
- type ChatRequestFrame
- type Deps
- type KeyStore
- func (ks *KeyStore) Create(ctx context.Context, name string, scopes []string) (APIKeyRecord, string, error)
- func (ks *KeyStore) Delete(ctx context.Context, id string) error
- func (ks *KeyStore) FindActiveByHash(ctx context.Context, tokenHash string) (*storedKey, error)
- func (ks *KeyStore) HasActiveKey(ctx context.Context) (bool, error)
- func (ks *KeyStore) List(ctx context.Context) ([]APIKeyRecord, error)
- func (ks *KeyStore) Revoke(ctx context.Context, id string) error
- func (ks *KeyStore) Rotate(ctx context.Context, id string) (APIKeyRecord, string, error)
- func (ks *KeyStore) TouchLastUsed(ctx context.Context, id string)
- type OAuthDeps
- type OIDCProvider
- type PingFrame
- type PongFrame
- type ReplayBuffer
- type ReplayStore
- type SSEStreamSession
- type Server
- type Session
- type SessionManager
- type SessionRecord
- type SessionStore
- func (ss *SessionStore) Close() error
- func (ss *SessionStore) Count(ctx context.Context) (int, error)
- func (ss *SessionStore) Create(ctx context.Context, email string, scopes []string, userAgent, ip string, ...) (string, error)
- func (ss *SessionStore) Delete(ctx context.Context, id string) error
- func (ss *SessionStore) DeleteAllByEmail(ctx context.Context, email string) (int64, error)
- func (ss *SessionStore) Get(ctx context.Context, id string) (*SessionRecord, error)
- func (ss *SessionStore) ListByEmail(ctx context.Context, email string) ([]SessionRecord, error)
- func (ss *SessionStore) PurgeExpired(ctx context.Context) (int64, error)
- func (ss *SessionStore) Touch(ctx context.Context, id string) error
- type StreamSession
- type WSClientFrame
- type WSConn
- type WSErrorFrame
- type WSEventFrame
- type WSHub
Constants ¶
const ( FrameTypeChatRequest = "chat_request" FrameTypeApprovalResponse = "approval_response" FrameTypeCancel = "cancel" FrameTypePong = "pong" FrameTypePing = "ping" FrameTypeError = "error" FrameTypeActivity = "activity" )
Variables ¶
var ValidScopes = scope.Valid
ValidScopes is the set of scope values accepted by the key management system. It delegates to the canonical list in the scope package.
Functions ¶
func ParseClientFrame ¶ added in v0.16.0
ParseClientFrame reads a raw JSON message from a WebSocket client and returns the appropriate typed frame. Returns an error for unknown or malformed frames.
func ScopesFromRecord ¶ added in v0.16.5
func ScopesFromRecord(rec *SessionRecord) []string
ScopesFromRecord parses the JSON scopes string into a string slice.
func ValidateKeyInput ¶ added in v0.1.0
ValidateKeyInput checks that name is within the length limit and every scope is in the ValidScopes allowlist. Returns a user-facing error on failure.
Types ¶
type APIKeyRecord ¶
type APIKeyRecord struct {
ID string `json:"id"`
Name string `json:"name"`
Scopes []string `json:"scopes"`
CreatedAt time.Time `json:"created_at"`
LastUsedAt *time.Time `json:"last_used_at,omitempty"`
Revoked bool `json:"revoked"`
}
APIKeyRecord is the public representation returned by the API (no hash exposed).
type ActivityFrame ¶ added in v0.16.9
type ActivityFrame struct {
Type string `json:"type"` // "activity"
ConversationID string `json:"conversation_id"` // e.g. "default:telegram:12345"
Agent string `json:"agent"` // agent name
Adapter string `json:"adapter"` // source adapter name
Summary string `json:"summary"` // brief description
}
ActivityFrame notifies WebSocket clients of new activity on a conversation from another adapter (e.g. a Telegram message was processed). It is broadcast to all connected clients so the web UI can refresh its session list or reload the active conversation.
type ApprovalResponseFrame ¶ added in v0.16.0
type ApprovalResponseFrame struct {
Type string `json:"type"` // "approval_response"
ApprovalID string `json:"approval_id"` // approval request ID
Action string `json:"action"` // "approve", "deny", "auto_session", "auto_always"
}
ApprovalResponseFrame is sent by the client to resolve a pending tool approval.
type CancelFrame ¶ added in v0.16.0
type CancelFrame struct {
Type string `json:"type"` // "cancel"
SessionID string `json:"session_id"` // session to cancel
}
CancelFrame is sent by the client to abort an in-progress agent turn.
type ChatRequestFrame ¶ added in v0.16.0
type ChatRequestFrame struct {
Type string `json:"type"` // "chat_request"
SessionID string `json:"session_id,omitempty"` // omit to create new session
Agent string `json:"agent,omitempty"` // agent name; defaults to "default"
Message string `json:"message"` // user message text
UserID string `json:"user_id,omitempty"` // optional user identifier
UserName string `json:"user_name,omitempty"` // optional display name
Seq int64 `json:"seq,omitempty"` // monotonically increasing per session
ResumeAfterSeq int64 `json:"resume_after_seq,omitempty"` // replay events after this seq on reconnect
}
ChatRequestFrame is sent by the client to start or continue a chat session.
type Deps ¶
type Deps struct {
Dispatcher *agent.Dispatcher
Scheduler *scheduler.Scheduler
CostTracker *llm.CostTracker
Memory agent.MemoryStore
Config *config.Config
Approvals *approval.Manager // nil = approval endpoints return 503
LifecycleMgr *tool.LifecycleManager // nil = tool CRUD endpoints return 503
BrowserProfiles *browser.ProfileService // nil = browser endpoints return 503
WebHandler http.Handler // nil = no web dashboard served
MetricsHandler http.Handler // nil = no /metrics endpoint
KeyStore *KeyStore // nil = API key CRUD endpoints return 503
KVStore kv.Store // nil = KV endpoints return 503
ConfigPath string // TOML config path for schedule persistence
Sessions *SessionManager // nil = no session-based auth
OIDCProvider *OIDCProvider // nil = no OIDC endpoints
PasswordHash string // bcrypt hash for password login
SetupPIN string // one-time PIN for account setup (empty = disabled)
ModelLister func(ctx context.Context) []string // returns available LLM models; nil = endpoint returns 503
ModelDetailLister func(ctx context.Context) []llm.ModelInfo // returns enriched model metadata; nil = endpoint returns 503
OAuthDeps *OAuthDeps // nil = OAuth tool endpoints return 503
ReloadFunc func() error // nil = reload endpoint returns 503
RestartFunc func() error // nil = restart endpoint returns 503
}
Deps holds the application dependencies the API server needs to serve data.
type KeyStore ¶
type KeyStore struct {
// contains filtered or unexported fields
}
KeyStore manages API keys persisted in SQLite.
func NewInMemoryKeyStore ¶
NewInMemoryKeyStore creates a KeyStore backed by an in-memory SQLite database. Intended for tests.
func NewKeyStore ¶
NewKeyStore opens (or creates) a SQLite DB at dbPath and applies the key schema. WAL mode is used so it can coexist with other connections to the same file.
func (*KeyStore) Create ¶
func (ks *KeyStore) Create(ctx context.Context, name string, scopes []string) (APIKeyRecord, string, error)
Create inserts a new API key. Returns the record and plaintext key (shown once).
func (*KeyStore) Delete ¶ added in v0.1.0
Delete permanently removes a revoked key from the store. Returns an error if the key does not exist or is still active (not revoked).
func (*KeyStore) FindActiveByHash ¶
FindActiveByHash returns the matching active key row for a given token hash, or nil if not found.
func (*KeyStore) HasActiveKey ¶ added in v0.1.0
HasActiveKey reports whether at least one non-revoked key exists in the store.
func (*KeyStore) List ¶
func (ks *KeyStore) List(ctx context.Context) ([]APIKeyRecord, error)
List returns all key records ordered by creation date descending.
func (*KeyStore) Revoke ¶
Revoke marks a key as revoked. Returns an error if the key does not exist or is already revoked.
type OAuthDeps ¶ added in v0.16.0
type OAuthDeps struct {
TokenStore *oauth.TokenStore
PendingMgr *oauth.PendingManager
}
OAuthDeps holds OAuth-specific dependencies for the API server.
type OIDCProvider ¶ added in v0.12.0
type OIDCProvider struct {
// contains filtered or unexported fields
}
OIDCProvider wraps the OIDC discovery provider and OAuth2 config.
func NewOIDCProvider ¶ added in v0.12.0
func NewOIDCProvider(ctx context.Context, issuer, clientID, clientSecret, redirectURL string, scopes, allowedEmails []string, sessions *SessionManager, logger *slog.Logger) (*OIDCProvider, error)
NewOIDCProvider creates an OIDCProvider by performing OIDC discovery.
func (*OIDCProvider) HandleCallback ¶ added in v0.12.0
func (op *OIDCProvider) HandleCallback(w http.ResponseWriter, r *http.Request)
HandleCallback completes the OIDC authorization code flow.
func (*OIDCProvider) HandleLogin ¶ added in v0.12.0
func (op *OIDCProvider) HandleLogin(w http.ResponseWriter, r *http.Request)
HandleLogin starts the OIDC authorization code flow with PKCE and nonce.
type PingFrame ¶ added in v0.16.0
type PingFrame struct {
Type string `json:"type"` // "ping"
}
PingFrame is the server's keepalive probe.
type PongFrame ¶ added in v0.16.0
type PongFrame struct {
Type string `json:"type"` // "pong"
}
PongFrame is the client's keepalive response to a server ping.
type ReplayBuffer ¶ added in v0.16.0
type ReplayBuffer struct {
// contains filtered or unexported fields
}
ReplayBuffer is a fixed-size circular buffer of WSEventFrames with time-based eviction. It is safe for concurrent use.
func NewReplayBuffer ¶ added in v0.16.0
func NewReplayBuffer(capacity int, ttl time.Duration) *ReplayBuffer
NewReplayBuffer creates a buffer with the given capacity and TTL.
func (*ReplayBuffer) Append ¶ added in v0.16.0
func (b *ReplayBuffer) Append(frame WSEventFrame)
Append adds a frame to the buffer. Old entries beyond capacity are overwritten. Entries older than the TTL are logically evicted on read.
func (*ReplayBuffer) Len ¶ added in v0.16.0
func (b *ReplayBuffer) Len() int
Len returns the number of entries currently in the buffer (including expired ones that haven't been overwritten yet).
func (*ReplayBuffer) ReplaySince ¶ added in v0.16.0
func (b *ReplayBuffer) ReplaySince(afterSeq int64) []WSEventFrame
ReplaySince returns all buffered frames with Seq > afterSeq that are within the TTL window. Frames are returned in insertion order.
type ReplayStore ¶ added in v0.16.0
type ReplayStore struct {
// contains filtered or unexported fields
}
ReplayStore manages per-session replay buffers.
func NewReplayStore ¶ added in v0.16.0
func NewReplayStore(capacity int, ttl time.Duration) *ReplayStore
NewReplayStore creates a store that allocates replay buffers on demand.
func (*ReplayStore) Buffer ¶ added in v0.16.0
func (s *ReplayStore) Buffer(sessionID string) *ReplayBuffer
Buffer returns the replay buffer for the given session, creating one if it does not exist. If the store is at the session limit, the oldest inactive buffer is evicted to make room.
func (*ReplayStore) Cleanup ¶ added in v0.16.0
func (s *ReplayStore) Cleanup()
Cleanup removes all buffers that have no entries within the TTL window. Call periodically to prevent unbounded growth.
func (*ReplayStore) Len ¶ added in v0.16.0
func (s *ReplayStore) Len() int
Len returns the number of tracked sessions.
func (*ReplayStore) Remove ¶ added in v0.16.0
func (s *ReplayStore) Remove(sessionID string)
Remove deletes the replay buffer for a session.
type SSEStreamSession ¶ added in v0.16.0
type SSEStreamSession struct {
// contains filtered or unexported fields
}
SSEStreamSession writes Server-Sent Events to an http.ResponseWriter.
func NewSSEStreamSession ¶ added in v0.16.0
func NewSSEStreamSession(w http.ResponseWriter) *SSEStreamSession
NewSSEStreamSession creates an SSE session. The caller must set SSE headers and write the status code before calling this.
func (*SSEStreamSession) SendContent ¶ added in v0.16.0
func (s *SSEStreamSession) SendContent(text string)
func (*SSEStreamSession) SendDone ¶ added in v0.16.0
func (s *SSEStreamSession) SendDone(sessionID string)
func (*SSEStreamSession) SendError ¶ added in v0.16.0
func (s *SSEStreamSession) SendError(message string)
func (*SSEStreamSession) SendEvent ¶ added in v0.16.0
func (s *SSEStreamSession) SendEvent(evt agent.ChatEvent)
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the external REST API server.
func (*Server) HTTPHandler ¶ added in v0.11.0
HTTPHandler returns the server's HTTP handler for use in tests.
func (*Server) RequireScope ¶
func (s *Server) RequireScope(scope string, next http.HandlerFunc) http.HandlerFunc
RequireScope returns middleware that checks for a valid API key with the required scope. Use this to wrap individual route handlers.
type Session ¶ added in v0.12.0
type Session struct {
Email string `json:"email"`
Scopes []string `json:"scopes"`
ExpiresAt int64 `json:"exp"` // Unix timestamp
}
Session represents a dashboard login session stored in an encrypted cookie.
type SessionManager ¶ added in v0.12.0
type SessionManager struct {
Store *SessionStore
// contains filtered or unexported fields
}
SessionManager handles AES-256-GCM encrypted session cookies. When Store is non-nil, sessions are server-tracked in SQLite and the cookie contains only a session ID. When Store is nil, legacy mode is used where the full session data is encrypted in the cookie.
func NewSessionManager ¶ added in v0.12.0
NewSessionManager creates a SessionManager from a hex-encoded AES key (≥32 bytes).
func (*SessionManager) Clear ¶ added in v0.12.0
func (sm *SessionManager) Clear(w http.ResponseWriter)
Clear removes the session cookie.
func (*SessionManager) Create ¶ added in v0.12.0
func (sm *SessionManager) Create(w http.ResponseWriter, s Session) error
Create encrypts the session and sets it as an HttpOnly cookie (legacy, no request context).
func (*SessionManager) CreateWithRequest ¶ added in v0.16.5
func (sm *SessionManager) CreateWithRequest(w http.ResponseWriter, r *http.Request, s Session) error
CreateWithRequest encrypts the session and sets it as an HttpOnly cookie. When server-tracked sessions are enabled, the session is also stored in SQLite and the cookie contains only the session ID.
func (*SessionManager) Read ¶ added in v0.12.0
func (sm *SessionManager) Read(r *http.Request) (*Session, error)
Read decrypts and validates the session cookie from the request. When server-tracked sessions are enabled, it looks up the session in SQLite. Falls back to legacy full-session decryption for rolling upgrades.
type SessionRecord ¶ added in v0.16.5
type SessionRecord struct {
ID string `db:"id" json:"id"`
Email string `db:"email" json:"email"`
Scopes string `db:"scopes" json:"-"` // JSON array stored as text
UserAgent string `db:"user_agent" json:"user_agent"`
IP string `db:"ip" json:"ip"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
ExpiresAt time.Time `db:"expires_at" json:"expires_at"`
LastSeenAt time.Time `db:"last_seen_at" json:"last_seen_at"`
}
SessionRecord represents a server-tracked session stored in SQLite.
type SessionStore ¶ added in v0.16.5
type SessionStore struct {
// contains filtered or unexported fields
}
SessionStore manages server-tracked sessions in SQLite.
func NewInMemorySessionStore ¶ added in v0.16.5
func NewInMemorySessionStore() (*SessionStore, error)
NewInMemorySessionStore creates an in-memory session store (for testing).
func NewSessionStore ¶ added in v0.16.5
func NewSessionStore(dbPath string) (*SessionStore, error)
NewSessionStore opens or creates a SQLite database for session tracking.
func (*SessionStore) Close ¶ added in v0.16.5
func (ss *SessionStore) Close() error
Close closes the underlying database connection.
func (*SessionStore) Count ¶ added in v0.16.5
func (ss *SessionStore) Count(ctx context.Context) (int, error)
Count returns the number of active (non-expired) sessions.
func (*SessionStore) Create ¶ added in v0.16.5
func (ss *SessionStore) Create(ctx context.Context, email string, scopes []string, userAgent, ip string, expiresAt time.Time) (string, error)
Create inserts a new session record and returns its ID.
func (*SessionStore) Delete ¶ added in v0.16.5
func (ss *SessionStore) Delete(ctx context.Context, id string) error
Delete removes a session by ID. Returns nil if not found (idempotent).
func (*SessionStore) DeleteAllByEmail ¶ added in v0.16.5
DeleteAllByEmail removes all sessions for a given email. Returns count deleted.
func (*SessionStore) Get ¶ added in v0.16.5
func (ss *SessionStore) Get(ctx context.Context, id string) (*SessionRecord, error)
Get retrieves a session record by ID. Returns nil if not found or expired.
func (*SessionStore) ListByEmail ¶ added in v0.16.5
func (ss *SessionStore) ListByEmail(ctx context.Context, email string) ([]SessionRecord, error)
ListByEmail returns all active sessions for a given email.
func (*SessionStore) PurgeExpired ¶ added in v0.16.5
func (ss *SessionStore) PurgeExpired(ctx context.Context) (int64, error)
PurgeExpired removes all sessions past their expiry time. Returns count deleted.
type StreamSession ¶ added in v0.16.0
type StreamSession interface {
// SendEvent streams an intermediate pipeline event to the client.
SendEvent(evt agent.ChatEvent)
// SendContent streams the final response text.
SendContent(text string)
// SendDone signals that the agent turn is complete.
SendDone(sessionID string)
// SendError reports a fatal error for the stream.
SendError(message string)
}
StreamSession abstracts the transport used to deliver chat events. Both SSE and WebSocket implement this interface.
type WSClientFrame ¶ added in v0.16.0
type WSClientFrame struct {
Type string `json:"type"`
}
WSClientFrame is the envelope used to determine the type of a client frame.
type WSConn ¶ added in v0.16.0
type WSConn struct {
// contains filtered or unexported fields
}
WSConn wraps a gorilla/websocket connection with read/write pump goroutines.
type WSErrorFrame ¶ added in v0.16.0
type WSErrorFrame struct {
Type string `json:"type"` // "error"
SessionID string `json:"session_id,omitempty"` // session this error relates to
Code string `json:"code"` // "rate_limited", "permission_denied", "agent_not_found", "internal", "replay_unavailable"
Message string `json:"message"` // human-readable detail
}
WSErrorFrame reports an error for a specific session without closing the connection.
type WSEventFrame ¶ added in v0.16.0
type WSEventFrame struct {
agent.ChatEvent
SessionID string `json:"session_id,omitempty"` // session this event belongs to
Seq int64 `json:"seq,omitempty"` // monotonically increasing per session
}
WSEventFrame wraps a ChatEvent with session routing and sequence info.
type WSHub ¶ added in v0.16.0
type WSHub struct {
// contains filtered or unexported fields
}
WSHub tracks active WebSocket connections and provides graceful shutdown.
func (*WSHub) Broadcast ¶ added in v0.16.9
Broadcast sends a JSON frame to all connected WebSocket clients. Frames are sent on a best-effort basis; slow clients may miss frames because sendJSON drops non-critical frames when the send buffer is full.
func (*WSHub) ConnCount ¶ added in v0.16.0
ConnCount returns the current number of active connections.
func (*WSHub) Register ¶ added in v0.16.0
Register adds a connection. Returns false if the hub is at capacity.
func (*WSHub) Shutdown ¶ added in v0.16.0
func (h *WSHub) Shutdown()
Shutdown closes all active connections gracefully.
func (*WSHub) StartCleanup ¶ added in v0.16.3
StartCleanup launches a background goroutine that periodically removes stale replay buffers. It stops when ctx is cancelled.
func (*WSHub) Unregister ¶ added in v0.16.0
Unregister removes a connection from the hub.