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 openai.WithLanguageModelToPromptFunc(languageModelToPrompt),
41 },
42 }
43 for _, o := range opts {
44 o(&providerOptions)
45 }
46
47 providerOptions.openaiOptions = append(providerOptions.openaiOptions, openai.WithLanguageModelOptions(providerOptions.languageModelOptions...))
48 return openai.New(providerOptions.openaiOptions...)
49}
50
51// WithAPIKey sets the API key for the OpenRouter provider.
52func WithAPIKey(apiKey string) Option {
53 return func(o *options) {
54 o.openaiOptions = append(o.openaiOptions, openai.WithAPIKey(apiKey))
55 }
56}
57
58// WithName sets the name for the OpenRouter provider.
59func WithName(name string) Option {
60 return func(o *options) {
61 o.openaiOptions = append(o.openaiOptions, openai.WithName(name))
62 }
63}
64
65// WithHeaders sets the headers for the OpenRouter provider.
66func WithHeaders(headers map[string]string) Option {
67 return func(o *options) {
68 o.openaiOptions = append(o.openaiOptions, openai.WithHeaders(headers))
69 }
70}
71
72// WithHTTPClient sets the HTTP client for the OpenRouter provider.
73func WithHTTPClient(client option.HTTPClient) Option {
74 return func(o *options) {
75 o.openaiOptions = append(o.openaiOptions, openai.WithHTTPClient(client))
76 }
77}
78
79func structToMapJSON(s any) (map[string]any, error) {
80 var result map[string]any
81 jsonBytes, err := json.Marshal(s)
82 if err != nil {
83 return nil, err
84 }
85 err = json.Unmarshal(jsonBytes, &result)
86 if err != nil {
87 return nil, err
88 }
89 return result, nil
90}