handlers

package
v7.0.0 Latest Latest
Warning

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

Go to latest
Published: Jun 16, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package handlers provides core API handler functionality for the CLI Proxy API server. It includes common types, client management, load balancing, and error handling shared across all API endpoint handlers (OpenAI, Claude, Gemini).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildErrorResponseBody

func BuildErrorResponseBody(status int, errText string) []byte

BuildErrorResponseBody builds an OpenAI-compatible JSON error response body. If errText is already valid JSON, it is returned as-is to preserve upstream error payloads.

func BuildOpenAIResponsesStreamErrorChunk

func BuildOpenAIResponsesStreamErrorChunk(status int, errText string, sequenceNumber int) []byte

BuildOpenAIResponsesStreamErrorChunk builds an OpenAI Responses streaming error chunk.

Important: OpenAI's HTTP error bodies are shaped like {"error":{...}}; those are valid for non-streaming responses, but streaming clients validate SSE `data:` payloads against a union of chunks that requires a top-level `type` field.

func FilterUpstreamHeaders

func FilterUpstreamHeaders(src http.Header) http.Header

FilterUpstreamHeaders returns a copy of src with hop-by-hop and security-sensitive headers removed. Returns nil if src is nil or empty after filtering.

func NonStreamingKeepAliveInterval

func NonStreamingKeepAliveInterval(cfg *config.SDKConfig) time.Duration

NonStreamingKeepAliveInterval returns the keep-alive interval for non-streaming responses. Returning 0 disables keep-alives (default when unset).

func PassthroughHeadersEnabled

func PassthroughHeadersEnabled(cfg *config.SDKConfig) bool

PassthroughHeadersEnabled returns whether upstream response headers should be forwarded to clients. Default is false.

func ReadRequestBody

func ReadRequestBody(c *gin.Context) ([]byte, error)

ReadRequestBody reads the incoming request body and decodes supported Content-Encoding values before handlers inspect JSON fields.

func StreamingBootstrapRetries

func StreamingBootstrapRetries(cfg *config.SDKConfig) int

StreamingBootstrapRetries returns how many times a streaming request may be retried before any bytes are sent.

func StreamingKeepAliveInterval

func StreamingKeepAliveInterval(cfg *config.SDKConfig) time.Duration

StreamingKeepAliveInterval returns the SSE keep-alive interval for this server. Returning 0 disables keep-alives (default when unset).

func WithDisallowFreeAuth

func WithDisallowFreeAuth(ctx context.Context) context.Context

WithDisallowFreeAuth returns a child context that requests skipping known free-tier credentials.

func WithExecutionSessionID

func WithExecutionSessionID(ctx context.Context, sessionID string) context.Context

WithExecutionSessionID returns a child context tagged with a long-lived execution session ID.

func WithModelExecutionForward

func WithModelExecutionForward(ctx context.Context, headers http.Header, query url.Values) context.Context

WithModelExecutionForward returns a copy of ctx that carries explicit forward headers and query parameters for the duration of a plugin-issued model execution. Passing nil values is supported and clears the override.

func WithPinnedAuthID

func WithPinnedAuthID(ctx context.Context, authID string) context.Context

WithPinnedAuthID returns a child context that requests execution on a specific auth ID.

func WithSelectedAuthIDCallback

func WithSelectedAuthIDCallback(ctx context.Context, callback func(string)) context.Context

WithSelectedAuthIDCallback returns a child context that receives the selected auth ID.

func WriteUpstreamHeaders

func WriteUpstreamHeaders(dst http.Header, src http.Header)

WriteUpstreamHeaders writes filtered upstream headers to the gin response writer. Headers already set by CPA (e.g., Content-Type) are NOT overwritten.

Types

type APIHandlerCancelFunc

type APIHandlerCancelFunc func(params ...interface{})

APIHandlerCancelFunc is a function type for canceling an API handler's context. It can optionally accept parameters, which are used for logging the response.

type BaseAPIHandler

type BaseAPIHandler struct {
	// AuthManager manages auth lifecycle and execution in the new architecture.
	AuthManager *coreauth.Manager

	// Cfg holds the current application configuration.
	Cfg *config.SDKConfig

	// PluginHost is the optional plugin host attached to this handler.
	PluginHost PluginInterceptorHost
}

BaseAPIHandler contains the handlers for API endpoints. It holds a pool of clients to interact with the backend service and manages load balancing, client selection, and configuration.

func NewBaseAPIHandlers

func NewBaseAPIHandlers(cfg *config.SDKConfig, authManager *coreauth.Manager) *BaseAPIHandler

NewBaseAPIHandlers creates a new API handlers instance. It takes a slice of clients and configuration as input.

Parameters:

  • cliClients: A slice of AI service clients
  • cfg: The application configuration

Returns:

  • *BaseAPIHandler: A new API handlers instance

