1- import OpenAI from 'openai ' ;
1+ import axios from 'axios ' ;
22import { BaseProvider , ProviderResponse } from './base' ;
33import { ProviderConfig } from '../types' ;
44
55export class OpenRouterProvider extends BaseProvider {
6- private client : OpenAI ;
6+ private baseURL : string ;
77
88 constructor ( config : ProviderConfig ) {
99 super ( config ) ;
10- this . client = new OpenAI ( {
11- apiKey : config . apiKey ,
12- baseURL : config . baseURL || 'https://openrouter.ai/api/v1' ,
13- defaultHeaders : {
14- 'HTTP-Referer' : 'https://github.com/tuneprompt/tuneprompt' ,
15- 'X-Title' : 'TunePrompt'
16- }
17- } ) ;
10+ this . baseURL = config . baseURL || 'https://openrouter.ai/api/v1' ;
1811 }
1912
2013 async complete ( prompt : string | { system ?: string ; user : string } ) : Promise < ProviderResponse > {
@@ -29,34 +22,70 @@ export class OpenRouterProvider extends BaseProvider {
2922 messages . push ( { role : 'user' , content : prompt . user } ) ;
3023 }
3124
32- const response = await this . client . chat . completions . create ( {
33- model : this . config . model ,
34- messages,
35- max_tokens : this . config . maxTokens ,
36- temperature : this . config . temperature
37- } ) ;
38-
39- const content = response . choices [ 0 ] ?. message ?. content || '' ;
40- const tokens = response . usage ?. total_tokens ;
41-
42- return {
43- content,
44- tokens,
45- // OpenRouter costs vary wildly by model, hard to calc locally without metadata
46- // For now, we'll return 0 or implement a lookup table later
47- cost : 0
48- } ;
25+ try {
26+ const response = await axios . post (
27+ `${ this . baseURL } /chat/completions` ,
28+ {
29+ model : this . config . model ,
30+ messages,
31+ max_tokens : this . config . maxTokens ,
32+ temperature : this . config . temperature
33+ } ,
34+ {
35+ headers : {
36+ 'Authorization' : `Bearer ${ this . config . apiKey } ` ,
37+ 'HTTP-Referer' : 'https://github.com/tuneprompt/tuneprompt' ,
38+ 'X-Title' : 'TunePrompt' ,
39+ 'Content-Type' : 'application/json'
40+ }
41+ }
42+ ) ;
43+
44+ const data = response . data ;
45+ const content = data . choices ?. [ 0 ] ?. message ?. content || '' ;
46+ const tokens = data . usage ?. total_tokens || 0 ;
47+
48+ return {
49+ content,
50+ tokens,
51+ cost : 0
52+ } ;
53+ } catch ( error : any ) {
54+ if ( error . response ) {
55+ const errorMsg = error . response . data ?. error ?. message || JSON . stringify ( error . response . data ) ;
56+ throw new Error ( `OpenRouter API Error (${ error . response . status } ): ${ errorMsg } ` ) ;
57+ }
58+ throw new Error ( `OpenRouter network error: ${ error . message } ` ) ;
59+ }
4960 }
5061
5162 async getEmbedding ( text : string ) : Promise < number [ ] > {
52- // OpenRouter does support embeddings for some models, but the endpoint might differ or require specific models
53- // We'll attempt to use the standard OpenAI-compatible embedding endpoint
54- // Users should ensure they select an embedding-capable model in their config if they use this
55- const response = await this . client . embeddings . create ( {
56- model : 'text-embedding-3-small' , // This likely won't work on OR unless they proxy it to OpenAI or have a mapped model
57- input : text
58- } ) ;
59-
60- return response . data [ 0 ] . embedding ;
63+ try {
64+ // Attempt to use OpenRouter's embedding endpoint (which proxies to OpenAI or others)
65+ // Note: User must be entitled to use the requested embedding model
66+ const response = await axios . post (
67+ `${ this . baseURL } /embeddings` ,
68+ {
69+ model : 'text-embedding-3-small' , // Default fallback, customizable in future
70+ input : text
71+ } ,
72+ {
73+ headers : {
74+ 'Authorization' : `Bearer ${ this . config . apiKey } ` ,
75+ 'HTTP-Referer' : 'https://github.com/tuneprompt/tuneprompt' ,
76+ 'X-Title' : 'TunePrompt' ,
77+ 'Content-Type' : 'application/json'
78+ }
79+ }
80+ ) ;
81+
82+ return response . data . data [ 0 ] . embedding ;
83+ } catch ( error : any ) {
84+ if ( error . response ) {
85+ const errorMsg = error . response . data ?. error ?. message || JSON . stringify ( error . response . data ) ;
86+ throw new Error ( `OpenRouter Embedding Error (${ error . response . status } ): ${ errorMsg } ` ) ;
87+ }
88+ throw new Error ( `OpenRouter embedding network error: ${ error . message } ` ) ;
89+ }
6190 }
6291}
0 commit comments