| 50 | } |
| 51 | |
| 52 | export class AskSageApi implements BaseLlmApi { |
| 53 | private apiBase: string; |
| 54 | private userApiUrl: string; |
| 55 | private apiKey?: string; |
| 56 | private email?: string; |
| 57 | private sessionTokenPromise: Promise<string> | null = null; |
| 58 | private tokenTimestamp: number = 0; |
| 59 | private fetchFn: typeof fetch; |
| 60 | |
| 61 | constructor(private config: AskSageConfig) { |
| 62 | this.apiBase = config.apiBase ?? DEFAULT_API_URL; |
| 63 | this.userApiUrl = config.env?.userApiUrl ?? DEFAULT_USER_API_URL; |
| 64 | this.apiKey = config.apiKey; |
| 65 | this.email = config.env?.email; |
| 66 | this.fetchFn = customFetch(config.requestOptions); |
| 67 | } |
| 68 | |
| 69 | /** |
| 70 | * Get session token from API key + email, or use API key directly |
| 71 | */ |
| 72 | private async getSessionToken(): Promise<string> { |
| 73 | if (!this.apiKey) { |
| 74 | throw new Error( |
| 75 | "AskSage adapter: missing apiKey. Provide it in your configuration.", |
| 76 | ); |
| 77 | } |
| 78 | |
| 79 | // If no email, use API key directly |
| 80 | if (!this.email || this.email.length === 0) { |
| 81 | return this.apiKey; |
| 82 | } |
| 83 | |
| 84 | const url = this.userApiUrl.replace(/\/$/, "") + "/get-token-with-api-key"; |
| 85 | const res = await this.fetchFn(url, { |
| 86 | method: "POST", |
| 87 | headers: { "Content-Type": "application/json" }, |
| 88 | body: JSON.stringify({ email: this.email, api_key: this.apiKey }), |
| 89 | }); |
| 90 | |
| 91 | const data = (await res.json()) as AskSageTokenResponse; |
| 92 | if (parseInt(String(data.status)) !== 200) { |
| 93 | throw new Error("Error getting access token: " + JSON.stringify(data)); |
| 94 | } |
| 95 | return data.response.access_token; |
| 96 | } |
| 97 | |
| 98 | /** |
| 99 | * Get cached token or refresh if expired |
| 100 | */ |
| 101 | private async getToken(): Promise<string> { |
| 102 | if ( |
| 103 | !this.sessionTokenPromise || |
| 104 | Date.now() - this.tokenTimestamp > TOKEN_TTL |
| 105 | ) { |
| 106 | this.sessionTokenPromise = this.getSessionToken(); |
| 107 | this.tokenTimestamp = Date.now(); |
| 108 | // Clear cache on failure so transient errors don't prevent retries |
| 109 | this.sessionTokenPromise.catch(() => { |
nothing calls this directly
no outgoing calls
no test coverage detected