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}
14
15const (
16 DefaultURL = "https://openrouter.ai/api/v1"
17 Name = "openrouter"
18)
19
20type Option = func(*options)
21
22func New(opts ...Option) ai.Provider {
23 providerOptions := options{
24 openaiOptions: []openai.Option{
25 openai.WithName(Name),
26 openai.WithBaseURL(DefaultURL),
27 openai.WithLanguageModelOptions(
28 openai.WithLanguageModelPrepareCallFunc(languagePrepareModelCall),
29 openai.WithLanguageModelUsageFunc(languageModelUsage),
30 openai.WithLanguageModelStreamUsageFunc(languageModelStreamUsage),
31 openai.WithLanguageModelStreamExtraFunc(languageModelStreamExtra),
32 openai.WithLanguageModelExtraContentFunc(languageModelExtraContent),
33 openai.WithLanguageModelMapFinishReasonFunc(languageModelMapFinishReason),
34 ),
35 },
36 }
37 for _, o := range opts {
38 o(&providerOptions)
39 }
40 return openai.New(providerOptions.openaiOptions...)
41}
42
43func WithAPIKey(apiKey string) Option {
44 return func(o *options) {
45 o.openaiOptions = append(o.openaiOptions, openai.WithAPIKey(apiKey))
46 }
47}
48
49func WithName(name string) Option {
50 return func(o *options) {
51 o.openaiOptions = append(o.openaiOptions, openai.WithName(name))
52 }
53}
54
55func WithHeaders(headers map[string]string) Option {
56 return func(o *options) {
57 o.openaiOptions = append(o.openaiOptions, openai.WithHeaders(headers))
58 }
59}
60
61func WithHTTPClient(client option.HTTPClient) Option {
62 return func(o *options) {
63 o.openaiOptions = append(o.openaiOptions, openai.WithHTTPClient(client))
64 }
65}
66
67func structToMapJSON(s any) (map[string]any, error) {
68 var result map[string]any
69 jsonBytes, err := json.Marshal(s)
70 if err != nil {
71 return nil, err
72 }
73 err = json.Unmarshal(jsonBytes, &result)
74 if err != nil {
75 return nil, err
76 }
77 return result, nil
78}