manifest 5.24.0 → 5.24.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/dist/backend/common/utils/sql-dialect.js +14 -11
- package/dist/backend/notifications/emails/threshold-alert.js +3 -2
- package/dist/backend/routing/proxy/google-adapter.js +42 -1
- package/dist/backend/routing/proxy/proxy.service.js +12 -13
- package/dist/backend/routing/resolve.controller.js +8 -2
- package/dist/backend/routing/routing.controller.js +2 -1
- package/dist/backend/routing/routing.service.js +23 -0
- package/dist/index.js +13 -13
- package/package.json +1 -1
- package/public/assets/{Account-BAroz-2n.js → Account-D79xeKyT.js} +1 -1
- package/public/assets/{Limits-_v1HGbea.js → Limits-68Jol4KI.js} +1 -1
- package/public/assets/{Login-C6lI_KqN.js → Login-q9JoAR_x.js} +1 -1
- package/public/assets/{MessageLog-BfxZUc6f.js → MessageLog-CUR9du7l.js} +1 -1
- package/public/assets/{ModelPrices-DlrK7bqu.js → ModelPrices-Dfn6eK1-.js} +1 -1
- package/public/assets/Overview-QSa9JMZx.js +1 -0
- package/public/assets/{Register-B-nLlx_2.js → Register-DH-OYkxl.js} +1 -1
- package/public/assets/{ResetPassword-CJEPkh6G.js → ResetPassword-Bd22sqer.js} +1 -1
- package/public/assets/{Routing-D1z4fqN4.js → Routing-C-8PKTEa.js} +1 -1
- package/public/assets/{Settings-DBVVmq_T.js → Settings-B7NcLutw.js} +1 -1
- package/public/assets/{SocialButtons-BQ4JTq-l.js → SocialButtons-BmEEEVZg.js} +1 -1
- package/public/assets/index-DBqZDW9Z.css +1 -0
- package/public/assets/{index-BhcU06cr.js → index-DKNLgS0h.js} +2 -2
- package/public/assets/{overview-_flXQc4-.js → overview-B6JfuXXv.js} +1 -1
- package/public/index.html +2 -2
- package/public/assets/Overview-CfezCKlq.js +0 -1
- package/public/assets/index-D4x6Xoo9.css +0 -1
|
@@ -18,13 +18,12 @@ function timestampType() {
|
|
|
18
18
|
return process.env['MANIFEST_MODE'] === 'local' ? 'datetime' : 'timestamp';
|
|
19
19
|
}
|
|
20
20
|
function timestampDefault() {
|
|
21
|
-
return process.env['MANIFEST_MODE'] === 'local'
|
|
22
|
-
? () => 'CURRENT_TIMESTAMP'
|
|
23
|
-
: () => 'NOW()';
|
|
21
|
+
return process.env['MANIFEST_MODE'] === 'local' ? () => 'CURRENT_TIMESTAMP' : () => 'NOW()';
|
|
24
22
|
}
|
|
25
23
|
function computeCutoff(interval) {
|
|
26
24
|
const ms = intervalToMs(interval);
|
|
27
|
-
|
|
25
|
+
const cutoff = new Date(Date.now() - ms);
|
|
26
|
+
return formatLocalIso(cutoff);
|
|
28
27
|
}
|
|
29
28
|
function intervalToMs(interval) {
|
|
30
29
|
const match = interval.match(/^(\d+)\s+(hour|hours|day|days)$/);
|
|
@@ -37,12 +36,13 @@ function intervalToMs(interval) {
|
|
|
37
36
|
return unit.startsWith('hour') ? n * 3600_000 : n * 86400_000;
|
|
38
37
|
}
|
|
39
38
|
function sqlNow() {
|
|
40
|
-
return new Date()
|
|
39
|
+
return formatLocalIso(new Date());
|
|
41
40
|
}
|
|
42
41
|
function sqlHourBucket(col, dialect) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
if (dialect === 'sqlite') {
|
|
43
|
+
return `strftime('%Y-%m-%dT%H:00:00', ${col})`;
|
|
44
|
+
}
|
|
45
|
+
return `to_char(date_trunc('hour', ${col}), 'YYYY-MM-DD"T"HH24:MI:SS')`;
|
|
46
46
|
}
|
|
47
47
|
function sqlDateBucket(col, dialect) {
|
|
48
48
|
return dialect === 'sqlite'
|
|
@@ -61,8 +61,11 @@ function portableSql(sql, dialect) {
|
|
|
61
61
|
return sql.replace(/\$\d+/g, '?');
|
|
62
62
|
}
|
|
63
63
|
function sqlCastInterval(paramName, dialect) {
|
|
64
|
-
return dialect === 'sqlite'
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
return dialect === 'sqlite' ? `:${paramName}` : `CAST(:${paramName} AS interval)`;
|
|
65
|
+
}
|
|
66
|
+
function formatLocalIso(d) {
|
|
67
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
68
|
+
return (`${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}` +
|
|
69
|
+
`T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`);
|
|
67
70
|
}
|
|
68
71
|
//# sourceMappingURL=sql-dialect.js.map
|
|
@@ -17,9 +17,10 @@ function formatTimestamp(raw) {
|
|
|
17
17
|
return `${monthName} ${dayNum}, ${timePart}`;
|
|
18
18
|
}
|
|
19
19
|
function formatValue(value, metric) {
|
|
20
|
+
const num = Number(value);
|
|
20
21
|
if (metric === 'cost')
|
|
21
|
-
return `$${
|
|
22
|
-
return
|
|
22
|
+
return `$${num.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
23
|
+
return num.toLocaleString(undefined, { maximumFractionDigits: 0 });
|
|
23
24
|
}
|
|
24
25
|
function ThresholdAlertEmail(props) {
|
|
25
26
|
const { agentName, metricType, threshold, actualValue, period, timestamp, agentUrl, logoUrl = 'https://app.manifest.build/manifest-logo.png', alertType = 'hard', periodResetDate, } = props;
|
|
@@ -4,6 +4,47 @@ exports.toGoogleRequest = toGoogleRequest;
|
|
|
4
4
|
exports.fromGoogleResponse = fromGoogleResponse;
|
|
5
5
|
exports.transformGoogleStreamChunk = transformGoogleStreamChunk;
|
|
6
6
|
const crypto_1 = require("crypto");
|
|
7
|
+
const UNSUPPORTED_SCHEMA_FIELDS = new Set([
|
|
8
|
+
'patternProperties',
|
|
9
|
+
'additionalProperties',
|
|
10
|
+
'$schema',
|
|
11
|
+
'$id',
|
|
12
|
+
'$ref',
|
|
13
|
+
'$defs',
|
|
14
|
+
'definitions',
|
|
15
|
+
'allOf',
|
|
16
|
+
'anyOf',
|
|
17
|
+
'oneOf',
|
|
18
|
+
'not',
|
|
19
|
+
'if',
|
|
20
|
+
'then',
|
|
21
|
+
'else',
|
|
22
|
+
'dependentSchemas',
|
|
23
|
+
'dependentRequired',
|
|
24
|
+
'unevaluatedProperties',
|
|
25
|
+
'unevaluatedItems',
|
|
26
|
+
'contentMediaType',
|
|
27
|
+
'contentEncoding',
|
|
28
|
+
'examples',
|
|
29
|
+
'default',
|
|
30
|
+
'const',
|
|
31
|
+
'title',
|
|
32
|
+
]);
|
|
33
|
+
function sanitizeSchema(schema, isPropertiesMap = false) {
|
|
34
|
+
if (schema === null || schema === undefined || typeof schema !== 'object') {
|
|
35
|
+
return schema;
|
|
36
|
+
}
|
|
37
|
+
if (Array.isArray(schema)) {
|
|
38
|
+
return schema.map((item) => sanitizeSchema(item));
|
|
39
|
+
}
|
|
40
|
+
const result = {};
|
|
41
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
42
|
+
if (!isPropertiesMap && UNSUPPORTED_SCHEMA_FIELDS.has(key))
|
|
43
|
+
continue;
|
|
44
|
+
result[key] = sanitizeSchema(value, key === 'properties');
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
7
48
|
function mapRole(role) {
|
|
8
49
|
if (role === 'assistant')
|
|
9
50
|
return 'model';
|
|
@@ -64,7 +105,7 @@ function convertTools(tools) {
|
|
|
64
105
|
return {
|
|
65
106
|
name: fn.name,
|
|
66
107
|
description: fn.description,
|
|
67
|
-
parameters: fn.parameters,
|
|
108
|
+
parameters: fn.parameters ? sanitizeSchema(fn.parameters) : undefined,
|
|
68
109
|
};
|
|
69
110
|
})
|
|
70
111
|
.filter(Boolean);
|
|
@@ -173,11 +173,11 @@ let ProxyService = ProxyService_1 = class ProxyService {
|
|
|
173
173
|
if (!exceeded)
|
|
174
174
|
return;
|
|
175
175
|
const fmt = exceeded.metricType === 'cost'
|
|
176
|
-
? `$${exceeded.actual.
|
|
177
|
-
: exceeded.actual.toLocaleString();
|
|
176
|
+
? `$${Number(exceeded.actual).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
|
|
177
|
+
: Number(exceeded.actual).toLocaleString(undefined, { maximumFractionDigits: 0 });
|
|
178
178
|
const threshFmt = exceeded.metricType === 'cost'
|
|
179
|
-
? `$${exceeded.threshold.
|
|
180
|
-
: exceeded.threshold.toLocaleString();
|
|
179
|
+
? `$${Number(exceeded.threshold).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`
|
|
180
|
+
: Number(exceeded.threshold).toLocaleString(undefined, { maximumFractionDigits: 0 });
|
|
181
181
|
throw new common_1.HttpException({
|
|
182
182
|
error: {
|
|
183
183
|
message: `Limit exceeded: ${exceeded.metricType} usage (${fmt}) exceeds ${threshFmt} per ${exceeded.period}`,
|
|
@@ -192,16 +192,15 @@ let ProxyService = ProxyService_1 = class ProxyService {
|
|
|
192
192
|
.slice(-SCORING_RECENT_MESSAGES);
|
|
193
193
|
}
|
|
194
194
|
detectHeartbeat(scoringMessages) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return false;
|
|
198
|
-
if (typeof m.content === 'string')
|
|
199
|
-
return m.content.includes('HEARTBEAT_OK');
|
|
200
|
-
if (Array.isArray(m.content)) {
|
|
201
|
-
return m.content.some((p) => p.type === 'text' && typeof p.text === 'string' && p.text.includes('HEARTBEAT_OK'));
|
|
202
|
-
}
|
|
195
|
+
const lastUser = [...scoringMessages].reverse().find((m) => m.role === 'user');
|
|
196
|
+
if (!lastUser)
|
|
203
197
|
return false;
|
|
204
|
-
|
|
198
|
+
if (typeof lastUser.content === 'string')
|
|
199
|
+
return lastUser.content.includes('HEARTBEAT_OK');
|
|
200
|
+
if (Array.isArray(lastUser.content)) {
|
|
201
|
+
return lastUser.content.some((p) => p.type === 'text' && typeof p.text === 'string' && p.text.includes('HEARTBEAT_OK'));
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
205
204
|
}
|
|
206
205
|
async forwardToProvider(provider, apiKey, model, body, stream, sessionKey, signal, authType) {
|
|
207
206
|
const extraHeaders = {};
|
|
@@ -21,6 +21,7 @@ const otlp_auth_guard_1 = require("../otlp/guards/otlp-auth.guard");
|
|
|
21
21
|
const resolve_service_1 = require("./resolve.service");
|
|
22
22
|
const routing_service_1 = require("./routing.service");
|
|
23
23
|
const resolve_request_dto_1 = require("./dto/resolve-request.dto");
|
|
24
|
+
const product_telemetry_1 = require("../common/utils/product-telemetry");
|
|
24
25
|
class SubscriptionProviderItem {
|
|
25
26
|
provider;
|
|
26
27
|
}
|
|
@@ -55,8 +56,13 @@ let ResolveController = class ResolveController {
|
|
|
55
56
|
const { agentId, userId } = req.ingestionContext;
|
|
56
57
|
let registered = 0;
|
|
57
58
|
for (const item of body.providers) {
|
|
58
|
-
await this.routingService.
|
|
59
|
-
|
|
59
|
+
const { isNew } = await this.routingService.registerSubscriptionProvider(agentId, userId, item.provider);
|
|
60
|
+
if (isNew) {
|
|
61
|
+
(0, product_telemetry_1.trackCloudEvent)('routing_provider_connected', userId, {
|
|
62
|
+
provider: `${item.provider} (Subscription)`,
|
|
63
|
+
});
|
|
64
|
+
registered++;
|
|
65
|
+
}
|
|
60
66
|
}
|
|
61
67
|
return { registered };
|
|
62
68
|
}
|
|
@@ -62,8 +62,9 @@ let RoutingController = class RoutingController {
|
|
|
62
62
|
}
|
|
63
63
|
const { provider: result, isNew } = await this.routingService.upsertProvider(agent.id, user.id, body.provider, body.apiKey, body.authType);
|
|
64
64
|
if (isNew) {
|
|
65
|
+
const providerLabel = body.authType === 'subscription' ? `${body.provider} (Subscription)` : body.provider;
|
|
65
66
|
(0, product_telemetry_1.trackCloudEvent)('routing_provider_connected', user.id, {
|
|
66
|
-
provider:
|
|
67
|
+
provider: providerLabel,
|
|
67
68
|
});
|
|
68
69
|
}
|
|
69
70
|
return {
|
|
@@ -90,6 +90,29 @@ let RoutingService = RoutingService_1 = class RoutingService {
|
|
|
90
90
|
this.routingCache.invalidateAgent(agentId);
|
|
91
91
|
return { provider: record, isNew: true };
|
|
92
92
|
}
|
|
93
|
+
async registerSubscriptionProvider(agentId, userId, provider) {
|
|
94
|
+
const existing = await this.providerRepo.findOne({
|
|
95
|
+
where: { agent_id: agentId, provider, auth_type: 'subscription' },
|
|
96
|
+
});
|
|
97
|
+
if (existing)
|
|
98
|
+
return { isNew: false };
|
|
99
|
+
const record = Object.assign(new user_provider_entity_1.UserProvider(), {
|
|
100
|
+
id: (0, crypto_1.randomUUID)(),
|
|
101
|
+
user_id: userId,
|
|
102
|
+
agent_id: agentId,
|
|
103
|
+
provider,
|
|
104
|
+
auth_type: 'subscription',
|
|
105
|
+
api_key_encrypted: null,
|
|
106
|
+
key_prefix: null,
|
|
107
|
+
is_active: true,
|
|
108
|
+
connected_at: new Date().toISOString(),
|
|
109
|
+
updated_at: new Date().toISOString(),
|
|
110
|
+
});
|
|
111
|
+
await this.providerRepo.insert(record);
|
|
112
|
+
await this.autoAssign.recalculate(agentId);
|
|
113
|
+
this.routingCache.invalidateAgent(agentId);
|
|
114
|
+
return { isNew: true };
|
|
115
|
+
}
|
|
93
116
|
async removeProvider(agentId, provider, authType) {
|
|
94
117
|
const where = { agent_id: agentId, provider };
|
|
95
118
|
if (authType)
|