openrouter.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	"charm.land/fantasy/providers/openai"
 9	"github.com/openai/openai-go/v2/option"
10)
11
12type options struct {
13	openaiOptions        []openai.Option
14	languageModelOptions []openai.LanguageModelOption
15}
16
17const (
18	// DefaultURL is the default URL for the OpenRouter API.
19	DefaultURL = "https://openrouter.ai/api/v1"
20	// Name is the name of the OpenRouter provider.
21	Name = "openrouter"
22)
23
24// Option defines a function that configures OpenRouter provider options.
25type Option = func(*options)
26
27// New creates a new OpenRouter provider with the given options.
28func New(opts ...Option) fantasy.Provider {
29	providerOptions := options{
30		openaiOptions: []openai.Option{
31			openai.WithName(Name),
32			openai.WithBaseURL(DefaultURL),
33		},
34		languageModelOptions: []openai.LanguageModelOption{
35			openai.WithLanguageModelPrepareCallFunc(languagePrepareModelCall),
36			openai.WithLanguageModelUsageFunc(languageModelUsage),
37			openai.WithLanguageModelStreamUsageFunc(languageModelStreamUsage),
38			openai.WithLanguageModelStreamExtraFunc(languageModelStreamExtra),
39			openai.WithLanguageModelExtraContentFunc(languageModelExtraContent),
40		},
41	}
42	for _, o := range opts {
43		o(&providerOptions)
44	}
45
46	providerOptions.openaiOptions = append(providerOptions.openaiOptions, openai.WithLanguageModelOptions(providerOptions.languageModelOptions...))
47	return openai.New(providerOptions.openaiOptions...)
48}
49
50// WithAPIKey sets the API key for the OpenRouter provider.
51func WithAPIKey(apiKey string) Option {
52	return func(o *options) {
53		o.openaiOptions = append(o.openaiOptions, openai.WithAPIKey(apiKey))
54	}
55}
56
57// WithName sets the name for the OpenRouter provider.
58func WithName(name string) Option {
59	return func(o *options) {
60		o.openaiOptions = append(o.openaiOptions, openai.WithName(name))
61	}
62}
63
64// WithHeaders sets the headers for the OpenRouter provider.
65func WithHeaders(headers map[string]string) Option {
66	return func(o *options) {
67		o.openaiOptions = append(o.openaiOptions, openai.WithHeaders(headers))
68	}
69}
70
71// WithHTTPClient sets the HTTP client for the OpenRouter provider.
72func WithHTTPClient(client option.HTTPClient) Option {
73	return func(o *options) {
74		o.openaiOptions = append(o.openaiOptions, openai.WithHTTPClient(client))
75	}
76}
77
78func structToMapJSON(s any) (map[string]any, error) {
79	var result map[string]any
80	jsonBytes, err := json.Marshal(s)
81	if err != nil {
82		return nil, err
83	}
84	err = json.Unmarshal(jsonBytes, &result)
85	if err != nil {
86		return nil, err
87	}
88	return result, nil
89}