capsule-ai-cli
Version:
The AI Model Orchestrator - Intelligent multi-model workflows with device-locked licensing
104 lines • 4.42 kB
JavaScript
import { BaseProvider } from './base.js';
import { authService } from '../services/auth.js';
import { analyticsService } from '../services/analytics.js';
import chalk from 'chalk';
export class ManagedProvider extends BaseProvider {
name;
models = [];
supportsStreaming = true;
supportsTools = true;
userProvider;
capsuleProvider;
providerName;
constructor(providerName, userProvider, capsuleProvider) {
super('managed', undefined);
this.providerName = providerName;
this.name = providerName;
this.userProvider = userProvider;
this.capsuleProvider = capsuleProvider;
if (userProvider) {
this.models = userProvider.models;
this.supportsStreaming = userProvider.supportsStreaming;
this.supportsTools = userProvider.supportsTools;
}
else if (capsuleProvider) {
this.models = capsuleProvider.models;
this.supportsStreaming = capsuleProvider.supportsStreaming;
this.supportsTools = capsuleProvider.supportsTools;
}
}
async complete(messages, options) {
const auth = await authService.getStatus();
if (auth.tier === 'super' && auth.remainingRUs && auth.remainingRUs > 0 && this.capsuleProvider) {
try {
console.log(chalk.gray(`Using Capsule managed API (${auth.remainingRUs} RUs remaining)`));
const response = await this.capsuleProvider.complete(messages, options);
await authService.deductRUs(response.usage);
const cost = this.calculateCost(response.usage);
await analyticsService.trackCompletion(this.providerName, options?.model || this.models[0], response.usage, cost);
return response;
}
catch (error) {
if (error.message.includes('Insufficient RUs') || error.message.includes('402')) {
console.log(chalk.yellow('RUs exhausted, falling back to your API keys...'));
}
else {
throw error;
}
}
}
if (!this.userProvider) {
throw new Error(`Please provide your ${this.providerName} API key:\n` +
`capsule config set providers.${this.providerName}.apiKey YOUR_KEY`);
}
const response = await this.userProvider.complete(messages, options);
const cost = this.calculateCost(response.usage);
await analyticsService.trackCompletion(this.providerName, options?.model || this.models[0], response.usage, cost);
return response;
}
async *stream(messages, options) {
const auth = await authService.getStatus();
if (auth.tier === 'super' && auth.remainingRUs && auth.remainingRUs > 0 && this.capsuleProvider) {
try {
console.log(chalk.gray(`Using Capsule managed API (${auth.remainingRUs} RUs remaining)`));
let totalTokens = 0;
for await (const chunk of this.capsuleProvider.stream(messages, options)) {
totalTokens += chunk.usage?.totalTokens || 0;
yield chunk;
}
await authService.deductRUs({ totalTokens });
return;
}
catch (error) {
if (error.message.includes('Insufficient RUs') || error.message.includes('402')) {
console.log(chalk.yellow('RUs exhausted, falling back to your API keys...'));
}
else {
throw error;
}
}
}
if (!this.userProvider) {
throw new Error(`Please provide your ${this.providerName} API key:\n` +
`capsule config set providers.${this.providerName}.apiKey YOUR_KEY`);
}
yield* this.userProvider.stream(messages, options);
}
calculateCost(usage, model) {
if (this.userProvider) {
return this.userProvider.calculateCost(usage, model);
}
else if (this.capsuleProvider) {
return this.capsuleProvider.calculateCost(usage, model);
}
return {
amount: 0,
currency: 'USD',
breakdown: {
prompt: 0,
completion: 0
}
};
}
}
//# sourceMappingURL=managed.js.map