manifest
Version:
Self-hosted Manifest LLM router with embedded server, SQLite database, and dashboard
309 lines • 15.2 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var ModelDiscoveryService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModelDiscoveryService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const user_provider_entity_1 = require("../entities/user-provider.entity");
const custom_provider_entity_1 = require("../entities/custom-provider.entity");
const provider_model_fetcher_service_1 = require("./provider-model-fetcher.service");
const provider_model_registry_service_1 = require("./provider-model-registry.service");
const crypto_util_1 = require("../common/utils/crypto.util");
const quality_score_util_1 = require("../database/quality-score.util");
const pricing_sync_service_1 = require("../database/pricing-sync.service");
const models_dev_sync_service_1 = require("../database/models-dev-sync.service");
const openai_oauth_types_1 = require("../routing/oauth/openai-oauth.types");
const qwen_region_1 = require("../routing/qwen-region");
const copilot_token_service_1 = require("../routing/proxy/copilot-token.service");
const anthropic_subscription_probe_1 = require("./anthropic-subscription-probe");
const model_fallback_1 = require("./model-fallback");
const known_model_prices_1 = require("./known-model-prices");
const customProviderKey = (id) => `custom:${id}`;
const customModelKey = (id, modelName) => `custom:${id}/${modelName}`;
function isQwenProvider(providerId) {
const lower = providerId.toLowerCase();
return lower === 'qwen' || lower === 'alibaba';
}
let ModelDiscoveryService = ModelDiscoveryService_1 = class ModelDiscoveryService {
providerRepo;
customProviderRepo;
fetcher;
pricingSync;
modelsDevSync;
modelRegistry;
copilotTokenService;
logger = new common_1.Logger(ModelDiscoveryService_1.name);
constructor(providerRepo, customProviderRepo, fetcher, pricingSync, modelsDevSync, modelRegistry, copilotTokenService) {
this.providerRepo = providerRepo;
this.customProviderRepo = customProviderRepo;
this.fetcher = fetcher;
this.pricingSync = pricingSync;
this.modelsDevSync = modelsDevSync;
this.modelRegistry = modelRegistry;
this.copilotTokenService = copilotTokenService;
}
async discoverModels(provider) {
let apiKey = '';
let endpointOverride;
const lowerProvider = provider.provider.toLowerCase();
if (provider.api_key_encrypted) {
try {
apiKey = (0, crypto_util_1.decrypt)(provider.api_key_encrypted, (0, crypto_util_1.getEncryptionSecret)());
}
catch {
this.logger.warn(`Failed to decrypt key for provider ${provider.provider}`);
return [];
}
}
if (provider.auth_type === 'subscription' && apiKey) {
if (lowerProvider === 'openai' || lowerProvider === 'minimax') {
const blob = (0, openai_oauth_types_1.parseOAuthTokenBlob)(apiKey);
if (blob?.t) {
apiKey = blob.t;
if (lowerProvider === 'minimax' && blob.u) {
endpointOverride = blob.u;
}
}
}
else if (lowerProvider === 'copilot' && this.copilotTokenService) {
try {
apiKey = await this.copilotTokenService.getCopilotToken(apiKey);
}
catch {
this.logger.warn('Copilot token exchange failed for model discovery — falling back to known models');
apiKey = '';
}
}
}
if (isQwenProvider(provider.provider) && (0, qwen_region_1.isQwenResolvedRegion)(provider.region)) {
endpointOverride = (0, qwen_region_1.getQwenCompatibleBaseUrl)(provider.region);
}
let raw;
if (provider.auth_type === 'subscription' && !apiKey) {
raw = (0, model_fallback_1.buildSubscriptionFallbackModels)(this.pricingSync, provider.provider);
if (raw.length > 0) {
this.logger.log(`No token for subscription provider ${provider.provider} — using ${raw.length} fallback models`);
}
}
else {
raw = await this.fetcher.fetch(provider.provider, apiKey, provider.auth_type, endpointOverride);
if (raw.length > 0 && this.modelRegistry) {
this.modelRegistry.registerModels(provider.provider, raw.map((m) => m.id));
}
if (raw.length === 0) {
raw = (0, model_fallback_1.buildModelsDevFallback)(this.modelsDevSync, provider.provider);
if (raw.length > 0) {
this.logger.log(`Native API returned 0 models for ${provider.provider} — using ${raw.length} models from models.dev`);
}
}
if (raw.length === 0 && !isQwenProvider(provider.provider)) {
const confirmed = this.modelRegistry?.getConfirmedModels(provider.provider) ?? null;
raw = (0, model_fallback_1.buildFallbackModels)(this.pricingSync, provider.provider, confirmed);
if (raw.length > 0) {
this.logger.log(`No models.dev data for ${provider.provider} — using ${raw.length} models from OpenRouter`);
}
}
}
if (provider.auth_type === 'subscription') {
raw = (0, model_fallback_1.supplementWithKnownModels)(raw, provider.provider);
}
if (lowerProvider === 'anthropic' && provider.auth_type === 'subscription' && apiKey) {
raw = await (0, anthropic_subscription_probe_1.filterBySubscriptionAccess)(raw, apiKey);
}
const authType = provider.auth_type === 'subscription' ? 'subscription' : 'api_key';
const enriched = raw.map((model) => ({
...this.enrichModel(model, provider.provider),
authType: authType,
}));
const filtered = enriched.filter((model) => {
const mdEntry = this.modelsDevSync?.lookupModel(provider.provider, model.id);
if (mdEntry && mdEntry.toolCall === false)
return false;
return true;
});
provider.cached_models = filtered;
provider.models_fetched_at = new Date().toISOString();
await this.providerRepo.save(provider);
this.logger.log(`Discovered ${filtered.length} models for provider ${provider.provider} (agent ${provider.agent_id})`);
return filtered;
}
async discoverAllForAgent(agentId) {
const providers = await this.providerRepo.find({
where: { agent_id: agentId, is_active: true },
});
await Promise.all(providers
.filter((p) => !p.provider.startsWith('custom:'))
.map((p) => this.discoverModels(p).catch((err) => {
this.logger.warn(`Discovery failed for ${p.provider}: ${err}`);
})));
}
async getModelsForAgent(agentId) {
const providers = await this.providerRepo.find({
where: { agent_id: agentId, is_active: true },
});
const models = [];
const seen = new Map();
for (const p of providers) {
if (p.provider.startsWith('custom:'))
continue;
const cached = p.cached_models;
if (!Array.isArray(cached))
continue;
const providerAuthType = p.auth_type === 'subscription' ? 'subscription' : 'api_key';
for (const m of cached) {
const effectiveAuthType = m.authType ?? providerAuthType;
const dedupeKey = `${m.id}::${effectiveAuthType}`;
if (!seen.has(dedupeKey)) {
seen.set(dedupeKey, models.length);
models.push({ ...m, authType: effectiveAuthType });
}
}
}
const customProviders = await this.customProviderRepo.find({
where: { agent_id: agentId },
});
for (const cp of customProviders) {
if (!Array.isArray(cp.models))
continue;
const cpKey = customProviderKey(cp.id);
for (const m of cp.models) {
const modelKey = customModelKey(cp.id, m.model_name);
if (seen.has(modelKey))
continue;
seen.set(modelKey, models.length);
const inputPerToken = m.input_price_per_million_tokens != null
? m.input_price_per_million_tokens / 1_000_000
: null;
const outputPerToken = m.output_price_per_million_tokens != null
? m.output_price_per_million_tokens / 1_000_000
: null;
models.push({
id: modelKey,
displayName: m.model_name,
provider: cpKey,
contextWindow: m.context_window ?? 128000,
inputPricePerToken: inputPerToken,
outputPricePerToken: outputPerToken,
capabilityReasoning: false,
capabilityCode: false,
qualityScore: 2,
});
}
}
return models;
}
async getModelForAgent(agentId, modelName) {
const all = await this.getModelsForAgent(agentId);
return all.find((m) => m.id === modelName);
}
enrichModel(model, providerId) {
if (model.inputPricePerToken !== null &&
model.inputPricePerToken >= 0 &&
model.outputPricePerToken !== null &&
model.outputPricePerToken >= 0) {
return this.computeScore(this.applyCapabilities(model, providerId));
}
if (this.modelsDevSync) {
const mdEntry = this.modelsDevSync.lookupModel(providerId, model.id);
if (mdEntry && mdEntry.inputPricePerToken !== null) {
return this.computeScore({
...model,
inputPricePerToken: mdEntry.inputPricePerToken,
outputPricePerToken: mdEntry.outputPricePerToken,
contextWindow: mdEntry.contextWindow ?? model.contextWindow,
displayName: mdEntry.name || model.displayName,
capabilityReasoning: mdEntry.reasoning ?? model.capabilityReasoning,
capabilityCode: mdEntry.toolCall ?? model.capabilityCode,
});
}
}
if (this.pricingSync) {
const orPrefix = (0, model_fallback_1.findOpenRouterPrefix)(providerId);
if (orPrefix) {
const orPricing = (0, model_fallback_1.lookupWithVariants)(this.pricingSync, orPrefix, model.id);
if (orPricing) {
return this.computeScore({
...model,
inputPricePerToken: orPricing.input,
outputPricePerToken: orPricing.output,
contextWindow: orPricing.contextWindow ?? model.contextWindow,
displayName: orPricing.displayName || model.displayName,
});
}
}
const exactPricing = this.pricingSync.lookupPricing(model.id);
if (exactPricing) {
return this.computeScore({
...model,
inputPricePerToken: exactPricing.input,
outputPricePerToken: exactPricing.output,
contextWindow: exactPricing.contextWindow ?? model.contextWindow,
displayName: exactPricing.displayName || model.displayName,
});
}
}
const known = (0, known_model_prices_1.lookupKnownPrice)(model.id);
if (known) {
return this.computeScore({
...model,
inputPricePerToken: known.input,
outputPricePerToken: known.output,
});
}
return this.computeScore(model);
}
applyCapabilities(model, providerId) {
if (!this.modelsDevSync)
return model;
const mdEntry = this.modelsDevSync.lookupModel(providerId, model.id);
if (!mdEntry)
return model;
return {
...model,
capabilityReasoning: mdEntry.reasoning ?? model.capabilityReasoning,
capabilityCode: mdEntry.toolCall ?? model.capabilityCode,
};
}
computeScore(model) {
const score = (0, quality_score_util_1.computeQualityScore)({
model_name: model.id,
input_price_per_token: model.inputPricePerToken,
output_price_per_token: model.outputPricePerToken,
capability_reasoning: model.capabilityReasoning,
capability_code: model.capabilityCode,
context_window: model.contextWindow,
});
return { ...model, qualityScore: score };
}
};
exports.ModelDiscoveryService = ModelDiscoveryService;
exports.ModelDiscoveryService = ModelDiscoveryService = ModelDiscoveryService_1 = __decorate([
(0, common_1.Injectable)(),
__param(0, (0, typeorm_1.InjectRepository)(user_provider_entity_1.UserProvider)),
__param(1, (0, typeorm_1.InjectRepository)(custom_provider_entity_1.CustomProvider)),
__param(3, (0, common_1.Optional)()),
__param(3, (0, common_1.Inject)(pricing_sync_service_1.PricingSyncService)),
__param(4, (0, common_1.Optional)()),
__param(4, (0, common_1.Inject)(models_dev_sync_service_1.ModelsDevSyncService)),
__param(5, (0, common_1.Optional)()),
__param(5, (0, common_1.Inject)(provider_model_registry_service_1.ProviderModelRegistryService)),
__param(6, (0, common_1.Optional)()),
__param(6, (0, common_1.Inject)(copilot_token_service_1.CopilotTokenService)),
__metadata("design:paramtypes", [typeorm_2.Repository,
typeorm_2.Repository,
provider_model_fetcher_service_1.ProviderModelFetcherService, Object, Object, Object, Object])
], ModelDiscoveryService);
//# sourceMappingURL=model-discovery.service.js.map