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.
Files changed (26) hide show
  1. package/dist/backend/common/utils/sql-dialect.js +14 -11
  2. package/dist/backend/notifications/emails/threshold-alert.js +3 -2
  3. package/dist/backend/routing/proxy/google-adapter.js +42 -1
  4. package/dist/backend/routing/proxy/proxy.service.js +12 -13
  5. package/dist/backend/routing/resolve.controller.js +8 -2
  6. package/dist/backend/routing/routing.controller.js +2 -1
  7. package/dist/backend/routing/routing.service.js +23 -0
  8. package/dist/index.js +13 -13
  9. package/package.json +1 -1
  10. package/public/assets/{Account-BAroz-2n.js → Account-D79xeKyT.js} +1 -1
  11. package/public/assets/{Limits-_v1HGbea.js → Limits-68Jol4KI.js} +1 -1
  12. package/public/assets/{Login-C6lI_KqN.js → Login-q9JoAR_x.js} +1 -1
  13. package/public/assets/{MessageLog-BfxZUc6f.js → MessageLog-CUR9du7l.js} +1 -1
  14. package/public/assets/{ModelPrices-DlrK7bqu.js → ModelPrices-Dfn6eK1-.js} +1 -1
  15. package/public/assets/Overview-QSa9JMZx.js +1 -0
  16. package/public/assets/{Register-B-nLlx_2.js → Register-DH-OYkxl.js} +1 -1
  17. package/public/assets/{ResetPassword-CJEPkh6G.js → ResetPassword-Bd22sqer.js} +1 -1
  18. package/public/assets/{Routing-D1z4fqN4.js → Routing-C-8PKTEa.js} +1 -1
  19. package/public/assets/{Settings-DBVVmq_T.js → Settings-B7NcLutw.js} +1 -1
  20. package/public/assets/{SocialButtons-BQ4JTq-l.js → SocialButtons-BmEEEVZg.js} +1 -1
  21. package/public/assets/index-DBqZDW9Z.css +1 -0
  22. package/public/assets/{index-BhcU06cr.js → index-DKNLgS0h.js} +2 -2
  23. package/public/assets/{overview-_flXQc4-.js → overview-B6JfuXXv.js} +1 -1
  24. package/public/index.html +2 -2
  25. package/public/assets/Overview-CfezCKlq.js +0 -1
  26. 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
- return new Date(Date.now() - ms).toISOString();
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().toISOString();
39
+ return formatLocalIso(new Date());
41
40
  }
42
41
  function sqlHourBucket(col, dialect) {
43
- return dialect === 'sqlite'
44
- ? `strftime('%Y-%m-%dT%H:00:00', ${col})`
45
- : `to_char(date_trunc('hour', ${col}), 'YYYY-MM-DD"T"HH24:MI:SS')`;
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
- ? `:${paramName}`
66
- : `CAST(:${paramName} AS interval)`;
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 `$${value.toFixed(4)}`;
22
- return value.toLocaleString();
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.toFixed(2)}`
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.toFixed(2)}`
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
- return scoringMessages.some((m) => {
196
- if (m.role !== 'user')
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.upsertProvider(agentId, userId, item.provider, undefined, 'subscription');
59
- registered++;
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: body.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)