func (*BaseAPIHandler) ExecuteCountWithAuthManager

func (h *BaseAPIHandler) ExecuteCountWithAuthManager(ctx context.Context, handlerType, modelName string, rawJSON []byte, alt string) ([]byte, http.Header, *interfaces.ErrorMessage)

ExecuteCountWithAuthManager executes a non-streaming request via the core auth manager. This path is the only supported execution route.

func (*BaseAPIHandler) ExecuteImageStreamWithAuthManager

func (h *BaseAPIHandler) ExecuteImageStreamWithAuthManager(ctx context.Context, handlerType, modelName string, rawJSON []byte, alt string) (<-chan []byte, http.Header, <-chan *interfaces.ErrorMessage)

ExecuteImageStreamWithAuthManager executes a streaming OpenAI-compatible image endpoint request.

func (*BaseAPIHandler) ExecuteImageWithAuthManager

func (h *BaseAPIHandler) ExecuteImageWithAuthManager(ctx context.Context, handlerType, modelName string, rawJSON []byte, alt string) ([]byte, http.Header, *interfaces.ErrorMessage)

ExecuteImageWithAuthManager executes an OpenAI-compatible image endpoint request.

func (*BaseAPIHandler) ExecuteModel

ExecuteModel performs a non-streaming internal model execution. It is the entry point used by the plugin host model-execution callback. Plugin-supplied headers/query take precedence over values derived from the caller's context. The method is safe to call concurrently with regular API traffic.

func (*BaseAPIHandler) ExecuteModelStream

ExecuteModelStream performs a streaming internal model execution. The returned stream channel must be drained by the caller; the channel is closed after the terminal chunk (payload or error) has been emitted.

func (*BaseAPIHandler) ExecuteStreamWithAuthManager

func (h *BaseAPIHandler) ExecuteStreamWithAuthManager(ctx context.Context, handlerType, modelName string, rawJSON []byte, alt string) (<-chan []byte, http.Header, <-chan *interfaces.ErrorMessage)

ExecuteStreamWithAuthManager executes a streaming request via the core auth manager. This path is the only supported execution route. The returned http.Header carries upstream response headers captured before streaming begins.

func (*BaseAPIHandler) ExecuteWithAuthManager

func (h *BaseAPIHandler) ExecuteWithAuthManager(ctx context.Context, handlerType, modelName string, rawJSON []byte, alt string) ([]byte, http.Header, *interfaces.ErrorMessage)

ExecuteWithAuthManager executes a non-streaming request via the core auth manager. This path is the only supported execution route.

func (*BaseAPIHandler) ForwardStream

func (h *BaseAPIHandler) ForwardStream(c *gin.Context, flusher http.Flusher, cancel func(error), data <-chan []byte, errs <-chan *interfaces.ErrorMessage, opts StreamForwardOptions)

func (*BaseAPIHandler) GetAlt

func (h *BaseAPIHandler) GetAlt(c *gin.Context) string

GetAlt extracts the 'alt' parameter from the request query string. It checks both 'alt' and '$alt' parameters and returns the appropriate value.

Parameters:

  • c: The Gin context containing the HTTP request

Returns:

  • string: The alt parameter value, or empty string if it's "sse"

func (*BaseAPIHandler) GetContextWithCancel

func (h *BaseAPIHandler) GetContextWithCancel(handler interfaces.APIHandler, c *gin.Context, ctx context.Context) (context.Context, APIHandlerCancelFunc)

GetContextWithCancel creates a new context with cancellation capabilities. It embeds the Gin context and the API handler into the new context for later use. The returned cancel function also handles logging the API response if request logging is enabled.

Parameters:

  • handler: The API handler associated with the request.
  • c: The Gin context of the current request.
  • ctx: The parent context (caller values/deadlines are preserved; request context adds cancellation and request ID).

Returns:

  • context.Context: The new context with cancellation and embedded values.
  • APIHandlerCancelFunc: A function to cancel the context and log the response.

func (*BaseAPIHandler) LoggingAPIResponseError

func (h *BaseAPIHandler) LoggingAPIResponseError(ctx context.Context, err *interfaces.ErrorMessage)

func (*BaseAPIHandler) SetPluginHost

func (h *BaseAPIHandler) SetPluginHost(host PluginInterceptorHost)

SetPluginHost configures the optional plugin host attached to handler execution.

func (*BaseAPIHandler) StartNonStreamingKeepAlive

func (h *BaseAPIHandler) StartNonStreamingKeepAlive(c *gin.Context, ctx context.Context) func()

StartNonStreamingKeepAlive emits blank lines every 5 seconds while waiting for a non-streaming response. It returns a stop function that must be called before writing the final response.

func (*BaseAPIHandler) UpdateClients

func (h *BaseAPIHandler) UpdateClients(cfg *config.SDKConfig)

UpdateClients updates the handlers' client list and configuration. This method is called when the configuration or authentication tokens change.

