provider_options.go

  1// Package openrouter provides an implementation of the fantasy AI SDK for OpenRouter's language models.
  2package openrouter
  3
  4import (
  5	"encoding/json"
  6
  7	"charm.land/fantasy"
  8)
  9
 10// ReasoningEffort represents the reasoning effort level for OpenRouter models.
 11type ReasoningEffort string
 12
 13const (
 14	// ReasoningEffortLow represents low reasoning effort.
 15	ReasoningEffortLow ReasoningEffort = "low"
 16	// ReasoningEffortMedium represents medium reasoning effort.
 17	ReasoningEffortMedium ReasoningEffort = "medium"
 18	// ReasoningEffortHigh represents high reasoning effort.
 19	ReasoningEffortHigh ReasoningEffort = "high"
 20)
 21
 22// Global type identifiers for OpenRouter-specific provider data.
 23const (
 24	TypeProviderOptions  = Name + ".options"
 25	TypeProviderMetadata = Name + ".metadata"
 26)
 27
 28// PromptTokensDetails represents details about prompt tokens for OpenRouter.
 29type PromptTokensDetails struct {
 30	CachedTokens int64
 31}
 32
 33// CompletionTokensDetails represents details about completion tokens for OpenRouter.
 34type CompletionTokensDetails struct {
 35	ReasoningTokens int64
 36}
 37
 38// CostDetails represents cost details for OpenRouter.
 39type CostDetails struct {
 40	UpstreamInferenceCost            float64 `json:"upstream_inference_cost"`
 41	UpstreamInferencePromptCost      float64 `json:"upstream_inference_prompt_cost"`
 42	UpstreamInferenceCompletionsCost float64 `json:"upstream_inference_completions_cost"`
 43}
 44
 45// UsageAccounting represents usage accounting details for OpenRouter.
 46type UsageAccounting struct {
 47	PromptTokens            int64                   `json:"prompt_tokens"`
 48	PromptTokensDetails     PromptTokensDetails     `json:"prompt_tokens_details"`
 49	CompletionTokens        int64                   `json:"completion_tokens"`
 50	CompletionTokensDetails CompletionTokensDetails `json:"completion_tokens_details"`
 51	TotalTokens             int64                   `json:"total_tokens"`
 52	Cost                    float64                 `json:"cost"`
 53	CostDetails             CostDetails             `json:"cost_details"`
 54}
 55
 56// ProviderMetadata represents metadata from OpenRouter provider.
 57type ProviderMetadata struct {
 58	Provider string          `json:"provider"`
 59	Usage    UsageAccounting `json:"usage"`
 60}
 61
 62// Options implements the ProviderOptionsData interface for ProviderMetadata.
 63func (*ProviderMetadata) Options() {}
 64
 65// MarshalJSON implements custom JSON marshaling with type info for ProviderMetadata.
 66func (m ProviderMetadata) MarshalJSON() ([]byte, error) {
 67	type plain ProviderMetadata
 68	raw, err := json.Marshal(plain(m))
 69	if err != nil {
 70		return nil, err
 71	}
 72	return json.Marshal(struct {
 73		Type string          `json:"type"`
 74		Data json.RawMessage `json:"data"`
 75	}{
 76		Type: TypeProviderMetadata,
 77		Data: raw,
 78	})
 79}
 80
 81// UnmarshalJSON implements custom JSON unmarshaling with type info for ProviderMetadata.
 82func (m *ProviderMetadata) UnmarshalJSON(data []byte) error {
 83	type plain ProviderMetadata
 84	var pm plain
 85	err := json.Unmarshal(data, &pm)
 86	if err != nil {
 87		return err
 88	}
 89	*m = ProviderMetadata(pm)
 90	return nil
 91}
 92
 93// ReasoningOptions represents reasoning options for OpenRouter.
 94type ReasoningOptions struct {
 95	// Whether reasoning is enabled
 96	Enabled *bool `json:"enabled,omitempty"`
 97	// Whether to exclude reasoning from the response
 98	Exclude *bool `json:"exclude,omitempty"`
 99	// Maximum number of tokens to use for reasoning
100	MaxTokens *int64 `json:"max_tokens,omitempty"`
101	// Reasoning effort level: "low" | "medium" | "high"
102	Effort *ReasoningEffort `json:"effort,omitempty"`
103}
104
105// Provider represents provider routing preferences for OpenRouter.
106type Provider struct {
107	// List of provider slugs to try in order (e.g. ["anthropic", "openai"])
108	Order []string `json:"order,omitempty"`
109	// Whether to allow backup providers when primary is unavailable (default: true)
110	AllowFallbacks *bool `json:"allow_fallbacks,omitempty"`
111	// Only use providers that support all parameters in your request (default: false)
112	RequireParameters *bool `json:"require_parameters,omitempty"`
113	// Control whether to use providers that may store data: "allow" | "deny"
114	DataCollection *string `json:"data_collection,omitempty"`
115	// List of provider slugs to allow for this request
116	Only []string `json:"only,omitempty"`
117	// List of provider slugs to skip for this request
118	Ignore []string `json:"ignore,omitempty"`
119	// List of quantization levels to filter by (e.g. ["int4", "int8"])
120	Quantizations []string `json:"quantizations,omitempty"`
121	// Sort providers by "price" | "throughput" | "latency"
122	Sort *string `json:"sort,omitempty"`
123}
124
125// ProviderOptions represents additional options for OpenRouter provider.
126type ProviderOptions struct {
127	Reasoning    *ReasoningOptions `json:"reasoning,omitempty"`
128	ExtraBody    map[string]any    `json:"extra_body,omitempty"`
129	IncludeUsage *bool             `json:"include_usage,omitempty"`
130	// Modify the likelihood of specified tokens appearing in the completion.
131	// Accepts a map that maps tokens (specified by their token ID) to an associated bias value from -100 to 100.
132	// The bias is added to the logits generated by the model prior to sampling.
133	LogitBias map[string]int64 `json:"logit_bias,omitempty"`
134	// Return the log probabilities of the tokens. Including logprobs will increase the response size.
135	// Setting to true will return the log probabilities of the tokens that were generated.
136	LogProbs *bool `json:"log_probs,omitempty"`
137	// Whether to enable parallel function calling during tool use. Default to true.
138	ParallelToolCalls *bool `json:"parallel_tool_calls,omitempty"`
139	// A unique identifier representing your end-user, which can help OpenRouter to monitor and detect abuse.
140	User *string `json:"user,omitempty"`
141	// Provider routing preferences to control request routing behavior
142	Provider *Provider `json:"provider,omitempty"`
143	// TODO: add the web search plugin config
144}
145
146// Options implements the ProviderOptionsData interface for ProviderOptions.
147func (*ProviderOptions) Options() {}
148
149// MarshalJSON implements custom JSON marshaling with type info for ProviderOptions.
150func (o ProviderOptions) MarshalJSON() ([]byte, error) {
151	type plain ProviderOptions
152	raw, err := json.Marshal(plain(o))
153	if err != nil {
154		return nil, err
155	}
156	return json.Marshal(struct {
157		Type string          `json:"type"`
158		Data json.RawMessage `json:"data"`
159	}{
160		Type: TypeProviderOptions,
161		Data: raw,
162	})
163}
164
165// UnmarshalJSON implements custom JSON unmarshaling with type info for ProviderOptions.
166func (o *ProviderOptions) UnmarshalJSON(data []byte) error {
167	type plain ProviderOptions
168	var oo plain
169	err := json.Unmarshal(data, &oo)
170	if err != nil {
171		return err
172	}
173	*o = ProviderOptions(oo)
174	return nil
175}
176
177// ReasoningDetail represents a reasoning detail for OpenRouter.
178type ReasoningDetail struct {
179	ID        string `json:"id,omitempty"`
180	Type      string `json:"type,omitempty"`
181	Text      string `json:"text,omitempty"`
182	Data      string `json:"data,omitempty"`
183	Format    string `json:"format,omitempty"`
184	Summary   string `json:"summary,omitempty"`
185	Signature string `json:"signature,omitempty"`
186	Index     int    `json:"index"`
187}
188
189// ReasoningData represents reasoning data for OpenRouter.
190type ReasoningData struct {
191	Reasoning        string            `json:"reasoning"`
192	ReasoningDetails []ReasoningDetail `json:"reasoning_details"`
193}
194
195// ReasoningEffortOption creates a pointer to a ReasoningEffort value for OpenRouter.
196func ReasoningEffortOption(e ReasoningEffort) *ReasoningEffort {
197	return &e
198}
199
200// NewProviderOptions creates new provider options for OpenRouter.
201func NewProviderOptions(opts *ProviderOptions) fantasy.ProviderOptions {
202	return fantasy.ProviderOptions{
203		Name: opts,
204	}
205}
206
207// ParseOptions parses provider options from a map for OpenRouter.
208func ParseOptions(data map[string]any) (*ProviderOptions, error) {
209	var options ProviderOptions
210	if err := fantasy.ParseOptions(data, &options); err != nil {
211		return nil, err
212	}
213	return &options, nil
214}
215
216// Register OpenRouter provider-specific types with the global registry.
217func init() {
218	fantasy.RegisterProviderType(TypeProviderOptions, func(data []byte) (fantasy.ProviderOptionsData, error) {
219		var v ProviderOptions
220		if err := json.Unmarshal(data, &v); err != nil {
221			return nil, err
222		}
223		return &v, nil
224	})
225	fantasy.RegisterProviderType(TypeProviderMetadata, func(data []byte) (fantasy.ProviderOptionsData, error) {
226		var v ProviderMetadata
227		if err := json.Unmarshal(data, &v); err != nil {
228			return nil, err
229		}
230		return &v, nil
231	})
232}