1package openrouter
2
3import (
4 "encoding/json"
5
6 "github.com/charmbracelet/fantasy/ai"
7 "github.com/charmbracelet/fantasy/openai"
8 "github.com/openai/openai-go/v2/option"
9)
10
11type options struct {
12 openaiOptions []openai.Option
13 languageModelOptions []openai.LanguageModelOption
14}
15
16const (
17 DefaultURL = "https://openrouter.ai/api/v1"
18 Name = "openrouter"
19)
20
21type Option = func(*options)
22
23func New(opts ...Option) ai.Provider {
24 providerOptions := options{
25 openaiOptions: []openai.Option{
26 openai.WithName(Name),
27 openai.WithBaseURL(DefaultURL),
28 },
29 languageModelOptions: []openai.LanguageModelOption{
30 openai.WithLanguageModelPrepareCallFunc(languagePrepareModelCall),
31 openai.WithLanguageModelUsageFunc(languageModelUsage),
32 openai.WithLanguageModelStreamUsageFunc(languageModelStreamUsage),
33 openai.WithLanguageModelStreamExtraFunc(languageModelStreamExtra),
34 openai.WithLanguageModelExtraContentFunc(languageModelExtraContent),
35 openai.WithLanguageModelMapFinishReasonFunc(languageModelMapFinishReason),
36 },
37 }
38 for _, o := range opts {
39 o(&providerOptions)
40 }
41
42 providerOptions.openaiOptions = append(providerOptions.openaiOptions, openai.WithLanguageModelOptions(providerOptions.languageModelOptions...))
43 return openai.New(providerOptions.openaiOptions...)
44}
45
46func WithAPIKey(apiKey string) Option {
47 return func(o *options) {
48 o.openaiOptions = append(o.openaiOptions, openai.WithAPIKey(apiKey))
49 }
50}
51
52func WithName(name string) Option {
53 return func(o *options) {
54 o.openaiOptions = append(o.openaiOptions, openai.WithName(name))
55 }
56}
57
58func WithHeaders(headers map[string]string) Option {
59 return func(o *options) {
60 o.openaiOptions = append(o.openaiOptions, openai.WithHeaders(headers))
61 }
62}
63
64func WithHTTPClient(client option.HTTPClient) Option {
65 return func(o *options) {
66 o.openaiOptions = append(o.openaiOptions, openai.WithHTTPClient(client))
67 }
68}
69
70func WithLanguageUniqueToolCallIds() Option {
71 return func(l *options) {
72 l.languageModelOptions = append(l.languageModelOptions, openai.WithLanguageUniqueToolCallIds())
73 }
74}
75
76func WithLanguageModelGenerateIDFunc(fn openai.LanguageModelGenerateIDFunc) Option {
77 return func(l *options) {
78 l.languageModelOptions = append(l.languageModelOptions, openai.WithLanguageModelGenerateIDFunc(fn))
79 }
80}
81
82func structToMapJSON(s any) (map[string]any, error) {
83 var result map[string]any
84 jsonBytes, err := json.Marshal(s)
85 if err != nil {
86 return nil, err
87 }
88 err = json.Unmarshal(jsonBytes, &result)
89 if err != nil {
90 return nil, err
91 }
92 return result, nil
93}