manifest 5.24.1 → 5.25.0
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 +1 -0
- package/dist/backend/analytics/controllers/agent-analytics.controller.js +7 -1
- package/dist/backend/analytics/controllers/agents.controller.js +16 -6
- package/dist/backend/analytics/controllers/messages.controller.js +1 -2
- package/dist/backend/analytics/dto/messages-query.dto.js +2 -8
- package/dist/backend/analytics/services/messages-query.service.js +23 -8
- package/dist/backend/auth/auth.instance.js +2 -1
- package/dist/backend/common/utils/product-telemetry.js +5 -2
- package/dist/backend/common/utils/provider-inference.js +30 -0
- package/dist/backend/database/migrations/1772960000000-PurgeNonCuratedModels.js +4 -0
- package/dist/backend/database/seed-models.js +25 -3
- package/dist/backend/model-prices/model-name-normalizer.js +22 -0
- package/dist/backend/otlp/guards/otlp-auth.guard.js +37 -1
- package/dist/backend/otlp/otlp.controller.js +0 -3
- package/dist/backend/routing/routing.service.js +9 -0
- package/dist/index.js +11 -11
- package/package.json +1 -1
- package/public/assets/{Account-D79xeKyT.js → Account-BTS5z9ZI.js} +1 -1
- package/public/assets/{AuthBadge-D4H7aZ6T.js → AuthBadge-CXkjgzF2.js} +1 -1
- package/public/assets/Help-BCxDh7o6.js +1 -0
- package/public/assets/{InfoTooltip-BgPRXOPt.js → InfoTooltip-Bno8U6nE.js} +1 -1
- package/public/assets/Limits-CRdLGW1-.js +1 -0
- package/public/assets/Login-CfGUFi77.js +1 -0
- package/public/assets/MessageLog-D_Cu7rch.js +1 -0
- package/public/assets/{ModelPrices-Dfn6eK1-.js → ModelPrices-BbHSkT6Z.js} +1 -1
- package/public/assets/Overview-kF_Bct6K.js +1 -0
- package/public/assets/{Pagination-qcyFxNyW.js → Pagination-CQk_Ps2L.js} +1 -1
- package/public/assets/{ProviderIcon-DkiiWOHz.js → ProviderIcon-CsB_Gx2t.js} +1 -1
- package/public/assets/{Register-DH-OYkxl.js → Register-CnO4K1tM.js} +1 -1
- package/public/assets/{ResetPassword-Bd22sqer.js → ResetPassword-iCeAfd1k.js} +1 -1
- package/public/assets/Routing-BRLZGQzX.js +3 -0
- package/public/assets/Settings-BKKkYuZx.js +1 -0
- package/public/assets/{SetupStepInstall-FQkRe6aV.js → SetupStepInstall-gm9pOgFh.js} +1 -1
- package/public/assets/{SetupStepVerify-NS7Lj6qk.js → SetupStepVerify-B01hQCeb.js} +1 -1
- package/public/assets/{SocialButtons-BmEEEVZg.js → SocialButtons-CJFTtTz6.js} +1 -1
- package/public/assets/{auth-yjhjkKyr.js → auth-C2bQ9WcQ.js} +1 -1
- package/public/assets/index-DrLOx3nR.js +2 -0
- package/public/assets/index-fyETryMo.css +1 -0
- package/public/assets/{overview-B6JfuXXv.js → overview-DoY4lTQc.js} +1 -1
- package/public/assets/vendor-K8fEFSq9.js +1 -0
- package/public/icons/providers/moonshot.svg +1 -1
- package/public/index.html +4 -4
- package/public/assets/Help-0qmJVFn8.js +0 -1
- package/public/assets/Limits-68Jol4KI.js +0 -1
- package/public/assets/Login-q9JoAR_x.js +0 -1
- package/public/assets/MessageLog-CUR9du7l.js +0 -1
- package/public/assets/Overview-QSa9JMZx.js +0 -1
- package/public/assets/Routing-C-8PKTEa.js +0 -3
- package/public/assets/Settings-B7NcLutw.js +0 -1
- package/public/assets/index-DBqZDW9Z.css +0 -1
- package/public/assets/index-DKNLgS0h.js +0 -2
- package/public/assets/vendor-COodrVsO.js +0 -1
package/README.md
CHANGED
|
@@ -57,6 +57,7 @@ Manifest is available in cloud and local versions. While both versions install t
|
|
|
57
57
|
- You don't want the telemetry data to move from your computer
|
|
58
58
|
- You don’t need multi-device access
|
|
59
59
|
- You don't want to subscribe to a cloud service
|
|
60
|
+
- You are using a local model like Ollama
|
|
60
61
|
|
|
61
62
|
If you don't know which version to choose, start with the **cloud version**.
|
|
62
63
|
|
|
@@ -21,6 +21,7 @@ const agent_analytics_service_1 = require("../services/agent-analytics.service")
|
|
|
21
21
|
const range_query_dto_1 = require("../../common/dto/range-query.dto");
|
|
22
22
|
const agent_cache_interceptor_1 = require("../../common/interceptors/agent-cache.interceptor");
|
|
23
23
|
const cache_constants_1 = require("../../common/constants/cache.constants");
|
|
24
|
+
const product_telemetry_1 = require("../../common/utils/product-telemetry");
|
|
24
25
|
let AgentAnalyticsController = class AgentAnalyticsController {
|
|
25
26
|
analytics;
|
|
26
27
|
constructor(analytics) {
|
|
@@ -29,7 +30,12 @@ let AgentAnalyticsController = class AgentAnalyticsController {
|
|
|
29
30
|
async getUsage(query, req) {
|
|
30
31
|
const range = query.range ?? '24h';
|
|
31
32
|
const ctx = req.ingestionContext;
|
|
32
|
-
|
|
33
|
+
const usage = await this.analytics.getUsage(range, ctx);
|
|
34
|
+
return {
|
|
35
|
+
...usage,
|
|
36
|
+
agentName: ctx.agentName,
|
|
37
|
+
telemetryId: (0, product_telemetry_1.hashForTelemetry)(ctx.userId),
|
|
38
|
+
};
|
|
33
39
|
}
|
|
34
40
|
async getCosts(query, req) {
|
|
35
41
|
const range = query.range ?? '7d';
|
|
@@ -14,6 +14,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.AgentsController = void 0;
|
|
16
16
|
const common_1 = require("@nestjs/common");
|
|
17
|
+
const typeorm_1 = require("typeorm");
|
|
17
18
|
const cache_manager_1 = require("@nestjs/cache-manager");
|
|
18
19
|
const config_1 = require("@nestjs/config");
|
|
19
20
|
const timeseries_queries_service_1 = require("../services/timeseries-queries.service");
|
|
@@ -52,12 +53,21 @@ let AgentsController = class AgentsController {
|
|
|
52
53
|
throw new common_1.BadRequestException('Agent name produces an empty slug');
|
|
53
54
|
}
|
|
54
55
|
const displayName = body.name.trim();
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
let result;
|
|
57
|
+
try {
|
|
58
|
+
result = await this.apiKeyGenerator.onboardAgent({
|
|
59
|
+
tenantName: user.id,
|
|
60
|
+
agentName: slug,
|
|
61
|
+
displayName,
|
|
62
|
+
email: user.email,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error instanceof typeorm_1.QueryFailedError && /unique|duplicate/i.test(error.message)) {
|
|
67
|
+
throw new common_1.ConflictException(`Agent "${slug}" already exists`);
|
|
68
|
+
}
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
61
71
|
(0, product_telemetry_1.trackCloudEvent)('agent_created', user.id, { agent_name: slug });
|
|
62
72
|
return {
|
|
63
73
|
agent: { id: result.agentId, name: slug, display_name: displayName },
|
|
@@ -26,9 +26,8 @@ let MessagesController = class MessagesController {
|
|
|
26
26
|
return this.messagesQuery.getMessages({
|
|
27
27
|
range: query.range,
|
|
28
28
|
userId: user.id,
|
|
29
|
-
|
|
29
|
+
provider: query.provider,
|
|
30
30
|
service_type: query.service_type,
|
|
31
|
-
model: query.model,
|
|
32
31
|
cost_min: query.cost_min,
|
|
33
32
|
cost_max: query.cost_max,
|
|
34
33
|
limit: Math.min(query.limit ?? 50, 200),
|
|
@@ -14,9 +14,8 @@ const class_transformer_1 = require("class-transformer");
|
|
|
14
14
|
const class_validator_1 = require("class-validator");
|
|
15
15
|
class MessagesQueryDto {
|
|
16
16
|
range;
|
|
17
|
-
|
|
17
|
+
provider;
|
|
18
18
|
service_type;
|
|
19
|
-
model;
|
|
20
19
|
cost_min;
|
|
21
20
|
cost_max;
|
|
22
21
|
limit;
|
|
@@ -33,17 +32,12 @@ __decorate([
|
|
|
33
32
|
(0, class_validator_1.IsOptional)(),
|
|
34
33
|
(0, class_validator_1.IsString)(),
|
|
35
34
|
__metadata("design:type", String)
|
|
36
|
-
], MessagesQueryDto.prototype, "
|
|
35
|
+
], MessagesQueryDto.prototype, "provider", void 0);
|
|
37
36
|
__decorate([
|
|
38
37
|
(0, class_validator_1.IsOptional)(),
|
|
39
38
|
(0, class_validator_1.IsString)(),
|
|
40
39
|
__metadata("design:type", String)
|
|
41
40
|
], MessagesQueryDto.prototype, "service_type", void 0);
|
|
42
|
-
__decorate([
|
|
43
|
-
(0, class_validator_1.IsOptional)(),
|
|
44
|
-
(0, class_validator_1.IsString)(),
|
|
45
|
-
__metadata("design:type", String)
|
|
46
|
-
], MessagesQueryDto.prototype, "model", void 0);
|
|
47
41
|
__decorate([
|
|
48
42
|
(0, class_validator_1.IsOptional)(),
|
|
49
43
|
(0, class_validator_1.IsNumber)(),
|
|
@@ -21,6 +21,7 @@ const range_util_1 = require("../../common/utils/range.util");
|
|
|
21
21
|
const query_helpers_1 = require("./query-helpers");
|
|
22
22
|
const tenant_cache_service_1 = require("../../common/services/tenant-cache.service");
|
|
23
23
|
const sql_dialect_1 = require("../../common/utils/sql-dialect");
|
|
24
|
+
const provider_inference_1 = require("../../common/utils/provider-inference");
|
|
24
25
|
const MODELS_CACHE_TTL_MS = 60_000;
|
|
25
26
|
const COUNT_CACHE_TTL_MS = 30_000;
|
|
26
27
|
const MAX_CACHE_ENTRIES = 5_000;
|
|
@@ -45,18 +46,23 @@ let MessagesQueryService = class MessagesQueryService {
|
|
|
45
46
|
baseQb.where('at.timestamp >= :cutoff', { cutoff });
|
|
46
47
|
}
|
|
47
48
|
(0, query_helpers_1.addTenantFilter)(baseQb, params.userId, undefined, tenantId);
|
|
48
|
-
if (params.status)
|
|
49
|
-
baseQb.andWhere('at.status = :status', { status: params.status });
|
|
50
49
|
if (params.service_type)
|
|
51
50
|
baseQb.andWhere('at.service_type = :serviceType', { serviceType: params.service_type });
|
|
52
|
-
if (params.model)
|
|
53
|
-
baseQb.andWhere('at.model = :model', { model: params.model });
|
|
54
51
|
if (params.cost_min !== undefined)
|
|
55
52
|
baseQb.andWhere('at.cost_usd >= :costMin', { costMin: params.cost_min });
|
|
56
53
|
if (params.cost_max !== undefined)
|
|
57
54
|
baseQb.andWhere('at.cost_usd <= :costMax', { costMax: params.cost_max });
|
|
58
55
|
if (params.agent_name)
|
|
59
56
|
baseQb.andWhere('at.agent_name = :filterAgent', { filterAgent: params.agent_name });
|
|
57
|
+
if (params.provider) {
|
|
58
|
+
const allModels = await this.getDistinctModels(params.userId, params.range, tenantId, params.agent_name);
|
|
59
|
+
const matching = allModels.filter((m) => (0, provider_inference_1.inferProviderFromModel)(m) === params.provider);
|
|
60
|
+
if (matching.length === 0) {
|
|
61
|
+
const providers = this.deriveProviders(allModels);
|
|
62
|
+
return { items: [], next_cursor: null, total_count: 0, providers };
|
|
63
|
+
}
|
|
64
|
+
baseQb.andWhere('at.model IN (:...providerModels)', { providerModels: matching });
|
|
65
|
+
}
|
|
60
66
|
const countCacheKey = this.buildCountCacheKey(params);
|
|
61
67
|
const countQb = baseQb.clone().select('COUNT(*)', 'total');
|
|
62
68
|
const costExpr = (0, sql_dialect_1.sqlCastFloat)((0, sql_dialect_1.sqlSanitizeCost)('at.cost_usd'), this.dialect);
|
|
@@ -98,7 +104,7 @@ let MessagesQueryService = class MessagesQueryService {
|
|
|
98
104
|
}
|
|
99
105
|
const cachedCount = params.cursor ? this.countCache.get(countCacheKey) : undefined;
|
|
100
106
|
const countHit = cachedCount && cachedCount.expiresAt > Date.now();
|
|
101
|
-
const [countResult, rows,
|
|
107
|
+
const [countResult, rows, allModels] = await Promise.all([
|
|
102
108
|
countHit ? null : countQb.getRawOne(),
|
|
103
109
|
dataQb
|
|
104
110
|
.orderBy('at.timestamp', 'DESC')
|
|
@@ -122,13 +128,23 @@ let MessagesQueryService = class MessagesQueryService {
|
|
|
122
128
|
const tsStr = ts instanceof Date ? (0, query_helpers_1.formatTimestamp)(ts) : String(ts ?? '');
|
|
123
129
|
const lastId = lastItem?.['id'];
|
|
124
130
|
const nextCursor = hasMore && lastItem ? `${tsStr}|${String(lastId)}` : null;
|
|
131
|
+
const providers = this.deriveProviders(allModels);
|
|
125
132
|
return {
|
|
126
133
|
items,
|
|
127
134
|
next_cursor: nextCursor,
|
|
128
135
|
total_count: totalCount,
|
|
129
|
-
|
|
136
|
+
providers,
|
|
130
137
|
};
|
|
131
138
|
}
|
|
139
|
+
deriveProviders(models) {
|
|
140
|
+
const seen = new Set();
|
|
141
|
+
for (const m of models) {
|
|
142
|
+
const p = (0, provider_inference_1.inferProviderFromModel)(m);
|
|
143
|
+
if (p)
|
|
144
|
+
seen.add(p);
|
|
145
|
+
}
|
|
146
|
+
return [...seen].sort();
|
|
147
|
+
}
|
|
132
148
|
async getDistinctModels(userId, range, tenantId, agentName) {
|
|
133
149
|
const cacheKey = `${userId}:${agentName ?? ''}:${range ?? 'all'}`;
|
|
134
150
|
const cached = this.modelsCache.get(cacheKey);
|
|
@@ -161,9 +177,8 @@ let MessagesQueryService = class MessagesQueryService {
|
|
|
161
177
|
return [
|
|
162
178
|
params.userId,
|
|
163
179
|
params.range ?? '',
|
|
164
|
-
params.
|
|
180
|
+
params.provider ?? '',
|
|
165
181
|
params.service_type ?? '',
|
|
166
|
-
params.model ?? '',
|
|
167
182
|
params.agent_name ?? '',
|
|
168
183
|
params.cost_min ?? '',
|
|
169
184
|
params.cost_max ?? '',
|
|
@@ -44,7 +44,7 @@ function buildTrustedOrigins() {
|
|
|
44
44
|
}
|
|
45
45
|
return origins;
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
const authInstance = isLocalMode
|
|
48
48
|
? null
|
|
49
49
|
: (0, better_auth_1.betterAuth)({
|
|
50
50
|
database: database,
|
|
@@ -126,4 +126,5 @@ exports.auth = isLocalMode
|
|
|
126
126
|
},
|
|
127
127
|
},
|
|
128
128
|
});
|
|
129
|
+
exports.auth = authInstance;
|
|
129
130
|
//# sourceMappingURL=auth.instance.js.map
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getMachineId = getMachineId;
|
|
4
4
|
exports.trackEvent = trackEvent;
|
|
5
|
+
exports.hashForTelemetry = hashForTelemetry;
|
|
5
6
|
exports.trackCloudEvent = trackCloudEvent;
|
|
6
7
|
const crypto_1 = require("crypto");
|
|
7
8
|
const os_1 = require("os");
|
|
@@ -34,13 +35,15 @@ function trackEvent(event, properties) {
|
|
|
34
35
|
...properties,
|
|
35
36
|
});
|
|
36
37
|
}
|
|
38
|
+
function hashForTelemetry(id) {
|
|
39
|
+
return (0, crypto_1.createHash)('sha256').update(id).digest('hex').slice(0, 16);
|
|
40
|
+
}
|
|
37
41
|
function trackCloudEvent(event, tenantId, properties) {
|
|
38
42
|
if (isOptedOut())
|
|
39
43
|
return;
|
|
40
|
-
const hashedTenant = (0, crypto_1.createHash)('sha256').update(tenantId).digest('hex').slice(0, 16);
|
|
41
44
|
const version = getPackageVersion();
|
|
42
45
|
(0, posthog_sender_1.sendToPostHog)(event, {
|
|
43
|
-
distinct_id:
|
|
46
|
+
distinct_id: hashForTelemetry(tenantId),
|
|
44
47
|
os: (0, os_1.platform)(),
|
|
45
48
|
os_version: (0, os_1.release)(),
|
|
46
49
|
node_version: process.versions.node,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.inferProviderFromModel = inferProviderFromModel;
|
|
4
|
+
const MODEL_PREFIX_MAP = [
|
|
5
|
+
[/^openrouter\//, 'openrouter'],
|
|
6
|
+
[/^claude-/, 'anthropic'],
|
|
7
|
+
[/^gpt-|^o[134]-|^o[134] |^chatgpt-/, 'openai'],
|
|
8
|
+
[/^gemini-/, 'gemini'],
|
|
9
|
+
[/^deepseek-/, 'deepseek'],
|
|
10
|
+
[/^grok-/, 'xai'],
|
|
11
|
+
[/^mistral-|^codestral|^pixtral|^open-mistral/, 'mistral'],
|
|
12
|
+
[/^kimi-|^moonshot-/, 'moonshot'],
|
|
13
|
+
[/^minimax-/i, 'minimax'],
|
|
14
|
+
[/^glm-/, 'zai'],
|
|
15
|
+
[/^qwen[23]|^qwq-/, 'qwen'],
|
|
16
|
+
[/^[a-z][\w-]*\//, 'openrouter'],
|
|
17
|
+
];
|
|
18
|
+
function inferProviderFromModel(model) {
|
|
19
|
+
if (model.startsWith('custom:'))
|
|
20
|
+
return 'custom';
|
|
21
|
+
if (/:/.test(model) && !model.endsWith(':free'))
|
|
22
|
+
return 'ollama';
|
|
23
|
+
const lower = model.toLowerCase();
|
|
24
|
+
for (const [re, id] of MODEL_PREFIX_MAP) {
|
|
25
|
+
if (re.test(lower))
|
|
26
|
+
return id;
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=provider-inference.js.map
|
|
@@ -3,8 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.PurgeNonCuratedModels1772960000000 = void 0;
|
|
4
4
|
const CURATED_MODELS = [
|
|
5
5
|
'claude-opus-4-6',
|
|
6
|
+
'claude-sonnet-4-6',
|
|
6
7
|
'claude-sonnet-4-5-20250929',
|
|
8
|
+
'claude-opus-4-5-20251101',
|
|
9
|
+
'claude-opus-4-1-20250805',
|
|
7
10
|
'claude-sonnet-4-20250514',
|
|
11
|
+
'claude-opus-4-20250514',
|
|
8
12
|
'claude-haiku-4-5-20251001',
|
|
9
13
|
'gpt-4o',
|
|
10
14
|
'gpt-4o-mini',
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SEED_MODELS = void 0;
|
|
4
4
|
exports.SEED_MODELS = [
|
|
5
|
-
['claude-opus-4-6', 'Anthropic', 0.
|
|
5
|
+
['claude-opus-4-6', 'Anthropic', 0.000005, 0.000025, 200000, true, true, 'Claude Opus 4.6'],
|
|
6
|
+
['claude-sonnet-4-6', 'Anthropic', 0.000003, 0.000015, 200000, true, true, 'Claude Sonnet 4.6'],
|
|
6
7
|
[
|
|
7
8
|
'claude-sonnet-4-5-20250929',
|
|
8
9
|
'Anthropic',
|
|
@@ -13,6 +14,26 @@ exports.SEED_MODELS = [
|
|
|
13
14
|
true,
|
|
14
15
|
'Claude Sonnet 4.5',
|
|
15
16
|
],
|
|
17
|
+
[
|
|
18
|
+
'claude-opus-4-5-20251101',
|
|
19
|
+
'Anthropic',
|
|
20
|
+
0.000015,
|
|
21
|
+
0.000075,
|
|
22
|
+
200000,
|
|
23
|
+
true,
|
|
24
|
+
true,
|
|
25
|
+
'Claude Opus 4.5',
|
|
26
|
+
],
|
|
27
|
+
[
|
|
28
|
+
'claude-opus-4-1-20250805',
|
|
29
|
+
'Anthropic',
|
|
30
|
+
0.000015,
|
|
31
|
+
0.000075,
|
|
32
|
+
200000,
|
|
33
|
+
true,
|
|
34
|
+
true,
|
|
35
|
+
'Claude Opus 4.1',
|
|
36
|
+
],
|
|
16
37
|
[
|
|
17
38
|
'claude-sonnet-4-20250514',
|
|
18
39
|
'Anthropic',
|
|
@@ -23,6 +44,7 @@ exports.SEED_MODELS = [
|
|
|
23
44
|
true,
|
|
24
45
|
'Claude Sonnet 4',
|
|
25
46
|
],
|
|
47
|
+
['claude-opus-4-20250514', 'Anthropic', 0.000015, 0.000075, 200000, true, true, 'Claude Opus 4'],
|
|
26
48
|
[
|
|
27
49
|
'claude-haiku-4-5-20251001',
|
|
28
50
|
'Anthropic',
|
|
@@ -100,8 +122,8 @@ exports.SEED_MODELS = [
|
|
|
100
122
|
[
|
|
101
123
|
'anthropic/claude-opus-4-6',
|
|
102
124
|
'OpenRouter',
|
|
103
|
-
0.
|
|
104
|
-
0.
|
|
125
|
+
0.000005,
|
|
126
|
+
0.000025,
|
|
105
127
|
200000,
|
|
106
128
|
true,
|
|
107
129
|
true,
|
|
@@ -3,12 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.stripProviderPrefix = stripProviderPrefix;
|
|
4
4
|
exports.stripDateSuffix = stripDateSuffix;
|
|
5
5
|
exports.buildAliasMap = buildAliasMap;
|
|
6
|
+
exports.normalizeDots = normalizeDots;
|
|
6
7
|
exports.resolveModelName = resolveModelName;
|
|
7
8
|
const KNOWN_ALIASES = [
|
|
8
9
|
['claude-opus-4', 'claude-opus-4-6'],
|
|
9
10
|
['claude-sonnet-4.5', 'claude-sonnet-4-5-20250929'],
|
|
11
|
+
['claude-sonnet-4-5', 'claude-sonnet-4-5-20250929'],
|
|
12
|
+
['claude-opus-4-5', 'claude-opus-4-5-20251101'],
|
|
13
|
+
['claude-opus-4-1', 'claude-opus-4-1-20250805'],
|
|
14
|
+
['claude-sonnet-4-0', 'claude-sonnet-4-20250514'],
|
|
15
|
+
['claude-opus-4-0', 'claude-opus-4-20250514'],
|
|
10
16
|
['claude-sonnet-4', 'claude-sonnet-4-20250514'],
|
|
11
17
|
['claude-haiku-4.5', 'claude-haiku-4-5-20251001'],
|
|
18
|
+
['claude-haiku-4-5', 'claude-haiku-4-5-20251001'],
|
|
12
19
|
['deepseek-v3', 'deepseek-chat'],
|
|
13
20
|
['deepseek-chat-v3-0324', 'deepseek-chat'],
|
|
14
21
|
['deepseek-r1', 'deepseek-reasoner'],
|
|
@@ -67,6 +74,9 @@ function buildAliasMap(canonicalNames) {
|
|
|
67
74
|
}
|
|
68
75
|
return map;
|
|
69
76
|
}
|
|
77
|
+
function normalizeDots(name) {
|
|
78
|
+
return name.replace(/\./g, '-');
|
|
79
|
+
}
|
|
70
80
|
function resolveModelName(name, aliasMap) {
|
|
71
81
|
const exact = aliasMap.get(name);
|
|
72
82
|
if (exact)
|
|
@@ -81,6 +91,18 @@ function resolveModelName(name, aliasMap) {
|
|
|
81
91
|
if (fromNoDate)
|
|
82
92
|
return fromNoDate;
|
|
83
93
|
}
|
|
94
|
+
const dotNorm = normalizeDots(stripped);
|
|
95
|
+
if (dotNorm !== stripped) {
|
|
96
|
+
const fromDotNorm = aliasMap.get(dotNorm);
|
|
97
|
+
if (fromDotNorm)
|
|
98
|
+
return fromDotNorm;
|
|
99
|
+
const dotNormNoDate = stripDateSuffix(dotNorm);
|
|
100
|
+
if (dotNormNoDate !== dotNorm) {
|
|
101
|
+
const fromDotNormNoDate = aliasMap.get(dotNormNoDate);
|
|
102
|
+
if (fromDotNormNoDate)
|
|
103
|
+
return fromDotNormNoDate;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
84
106
|
return undefined;
|
|
85
107
|
}
|
|
86
108
|
//# sourceMappingURL=model-name-normalizer.js.map
|
|
@@ -26,6 +26,7 @@ let OtlpAuthGuard = OtlpAuthGuard_1 = class OtlpAuthGuard {
|
|
|
26
26
|
keyRepo;
|
|
27
27
|
logger = new common_1.Logger(OtlpAuthGuard_1.name);
|
|
28
28
|
cache = new Map();
|
|
29
|
+
devContext = null;
|
|
29
30
|
CACHE_TTL_MS = 5 * 60 * 1000;
|
|
30
31
|
MAX_CACHE_SIZE = 10_000;
|
|
31
32
|
cleanupTimer;
|
|
@@ -42,7 +43,9 @@ let OtlpAuthGuard = OtlpAuthGuard_1 = class OtlpAuthGuard {
|
|
|
42
43
|
async canActivate(context) {
|
|
43
44
|
const request = context.switchToHttp().getRequest();
|
|
44
45
|
const authHeader = request.headers['authorization'];
|
|
45
|
-
const
|
|
46
|
+
const isLoopback = LOOPBACK_IPS.has(request.ip ?? '');
|
|
47
|
+
const isLocal = process.env['MANIFEST_MODE'] === 'local' && isLoopback;
|
|
48
|
+
const isDevLoopback = process.env['NODE_ENV'] === 'development' && isLoopback;
|
|
46
49
|
if (!authHeader && isLocal) {
|
|
47
50
|
request.ingestionContext = {
|
|
48
51
|
tenantId: local_mode_constants_1.LOCAL_TENANT_ID,
|
|
@@ -52,6 +55,13 @@ let OtlpAuthGuard = OtlpAuthGuard_1 = class OtlpAuthGuard {
|
|
|
52
55
|
};
|
|
53
56
|
return true;
|
|
54
57
|
}
|
|
58
|
+
if (!authHeader && isDevLoopback) {
|
|
59
|
+
const devCtx = await this.resolveDevContext();
|
|
60
|
+
if (devCtx) {
|
|
61
|
+
request.ingestionContext = devCtx;
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
55
65
|
if (!authHeader) {
|
|
56
66
|
this.logger.warn(`OTLP request without auth from ${request.ip}`);
|
|
57
67
|
throw new common_1.UnauthorizedException('Authorization header required');
|
|
@@ -70,6 +80,13 @@ let OtlpAuthGuard = OtlpAuthGuard_1 = class OtlpAuthGuard {
|
|
|
70
80
|
};
|
|
71
81
|
return true;
|
|
72
82
|
}
|
|
83
|
+
if (isDevLoopback) {
|
|
84
|
+
const devCtx = await this.resolveDevContext();
|
|
85
|
+
if (devCtx) {
|
|
86
|
+
request.ingestionContext = devCtx;
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
73
90
|
throw new common_1.UnauthorizedException('Invalid API key format');
|
|
74
91
|
}
|
|
75
92
|
const cached = this.cache.get(token);
|
|
@@ -127,6 +144,25 @@ let OtlpAuthGuard = OtlpAuthGuard_1 = class OtlpAuthGuard {
|
|
|
127
144
|
clearCache() {
|
|
128
145
|
this.cache.clear();
|
|
129
146
|
}
|
|
147
|
+
async resolveDevContext() {
|
|
148
|
+
if (this.devContext && this.devContext.expiresAt > Date.now()) {
|
|
149
|
+
return this.devContext.context;
|
|
150
|
+
}
|
|
151
|
+
const keyRecord = await this.keyRepo.findOne({
|
|
152
|
+
where: { is_active: true },
|
|
153
|
+
relations: ['agent', 'tenant'],
|
|
154
|
+
});
|
|
155
|
+
if (!keyRecord)
|
|
156
|
+
return null;
|
|
157
|
+
const ctx = {
|
|
158
|
+
tenantId: keyRecord.tenant_id,
|
|
159
|
+
agentId: keyRecord.agent_id,
|
|
160
|
+
agentName: keyRecord.agent.name,
|
|
161
|
+
userId: keyRecord.tenant.name,
|
|
162
|
+
};
|
|
163
|
+
this.devContext = { context: ctx, expiresAt: Date.now() + this.CACHE_TTL_MS };
|
|
164
|
+
return ctx;
|
|
165
|
+
}
|
|
130
166
|
evictExpired() {
|
|
131
167
|
const now = Date.now();
|
|
132
168
|
for (const [key, entry] of this.cache) {
|
|
@@ -91,9 +91,6 @@ let OtlpController = OtlpController_1 = class OtlpController {
|
|
|
91
91
|
if (this.seenAgents.has(ctx.agentId))
|
|
92
92
|
return;
|
|
93
93
|
this.seenAgents.add(ctx.agentId);
|
|
94
|
-
(0, product_telemetry_1.trackCloudEvent)('plugin_registered', ctx.userId, {
|
|
95
|
-
source: 'backend',
|
|
96
|
-
});
|
|
97
94
|
(0, product_telemetry_1.trackCloudEvent)('first_telemetry_received', ctx.userId, {
|
|
98
95
|
agent_id_hash: ctx.agentId.slice(0, 8),
|
|
99
96
|
});
|
|
@@ -96,6 +96,11 @@ let RoutingService = RoutingService_1 = class RoutingService {
|
|
|
96
96
|
});
|
|
97
97
|
if (existing)
|
|
98
98
|
return { isNew: false };
|
|
99
|
+
const hasApiKey = await this.providerRepo.findOne({
|
|
100
|
+
where: { agent_id: agentId, provider, auth_type: 'api_key', is_active: true },
|
|
101
|
+
});
|
|
102
|
+
if (hasApiKey)
|
|
103
|
+
return { isNew: false };
|
|
99
104
|
const record = Object.assign(new user_provider_entity_1.UserProvider(), {
|
|
100
105
|
id: (0, crypto_1.randomUUID)(),
|
|
101
106
|
user_id: userId,
|
|
@@ -279,6 +284,10 @@ let RoutingService = RoutingService_1 = class RoutingService {
|
|
|
279
284
|
if (existing) {
|
|
280
285
|
existing.override_model = model;
|
|
281
286
|
existing.override_auth_type = authType ?? null;
|
|
287
|
+
if (existing.fallback_models?.includes(model)) {
|
|
288
|
+
const filtered = existing.fallback_models.filter((m) => m !== model);
|
|
289
|
+
existing.fallback_models = filtered.length > 0 ? filtered : null;
|
|
290
|
+
}
|
|
282
291
|
existing.updated_at = new Date().toISOString();
|
|
283
292
|
await this.tierRepo.save(existing);
|
|
284
293
|
this.routingCache.invalidateAgent(agentId);
|