Parameters:

  • clients: The new slice of AI service clients
  • cfg: The new application configuration

func (*BaseAPIHandler) WriteErrorResponse

func (h *BaseAPIHandler) WriteErrorResponse(c *gin.Context, msg *interfaces.ErrorMessage)

WriteErrorResponse writes an error message to the response writer using the HTTP status embedded in the message.

type ErrorDetail

type ErrorDetail struct {
	// Message is a human-readable message providing more details about the error.
	Message string `json:"message"`

	// Type is the category of error that occurred (e.g., "invalid_request_error").
	Type string `json:"type"`

	// Code is a short code identifying the error, if applicable.
	Code string `json:"code,omitempty"`
}

ErrorDetail provides specific information about an error that occurred. It includes a human-readable message, an error type, and an optional error code.

type ErrorResponse

type ErrorResponse struct {
	// Error contains detailed information about the error that occurred.
	Error ErrorDetail `json:"error"`
}

ErrorResponse represents a standard error response format for the API. It contains a single ErrorDetail field.

type ModelExecutionChunk

type ModelExecutionChunk struct {
	Payload []byte
	Err     *ModelExecutionStreamError
}

ModelExecutionChunk carries either a streaming payload or a terminal stream error. When Err is non-nil the chunk is the final one for the stream.

type ModelExecutionRequest

type ModelExecutionRequest struct {
	EntryProtocol           string
	ExitProtocol            string
	Model                   string
	Stream                  bool
	Body                    []byte
	Headers                 http.Header
	Query                   url.Values
	Alt                     string
	SkipInterceptorPluginID string
}

ModelExecutionRequest describes an internal model execution request issued by plugin-host callbacks. EntryProtocol and ExitProtocol carry SDK translator names such as "openai" or "gemini". When both protocols match (the common case) the call behaves like a same-protocol request. When they differ, the entry protocol is used as the source format because the local executor path is single-protocol for now; protocol translation across the public API is handled by the regular HTTP entrypoints.

Headers and Query allow plugin callers to supply explicit forward values which take precedence over anything derived from the caller's context.

SkipInterceptorPluginID is retained for forwards-compatibility with plugins built against the upstream ABI; it is currently a no-op on this fork because per-request plugin interceptors are not yet wired into the executor pipeline.

type ModelExecutionResponse

type ModelExecutionResponse struct {
	StatusCode int
	Headers    http.Header
	Body       []byte
}

ModelExecutionResponse describes a non-streaming internal model execution response returned to plugin callers.

type ModelExecutionStream

type ModelExecutionStream struct {
	StatusCode int
	Headers    http.Header
	Chunks     <-chan ModelExecutionChunk
}

ModelExecutionStream describes a streaming internal model execution response. Chunks must be drained by the caller; the channel is closed when the stream ends or aborts with a terminal error.

type ModelExecutionStreamError

type ModelExecutionStreamError struct {
	StatusCode int
	Headers    http.Header
	Err        error
}

ModelExecutionStreamError carries a terminal streaming error produced while serving a ModelExecutionStream. It mirrors the most relevant fields of interfaces.ErrorMessage so plugin callers can preserve status codes and response headers when relaying errors.

func (*ModelExecutionStreamError) Error

func (e *ModelExecutionStreamError) Error() string

Error implements the error interface.

type PluginInterceptorHost

type PluginInterceptorHost interface{}

PluginInterceptorHost is the optional plugin host attached to API handlers.

type StreamForwardOptions

type StreamForwardOptions struct {
	// KeepAliveInterval overrides the configured streaming keep-alive interval.
	// If nil, the configured default is used. If set to <= 0, keep-alives are disabled.
	KeepAliveInterval *time.Duration

	// WriteChunk writes a single data chunk to the response body. It should not flush.
	WriteChunk func(chunk []byte)

	// WriteTerminalError writes an error payload to the response body when streaming fails
	// after headers have already been committed. It should not flush.
	WriteTerminalError func(errMsg *interfaces.ErrorMessage)

	// WriteDone optionally writes a terminal marker when the upstream data channel closes
	// without an error (e.g. OpenAI's `[DONE]`). It should not flush.
	WriteDone func()

	// WriteKeepAlive optionally writes a keep-alive heartbeat. It should not flush.
	// When nil, a standard SSE comment heartbeat is used.
	WriteKeepAlive func()
}

Directories

Path Synopsis
Package claude provides HTTP handlers for Claude API code-related functionality.
Package claude provides HTTP handlers for Claude API code-related functionality.
Package gemini provides HTTP handlers for Gemini CLI API functionality.
Package gemini provides HTTP handlers for Gemini CLI API functionality.
Package openai provides HTTP handlers for OpenAI API endpoints.
Package openai provides HTTP handlers for OpenAI API endpoints.

Jump to

Keyboard shortcuts

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