republic

package module
v0.0.0-...-6e72bf5 Latest Latest
Warning

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

Go to latest
Published: Oct 25, 2026 License: Apache-2.0 Imports: 31 Imported by: 0

README

Republic

One Go interface for chat, streaming, tool calls, structured output, embeddings, images and decisions across AI providers. Republic stops at providers: agent loops, tool execution and gateways stay in your application.

Requires Go 1.23 or later.

go get github.com/AstraFoundry/republic
export REPUBLIC_OPENAI_API_KEY="your-api-key"
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/AstraFoundry/republic"
)

func main() {
    model, err := republic.GetModel("openai:gpt-6-sol", republic.ProviderConfig{})
    if err != nil { log.Fatal(err) }
    defer model.Close()

    response, err := model.Chat(context.Background(), "Explain a tool call.", nil)
    if err != nil { log.Fatal(err) }
    fmt.Println(response.Text())

    stream, err := model.Stream(context.Background(), "Explain streaming.", nil)
    if err != nil { log.Fatal(err) }
    defer stream.Close()
    for event, err := range stream.Events() {
        if err != nil { log.Print(err); return }
        if event.Type == "text_delta" { fmt.Print(event.Chunk) }
    }
}

Model names use provider:model. Credentials default to REPUBLIC_<PROVIDER>_API_KEY; hyphens become underscores. Codex, GitHub Copilot and Grok can reuse their CLI credentials. Every request accepts a context for cancellation and deadlines.

Documentation

Development

make check
make test
make parity
make build

The library, tests and compatibility checks require only Go. The original Python implementation and its tooling have been removed. make parity compares 570 request cases and 58 recorded responses against frozen original-behavior baselines in testdata; it does not run a second implementation. See Contributing for development and optional documentation tools.

License

Apache 2.0.

Documentation

Overview

Package republic provides one interface to AI providers. Agent loops, gateways, and tool execution belong to the caller.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AllProviders

func AllProviders() []string

func DeepMerge

func DeepMerge(base, override map[string]any) map[string]any

func LoginCLI

func LoginCLI(ctx context.Context, executable string, args ...string) error

LoginCLI runs an explicit user-initiated login in the caller's terminal.

func ReadSSE

func ReadSSE(r io.Reader, endMarker string, yield func(ServerSentEvent) error) error

ReadSSE reads arbitrarily long events without Scanner's default 64 KiB limit. Returning an error from yield stops reading immediately.

func RegisterProvider

func RegisterProvider(name string, spec ProviderSpec)

func StrictSchema

func StrictSchema(schema map[string]any, requireAll bool) (map[string]any, error)

StrictSchema adapts JSON Schema to provider strict structured output rules.

Types

type Answer

type Answer struct {
	Type          string             `json:"type"`
	Noul          float64            `json:"noul,omitempty"`
	Choice        string             `json:"choice,omitempty"`
	Score         float64            `json:"score,omitempty"`
	Probabilities map[string]float64 `json:"probabilities,omitempty"`
	Confidence    float64            `json:"confidence,omitempty"`
	Legend        map[string]string  `json:"legend,omitempty"`
}

type Auth

type Auth interface {
	Apply(context.Context, *http.Request) error
}

Auth signs a fresh request on every attempt, allowing refreshable credentials.

type AuthFunc

type AuthFunc func(context.Context, *http.Request) error

func (AuthFunc) Apply

func (f AuthFunc) Apply(ctx context.Context, r *http.Request) error

type BuiltinTool

type BuiltinTool struct {
	Kind           string         `json:"kind"`
	MaxUses        *int           `json:"max_uses"`
	AllowedDomains []string       `json:"allowed_domains"`
	BlockedDomains []string       `json:"blocked_domains"`
	UserLocation   *UserLocation  `json:"user_location"`
	APIFormat      string         `json:"api_format"`
	Definition     map[string]any `json:"definition"`
}

func CodeExecution

func CodeExecution() BuiltinTool

func ImageGeneration

func ImageGeneration() BuiltinTool

func NativeTool

func NativeTool(format string, definition map[string]any) BuiltinTool

func WebFetch

func WebFetch() BuiltinTool

func WebSearch

func WebSearch() BuiltinTool

type BuiltinToolCall

type BuiltinToolCall struct {
	Name   string         `json:"name"`
	Input  map[string]any `json:"input"`
	Output any            `json:"output"`
	ID     string         `json:"id,omitempty"`
}

type ChatFormat

type ChatFormat interface {
	Name() string
	Headers() http.Header
	Build(ChatRequest, bool) (HTTPRequest, error)
	Parse([]byte) ([]Delta, error)
	NewParser() StreamParser
}

ChatFormat is implemented by custom wire protocols. Methods must be safe for concurrent calls; NewParser returns fresh state for each stream.

type ChatModel

type ChatModel struct {
	Provider *Provider
	Name     string
	Format   ChatFormat
	History  History
}

func GetModel

func GetModel(spec string, c ProviderConfig) (*ChatModel, error)

func (*ChatModel) Chat

func (m *ChatModel) Chat(ctx context.Context, prompt any, o Options) (result Response, err error)

func (*ChatModel) Close

func (m *ChatModel) Close() error

func (*ChatModel) Stream

func (m *ChatModel) Stream(ctx context.Context, prompt any, o Options) (*Stream, error)

Stream opens the HTTP response immediately. Always close it, even if no events are consumed. Events is a single-pass iterator; breaking the loop closes it.

type ChatRequest

type ChatRequest struct {
	Model        string
	Messages     []Message
	Options      Options
	OutputSchema *OutputSchema
}

type Citation

type Citation struct {
	URL       string `json:"url"`
	Title     string `json:"title,omitempty"`
	CitedText string `json:"cited_text,omitempty"`
}

type CopilotAuth

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

func LoginCopilot

func LoginCopilot(ctx context.Context, onAuthorize DeviceAuthorize) (*CopilotAuth, error)

func NewCopilotAuth

func NewCopilotAuth(githubToken string) (*CopilotAuth, error)

func (*CopilotAuth) Apply

func (a *CopilotAuth) Apply(ctx context.Context, r *http.Request) error

func (*CopilotAuth) GitHubToken

func (a *CopilotAuth) GitHubToken() string

type DecisionAPIFormat

type DecisionAPIFormat interface {
	Name() string
	Headers() http.Header
	Build(model string, state any, questions map[string]Question) (HTTPRequest, error)
	Parse(map[string]any) (DecisionResponse, error)
}

DecisionAPIFormat implements a typed decision protocol.

type DecisionModel

type DecisionModel struct {
	Provider     *Provider
	Name, Format string
	APIFormat    DecisionAPIFormat
}

func GetDecisionModel

func GetDecisionModel(spec string, c ProviderConfig) (*DecisionModel, error)

func (*DecisionModel) Close

func (m *DecisionModel) Close() error

func (*DecisionModel) Decide

func (m *DecisionModel) Decide(ctx context.Context, state any, questions map[string]Question) (r DecisionResponse, err error)

type DecisionResponse

type DecisionResponse struct {
	Answers          map[string]Answer
	TokenUsage       TokenUsage
	Model, RequestID string
	Headers          http.Header
}

type Delta

type Delta struct {
	Event        *Event
	ProviderData *Part
	Fragment     *ToolCallFragment
	Usage        map[string]int
	ID           string
	Model        string
	FinishReason string
}

Delta contains either a public event or an internal cumulative update.

type DeviceAuthorize

type DeviceAuthorize func(context.Context, string, string) error

type EmbeddingAPIFormat

type EmbeddingAPIFormat interface {
	Name() string
	Headers() http.Header
	Build(model string, texts []string, dimensions *int) (HTTPRequest, error)
	Parse(map[string]any) (EmbeddingResponse, error)
}

EmbeddingAPIFormat implements a custom embedding protocol.

type EmbeddingModel

type EmbeddingModel struct {
	Provider     *Provider
	Name, Format string
	APIFormat    EmbeddingAPIFormat
}

func GetEmbeddingModel

func GetEmbeddingModel(spec string, c ProviderConfig) (*EmbeddingModel, error)

func (*EmbeddingModel) Close

func (m *EmbeddingModel) Close() error

func (*EmbeddingModel) Embed

func (m *EmbeddingModel) Embed(ctx context.Context, text string, dimensions *int) (EmbeddingResponse, error)

func (*EmbeddingModel) EmbedMany

func (m *EmbeddingModel) EmbedMany(ctx context.Context, texts []string, dimensions *int) (r EmbeddingResponse, err error)

type EmbeddingResponse

type EmbeddingResponse struct {
	Vectors          [][]float64
	TokenUsage       TokenUsage
	Model, RequestID string
	Headers          http.Header
}

func (EmbeddingResponse) Vector

func (r EmbeddingResponse) Vector() ([]float64, error)

type Error

type Error struct {
	Kind       ErrorKind
	Message    string
	StatusCode int
	Body       string
	Headers    http.Header
	RequestID  string
	Cause      error
}

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

type ErrorKind

type ErrorKind string
const (
	ErrAuthentication     ErrorKind = "authentication"
	ErrProviderNotFound   ErrorKind = "provider_not_found"
	ErrUnsupportedFormat  ErrorKind = "unsupported_api_format"
	ErrUnsupportedFeature ErrorKind = "unsupported_feature"
	ErrAPIStatus          ErrorKind = "api_status"
	ErrConnection         ErrorKind = "api_connection"
	ErrTimeout            ErrorKind = "api_timeout"
	ErrAPIResponse        ErrorKind = "api_response"
	ErrStreamIncomplete   ErrorKind = "stream_incomplete"
	ErrStreamNotFinished  ErrorKind = "stream_not_finished"
	ErrClosed             ErrorKind = "closed"
)

type Event

type Event struct {
	Type        string           `json:"type"`
	Chunk       string           `json:"chunk,omitempty"`
	CallID      string           `json:"call_id,omitempty"`
	Name        string           `json:"name,omitempty"`
	Usage       TokenUsage       `json:"usage,omitempty"`
	Image       *Part            `json:"image,omitempty"`
	Call        *ToolCall        `json:"call,omitempty"`
	BuiltinCall *BuiltinToolCall `json:"builtin_call,omitempty"`
	Citation    *Citation        `json:"citation,omitempty"`
	Response    *Response        `json:"response,omitempty"`
}

Event is emitted in protocol order. Completed always contains the final result.

type Extension

type Extension interface {
	OnStart(provider, operation, model string) any
	OnRetry(state any, err error, attempt int, delay time.Duration)
	OnFinish(state, response any, err error)
}

Extension hooks run synchronously in registration order. A panic is isolated and logged; hooks must not mutate responses borrowed from the library.

type ExtensionFuncs

type ExtensionFuncs struct {
	Start  func(provider, operation, model string) any
	Retry  func(state any, err error, attempt int, delay time.Duration)
	Finish func(state, response any, err error)
}

ExtensionFuncs allows callers to implement only the hooks they need.

func (ExtensionFuncs) OnFinish

func (e ExtensionFuncs) OnFinish(s, r any, err error)

func (ExtensionFuncs) OnRetry

func (e ExtensionFuncs) OnRetry(s any, err error, a int, d time.Duration)

func (ExtensionFuncs) OnStart

func (e ExtensionFuncs) OnStart(p, o, m string) any

type FilePart

type FilePart struct {
	Field, Filename, MediaType string
	Data                       []byte
}

type GitHubCLIAuth

type GitHubCLIAuth struct{ Hostname, Executable string }

func LoginGitHubCLI

func LoginGitHubCLI(ctx context.Context, executable, hostname string) (GitHubCLIAuth, error)

func (GitHubCLIAuth) Apply

func (a GitHubCLIAuth) Apply(ctx context.Context, r *http.Request) error

type HTTPRequest

type HTTPRequest struct {
	Path   string
	Body   map[string]any
	Params map[string]string
	Files  []FilePart
}

type HeaderAuth

type HeaderAuth struct{ Name, Value string }

func (HeaderAuth) Apply

func (a HeaderAuth) Apply(_ context.Context, r *http.Request) error

type History

type History interface {
	Read(context.Context) ([]Message, error)
	Write(context.Context, []Message) error
}

type ImageAPIFormat

type ImageAPIFormat interface {
	Name() string
	Headers() http.Header
	Generate(model, prompt string, options Options) (HTTPRequest, error)
	Edit(model, prompt string, images []Part, mask *Part, options Options) (HTTPRequest, error)
	Parse(map[string]any) (ImageResponse, error)
}

ImageAPIFormat implements image generation and editing.

type ImageModel

type ImageModel struct {
	Provider     *Provider
	Name, Format string
	APIFormat    ImageAPIFormat
}

func GetImageModel

func GetImageModel(spec string, c ProviderConfig) (*ImageModel, error)

func (*ImageModel) Close

func (m *ImageModel) Close() error

func (*ImageModel) Edit

func (m *ImageModel) Edit(ctx context.Context, prompt string, images []Part, mask *Part, options Options) (ImageResponse, error)

func (*ImageModel) Generate

func (m *ImageModel) Generate(ctx context.Context, prompt string, options Options) (ImageResponse, error)

type ImageResponse

type ImageResponse struct {
	ImageParts     []Part
	RevisedPrompts []*string
	TokenUsage     TokenUsage
	RequestID      string
	Headers        http.Header
}

type InMemoryHistory

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

InMemoryHistory keeps whole user turns when bounded. Zero means unbounded.

func NewHistory

func NewHistory(maxEntries int) (*InMemoryHistory, error)

func (*InMemoryHistory) Read

func (h *InMemoryHistory) Read(ctx context.Context) ([]Message, error)

func (*InMemoryHistory) Write

func (h *InMemoryHistory) Write(ctx context.Context, messages []Message) error

type Message

type Message struct {
	Role      string
	Parts     []Part
	ToolCalls []ToolCall
	ToolCall  *ToolCall
	IsError   bool
}

func Assistant

func Assistant(parts ...Part) Message

func Normalize

func Normalize(messages []Message) ([]Message, error)

Normalize announces orphan tool calls without changing the caller's messages.

func System

func System(s string) Message

func ToolResult

func ToolResult(call ToolCall, isError bool, parts ...Part) Message

func User

func User(parts ...Part) Message

func (Message) MarshalJSON

func (m Message) MarshalJSON() ([]byte, error)

func (Message) Reasoning

func (m Message) Reasoning() string

func (Message) Text

func (m Message) Text() string

func (*Message) UnmarshalJSON

func (m *Message) UnmarshalJSON(b []byte) error

func (Message) Validate

func (m Message) Validate() error

type ModelInfo

type ModelInfo struct {
	ID, DisplayName string
	Raw             map[string]any
}

type OAuth2Auth

type OAuth2Auth struct{ AccessToken string }

OAuth2Auth sends a caller-managed bearer token without persisting it.

func (OAuth2Auth) Apply

func (a OAuth2Auth) Apply(_ context.Context, r *http.Request) error

type OpenRouterAuth

type OpenRouterAuth struct{ APIKey string }

func LoginOpenRouter

func LoginOpenRouter(ctx context.Context, authorize func(context.Context, string) (string, error)) (OpenRouterAuth, error)

LoginOpenRouter delegates displaying the authorization URL and collecting its code to the caller. The resulting API key is persisted only by the caller.

func NewOpenRouterAuth

func NewOpenRouterAuth(key string) (OpenRouterAuth, error)

func (OpenRouterAuth) Apply

func (a OpenRouterAuth) Apply(ctx context.Context, r *http.Request) error

type Options

type Options map[string]any

Options uses Republic's portable option names. Presence matters: false and zero are sent when explicitly supplied.

type OutputSchema

type OutputSchema struct {
	Name   string
	Schema map[string]any
}

type Part

type Part struct {
	Type      string         `json:"type"`
	Text      string         `json:"-"`
	MediaType string         `json:"media_type,omitempty"`
	Data      []byte         `json:"data,omitempty"`
	URL       string         `json:"url,omitempty"`
	APIFormat string         `json:"api_format,omitempty"`
	Payload   map[string]any `json:"payload,omitempty"`
}

Part is a typed message content item. Data is encoded as base64 in JSON. ProviderData is opaque and may only be replayed to its originating format.

func Audio

func Audio(source any, mediaType string) (Part, error)

func Image

func Image(source any, mediaType string) (Part, error)

func LoadMedia

func LoadMedia(kind string, source any, mediaType string) (Part, error)

LoadMedia accepts a file path, remote URL, data URL, or []byte.

func ProviderData

func ProviderData(format string, payload map[string]any) Part

func Reasoning

func Reasoning(s string) Part

func Text

func Text(s string) Part

func Video

func Video(source any, mediaType string) (Part, error)

func (Part) Base64Data

func (p Part) Base64Data() (string, error)

func (Part) DataURL

func (p Part) DataURL() (string, error)

func (Part) MarshalJSON

func (p Part) MarshalJSON() ([]byte, error)

func (*Part) UnmarshalJSON

func (p *Part) UnmarshalJSON(b []byte) error

type Provider

type Provider struct {
	Name, APIBase string
	// contains filtered or unexported fields
}

func GetProvider

func GetProvider(name string, c ProviderConfig) (*Provider, error)

func NewProvider

func NewProvider(spec ProviderSpec, c ProviderConfig) (*Provider, error)

func (*Provider) Close

func (p *Provider) Close() error

Close is idempotent. Caller-owned clients are never closed.

func (*Provider) GetDecisionModel

func (p *Provider) GetDecisionModel(name string) (*DecisionModel, error)

func (*Provider) GetEmbeddingModel

func (p *Provider) GetEmbeddingModel(name string) (*EmbeddingModel, error)

func (*Provider) GetImageModel

func (p *Provider) GetImageModel(name string) (*ImageModel, error)

func (*Provider) GetModel

func (p *Provider) GetModel(name string) (*ChatModel, error)

func (*Provider) IsClosed

func (p *Provider) IsClosed() bool

func (*Provider) ListModels

func (p *Provider) ListModels(ctx context.Context) (models []ModelInfo, err error)

type ProviderConfig

type ProviderConfig struct {
	APIKey, APIBase, APIFormat, EnvPrefix, Resource string
	Auth                                            Auth
	Headers                                         http.Header
	ExtraBody                                       map[string]any
	HTTPClient                                      *http.Client
	Timeout                                         time.Duration
	MaxRetries                                      *int
	RetryDelay, MaxRetryDelay                       *time.Duration
	Extensions                                      []Extension
}

type ProviderSpec

type ProviderSpec struct {
	Name, APIBase, ModelsPath, AuthHeader string
	Formats                               []string
	// SelectFormat overrides chat dialect selection for custom providers.
	SelectFormat          func(model, format string) ChatFormat
	SelectEmbeddingFormat func(model, format string) EmbeddingAPIFormat
	SelectImageFormat     func(model, format string) ImageAPIFormat
	SelectDecisionFormat  func(model, format string) DecisionAPIFormat
	ModelsParams          func(previous any) map[string]string
	ParseModels           func(data any) ([]ModelInfo, error)
}

type Question

type Question struct {
	Kind         string
	Instructions any
	Criteria     any
}

func Choice

func Choice(instructions, criteria any) Question

func Noul

func Noul(instructions any, criteria map[string]any) Question

func Score

func Score(instructions any, criteria []any) Question

type Response

type Response struct {
	Message          Message           `json:"message"`
	TokenUsage       TokenUsage        `json:"token_usage"`
	Output           any               `json:"output"`
	FinishReason     string            `json:"finish_reason,omitempty"`
	Refusal          string            `json:"refusal,omitempty"`
	Citations        []Citation        `json:"citations"`
	BuiltinToolCalls []BuiltinToolCall `json:"builtin_tool_calls"`
	ID               string            `json:"id,omitempty"`
	Model            string            `json:"model,omitempty"`
	RequestID        string            `json:"request_id,omitempty"`
	Headers          http.Header       `json:"-"`
}

func ParseChat

func ParseChat(format string, data []byte) (Response, error)

ParseChat parses a complete JSON response, including metadata needed for replay.

func (Response) ImageParts

func (r Response) ImageParts() []Part

func (Response) Reasoning

func (r Response) Reasoning() string

func (Response) Text

func (r Response) Text() string

func (Response) ToolCalls

func (r Response) ToolCalls() []ToolCall

type ResponseBuilder

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

func (*ResponseBuilder) Add

func (b *ResponseBuilder) Add(d Delta) []Event

