proxy

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Mar 30, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// DefaultPort is the default proxy listen port.
	DefaultPort = 19280
	// DefaultUpstream is the default Claude API upstream.
	DefaultUpstream = "https://api.anthropic.com"
	// DefaultCodexUpstream is the default ChatGPT backend API upstream for Codex models.
	// ChatGPT OAuth tokens authenticate against this endpoint (not api.openai.com,
	// which requires the api.responses.write scope unavailable to OAuth clients).
	DefaultCodexUpstream = "https://chatgpt.com/backend-api/codex"
)
View Source
const CooldownDuration = 5 * time.Minute

CooldownDuration is how long an account is skipped after a 429.

Variables

This section is empty.

Functions

func DefaultPersister

func DefaultPersister(acct *keyring.ClaudeOAuth)

DefaultPersister persists refreshed tokens to all credential stores.

func ParseModelEffort

func ParseModelEffort(model string) (baseModel, effort string)

ParseModelEffort splits a model name into the base model and an optional effort override from a recognised suffix. Returns ("gpt-5.4", "xhigh") for input "gpt-5.4-xhigh", or ("gpt-5.4", "") for input "gpt-5.4".

Types

type ClaudeDiscoverer

type ClaudeDiscoverer func() []keyring.ClaudeOAuth

ClaudeDiscoverer abstracts keyring discovery for testability.

type ClaudeSelector

type ClaudeSelector interface {
	Select(ctx context.Context, exclude ...string) (*keyring.ClaudeOAuth, error)
}

ClaudeSelector picks the best account for a request.

func NewAccountSelector

func NewAccountSelector(discover ClaudeDiscoverer) ClaudeSelector

NewAccountSelector creates a ClaudeSelector backed by the given discovery function.

type CodexDiscoverer

type CodexDiscoverer func() []codex.CodexAccount

CodexDiscoverer abstracts Codex account discovery for testability.

type CodexSelector

type CodexSelector interface {
	Select(ctx context.Context) (*codex.CodexAccount, error)
}

CodexSelector picks a Codex account for a request.

func NewCodexSelector

func NewCodexSelector(discover CodexDiscoverer) CodexSelector

NewCodexSelector creates a CodexSelector backed by the given discovery function.

type Config

type Config struct {
	Port           int    `json:"port"`
	ClaudeUpstream string `json:"claude_upstream"`
	CodexUpstream  string `json:"codex_upstream"`
	LocalToken     string `json:"local_token"`
}

Config holds proxy configuration persisted to disk.

func LoadConfig

func LoadConfig() (*Config, error)

LoadConfig reads proxy config from disk, generating defaults on first run.

type PersistFunc

type PersistFunc func(acct *keyring.ClaudeOAuth)

PersistFunc persists refreshed account credentials (best-effort).

type Provider

type Provider int

Provider identifies the upstream API provider for routing.

const (
	// ProviderClaude routes to the Anthropic API.
	ProviderClaude Provider = iota
	// ProviderCodex routes to the OpenAI Responses API.
	ProviderCodex
)

func RouteModel

func RouteModel(model string) Provider

RouteModel maps a model name to the provider that serves it. Effort suffixes (e.g. "-xhigh") are stripped before matching.

type RefreshFunc

type RefreshFunc func(ctx context.Context, client httputil.Doer, refreshToken string, scopes []string) (*claude.RefreshResult, error)

RefreshFunc exchanges a refresh token for new credentials.

type Server

type Server struct {
	Config         *Config
	Selector       ClaudeSelector
	Discover       ClaudeDiscoverer
	Transport      http.RoundTripper
	CodexSelector  CodexSelector
	CodexDiscover  CodexDiscoverer
	CodexTransport http.RoundTripper
}

Server is the reverse proxy HTTP server.

func (*Server) ListenAndServe

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

ListenAndServe starts the proxy and blocks until the context is cancelled or a signal is received.

type StreamTranslator

type StreamTranslator struct {
	// contains filtered or unexported fields
}

StreamTranslator reads OpenAI Responses SSE events from a reader and writes Anthropic Messages SSE events to an http.ResponseWriter. It also accumulates state for assembling a non-streaming JSON response.

func NewStreamTranslator

func NewStreamTranslator(model string) *StreamTranslator

NewStreamTranslator creates a StreamTranslator for the given model.

func (*StreamTranslator) AssembleResponse

func (st *StreamTranslator) AssembleResponse(model string) ([]byte, error)

AssembleResponse builds a complete Anthropic Messages JSON response from accumulated stream state.

func (*StreamTranslator) Collect

func (st *StreamTranslator) Collect(r io.Reader) error

Collect reads all SSE events from r, accumulating state without writing SSE output. After calling Collect, use AssembleResponse to get the final Anthropic JSON response.

func (*StreamTranslator) Translate

func (st *StreamTranslator) Translate(w http.ResponseWriter, r io.Reader) error

Translate reads all SSE events from r and writes translated events to w.

type TokenTransport

type TokenTransport struct {
	Selector    ClaudeSelector
	Refresher   RefreshFunc
	Persister   PersistFunc
	RefreshHTTP httputil.Doer
	Inner       http.RoundTripper
	// contains filtered or unexported fields
}

TokenTransport is an http.RoundTripper that injects OAuth tokens and handles 401 (refresh) and 429 (account failover with cooldown).

func (*TokenTransport) RoundTrip

func (t *TokenTransport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements http.RoundTripper.

Jump to

Keyboard shortcuts

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