manifest 5.20.0 → 5.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/backend/analytics/services/aggregation.service.js +18 -18
- package/dist/backend/auth/auth.instance.js +1 -1
- package/dist/backend/common/utils/period.util.js +26 -1
- package/dist/backend/database/database-seeder.service.js +4 -20
- package/dist/backend/database/database.module.js +13 -0
- package/dist/backend/database/local-bootstrap.service.js +24 -40
- package/dist/backend/database/migrations/1771800000000-AddQualityScore.js +2 -2
- package/dist/backend/database/migrations/1771800100000-SeedQualityScores.js +2 -2
- package/dist/backend/database/migrations/1772668898071-AddCustomProviders.js +31 -0
- package/dist/backend/database/migrations/1772682112419-NullablePricing.js +17 -0
- package/dist/backend/database/migrations/1772843035514-AddPerformanceIndexes.js +56 -0
- package/dist/backend/database/pricing-sync.service.js +26 -0
- package/dist/backend/database/quality-score.util.js +5 -4
- package/dist/backend/database/seed-messages.js +13 -3
- package/dist/backend/entities/agent-message.entity.js +4 -1
- package/dist/backend/entities/cost-snapshot.entity.js +2 -1
- package/dist/backend/entities/custom-provider.entity.js +64 -0
- package/dist/backend/entities/model-pricing.entity.js +4 -4
- package/dist/backend/entities/security-event.entity.js +2 -1
- package/dist/backend/entities/user-provider.entity.js +5 -0
- package/dist/backend/health/health.controller.js +3 -5
- package/dist/backend/main.js +3 -8
- package/dist/backend/model-prices/model-name-normalizer.js +5 -5
- package/dist/backend/model-prices/model-prices.service.js +2 -2
- package/dist/backend/model-prices/model-pricing-cache.service.js +5 -1
- package/dist/backend/notifications/emails/reset-password.js +8 -8
- package/dist/backend/notifications/emails/test-email.js +9 -8
- package/dist/backend/notifications/emails/threshold-alert.js +52 -13
- package/dist/backend/notifications/emails/verify-email.js +8 -8
- package/dist/backend/notifications/services/limit-check.service.js +25 -2
- package/dist/backend/notifications/services/notification-cron.service.js +14 -2
- package/dist/backend/notifications/services/notification-email.service.js +2 -1
- package/dist/backend/otlp/guards/otlp-auth.guard.js +8 -0
- package/dist/backend/otlp/services/log-ingest.service.js +7 -8
- package/dist/backend/otlp/services/metric-ingest.service.js +17 -20
- package/dist/backend/otlp/services/trace-ingest.service.js +124 -25
- package/dist/backend/routing/custom-provider.controller.js +144 -0
- package/dist/backend/routing/custom-provider.service.js +190 -0
- package/dist/backend/routing/dto/custom-provider.dto.js +124 -0
- package/dist/backend/routing/provider-aliases.js +4 -1
- package/dist/backend/routing/proxy/google-adapter.js +9 -9
- package/dist/backend/routing/proxy/provider-client.js +44 -9
- package/dist/backend/routing/proxy/provider-endpoints.js +18 -0
- package/dist/backend/routing/proxy/proxy-rate-limiter.js +10 -5
- package/dist/backend/routing/proxy/proxy.controller.js +18 -4
- package/dist/backend/routing/proxy/proxy.service.js +65 -38
- package/dist/backend/routing/proxy/stream-writer.js +4 -0
- package/dist/backend/routing/resolve-agent.util.js +16 -0
- package/dist/backend/routing/routing.controller.js +33 -24
- package/dist/backend/routing/routing.module.js +7 -2
- package/dist/backend/routing/routing.service.js +19 -12
- package/dist/backend/routing/tier-auto-assign.service.js +2 -3
- package/dist/backend/telemetry/telemetry.service.js +39 -16
- package/dist/index.js +11 -11
- package/package.json +1 -1
- package/public/assets/index-CM4JbafH.css +1 -0
- package/public/assets/index-XSLPss-g.js +7 -0
- package/public/index.html +5 -5
- package/public/manifest-logo.png +0 -0
- package/skills/manifest/SKILL.md +73 -10
- package/public/assets/index-BGkNs31t.js +0 -7
- package/public/assets/index-CTglHtZk.css +0 -1
package/README.md
CHANGED
|
@@ -30,9 +30,9 @@ OpenClaw costs
|
|
|
30
30
|
|
|
31
31
|
## What do you get?
|
|
32
32
|
|
|
33
|
-
- 🔀 **
|
|
34
|
-
- 📊 **Track
|
|
35
|
-
- 🔔 **Set limits** —
|
|
33
|
+
- 🔀 **Route requests to the right model** — cut costs up to 70%
|
|
34
|
+
- 📊 **Track spending** — see tokens and costs per model in real time
|
|
35
|
+
- 🔔 **Set limits** — get alerts when usage goes over a threshold
|
|
36
36
|
|
|
37
37
|
## Why Manifest
|
|
38
38
|
|
|
@@ -122,14 +122,14 @@ Or add `"telemetryOptOut": true` to `~/.openclaw/manifest/config.json`.
|
|
|
122
122
|
|
|
123
123
|
## Supported Providers
|
|
124
124
|
|
|
125
|
-
|
|
125
|
+
Works with **300+ models** across these providers:
|
|
126
126
|
|
|
127
127
|
| Provider | Models |
|
|
128
128
|
|----------|--------|
|
|
129
129
|
| [OpenAI](https://platform.openai.com/) | `gpt-5.3`, `gpt-4.1`, `o3`, `o4-mini` + 54 more |
|
|
130
130
|
| [Anthropic](https://www.anthropic.com/) | `claude-opus-4-6`, `claude-sonnet-4.5`, `claude-haiku-4.5` + 14 more |
|
|
131
131
|
| [Google Gemini](https://ai.google.dev/) | `gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-3-pro` + 19 more |
|
|
132
|
-
| [DeepSeek](https://www.deepseek.com/) | `deepseek-
|
|
132
|
+
| [DeepSeek](https://www.deepseek.com/) | `deepseek-chat`, `deepseek-reasoner` + 11 more |
|
|
133
133
|
| [xAI](https://x.ai/) | `grok-4`, `grok-3`, `grok-3-mini` + 8 more |
|
|
134
134
|
| [Mistral AI](https://mistral.ai/) | `mistral-large`, `codestral`, `devstral` + 26 more |
|
|
135
135
|
| [Qwen (Alibaba)](https://www.alibabacloud.com/en/solutions/generative-ai/qwen) | `qwen3-235b`, `qwen3-coder`, `qwq-32b` + 42 more |
|
|
@@ -174,21 +174,23 @@ let AggregationService = class AggregationService {
|
|
|
174
174
|
.set(agentUpdate)
|
|
175
175
|
.where('id = :id', { id: agent.id })
|
|
176
176
|
.execute();
|
|
177
|
-
const tables = [
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
177
|
+
const tables = [
|
|
178
|
+
'agent_messages',
|
|
179
|
+
'notification_rules',
|
|
180
|
+
'notification_logs',
|
|
181
|
+
'token_usage_snapshots',
|
|
182
|
+
'cost_snapshots',
|
|
183
|
+
];
|
|
184
|
+
await Promise.all(tables.map((table) => manager
|
|
185
|
+
.createQueryBuilder()
|
|
186
|
+
.update(table)
|
|
187
|
+
.set({ agent_name: newName })
|
|
188
|
+
.where('agent_name = :currentName', { currentName })
|
|
189
|
+
.execute()));
|
|
186
190
|
});
|
|
187
191
|
}
|
|
188
192
|
async getMessages(params) {
|
|
189
|
-
const cutoff = params.range
|
|
190
|
-
? (0, sql_dialect_1.computeCutoff)((0, range_util_1.rangeToInterval)(params.range))
|
|
191
|
-
: undefined;
|
|
193
|
+
const cutoff = params.range ? (0, sql_dialect_1.computeCutoff)((0, range_util_1.rangeToInterval)(params.range)) : undefined;
|
|
192
194
|
const baseQb = this.turnRepo.createQueryBuilder('at');
|
|
193
195
|
if (cutoff) {
|
|
194
196
|
baseQb.where('at.timestamp >= :cutoff', { cutoff });
|
|
@@ -210,7 +212,8 @@ let AggregationService = class AggregationService {
|
|
|
210
212
|
const countResult = await countQb.getRawOne();
|
|
211
213
|
const totalCount = Number(countResult?.total ?? 0);
|
|
212
214
|
const costExpr = (0, sql_dialect_1.sqlCastFloat)((0, sql_dialect_1.sqlSanitizeCost)('at.cost_usd'), this.dialect);
|
|
213
|
-
const dataQb = baseQb
|
|
215
|
+
const dataQb = baseQb
|
|
216
|
+
.clone()
|
|
214
217
|
.select('at.id', 'id')
|
|
215
218
|
.addSelect('at.timestamp', 'timestamp')
|
|
216
219
|
.addSelect('at.agent_name', 'agent_name')
|
|
@@ -234,9 +237,7 @@ let AggregationService = class AggregationService {
|
|
|
234
237
|
const cursorTs = params.cursor.substring(0, sepIdx);
|
|
235
238
|
const cursorId = params.cursor.substring(sepIdx + 1);
|
|
236
239
|
dataQb.andWhere(new typeorm_2.Brackets((sub) => {
|
|
237
|
-
sub
|
|
238
|
-
.where('at.timestamp < :cursorTs', { cursorTs })
|
|
239
|
-
.orWhere(new typeorm_2.Brackets((inner) => {
|
|
240
|
+
sub.where('at.timestamp < :cursorTs', { cursorTs }).orWhere(new typeorm_2.Brackets((inner) => {
|
|
240
241
|
inner
|
|
241
242
|
.where('at.timestamp = :cursorTs2', { cursorTs2: cursorTs })
|
|
242
243
|
.andWhere('at.id < :cursorId', { cursorId });
|
|
@@ -255,8 +256,7 @@ let AggregationService = class AggregationService {
|
|
|
255
256
|
const ts = lastItem?.['timestamp'];
|
|
256
257
|
const tsStr = ts instanceof Date ? (0, query_helpers_1.formatTimestamp)(ts) : String(ts ?? '');
|
|
257
258
|
const lastId = lastItem?.['id'];
|
|
258
|
-
const nextCursor = hasMore && lastItem
|
|
259
|
-
? `${tsStr}|${String(lastId)}` : null;
|
|
259
|
+
const nextCursor = hasMore && lastItem ? `${tsStr}|${String(lastId)}` : null;
|
|
260
260
|
const modelsQb = this.turnRepo
|
|
261
261
|
.createQueryBuilder('at')
|
|
262
262
|
.select('DISTINCT at.model', 'model')
|
|
@@ -7,6 +7,7 @@ const verify_email_1 = require("../notifications/emails/verify-email");
|
|
|
7
7
|
const reset_password_1 = require("../notifications/emails/reset-password");
|
|
8
8
|
const send_email_1 = require("../notifications/services/email-providers/send-email");
|
|
9
9
|
const product_telemetry_1 = require("../common/utils/product-telemetry");
|
|
10
|
+
const local_mode_constants_1 = require("../common/constants/local-mode.constants");
|
|
10
11
|
const isLocalMode = process.env['MANIFEST_MODE'] === 'local';
|
|
11
12
|
const port = process.env['PORT'] ?? '3001';
|
|
12
13
|
const isDev = (process.env['NODE_ENV'] ?? '') !== 'production';
|
|
@@ -24,7 +25,6 @@ const nodeEnv = process.env['NODE_ENV'] ?? '';
|
|
|
24
25
|
if (!isLocalMode && nodeEnv !== 'test' && (!betterAuthSecret || betterAuthSecret.length < 32)) {
|
|
25
26
|
throw new Error('BETTER_AUTH_SECRET must be set to a value of at least 32 characters');
|
|
26
27
|
}
|
|
27
|
-
const local_mode_constants_1 = require("../common/constants/local-mode.constants");
|
|
28
28
|
function buildTrustedOrigins() {
|
|
29
29
|
const origins = [];
|
|
30
30
|
if (process.env['BETTER_AUTH_URL']) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.computePeriodBoundaries = computePeriodBoundaries;
|
|
4
|
+
exports.computePeriodResetDate = computePeriodResetDate;
|
|
5
|
+
const fmt = (d) => d.toISOString().replace('T', ' ').replace('Z', '').slice(0, 19);
|
|
4
6
|
function computePeriodBoundaries(period) {
|
|
5
7
|
const now = new Date();
|
|
6
8
|
let start;
|
|
@@ -24,7 +26,30 @@ function computePeriodBoundaries(period) {
|
|
|
24
26
|
start = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours() - 1));
|
|
25
27
|
}
|
|
26
28
|
const end = new Date(now.getTime());
|
|
27
|
-
const fmt = (d) => d.toISOString().replace('T', ' ').replace('Z', '').slice(0, 19);
|
|
28
29
|
return { periodStart: fmt(start), periodEnd: fmt(end) };
|
|
29
30
|
}
|
|
31
|
+
function computePeriodResetDate(period) {
|
|
32
|
+
const now = new Date();
|
|
33
|
+
let reset;
|
|
34
|
+
switch (period) {
|
|
35
|
+
case 'hour':
|
|
36
|
+
reset = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours() + 1));
|
|
37
|
+
break;
|
|
38
|
+
case 'day':
|
|
39
|
+
reset = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1));
|
|
40
|
+
break;
|
|
41
|
+
case 'week': {
|
|
42
|
+
const dayOfWeek = now.getUTCDay();
|
|
43
|
+
const daysUntilMonday = (8 - dayOfWeek) % 7 || 7;
|
|
44
|
+
reset = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + daysUntilMonday));
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
case 'month':
|
|
48
|
+
reset = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1));
|
|
49
|
+
break;
|
|
50
|
+
default:
|
|
51
|
+
reset = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours() + 1));
|
|
52
|
+
}
|
|
53
|
+
return fmt(reset);
|
|
54
|
+
}
|
|
30
55
|
//# sourceMappingURL=period.util.js.map
|
|
@@ -177,29 +177,25 @@ let DatabaseSeederService = DatabaseSeederService_1 = class DatabaseSeederServic
|
|
|
177
177
|
['o3', 'OpenAI', 0.000002, 0.000008, 200000, true, true],
|
|
178
178
|
['o3-mini', 'OpenAI', 0.0000011, 0.0000044, 200000, true, true],
|
|
179
179
|
['o4-mini', 'OpenAI', 0.0000011, 0.0000044, 200000, true, true],
|
|
180
|
-
['gpt-5.3', 'OpenAI', 0.00001, 0.00003, 200000, true, true],
|
|
181
|
-
['gpt-5.3-codex', 'OpenAI', 0.00001, 0.00003, 200000, true, true],
|
|
182
|
-
['gpt-5.3-mini', 'OpenAI', 0.0000015, 0.000006, 200000, true, true],
|
|
183
180
|
['gemini-2.5-pro', 'Google', 0.00000125, 0.00001, 1048576, true, true],
|
|
184
181
|
['gemini-2.5-flash', 'Google', 0.00000015, 0.0000006, 1048576, false, true],
|
|
185
182
|
['gemini-2.5-flash-lite', 'Google', 0.0000001, 0.0000004, 1048576, false, false],
|
|
186
183
|
['gemini-2.0-flash', 'Google', 0.0000001, 0.0000004, 1048576, false, true],
|
|
187
|
-
['deepseek-
|
|
188
|
-
['deepseek-
|
|
184
|
+
['deepseek-chat', 'DeepSeek', 0.00000014, 0.00000028, 128000, false, true],
|
|
185
|
+
['deepseek-reasoner', 'DeepSeek', 0.00000055, 0.00000219, 128000, true, false],
|
|
189
186
|
['kimi-k2', 'Moonshot', 0.0000006, 0.0000024, 262144, true, true],
|
|
190
187
|
['qwen-2.5-72b-instruct', 'Alibaba', 0.00000034, 0.00000039, 131072, false, true],
|
|
191
188
|
['qwq-32b', 'Alibaba', 0.00000012, 0.00000018, 131072, true, false],
|
|
192
189
|
['qwen-2.5-coder-32b-instruct', 'Alibaba', 0.00000018, 0.00000018, 131072, false, true],
|
|
193
190
|
['qwen3-235b-a22b', 'Alibaba', 0.0000003, 0.0000012, 131072, true, true],
|
|
194
191
|
['qwen3-32b', 'Alibaba', 0.0000001, 0.0000003, 131072, true, true],
|
|
195
|
-
['mistral-large', 'Mistral', 0.000002, 0.000006, 128000, false, true],
|
|
192
|
+
['mistral-large-latest', 'Mistral', 0.000002, 0.000006, 128000, false, true],
|
|
196
193
|
['mistral-small', 'Mistral', 0.0000002, 0.0000006, 128000, false, false],
|
|
197
|
-
['codestral', 'Mistral', 0.0000003, 0.0000009, 256000, false, true],
|
|
194
|
+
['codestral-latest', 'Mistral', 0.0000003, 0.0000009, 256000, false, true],
|
|
198
195
|
['grok-3', 'xAI', 0.000003, 0.000015, 131072, true, true],
|
|
199
196
|
['grok-3-mini', 'xAI', 0.0000003, 0.0000005, 131072, true, true],
|
|
200
197
|
['grok-3-fast', 'xAI', 0.000005, 0.000025, 131072, false, true],
|
|
201
198
|
['grok-3-mini-fast', 'xAI', 0.0000006, 0.000004, 131072, false, true],
|
|
202
|
-
['grok-2', 'xAI', 0.000002, 0.00001, 131072, false, true],
|
|
203
199
|
['openrouter/auto', 'OpenRouter', 0.000003, 0.000015, 200000, true, true],
|
|
204
200
|
['anthropic/claude-opus-4-6', 'OpenRouter', 0.000015, 0.000075, 200000, true, true],
|
|
205
201
|
['anthropic/claude-sonnet-4-5', 'OpenRouter', 0.000003, 0.000015, 200000, true, true],
|
|
@@ -213,13 +209,6 @@ let DatabaseSeederService = DatabaseSeederService_1 = class DatabaseSeederServic
|
|
|
213
209
|
['mistralai/mistral-large', 'OpenRouter', 0.000002, 0.000006, 128000, false, true],
|
|
214
210
|
['x-ai/grok-3', 'OpenRouter', 0.000003, 0.000015, 131072, true, true],
|
|
215
211
|
['openrouter/free', 'OpenRouter', 0, 0, 200000, true, true],
|
|
216
|
-
['stepfun/step-3.5-flash:free', 'OpenRouter', 0, 0, 256000, false, true],
|
|
217
|
-
['arcee-ai/trinity-large-preview:free', 'OpenRouter', 0, 0, 131072, false, true],
|
|
218
|
-
['upstage/solar-pro-3:free', 'OpenRouter', 0, 0, 128000, false, true],
|
|
219
|
-
['liquid/lfm-2.5-1.2b-thinking:free', 'OpenRouter', 0, 0, 32768, true, false],
|
|
220
|
-
['liquid/lfm-2.5-1.2b-instruct:free', 'OpenRouter', 0, 0, 32768, false, false],
|
|
221
|
-
['arcee-ai/trinity-mini:free', 'OpenRouter', 0, 0, 131072, false, false],
|
|
222
|
-
['nvidia/nemotron-3-nano-30b-a3b:free', 'OpenRouter', 0, 0, 256000, false, true],
|
|
223
212
|
['minimax/minimax-m2.5', 'OpenRouter', 0.000000295, 0.0000012, 196608, true, true],
|
|
224
213
|
['minimax/minimax-m1', 'OpenRouter', 0.0000004, 0.0000022, 1000000, true, true],
|
|
225
214
|
['minimax-m2.5', 'MiniMax', 0.000000295, 0.0000012, 196608, true, true],
|
|
@@ -227,9 +216,7 @@ let DatabaseSeederService = DatabaseSeederService_1 = class DatabaseSeederServic
|
|
|
227
216
|
['minimax-m2.1', 'MiniMax', 0.00000027, 0.00000095, 196608, true, true],
|
|
228
217
|
['minimax-m2.1-highspeed', 'MiniMax', 0.00000027, 0.00000095, 196608, true, true],
|
|
229
218
|
['minimax-m2', 'MiniMax', 0.000000255, 0.000001, 196608, true, true],
|
|
230
|
-
['minimax-m2-her', 'MiniMax', 0.0000003, 0.0000012, 65536, false, false],
|
|
231
219
|
['minimax-m1', 'MiniMax', 0.0000004, 0.0000022, 1000000, true, true],
|
|
232
|
-
['minimax-01', 'MiniMax', 0.0000002, 0.0000011, 1000192, false, false],
|
|
233
220
|
['glm-5', 'Z.ai', 0.00000095, 0.00000255, 204800, true, true],
|
|
234
221
|
['glm-4.7', 'Z.ai', 0.0000003, 0.0000014, 202752, true, true],
|
|
235
222
|
['glm-4.7-flash', 'Z.ai', 0.00000006, 0.0000004, 202752, false, false],
|
|
@@ -242,9 +229,6 @@ let DatabaseSeederService = DatabaseSeederService_1 = class DatabaseSeederServic
|
|
|
242
229
|
['z-ai/glm-4.7', 'OpenRouter', 0.0000003, 0.0000014, 202752, true, true],
|
|
243
230
|
['glm-4-plus', 'Zhipu', 0.0000005, 0.0000005, 128000, false, true],
|
|
244
231
|
['glm-4-flash', 'Zhipu', 0.00000005, 0.00000005, 128000, false, false],
|
|
245
|
-
['nova-pro', 'Amazon', 0.0000008, 0.0000032, 300000, false, true],
|
|
246
|
-
['nova-lite', 'Amazon', 0.00000006, 0.00000024, 300000, false, true],
|
|
247
|
-
['nova-micro', 'Amazon', 0.000000035, 0.00000014, 128000, false, false],
|
|
248
232
|
];
|
|
249
233
|
for (const [name, provider, inputPrice, outputPrice, ctxWindow, reasoning, code] of models) {
|
|
250
234
|
await this.pricingRepo.upsert({
|
|
@@ -30,6 +30,7 @@ const notification_log_entity_1 = require("../entities/notification-log.entity")
|
|
|
30
30
|
const email_provider_config_entity_1 = require("../entities/email-provider-config.entity");
|
|
31
31
|
const user_provider_entity_1 = require("../entities/user-provider.entity");
|
|
32
32
|
const tier_assignment_entity_1 = require("../entities/tier-assignment.entity");
|
|
33
|
+
const custom_provider_entity_1 = require("../entities/custom-provider.entity");
|
|
33
34
|
const database_seeder_service_1 = require("./database-seeder.service");
|
|
34
35
|
const local_bootstrap_service_1 = require("./local-bootstrap.service");
|
|
35
36
|
const model_prices_module_1 = require("../model-prices/model-prices.module");
|
|
@@ -49,6 +50,9 @@ const _1772200000000_AddLimitAction_1 = require("./migrations/1772200000000-AddL
|
|
|
49
50
|
const _1772300000000_AddRoutingReason_1 = require("./migrations/1772300000000-AddRoutingReason");
|
|
50
51
|
const _1772400000000_AddAgentDisplayName_1 = require("./migrations/1772400000000-AddAgentDisplayName");
|
|
51
52
|
const _1772500000000_PerAgentRouting_1 = require("./migrations/1772500000000-PerAgentRouting");
|
|
53
|
+
const _1772668898071_AddCustomProviders_1 = require("./migrations/1772668898071-AddCustomProviders");
|
|
54
|
+
const _1772682112419_NullablePricing_1 = require("./migrations/1772682112419-NullablePricing");
|
|
55
|
+
const _1772843035514_AddPerformanceIndexes_1 = require("./migrations/1772843035514-AddPerformanceIndexes");
|
|
52
56
|
const entities = [
|
|
53
57
|
agent_message_entity_1.AgentMessage,
|
|
54
58
|
llm_call_entity_1.LlmCall,
|
|
@@ -69,6 +73,7 @@ const entities = [
|
|
|
69
73
|
email_provider_config_entity_1.EmailProviderConfig,
|
|
70
74
|
user_provider_entity_1.UserProvider,
|
|
71
75
|
tier_assignment_entity_1.TierAssignment,
|
|
76
|
+
custom_provider_entity_1.CustomProvider,
|
|
72
77
|
];
|
|
73
78
|
const migrations = [
|
|
74
79
|
_1771464895790_InitialSchema_1.InitialSchema1771464895790,
|
|
@@ -87,6 +92,9 @@ const migrations = [
|
|
|
87
92
|
_1772300000000_AddRoutingReason_1.AddRoutingReason1772300000000,
|
|
88
93
|
_1772400000000_AddAgentDisplayName_1.AddAgentDisplayName1772400000000,
|
|
89
94
|
_1772500000000_PerAgentRouting_1.PerAgentRouting1772500000000,
|
|
95
|
+
_1772668898071_AddCustomProviders_1.AddCustomProviders1772668898071,
|
|
96
|
+
_1772682112419_NullablePricing_1.NullablePricing1772682112419,
|
|
97
|
+
_1772843035514_AddPerformanceIndexes_1.AddPerformanceIndexes1772843035514,
|
|
90
98
|
];
|
|
91
99
|
const isLocalMode = process.env['MANIFEST_MODE'] === 'local';
|
|
92
100
|
function buildModeServices() {
|
|
@@ -124,6 +132,10 @@ exports.DatabaseModule = DatabaseModule = __decorate([
|
|
|
124
132
|
migrationsTransactionMode: 'all',
|
|
125
133
|
migrations,
|
|
126
134
|
logging: false,
|
|
135
|
+
extra: {
|
|
136
|
+
max: 20,
|
|
137
|
+
idleTimeoutMillis: 30000,
|
|
138
|
+
},
|
|
127
139
|
};
|
|
128
140
|
},
|
|
129
141
|
}),
|
|
@@ -137,6 +149,7 @@ exports.DatabaseModule = DatabaseModule = __decorate([
|
|
|
137
149
|
security_event_entity_1.SecurityEvent,
|
|
138
150
|
user_provider_entity_1.UserProvider,
|
|
139
151
|
tier_assignment_entity_1.TierAssignment,
|
|
152
|
+
custom_provider_entity_1.CustomProvider,
|
|
140
153
|
]),
|
|
141
154
|
model_prices_module_1.ModelPricesModule,
|
|
142
155
|
],
|
|
@@ -72,28 +72,28 @@ let LocalBootstrapService = LocalBootstrapService_1 = class LocalBootstrapServic
|
|
|
72
72
|
}
|
|
73
73
|
async ensureTenantAndAgent() {
|
|
74
74
|
const count = await this.tenantRepo.count({ where: { id: local_mode_constants_1.LOCAL_TENANT_ID } });
|
|
75
|
-
if (count
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
75
|
+
if (count === 0) {
|
|
76
|
+
await this.tenantRepo.insert({
|
|
77
|
+
id: local_mode_constants_1.LOCAL_TENANT_ID,
|
|
78
|
+
name: local_mode_constants_1.LOCAL_USER_ID,
|
|
79
|
+
organization_name: 'Local',
|
|
80
|
+
email: local_mode_constants_1.LOCAL_EMAIL,
|
|
81
|
+
is_active: true,
|
|
82
|
+
});
|
|
83
|
+
await this.agentRepo.insert({
|
|
84
|
+
id: local_mode_constants_1.LOCAL_AGENT_ID,
|
|
85
|
+
name: local_mode_constants_1.LOCAL_AGENT_NAME,
|
|
86
|
+
description: 'Default local agent',
|
|
87
|
+
is_active: true,
|
|
88
|
+
tenant_id: local_mode_constants_1.LOCAL_TENANT_ID,
|
|
89
|
+
});
|
|
90
|
+
(0, product_telemetry_1.trackEvent)('agent_created', { agent_name: local_mode_constants_1.LOCAL_AGENT_NAME });
|
|
91
|
+
this.logger.log(`Created tenant/agent for local mode`);
|
|
92
|
+
}
|
|
92
93
|
const apiKey = this.readApiKeyFromConfig();
|
|
93
94
|
if (apiKey) {
|
|
94
95
|
await this.registerApiKey(apiKey);
|
|
95
96
|
}
|
|
96
|
-
this.logger.log(`Created tenant/agent for local mode`);
|
|
97
97
|
}
|
|
98
98
|
readApiKeyFromConfig() {
|
|
99
99
|
try {
|
|
@@ -112,7 +112,7 @@ let LocalBootstrapService = LocalBootstrapService_1 = class LocalBootstrapServic
|
|
|
112
112
|
const existing = await this.agentKeyRepo.count({ where: { key_hash: hash } });
|
|
113
113
|
if (existing > 0)
|
|
114
114
|
return;
|
|
115
|
-
await this.agentKeyRepo.
|
|
115
|
+
await this.agentKeyRepo.upsert({
|
|
116
116
|
id: 'local-otlp-key-001',
|
|
117
117
|
key: null,
|
|
118
118
|
key_hash: hash,
|
|
@@ -121,7 +121,7 @@ let LocalBootstrapService = LocalBootstrapService_1 = class LocalBootstrapServic
|
|
|
121
121
|
tenant_id: local_mode_constants_1.LOCAL_TENANT_ID,
|
|
122
122
|
agent_id: local_mode_constants_1.LOCAL_AGENT_ID,
|
|
123
123
|
is_active: true,
|
|
124
|
-
});
|
|
124
|
+
}, ['id']);
|
|
125
125
|
}
|
|
126
126
|
async fixupRoutingAgentIds() {
|
|
127
127
|
const orphanedProviders = await this.providerRepo.find({
|
|
@@ -159,29 +159,25 @@ let LocalBootstrapService = LocalBootstrapService_1 = class LocalBootstrapServic
|
|
|
159
159
|
['o3', 'OpenAI', 0.000002, 0.000008, 200000, true, true],
|
|
160
160
|
['o3-mini', 'OpenAI', 0.0000011, 0.0000044, 200000, true, true],
|
|
161
161
|
['o4-mini', 'OpenAI', 0.0000011, 0.0000044, 200000, true, true],
|
|
162
|
-
['gpt-5.3', 'OpenAI', 0.00001, 0.00003, 200000, true, true],
|
|
163
|
-
['gpt-5.3-codex', 'OpenAI', 0.00001, 0.00003, 200000, true, true],
|
|
164
|
-
['gpt-5.3-mini', 'OpenAI', 0.0000015, 0.000006, 200000, true, true],
|
|
165
162
|
['gemini-2.5-pro', 'Google', 0.00000125, 0.00001, 1048576, true, true],
|
|
166
163
|
['gemini-2.5-flash', 'Google', 0.00000015, 0.0000006, 1048576, false, true],
|
|
167
164
|
['gemini-2.5-flash-lite', 'Google', 0.0000001, 0.0000004, 1048576, false, false],
|
|
168
165
|
['gemini-2.0-flash', 'Google', 0.0000001, 0.0000004, 1048576, false, true],
|
|
169
|
-
['deepseek-
|
|
170
|
-
['deepseek-
|
|
166
|
+
['deepseek-chat', 'DeepSeek', 0.00000014, 0.00000028, 128000, false, true],
|
|
167
|
+
['deepseek-reasoner', 'DeepSeek', 0.00000055, 0.00000219, 128000, true, false],
|
|
171
168
|
['kimi-k2', 'Moonshot', 0.0000006, 0.0000024, 262144, true, true],
|
|
172
169
|
['qwen-2.5-72b-instruct', 'Alibaba', 0.00000034, 0.00000039, 131072, false, true],
|
|
173
170
|
['qwq-32b', 'Alibaba', 0.00000012, 0.00000018, 131072, true, false],
|
|
174
171
|
['qwen-2.5-coder-32b-instruct', 'Alibaba', 0.00000018, 0.00000018, 131072, false, true],
|
|
175
172
|
['qwen3-235b-a22b', 'Alibaba', 0.0000003, 0.0000012, 131072, true, true],
|
|
176
173
|
['qwen3-32b', 'Alibaba', 0.0000001, 0.0000003, 131072, true, true],
|
|
177
|
-
['mistral-large', 'Mistral', 0.000002, 0.000006, 128000, false, true],
|
|
174
|
+
['mistral-large-latest', 'Mistral', 0.000002, 0.000006, 128000, false, true],
|
|
178
175
|
['mistral-small', 'Mistral', 0.0000002, 0.0000006, 128000, false, false],
|
|
179
|
-
['codestral', 'Mistral', 0.0000003, 0.0000009, 256000, false, true],
|
|
176
|
+
['codestral-latest', 'Mistral', 0.0000003, 0.0000009, 256000, false, true],
|
|
180
177
|
['grok-3', 'xAI', 0.000003, 0.000015, 131072, true, true],
|
|
181
178
|
['grok-3-mini', 'xAI', 0.0000003, 0.0000005, 131072, true, true],
|
|
182
179
|
['grok-3-fast', 'xAI', 0.000005, 0.000025, 131072, false, true],
|
|
183
180
|
['grok-3-mini-fast', 'xAI', 0.0000006, 0.000004, 131072, false, true],
|
|
184
|
-
['grok-2', 'xAI', 0.000002, 0.00001, 131072, false, true],
|
|
185
181
|
['openrouter/auto', 'OpenRouter', 0.000003, 0.000015, 200000, true, true],
|
|
186
182
|
['anthropic/claude-opus-4-6', 'OpenRouter', 0.000015, 0.000075, 200000, true, true],
|
|
187
183
|
['anthropic/claude-sonnet-4-5', 'OpenRouter', 0.000003, 0.000015, 200000, true, true],
|
|
@@ -195,21 +191,12 @@ let LocalBootstrapService = LocalBootstrapService_1 = class LocalBootstrapServic
|
|
|
195
191
|
['mistralai/mistral-large', 'OpenRouter', 0.000002, 0.000006, 128000, false, true],
|
|
196
192
|
['x-ai/grok-3', 'OpenRouter', 0.000003, 0.000015, 131072, true, true],
|
|
197
193
|
['openrouter/free', 'OpenRouter', 0, 0, 200000, true, true],
|
|
198
|
-
['stepfun/step-3.5-flash:free', 'OpenRouter', 0, 0, 256000, false, true],
|
|
199
|
-
['arcee-ai/trinity-large-preview:free', 'OpenRouter', 0, 0, 131072, false, true],
|
|
200
|
-
['upstage/solar-pro-3:free', 'OpenRouter', 0, 0, 128000, false, true],
|
|
201
|
-
['liquid/lfm-2.5-1.2b-thinking:free', 'OpenRouter', 0, 0, 32768, true, false],
|
|
202
|
-
['liquid/lfm-2.5-1.2b-instruct:free', 'OpenRouter', 0, 0, 32768, false, false],
|
|
203
|
-
['arcee-ai/trinity-mini:free', 'OpenRouter', 0, 0, 131072, false, false],
|
|
204
|
-
['nvidia/nemotron-3-nano-30b-a3b:free', 'OpenRouter', 0, 0, 256000, false, true],
|
|
205
194
|
['minimax-m2.5', 'MiniMax', 0.000000295, 0.0000012, 196608, true, true],
|
|
206
195
|
['minimax-m2.5-highspeed', 'MiniMax', 0.000000295, 0.0000012, 196608, true, true],
|
|
207
196
|
['minimax-m2.1', 'MiniMax', 0.00000027, 0.00000095, 196608, true, true],
|
|
208
197
|
['minimax-m2.1-highspeed', 'MiniMax', 0.00000027, 0.00000095, 196608, true, true],
|
|
209
198
|
['minimax-m2', 'MiniMax', 0.000000255, 0.000001, 196608, true, true],
|
|
210
|
-
['minimax-m2-her', 'MiniMax', 0.0000003, 0.0000012, 65536, false, false],
|
|
211
199
|
['minimax-m1', 'MiniMax', 0.0000004, 0.0000022, 1000000, true, true],
|
|
212
|
-
['minimax-01', 'MiniMax', 0.0000002, 0.0000011, 1000192, false, false],
|
|
213
200
|
['glm-5', 'Z.ai', 0.00000095, 0.00000255, 204800, true, true],
|
|
214
201
|
['glm-4.7', 'Z.ai', 0.0000003, 0.0000014, 202752, true, true],
|
|
215
202
|
['glm-4.7-flash', 'Z.ai', 0.00000006, 0.0000004, 202752, false, false],
|
|
@@ -220,9 +207,6 @@ let LocalBootstrapService = LocalBootstrapService_1 = class LocalBootstrapServic
|
|
|
220
207
|
['glm-4.5-flash', 'Z.ai', 0, 0, 131072, false, false],
|
|
221
208
|
['glm-4-plus', 'Zhipu', 0.0000005, 0.0000005, 128000, false, true],
|
|
222
209
|
['glm-4-flash', 'Zhipu', 0.00000005, 0.00000005, 128000, false, false],
|
|
223
|
-
['nova-pro', 'Amazon', 0.0000008, 0.0000032, 300000, false, true],
|
|
224
|
-
['nova-lite', 'Amazon', 0.00000006, 0.00000024, 300000, false, true],
|
|
225
|
-
['nova-micro', 'Amazon', 0.000000035, 0.00000014, 128000, false, false],
|
|
226
210
|
];
|
|
227
211
|
for (const [name, provider, inputPrice, outputPrice, ctxWindow, reasoning, code] of models) {
|
|
228
212
|
await this.pricingRepo.upsert({
|
|
@@ -24,8 +24,8 @@ class AddQualityScore1771800000000 {
|
|
|
24
24
|
['gemini-2.5-flash', 2],
|
|
25
25
|
['gemini-2.5-flash-lite', 1],
|
|
26
26
|
['gemini-2.0-flash', 2],
|
|
27
|
-
['deepseek-
|
|
28
|
-
['deepseek-
|
|
27
|
+
['deepseek-chat', 2],
|
|
28
|
+
['deepseek-reasoner', 4],
|
|
29
29
|
['kimi-k2', 3],
|
|
30
30
|
['qwen-2.5-72b-instruct', 2],
|
|
31
31
|
['qwq-32b', 1],
|
|
@@ -20,8 +20,8 @@ class SeedQualityScores1771800100000 {
|
|
|
20
20
|
['gemini-2.5-flash', 2],
|
|
21
21
|
['gemini-2.5-flash-lite', 1],
|
|
22
22
|
['gemini-2.0-flash', 2],
|
|
23
|
-
['deepseek-
|
|
24
|
-
['deepseek-
|
|
23
|
+
['deepseek-chat', 2],
|
|
24
|
+
['deepseek-reasoner', 4],
|
|
25
25
|
['kimi-k2', 3],
|
|
26
26
|
['qwen-2.5-72b-instruct', 2],
|
|
27
27
|
['qwq-32b', 1],
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AddCustomProviders1772668898071 = void 0;
|
|
4
|
+
class AddCustomProviders1772668898071 {
|
|
5
|
+
async up(queryRunner) {
|
|
6
|
+
await queryRunner.query(`
|
|
7
|
+
CREATE TABLE "custom_providers" (
|
|
8
|
+
"id" varchar NOT NULL,
|
|
9
|
+
"agent_id" varchar NOT NULL,
|
|
10
|
+
"user_id" varchar NOT NULL,
|
|
11
|
+
"name" varchar NOT NULL,
|
|
12
|
+
"base_url" varchar NOT NULL,
|
|
13
|
+
"models" text NOT NULL,
|
|
14
|
+
"created_at" timestamp NOT NULL DEFAULT NOW(),
|
|
15
|
+
CONSTRAINT "PK_custom_providers" PRIMARY KEY ("id"),
|
|
16
|
+
CONSTRAINT "FK_custom_providers_agent" FOREIGN KEY ("agent_id")
|
|
17
|
+
REFERENCES "agents"("id") ON DELETE CASCADE
|
|
18
|
+
)
|
|
19
|
+
`);
|
|
20
|
+
await queryRunner.query(`
|
|
21
|
+
CREATE UNIQUE INDEX "IDX_custom_providers_agent_name"
|
|
22
|
+
ON "custom_providers" ("agent_id", "name")
|
|
23
|
+
`);
|
|
24
|
+
}
|
|
25
|
+
async down(queryRunner) {
|
|
26
|
+
await queryRunner.query(`DROP INDEX IF EXISTS "IDX_custom_providers_agent_name"`);
|
|
27
|
+
await queryRunner.query(`DROP TABLE IF EXISTS "custom_providers"`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.AddCustomProviders1772668898071 = AddCustomProviders1772668898071;
|
|
31
|
+
//# sourceMappingURL=1772668898071-AddCustomProviders.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NullablePricing1772682112419 = void 0;
|
|
4
|
+
class NullablePricing1772682112419 {
|
|
5
|
+
async up(queryRunner) {
|
|
6
|
+
await queryRunner.query(`ALTER TABLE model_pricing ALTER COLUMN input_price_per_token DROP NOT NULL`);
|
|
7
|
+
await queryRunner.query(`ALTER TABLE model_pricing ALTER COLUMN output_price_per_token DROP NOT NULL`);
|
|
8
|
+
}
|
|
9
|
+
async down(queryRunner) {
|
|
10
|
+
await queryRunner.query(`UPDATE model_pricing SET input_price_per_token = 0 WHERE input_price_per_token IS NULL`);
|
|
11
|
+
await queryRunner.query(`UPDATE model_pricing SET output_price_per_token = 0 WHERE output_price_per_token IS NULL`);
|
|
12
|
+
await queryRunner.query(`ALTER TABLE model_pricing ALTER COLUMN input_price_per_token SET NOT NULL`);
|
|
13
|
+
await queryRunner.query(`ALTER TABLE model_pricing ALTER COLUMN output_price_per_token SET NOT NULL`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.NullablePricing1772682112419 = NullablePricing1772682112419;
|
|
17
|
+
//# sourceMappingURL=1772682112419-NullablePricing.js.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AddPerformanceIndexes1772843035514 = void 0;
|
|
4
|
+
const crypto_util_1 = require("../../common/utils/crypto.util");
|
|
5
|
+
class AddPerformanceIndexes1772843035514 {
|
|
6
|
+
name = 'AddPerformanceIndexes1772843035514';
|
|
7
|
+
async up(queryRunner) {
|
|
8
|
+
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_agent_messages_user_id_timestamp" ON "agent_messages" ("user_id", "timestamp")`);
|
|
9
|
+
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_agent_messages_tenant_agent_name_ts" ON "agent_messages" ("tenant_id", "agent_name", "timestamp")`);
|
|
10
|
+
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_agent_messages_timestamp" ON "agent_messages" ("timestamp")`);
|
|
11
|
+
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_security_event_user_id_timestamp" ON "security_event" ("user_id", "timestamp")`);
|
|
12
|
+
await queryRunner.query(`CREATE INDEX IF NOT EXISTS "IDX_cost_snapshots_tenant_agent_time" ON "cost_snapshots" ("tenant_id", "agent_id", "snapshot_time")`);
|
|
13
|
+
await queryRunner.query(`ALTER TABLE "user_providers" ADD COLUMN "key_prefix" varchar DEFAULT NULL`);
|
|
14
|
+
await this.backfillKeyPrefix(queryRunner);
|
|
15
|
+
}
|
|
16
|
+
async down(queryRunner) {
|
|
17
|
+
await queryRunner.query(`ALTER TABLE "user_providers" DROP COLUMN "key_prefix"`);
|
|
18
|
+
await queryRunner.query(`DROP INDEX IF EXISTS "IDX_cost_snapshots_tenant_agent_time"`);
|
|
19
|
+
await queryRunner.query(`DROP INDEX IF EXISTS "IDX_security_event_user_id_timestamp"`);
|
|
20
|
+
await queryRunner.query(`DROP INDEX IF EXISTS "IDX_agent_messages_timestamp"`);
|
|
21
|
+
await queryRunner.query(`DROP INDEX IF EXISTS "IDX_agent_messages_tenant_agent_name_ts"`);
|
|
22
|
+
await queryRunner.query(`DROP INDEX IF EXISTS "IDX_agent_messages_user_id_timestamp"`);
|
|
23
|
+
}
|
|
24
|
+
async backfillKeyPrefix(queryRunner) {
|
|
25
|
+
let secret;
|
|
26
|
+
try {
|
|
27
|
+
secret = (0, crypto_util_1.getEncryptionSecret)();
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
console.warn('AddPerformanceIndexes: No encryption secret found. Skipping key_prefix backfill.');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const rows = await queryRunner.query(`SELECT id, api_key_encrypted FROM "user_providers" WHERE api_key_encrypted IS NOT NULL AND api_key_encrypted != ''`);
|
|
34
|
+
let backfilled = 0;
|
|
35
|
+
for (const row of rows) {
|
|
36
|
+
let prefix;
|
|
37
|
+
try {
|
|
38
|
+
const plaintext = (0, crypto_util_1.decrypt)(row.api_key_encrypted, secret);
|
|
39
|
+
prefix = plaintext.substring(0, 8);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
await queryRunner.query(`UPDATE "user_providers" SET key_prefix = $1 WHERE id = $2`, [
|
|
45
|
+
prefix,
|
|
46
|
+
row.id,
|
|
47
|
+
]);
|
|
48
|
+
backfilled++;
|
|
49
|
+
}
|
|
50
|
+
if (backfilled > 0) {
|
|
51
|
+
console.log(`AddPerformanceIndexes: Backfilled key_prefix for ${backfilled} provider(s).`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.AddPerformanceIndexes1772843035514 = AddPerformanceIndexes1772843035514;
|
|
56
|
+
//# sourceMappingURL=1772843035514-AddPerformanceIndexes.js.map
|
|
@@ -74,6 +74,7 @@ const PROVIDER_DISPLAY_NAMES = {
|
|
|
74
74
|
'z-ai': 'Z.ai',
|
|
75
75
|
openrouter: 'OpenRouter',
|
|
76
76
|
};
|
|
77
|
+
const SUPPORTED_PREFIXES = new Set(Object.keys(PROVIDER_DISPLAY_NAMES));
|
|
77
78
|
const OPENROUTER_API = 'https://openrouter.ai/api/v1/models';
|
|
78
79
|
const FRESHNESS_HOURS = 12;
|
|
79
80
|
let PricingSyncService = PricingSyncService_1 = class PricingSyncService {
|
|
@@ -111,6 +112,7 @@ let PricingSyncService = PricingSyncService_1 = class PricingSyncService {
|
|
|
111
112
|
return 0;
|
|
112
113
|
const updated = await this.syncAllModels(data);
|
|
113
114
|
await this.resolveUnresolvedModels(data);
|
|
115
|
+
await this.removeUnsupportedModels();
|
|
114
116
|
this.logger.log(`Pricing sync complete: ${updated} models updated`);
|
|
115
117
|
if (updated > 0) {
|
|
116
118
|
await this.pricingCache.reload();
|
|
@@ -167,6 +169,12 @@ let PricingSyncService = PricingSyncService_1 = class PricingSyncService {
|
|
|
167
169
|
failed++;
|
|
168
170
|
continue;
|
|
169
171
|
}
|
|
172
|
+
if (!model.id.startsWith('openrouter/')) {
|
|
173
|
+
const slashIdx = model.id.indexOf('/');
|
|
174
|
+
if (slashIdx === -1 || !SUPPORTED_PREFIXES.has(model.id.substring(0, slashIdx))) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
170
178
|
const { canonical, provider } = this.deriveNames(model.id);
|
|
171
179
|
const existing = await this.pricingRepo.findOneBy({
|
|
172
180
|
model_name: canonical,
|
|
@@ -236,6 +244,24 @@ let PricingSyncService = PricingSyncService_1 = class PricingSyncService {
|
|
|
236
244
|
titleCase(str) {
|
|
237
245
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
238
246
|
}
|
|
247
|
+
async removeUnsupportedModels() {
|
|
248
|
+
const all = await this.pricingRepo.find({ select: ['model_name'] });
|
|
249
|
+
const toDelete = [];
|
|
250
|
+
for (const row of all) {
|
|
251
|
+
const slashIdx = row.model_name.indexOf('/');
|
|
252
|
+
if (slashIdx === -1)
|
|
253
|
+
continue;
|
|
254
|
+
const prefix = row.model_name.substring(0, slashIdx);
|
|
255
|
+
if (prefix === 'openrouter')
|
|
256
|
+
continue;
|
|
257
|
+
if (!SUPPORTED_PREFIXES.has(prefix))
|
|
258
|
+
toDelete.push(row.model_name);
|
|
259
|
+
}
|
|
260
|
+
if (toDelete.length > 0) {
|
|
261
|
+
await this.pricingRepo.delete({ model_name: (0, typeorm_2.In)(toDelete) });
|
|
262
|
+
this.logger.log(`Removed ${toDelete.length} models from unsupported providers`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
239
265
|
async resolveUnresolvedModels(data) {
|
|
240
266
|
const unresolved = await this.unresolvedTracker.getUnresolved();
|
|
241
267
|
if (unresolved.length === 0)
|
|
@@ -6,8 +6,7 @@ exports.QUALITY_OVERRIDES = new Map([
|
|
|
6
6
|
['claude-sonnet-4-5-20250929', 4],
|
|
7
7
|
['claude-sonnet-4-20250514', 4],
|
|
8
8
|
['gpt-4o', 3],
|
|
9
|
-
['
|
|
10
|
-
['mistral-large', 3],
|
|
9
|
+
['mistral-large-latest', 3],
|
|
11
10
|
['kimi-k2', 3],
|
|
12
11
|
['openrouter/auto', 5],
|
|
13
12
|
['openrouter/free', 3],
|
|
@@ -17,6 +16,8 @@ function computeQualityScore(model) {
|
|
|
17
16
|
const override = exports.QUALITY_OVERRIDES.get(model.model_name);
|
|
18
17
|
if (override !== undefined)
|
|
19
18
|
return override;
|
|
19
|
+
if (model.input_price_per_token == null || model.output_price_per_token == null)
|
|
20
|
+
return 2;
|
|
20
21
|
const totalPerM = (Number(model.input_price_per_token) + Number(model.output_price_per_token)) * 1_000_000;
|
|
21
22
|
const hasReasoning = model.capability_reasoning;
|
|
22
23
|
const hasCode = model.capability_code;
|
|
@@ -44,9 +45,9 @@ function computeQualityScore(model) {
|
|
|
44
45
|
return 4;
|
|
45
46
|
if (totalPerM >= 3.0 && hasCode && !isMini)
|
|
46
47
|
return 3;
|
|
47
|
-
if (totalPerM >= 0.
|
|
48
|
+
if (totalPerM >= 0.5 && hasBoth && !isMini)
|
|
48
49
|
return 3;
|
|
49
|
-
if (hasReasoning && isMini && totalPerM >= 0.
|
|
50
|
+
if (hasReasoning && isMini && totalPerM >= 0.5)
|
|
50
51
|
return 3;
|
|
51
52
|
if (hasCode)
|
|
52
53
|
return 2;
|