api

package
v0.16.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 6, 2026 License: Apache-2.0 Imports: 40 Imported by: 0

Documentation

Index

Constants

View Source
const (
	FrameTypeChatRequest      = "chat_request"
	FrameTypeApprovalResponse = "approval_response"
	FrameTypeCancel           = "cancel"
	FrameTypePong             = "pong"
	FrameTypePing             = "ping"
	FrameTypeError            = "error"
)

Variables

View Source
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

func ParseClientFrame(data []byte) (any, error)

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 ValidateKeyInput added in v0.1.0

func ValidateKeyInput(name string, scopes []string) error

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 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
	OAuthDeps       *OAuthDeps                         // nil = OAuth tool endpoints return 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

func NewInMemoryKeyStore() (*KeyStore, error)

NewInMemoryKeyStore creates a KeyStore backed by an in-memory SQLite database. Intended for tests.

func NewKeyStore

func NewKeyStore(dbPath string) (*KeyStore, error)

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

func (ks *KeyStore) Delete(ctx context.Context, id string) error

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

func (ks *KeyStore) FindActiveByHash(ctx context.Context, tokenHash string) (*storedKey, error)

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

func (ks *KeyStore) HasActiveKey(ctx context.Context) (bool, error)

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

func (ks *KeyStore) Revoke(ctx context.Context, id string) error

Revoke marks a key as revoked. Returns an error if the key does not exist or is already revoked.

func (*KeyStore) Rotate

func (ks *KeyStore) Rotate(ctx context.Context, id string) (APIKeyRecord, string, error)

Rotate revokes the existing key and creates a replacement with the same name and scopes. Returns the new record and plaintext key.

func (*KeyStore) TouchLastUsed

func (ks *KeyStore) TouchLastUsed(ctx context.Context, id string)

TouchLastUsed updates last_used_at for the given key ID (best-effort, non-fatal).

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.

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 New

func New(cfg config.APIConfig, deps Deps, logger *slog.Logger) *Server

New creates a new API server. The server is not started until Run is called.

func (*Server) HTTPHandler added in v0.11.0

func (s *Server) HTTPHandler() http.Handler

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.

func (*Server) Run

func (s *Server) Run(ctx context.Context) error

Run starts the server and blocks until ctx is cancelled. It performs a graceful shutdown with a 5-second deadline.

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 {
	// contains filtered or unexported fields
}

SessionManager handles AES-256-GCM encrypted session cookies.

func NewSessionManager added in v0.12.0

func NewSessionManager(hexKey string, maxAge time.Duration, secure bool) (*SessionManager, error)

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.

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.

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.

func (*WSConn) Close added in v0.16.0

func (c *WSConn) Close(code int, text string)

Close sends a close frame and shuts down the connection.

func (*WSConn) Start added in v0.16.0

func (c *WSConn) Start()

Start spawns the read and 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 NewWSHub added in v0.16.0

func NewWSHub(maxConns int, replayTTL time.Duration, logger *slog.Logger) *WSHub

NewWSHub creates a hub. maxConns=0 means unlimited.

func (*WSHub) ConnCount added in v0.16.0

func (h *WSHub) ConnCount() int

ConnCount returns the current number of active connections.

func (*WSHub) Register added in v0.16.0

func (h *WSHub) Register(c *WSConn) bool

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

func (h *WSHub) StartCleanup(ctx context.Context)

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

func (h *WSHub) Unregister(c *WSConn)

Unregister removes a connection from the hub.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL