sorus

package module
v0.0.0-...-9b30ce0 Latest Latest
Warning

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

Go to latest
Published: Sep 21, 2026 License: MIT Imports: 16 Imported by: 0

README

sorus

A Go client for (mostly) any provider in the models.dev catalog.

Sorus is meant primarily for cases where dynamic model usage is ideal.

Loads the catalog of providers and models into typed Go structs and gives you one Client to call any provider that speaks a supported wire protocol. Build a Request fluently, get a Response back.

Supported wire protocols: OpenAI chat completions (@ai-sdk/openai-compatible, @ai-sdk/openai) and Anthropic (@ai-sdk/anthropic). Anything else returns ErrUnsupportedProvider.

Install

go get github.com/nalanj/sorus

Go 1.24+.

import "github.com/nalanj/sorus"

Quick start

ctx := context.Background()

cat, err := sorus.LoadCatalog(ctx)
if err != nil {
    panic(err)
}

client, err := sorus.New(ctx, cat, "openrouter")
if err != nil {
    panic(err)
}

model := cat.Provider("openrouter").MustModel("anthropic/claude-sonnet-4-5")

req := sorus.NewRequest(model).
    System("You are a helpful assistant.").
    Temperature(0.7).
    MaxTokens(2048).
    User("Hello, world!")

resp, err := client.Chat(ctx, req)
if err != nil {
    panic(err)
}
fmt.Println(resp.Message.Text())

LoadCatalog fetches https://models.dev/api.json and caches the parsed result for the process lifetime. New(ctx, cat, "openrouter") reads the env var the catalog says OpenRouter expects (OPENROUTER_API_KEY) and points at the right base URL. Set the key, call Chat, get a response.

CLI

sorus ships with a small binary that wraps the library — handy for smoke-testing providers from your terminal.

go install github.com/nalanj/sorus/cmd/sorus@latest

It loads the catalog, resolves the API key from the provider's documented env vars, and streams the response to stdout. Reasoning and tool-call events go to stderr.

ANTHROPIC_API_KEY=... sorus -provider anthropic -model claude-sonnet-4-5 -prompt "Hello, world!"
echo "Summarize this:" | sorus -provider openrouter -model anthropic/claude-sonnet-4-5

-provider and -model are required. Flags:

Flag Default Description
-provider (required) Provider id from the models.dev catalog
-model (required) Model id on that provider
-system (unset) System prompt
-prompt (unset) User prompt; if empty, read from stdin
-temperature -1 (unset) Sampling temperature 0.0–1.0
-max-tokens -1 (unset) Maximum output tokens
-no-stream false Single non-streaming request
-quiet false Suppress reasoning/tool-call events on stderr

Run sorus -h for the canonical flag list.

Design

Wrapped, not pass-through

"OpenAI-compatible" describes the wire, not the API. Different providers expose different params — reasoning_effort here, enable_thinking there. sorus hides those differences behind one type. You import only github.com/nalanj/sorus; the package internally implements Client for each supported wire protocol and converts your fluent Request into the right shape.

There is no protocol-specific escape hatch by design. If Client misses something you need, that's the seam — open an issue.

Model is description, Request is configuration

Model is read-only: name, family, modalities, limits, cost, capabilities, release date. Nothing on it can be configured.

Request is built fluently. All setters take literal values and return *Request for chaining. Reuse defaults with req.Clone().

Auth via env vars

The catalog records the env-var names each provider expects (env: ["OPENROUTER_API_KEY"]). New reads the first one that's set, errors if none are. OAuth flows aren't built in — populating GITHUB_TOKEN via gh auth for the github-copilot provider is your job.

Override per-call:

client, err := sorus.New(ctx, cat, "openrouter",
    sorus.WithAPIKey(os.Getenv("MY_KEY")),
    sorus.WithHTTPClient(myHTTPClient),
)
Reasoning, multimodal, capabilities

The catalog records what each model can do — modalities, limits, cost, reasoning capability, tool calling, structured output — and Model exposes those as plain fields. Configuration knobs go on Request.

The generic Reasoning struct maps onto each implementation's idiom:

Reasoning field Chat completions Anthropic
Effort reasoning_effort
BudgetTokens thinking.budget_tokens

Each implementation reads only the fields it understands; over-populating is harmless.

API reference

Full type and function reference lives on pkg.go.dev/github.com/nalanj/sorus.

Recipes

Stream a response
stream, err := client.Stream(ctx, req)
if err != nil { panic(err) }
defer stream.Close()

var out strings.Builder
for stream.Next() {
    ev := stream.Event()
    switch ev.Type {
    case sorus.EventContentDelta:
        out.WriteString(ev.TextDelta)
        fmt.Print(ev.TextDelta)
    case sorus.EventReasoningDelta:
        // collect or display; e.g. ui.Spin(ev.ReasoningDelta)
    case sorus.EventDone:
        fmt.Printf("\n--- done, usage=%+v ---\n", ev.Usage)
    case sorus.EventError:
        return ev.Err
    }
}

// Or skip the loop entirely:
resp, err := stream.Collect()
Tool calling
type GetWeatherArgs struct {
    Location string `json:"location"`
}

req := sorus.NewRequest(model).
    System("...").
    User("Weather in Paris?").
    Tools(sorus.Tool{
        Name:        "get_weather",
        Description: "Get the current weather for a location.",
        Parameters: map[string]any{
            "type": "object",
            "properties": map[string]any{
                "location": map[string]any{"type": "string"},
            },
            "required": []string{"location"},
        },
    }).
    ToolChoice(sorus.ToolChoice{Mode: sorus.ToolChoiceRequired, Name: "get_weather"})

resp, err := client.Chat(ctx, req)

if len(resp.Message.ToolCalls) > 0 {
    var toolResults []sorus.Part
    for _, tc := range resp.Message.ToolCalls {
        var args GetWeatherArgs
        _ = json.Unmarshal([]byte(tc.Arguments), &args)
        toolResults = append(toolResults, sorus.ToolResult{
            ToolCallID: tc.ID,
            Content: []sorus.Part{
                sorus.Text{Value: fetchWeather(ctx, args.Location)},
            },
        })
    }

    req = req.Clone().
        Message(resp.Message).                          // the assistant's tool-call turn
        Message(sorus.Message{
            Role:    sorus.RoleTool,
            Content: toolResults,
        })

    resp, err = client.Chat(ctx, req)
}
Structured output (JSON schema)
req := sorus.NewRequest(model).
    User("Summarize today's weather in Paris.").
    ResponseFormat(&sorus.ResponseFormat{
        Type: "json_schema",
        JSONSchema: &sorus.JSONSchema{
            Name:   "weather_report",
            Strict: true,
            Schema: map[string]any{
                "type": "object",
                "properties": map[string]any{
                    "summary": map[string]any{"type": "string"},
                    "temp_f":  map[string]any{"type": "number"},
                },
                "required": []string{"summary", "temp_f"},
            },
        },
    })
Reasoning
// Chat-completions providers honor Effort:
req := sorus.NewRequest(model).
    User("Solve this step-by-step.").
    Reasoning(sorus.Reasoning{Effort: "medium"})

// Anthropic honors BudgetTokens:
req = sorus.NewRequest(model).
    User("Solve this step-by-step.").
    Reasoning(sorus.Reasoning{BudgetTokens: 4096})
Multimodal input
req := sorus.NewRequest(model).
    Message(sorus.Message{
        Role: sorus.RoleUser,
        Content: []sorus.Part{
            sorus.Text{Value: "What's in this image?"},
            sorus.ImageURL{URL: "https://example.com/cat.jpg", Detail: "high"},
            // Or:
            sorus.ImageData{Data: pngBytes, MIMEType: "image/png"},
        },
    })
Find all Claude Sonnet models across providers
sonnets := cat.ModelsByFamily("claude-sonnet")
for _, m := range sonnets {
    fmt.Printf("%s (%s): $%.2f/Mtok in\n", m.Ref(), m.Provider().ID, m.Cost.Input)
}
Vendored / offline usage
//go:embed api.json
var apiJSON []byte

func loadCatalog() (*sorus.Catalog, error) {
    return sorus.LoadCatalogFromBytes(apiJSON)
}
Reusable defaults with Clone
defaultReq := sorus.NewRequest(model).
    System("You are a helpful assistant.").
    Temperature(0.7).
    MaxTokens(2048)

for _, query := range queries {
    req := defaultReq.Clone().User(query)
    resp, err := client.Chat(ctx, req)
    if err != nil { /* ... */ }
}

Clone() produces an independent *Request you can extend per call without touching defaultReq.

Caveats

  • No OAuth flows. Setting GITHUB_TOKEN to a valid Copilot token via gh auth is fine; running an OAuth browser flow inside this package is not.
  • No protocol-specific escape hatch. If Client doesn't expose what you need, that's the seam — open an issue. The package deliberately doesn't expose wire-protocol SDK types from its public surface.
  • Tool.Parameters is raw map[string]any. Build JSON Schema manually (or with invopop/jsonschema); we don't ship a builder.
  • Stream.Event() returns a value type, not a pointer. The hot path allocates an Event per token. If that's a problem for your workload, a Stream.Visit(func(Event) bool) variant would be straightforward to add.
  • Catalog freshness. LoadCatalog relies on https://models.dev/api.json and caches the parsed catalog in memory for the process lifetime. For reproducible builds, prefer vendoring via LoadCatalogFromBytes or LoadCatalogFromFS so the network isn't touched.

Contributing

Open an issue first. Pull requests are only open to existing contributors, so the issue tracker is where outside contributions start — file an issue describing what you want to change or report, and we'll coordinate on approach and scope there. Bugs, feature ideas, and questions all fit.

License

MIT. See LICENSE for details.

Documentation

Overview

Package sorus reads the [models.dev] catalog of LLM providers and models, and exposes a provider-agnostic Client interface that hides each provider's wire-protocol details behind a single fluent Request builder.

The typical flow is:

cat, _ := sorus.LoadCatalog(ctx)
client, _ := sorus.New(ctx, cat, "openrouter") // reads OPENROUTER_API_KEY from env
req := sorus.NewRequest(cat.Provider("openrouter").MustModel("anthropic/claude-sonnet-4-5")).
    System("...").
    Temperature(0.7).
    User("Hello")
resp, err := client.Chat(ctx, req)

Supported wire protocols are listed on New: today, anything whose catalog `npm` is one of the supported values.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrUnknownProvider     = errors.New("sorus: unknown provider id")
	ErrUnsupportedProvider = errors.New("sorus: provider npm not supported by this build")
	ErrMissingAPIKey       = errors.New("sorus: no API key found in expected env vars")
	ErrCatalogFetch        = errors.New("sorus: catalog fetch failed")
	ErrCatalogParse        = errors.New("sorus: catalog parse failed")
	ErrStreamClosed        = errors.New("sorus: stream is closed")
)

Errors returned by catalog and client operations.

Functions

This section is empty.

Types

type Catalog

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

Catalog is the loaded models.dev catalog.

func LoadCatalog

func LoadCatalog(ctx context.Context, opts ...CatalogOption) (*Catalog, error)

LoadCatalog fetches the models.dev catalog and parses it. The result is cached in memory for the lifetime of the process; subsequent calls with default options return the cached instance.

LoadCatalogFromBytes and LoadCatalogFromFS bypass the cache because they take user-supplied data and never touch the network.

func LoadCatalogFromBytes

func LoadCatalogFromBytes(b []byte) (*Catalog, error)

LoadCatalogFromBytes parses an in-memory catalog JSON blob.

func LoadCatalogFromFS

func LoadCatalogFromFS(fsys fs.FS, name string) (*Catalog, error)

LoadCatalogFromFS parses a catalog stored in the given fs.FS.

func (*Catalog) FindModel

func (c *Catalog) FindModel(qualifiedID string) (*Provider, *Model, bool)

FindModel looks up a model by qualified id of the form "provider/model". Returns the provider, the model, and ok.

func (*Catalog) Models

func (c *Catalog) Models() []*Model

Models returns every model across every provider (cross-provider enumeration).

func (*Catalog) ModelsByFamily

func (c *Catalog) ModelsByFamily(family string) []*Model

ModelsByFamily returns every model across every provider whose Family matches.

func (*Catalog) MustProvider

func (c *Catalog) MustProvider(id string) *Provider

MustProvider returns the provider with the given id, panicking if unknown.

func (*Catalog) Provider

func (c *Catalog) Provider(id string) *Provider

Provider returns the provider with the given id, or nil if unknown.

func (*Catalog) Providers

func (c *Catalog) Providers() []*Provider

Providers returns all providers.

type CatalogOption

type CatalogOption func(*catalogConfig)

CatalogOption configures LoadCatalog.

func WithCatalogURL

func WithCatalogURL(url string) CatalogOption

WithCatalogURL overrides the URL to fetch the catalog from. The default is the upstream https://models.dev/api.json. Any non-default URL bypasses the in-memory cache and re-fetches on every call.

Use a file:// URI for a vendored copy.

func WithFetchHTTPClient

func WithFetchHTTPClient(h *http.Client) CatalogOption

WithFetchHTTPClient lets callers inject a custom http.Client used for fetching the catalog (timeouts, retries, transport instrumentation). Supplying one bypasses the in-memory cache so the custom client is actually used.

func WithRefresh

func WithRefresh() CatalogOption

WithRefresh forces a fresh fetch even when an in-memory cache exists.

type Client

type Client interface {
	// Chat sends req and returns a single non-streaming [Response].
	Chat(ctx context.Context, req *Request) (*Response, error)

	// Stream sends req and returns a streaming [Stream]. Always call
	// [Stream.Close] when done, even on error paths.
	Stream(ctx context.Context, req *Request) (*Stream, error)
}

Client is the provider-agnostic chat surface. Implementations are selected by New based on the provider's `npm` value in the catalog.

A Client is bound to one provider. To switch providers, call New again.

func New

func New(ctx context.Context, cat *Catalog, providerID string, opts ...Option) (Client, error)

New builds a Client for the named provider.

The provider's `env` list determines API-key resolution: the first name that's set in the process environment wins. Override with WithAPIKey if you already have a credential in hand (tests, multi-tenant apps, key rings).

Returns ErrUnknownProvider if the provider id isn't in the catalog, ErrUnsupportedProvider if the provider's `npm` value isn't handled by this build (today: anything other than `@ai-sdk/openai-compatible` or `@ai-sdk/openai`), or ErrMissingAPIKey if no credential was found and no WithAPIKey was supplied.

type Event

type Event struct {
	Type EventType

	// EventContentDelta:
	TextDelta string

	// EventReasoningDelta:
	ReasoningDelta string

	// EventToolCallStart: the assembled tool call with ID and Name; Arguments
	// may be empty if the model streams them separately.
	ToolCall *ToolCall

	// EventToolCallDelta: incremental JSON fragment of the in-progress
	// arguments.
	ArgumentDelta string

	// EventDone: aggregated terminal fields.
	StopReason string
	Usage      *Usage
	Message    *Message

	// EventError:
	Err error
}

Event is a single event yielded by a Stream.

type EventType

type EventType string

EventType identifies the kind of Event.

const (
	EventContentStart   EventType = "content_start"
	EventContentDelta   EventType = "content_delta"
	EventContentEnd     EventType = "content_end"
	EventReasoningStart EventType = "reasoning_start"
	EventReasoningDelta EventType = "reasoning_delta"
	EventReasoningEnd   EventType = "reasoning_end"
	EventToolCallStart  EventType = "tool_call_start"
	EventToolCallDelta  EventType = "tool_call_delta"
	EventToolCallEnd    EventType = "tool_call_end"
	EventDone           EventType = "done"
	EventError          EventType = "error"
)

type ImageData

type ImageData struct {
	Data     []byte
	MIMEType string // e.g. "image/png"
}

ImageData is an image embedded as bytes.

type ImageURL

type ImageURL struct {
	URL    string
	Detail string // "auto" | "low" | "high"; empty means provider default
}

ImageURL is an image referenced by URL.

type JSONSchema

type JSONSchema struct {
	Name   string
	Schema map[string]any
	Strict bool // best-effort "strict" mode; provider-dependent whether honored
}

JSONSchema is the JSON Schema for the response. Schema is the schema body as a Go map. Use a schema-builder library like invopop/jsonschema if you want typesafety.

type Message

type Message struct {
	Role      Role
	Content   []Part
	ToolCalls []ToolCall // populated on assistant messages that emit tool calls
}

Message is one turn in a conversation.

func AssistantMessage

func AssistantMessage(text string) Message

AssistantMessage constructs a plain-text assistant message.

func SystemMessage

func SystemMessage(text string) Message

SystemMessage constructs a plain-text system message.

func UserMessage

func UserMessage(text string) Message

UserMessage constructs a plain-text user message.

func (Message) Text

func (m Message) Text() string

Text returns the concatenation of every Text part in the message. Non-text parts are ignored.

type Model

type Model struct {
	ID               string // provider-local id, e.g. "anthropic/claude-sonnet-4-5"
	Name             string // "Claude Sonnet 4.5"
	Family           string // "claude-sonnet"
	Description      string
	Modalities       ModelModalities // {input: [...], output: [...]}
	Limit            ModelLimit      // {context, input, output}
	Cost             ModelCost       // per-1M-token USD prices; zero means "not advertised"
	Reasoning        bool
	ReasoningOptions []ReasoningOption // effort enum / toggle / budget_tokens
	ToolCall         bool
	StructuredOutput bool
	Temperature      bool
	Attachment       bool
	Knowledge        string // cutoff, "YYYY-MM" or "YYYY-MM-DD"
	ReleaseDate      string // "YYYY-MM-DD"
	LastUpdated      string // "YYYY-MM-DD"
	Status           string // "", "alpha", "beta", "deprecated"
	OpenWeights      bool
	// contains filtered or unexported fields
}

Model is one model record on a provider. Model is pure description — no configuration is attached. Configuration lives on Request.

func (*Model) Provider

func (m *Model) Provider() *Provider

Provider returns the parent provider of this model.

func (*Model) Ref

func (m *Model) Ref() string

Ref returns the provider-local id. Useful for logging.

type ModelCost

type ModelCost struct {
	Input       float64
	Output      float64
	CacheRead   float64
	CacheWrite  float64
	Reasoning   float64
	InputAudio  float64
	OutputAudio float64
}

type ModelLimit

type ModelLimit struct {
	Context int
	Input   int
	Output  int
}

type ModelModalities

type ModelModalities struct {
	Input  []string
	Output []string
}

type Option

type Option func(*config)

Option configures New.

func WithAPIKey

func WithAPIKey(key string) Option

WithAPIKey overrides the API-key lookup. By default the catalog's `env` list is consulted for an env-var that's set.

func WithHTTPClient

func WithHTTPClient(h *http.Client) Option

WithHTTPClient injects a custom *http.Client used by the underlying provider transport.

type Part

type Part interface {
	// contains filtered or unexported methods
}

Part is a content part of a Message. The interface is sealed: only Text, ImageURL, ImageData, and ToolResult implement it. Adding new part types is purely additive because the marker method is unexported.

type Provider

type Provider struct {
	ID   string   // short id, e.g. "openrouter"
	NPM  string   // the upstream AI SDK package identifier, e.g. "@ai-sdk/openai-compatible"
	Name string   // human-readable name, e.g. "OpenRouter"
	Env  []string // env-var names this provider reads for credentials, in priority order
	API  string   // base URL, e.g. "https://openrouter.ai/api/v1"; empty if the SDK ships its own default
	Doc  string   // docs URL (may be empty)
	// contains filtered or unexported fields
}

Provider is one catalog provider entry. It carries the metadata needed to pick a wire-protocol implementation and to look up credentials in the process environment.

func (*Provider) Model

func (p *Provider) Model(id string) (*Model, bool)

Model returns the model with the given id, or nil if unknown.

func (*Provider) Models

func (p *Provider) Models() []*Model

Models returns all models for this provider.

func (*Provider) ModelsByFamily

func (p *Provider) ModelsByFamily(family string) []*Model

ModelsByFamily returns models on this provider whose Family matches.

func (*Provider) MustModel

func (p *Provider) MustModel(id string) *Model

MustModel returns the model with the given id, panicking if unknown.

type Reasoning

type Reasoning struct {
	// Effort is a categorical effort level: "low", "medium", "high",
	// "xhigh", etc. Provider-specific values are accepted verbatim.
	Effort string

	// BudgetTokens is the reasoning token budget. Zero means unset.
	// Honored by providers that expose a budget-style control
	// (Anthropic `thinking.budget_tokens`, Gemini `thinking_budget`,
	// DeepSeek `thinking_budget`); ignored by chat-completions-style
	// providers that don't take a budget.
	BudgetTokens int
}

Reasoning configures model reasoning effort/budget.

Each implementation reads only the fields it understands; over-populating is harmless. For chat-completions providers only Effort is honored today (it maps to the upstream `reasoning_effort` parameter).

type ReasoningOption

type ReasoningOption struct {
	Type   ReasoningOptionType
	Values []string // populated when Type == ReasoningEffort
	Min    *int     // populated when Type == ReasoningBudgetTokens
	Max    *int     // populated when Type == ReasoningBudgetTokens (may be nil)
}

ReasoningOption describes a model's reasoning control surface.

type ReasoningOptionType

type ReasoningOptionType string

ReasoningOptionType is the shape of one entry in Model.ReasoningOptions.

const (
	ReasoningEffort       ReasoningOptionType = "effort"
	ReasoningToggle       ReasoningOptionType = "toggle"
	ReasoningBudgetTokens ReasoningOptionType = "budget_tokens"
)

type Request

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

Request is the unit of work sent to a Client. It is built by fluent configuration starting with NewRequest.

Internally, all optional fields are stored as pointers (or sentinel zero values) so we can distinguish "unset" from "set to zero". Externally, callers see only literal setters taking primitive types.

func NewRequest

func NewRequest(model *Model, messages ...Message) *Request

NewRequest begins a fluent request bound to model. Initial messages can be passed positionally.

func (*Request) Assistant

func (r *Request) Assistant(text string) *Request

Assistant appends a plain-text assistant message.

func (*Request) Clone

func (r *Request) Clone() *Request

Clone returns an independent copy of r. Mutations on the clone do not affect the original.

func (*Request) MaxTokens

func (r *Request) MaxTokens(v int) *Request

MaxTokens sets the max output token count.

func (*Request) Message

func (r *Request) Message(msg Message) *Request

Message appends a complete Message to the conversation.

func (*Request) Messages

func (r *Request) Messages() []Message

Messages returns the current message list (a copy).

func (*Request) Model

func (r *Request) Model() *Model

Model returns the bound model.

func (*Request) Reasoning

func (r *Request) Reasoning(r2 Reasoning) *Request

Reasoning sets the reasoning controls.

func (*Request) ResponseFormat

func (r *Request) ResponseFormat(rf *ResponseFormat) *Request

ResponseFormat sets the structured-output format.

func (*Request) Stop

func (r *Request) Stop(seqs ...string) *Request

Stop appends to the stop-sequence list.

func (*Request) System

func (r *Request) System(text string) *Request

System appends a plain-text system message. Equivalent to Message(SystemMessage(text)).

func (*Request) Temperature

func (r *Request) Temperature(v float64) *Request

Temperature sets the sampling temperature.

func (*Request) ToolChoice

func (r *Request) ToolChoice(choice ToolChoice) *Request

ToolChoice sets the tool-choice mode for this request.

func (*Request) Tools

func (r *Request) Tools(tool ...Tool) *Request

Tools appends to the tool list.

func (*Request) TopP

func (r *Request) TopP(v float64) *Request

TopP sets the nucleus sampling parameter.

func (*Request) User

func (r *Request) User(text string) *Request

User appends a plain-text user message.

type Response

type Response struct {
	ID         string
	Model      string
	Message    Message
	StopReason string // "end_turn" | "max_tokens" | "tool_use" | "stop_sequence" | provider-specific
	Usage      Usage
	Raw        any // provider-specific raw payload; nil if the implementation doesn't expose one
}

Response is what Client.Chat returns.

type ResponseFormat

type ResponseFormat struct {
	Type       string      // "json_object" | "json_schema"
	JSONSchema *JSONSchema // required when Type == "json_schema"
}

ResponseFormat asks the model to produce structured output.

Type is "json_object" for unconstrained JSON output, or "json_schema" to constrain by a schema. JSONSchema is required when Type == "json_schema".

type Role

type Role string

Role is the author of a Message.

const (
	RoleSystem    Role = "system"
	RoleUser      Role = "user"
	RoleAssistant Role = "assistant"
	RoleTool      Role = "tool"
)

type Stream

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

Stream is a streaming response. Iterate with Stream.Next, inspect the latest event with Stream.Event, then call Stream.Close. Read errors via Stream.Err.

func (*Stream) Close

func (s *Stream) Close() error

Close releases the stream's underlying resources. Calling Close after Close is a no-op.

func (*Stream) Collect

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

Collect drains the stream into a Response.

func (*Stream) Err

func (s *Stream) Err() error

Err returns the terminal error from the stream, if any.

func (*Stream) Event

func (s *Stream) Event() Event

Event returns the most recent event from the most recent successful Stream.Next call.

func (*Stream) Next

func (s *Stream) Next() bool

Next advances the stream. Returns false when the stream is exhausted or closed. After Next returns false, Stream.Err reports any terminal error.

type Text

type Text struct {
	Value string
}

Text is a plain-text content part.

type Tool

type Tool struct {
	Name        string
	Description string
	Parameters  map[string]any
}

Tool describes one tool the model may call. Parameters is a JSON Schema object; build it manually or with invopop/jsonschema.

type ToolCall

type ToolCall struct {
	ID        string
	Name      string
	Arguments string
}

ToolCall is one tool call emitted by the model. Arguments is a JSON string; json.Unmarshal it to get structured input.

type ToolChoice

type ToolChoice struct {
	Mode ToolChoiceMode
	Name string
}

ToolChoice controls how the model picks tools. Mode is required; Name is only meaningful when Mode == ToolChoiceSpecific.

type ToolChoiceMode

type ToolChoiceMode string

ToolChoiceMode enumerates the tool-selection modes.

const (
	ToolChoiceAuto     ToolChoiceMode = "auto"
	ToolChoiceNone     ToolChoiceMode = "none"
	ToolChoiceRequired ToolChoiceMode = "required"
	ToolChoiceSpecific ToolChoiceMode = "specific"
)

type ToolResult

type ToolResult struct {
	ToolCallID string
	Content    []Part
	IsError    bool
}

ToolResult is one tool result in a Message with role RoleTool.

type Usage

type Usage struct {
	InputTokens      int
	OutputTokens     int
	ReasoningTokens  int
	CacheReadTokens  int
	CacheWriteTokens int
	TotalTokens      int
}

Usage is the model's reported token usage.

Directories

Path Synopsis
cmd
sorus command
Command sorus is a small CLI for talking to any models.dev provider that sorus supports.
Command sorus is a small CLI for talking to any models.dev provider that sorus supports.

Jump to

Keyboard shortcuts

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