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}