func (*ResponseBuilder) ReleaseToolCalls

func (b *ResponseBuilder) ReleaseToolCalls() []Event

func (*ResponseBuilder) Response

func (b *ResponseBuilder) Response() Response

type ServerSentEvent

type ServerSentEvent struct {
	Event string
	Data  string
}

type Stream

type Stream struct {
	Headers   http.Header
	RequestID string
	// contains filtered or unexported fields
}

func (*Stream) Close

func (s *Stream) Close() error

func (*Stream) Events

func (s *Stream) Events() iter.Seq2[Event, error]

func (*Stream) Response

func (s *Stream) Response() (Response, error)

type StreamParser

type StreamParser interface {
	Feed(event, data string) ([]Delta, error)
	Finish() error
}

StreamParser converts one wire protocol into deltas, retaining per-stream state. A parser must never be shared by independent requests.

func NewStreamParser

func NewStreamParser(format string) (StreamParser, error)

type TokenAuth

type TokenAuth struct {
	HTTPClient *http.Client
	// contains filtered or unexported fields
}

TokenAuth maintains Codex or Grok OAuth credentials. Token returns a snapshot; refreshes are serialized. HTTPClient may be set before first use.

func CodexAuthFromFile

func CodexAuthFromFile(path string) (*TokenAuth, error)

func GrokAuthFromFile

func GrokAuthFromFile(path string) (*TokenAuth, error)

func LoginCodex

func LoginCodex(ctx context.Context, executable string, device bool) (*TokenAuth, error)

func LoginGrok

func LoginGrok(ctx context.Context, executable string, device bool) (*TokenAuth, error)

func NewCodexAuth

func NewCodexAuth(token map[string]any, accountID string) (*TokenAuth, error)

func NewGrokAuth

func NewGrokAuth(token map[string]any) (*TokenAuth, error)

func (*TokenAuth) AccountID

func (a *TokenAuth) AccountID() string

func (*TokenAuth) Apply

func (a *TokenAuth) Apply(ctx context.Context, r *http.Request) error

func (*TokenAuth) Token

func (a *TokenAuth) Token() map[string]any

type TokenUsage

type TokenUsage struct {
	InputTokens      int `json:"input_tokens"`
	OutputTokens     int `json:"output_tokens"`
	ReasoningTokens  int `json:"reasoning_tokens"`
	CachedTokens     int `json:"cached_tokens"`
	CacheWriteTokens int `json:"cache_write_tokens"`
}

func (TokenUsage) TotalTokens

func (u TokenUsage) TotalTokens() int

type Tool

type Tool struct {
	Name        string         `json:"name"`
	Description string         `json:"description"`
	Parameters  map[string]any `json:"parameters"`
	Strict      bool           `json:"strict,omitempty"`
}

func (Tool) Schema

func (t Tool) Schema() map[string]any

type ToolCall

type ToolCall struct {
	ID        string         `json:"id"`
	Name      string         `json:"name"`
	Arguments string         `json:"arguments"`
	Metadata  map[string]any `json:"metadata,omitempty"`
}

func (ToolCall) Args

func (c ToolCall) Args() (any, error)

type ToolCallFragment

type ToolCallFragment struct {
	Key       string
	ID        string
	Name      string
	Arguments string
	Metadata  map[string]any
	Done      bool
}

type UserLocation

type UserLocation struct {
	City     string `json:"city"`
	Region   string `json:"region"`
	Country  string `json:"country"`
	Timezone string `json:"timezone"`
}

type WireFormat

type WireFormat struct {
	Format  string
	Dialect string
}

func (WireFormat) Build

func (f WireFormat) Build(r ChatRequest, stream bool) (HTTPRequest, error)

func (WireFormat) Headers

func (f WireFormat) Headers() http.Header

func (WireFormat) Name

func (f WireFormat) Name() string

func (WireFormat) NewParser

func (f WireFormat) NewParser() StreamParser

func (WireFormat) Parse

func (f WireFormat) Parse(b []byte) ([]Delta, error)

Directories

Path Synopsis
examples
chat command
Run with REPUBLIC_OPENAI_API_KEY set.
Run with REPUBLIC_OPENAI_API_KEY set.

Jump to

Keyboard shortcuts

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