manifest 5.35.0 → 5.35.2
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/database/models-dev-sync.service.js +7 -0
- package/dist/backend/model-discovery/model-fallback.js +7 -0
- package/dist/backend/model-discovery/provider-model-fetcher.service.js +9 -1
- package/dist/backend/model-prices/model-name-normalizer.js +16 -0
- package/dist/backend/model-prices/model-pricing-cache.service.js +16 -1
- package/dist/backend/notifications/emails/threshold-alert.js +5 -1
- package/dist/backend/notifications/notifications.controller.js +16 -1
- package/dist/backend/notifications/services/limit-check.service.js +11 -14
- package/dist/backend/notifications/services/notification-cron.service.js +15 -18
- package/dist/backend/notifications/services/notification-email.service.js +3 -2
- package/dist/backend/notifications/services/notification-log.service.js +9 -0
- package/dist/backend/routing/proxy/anthropic-adapter.js +1 -3
- package/dist/backend/routing/proxy/chatgpt-adapter.js +119 -85
- package/dist/backend/routing/proxy/chatgpt-helpers.js +108 -0
- package/dist/backend/routing/proxy/proxy-fallback.service.js +15 -3
- package/dist/backend/routing/proxy/proxy-response-handler.js +2 -2
- package/dist/backend/routing/proxy/proxy.service.js +17 -6
- package/dist/backend/routing/resolve/resolve.service.js +2 -1
- package/dist/backend/routing/routing-core/provider-key.service.js +12 -2
- package/dist/openclaw.plugin.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/public/assets/{Account-Bmij8ZrS.js → Account-B_oSTrdf.js} +1 -1
- package/public/assets/Limits-HwYePaDb.js +1 -0
- package/public/assets/{Login-B6PWrEGq.js → Login-BWgCdMOB.js} +1 -1
- package/public/assets/{MessageLog-Cb_ucG8H.js → MessageLog-TkfamA_u.js} +1 -1
- package/public/assets/ModelPrices-Bg-zVU9G.js +1 -0
- package/public/assets/{Overview-DY7f_oAi.js → Overview-ByF5CHrf.js} +1 -1
- package/public/assets/{Register-CbGDtQku.js → Register-BDPUwPD6.js} +1 -1
- package/public/assets/{ResetPassword-DFQ1lTig.js → ResetPassword-BuNNDKRS.js} +1 -1
- package/public/assets/{Routing-Kn93Tqlz.js → Routing-95JQekwl.js} +1 -1
- package/public/assets/{Settings-BZw5xW8c.js → Settings-DPVOsBPN.js} +1 -1
- package/public/assets/{SocialButtons-DEIg2R3v.js → SocialButtons-tQY9m0lz.js} +1 -1
- package/public/assets/{index-BCCvBxnZ.js → index--P4PCJDm.js} +2 -2
- package/public/assets/index-BsqwVwB3.css +1 -0
- package/public/assets/{model-display-C23X2Y_y.js → model-display-DmgfqEg8.js} +1 -1
- package/public/assets/{overview-DGoLsOFJ.js → overview-D5Ohx_UN.js} +1 -1
- package/public/assets/{routing-C26EmiVE.js → routing-Bf9SE33r.js} +1 -1
- package/public/assets/{routing-utils-DGg0JMgE.js → routing-utils-U3G1-aWH.js} +1 -1
- package/public/index.html +2 -2
- package/public/logo-white.svg +81 -79
- package/public/assets/Limits-CJay2wDy.js +0 -1
- package/public/assets/ModelPrices-CK2tG0zg.js +0 -1
- package/public/assets/index-D6OW2yDC.css +0 -1
|
@@ -41,6 +41,7 @@ const VERSION_SUFFIX_RE = /-\d{3}$/;
|
|
|
41
41
|
const DATE_SUFFIX_RE = /-\d{4}-?\d{2}-?\d{2}$/;
|
|
42
42
|
const SHORT_DATE_SUFFIX_RE = /-\d{4}$/;
|
|
43
43
|
const LATEST_SUFFIX = '-latest';
|
|
44
|
+
const GOOGLE_VARIANT_RE = /-(?:preview(?:-\d{2,4}){1,3}|exp-\d{4}|latest)$/;
|
|
44
45
|
const REASONING_SUFFIX_RE = /-(reasoning|non-reasoning)$/;
|
|
45
46
|
let ModelsDevSyncService = ModelsDevSyncService_1 = class ModelsDevSyncService {
|
|
46
47
|
logger = new common_1.Logger(ModelsDevSyncService_1.name);
|
|
@@ -111,6 +112,12 @@ let ModelsDevSyncService = ModelsDevSyncService_1 = class ModelsDevSyncService {
|
|
|
111
112
|
if (found)
|
|
112
113
|
return found;
|
|
113
114
|
}
|
|
115
|
+
const noGoogleVariant = modelId.replace(GOOGLE_VARIANT_RE, '');
|
|
116
|
+
if (noGoogleVariant !== modelId) {
|
|
117
|
+
const found = providerModels.get(noGoogleVariant);
|
|
118
|
+
if (found)
|
|
119
|
+
return found;
|
|
120
|
+
}
|
|
114
121
|
const noReasoning = modelId.replace(REASONING_SUFFIX_RE, '');
|
|
115
122
|
if (noReasoning !== modelId) {
|
|
116
123
|
const found = providerModels.get(noReasoning);
|
|
@@ -9,6 +9,7 @@ exports.supplementWithKnownModels = supplementWithKnownModels;
|
|
|
9
9
|
const providers_1 = require("../common/constants/providers");
|
|
10
10
|
const manifest_shared_1 = require("manifest-shared");
|
|
11
11
|
const anthropic_model_id_1 = require("../common/utils/anthropic-model-id");
|
|
12
|
+
const model_name_normalizer_1 = require("../model-prices/model-name-normalizer");
|
|
12
13
|
function normalizeProviderModelId(providerId, modelId) {
|
|
13
14
|
return providerId.toLowerCase() === 'anthropic'
|
|
14
15
|
? (0, anthropic_model_id_1.normalizeAnthropicShortModelId)(modelId)
|
|
@@ -62,6 +63,12 @@ function lookupWithVariants(pricingSync, prefix, modelId) {
|
|
|
62
63
|
const freeResult = pricingSync.lookupPricing(`${prefix}/${modelId}:free`);
|
|
63
64
|
if (freeResult)
|
|
64
65
|
return freeResult;
|
|
66
|
+
const noGoogleVariant = modelId.replace(model_name_normalizer_1.GOOGLE_VARIANT_RE, '');
|
|
67
|
+
if (noGoogleVariant !== modelId) {
|
|
68
|
+
const result = pricingSync.lookupPricing(`${prefix}/${noGoogleVariant}`);
|
|
69
|
+
if (result)
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
65
72
|
return null;
|
|
66
73
|
}
|
|
67
74
|
function buildModelsDevFallback(modelsDevSync, providerId) {
|
|
@@ -49,9 +49,17 @@ const parseOpenAI = createModelParser({
|
|
|
49
49
|
getDisplayName: (_entry, id) => id,
|
|
50
50
|
});
|
|
51
51
|
const OPENAI_NON_CHAT_RE = /(?:embed|tts|whisper|dall-e|moderation|davinci|babbage|^text-|audio|realtime|-transcribe|^sora|^gpt-3\.5-turbo-instruct)/i;
|
|
52
|
+
const OPENAI_DATE_SUFFIX_RE = /-\d{4}-\d{2}-\d{2}$/;
|
|
52
53
|
const OPENAI_RESPONSES_ONLY_RE = /(?:-codex(?!-mini-latest)|^gpt-5[^/]*-pro(?:-|$))/i;
|
|
53
54
|
function parseOpenAIChatOnly(body, provider) {
|
|
54
|
-
|
|
55
|
+
const filtered = parseOpenAI(body, provider).filter((m) => !OPENAI_NON_CHAT_RE.test(m.id) && !OPENAI_RESPONSES_ONLY_RE.test(m.id));
|
|
56
|
+
const ids = new Set(filtered.map((m) => m.id));
|
|
57
|
+
return filtered.filter((m) => {
|
|
58
|
+
if (!OPENAI_DATE_SUFFIX_RE.test(m.id))
|
|
59
|
+
return true;
|
|
60
|
+
const alias = m.id.replace(OPENAI_DATE_SUFFIX_RE, '');
|
|
61
|
+
return !ids.has(alias);
|
|
62
|
+
});
|
|
55
63
|
}
|
|
56
64
|
const MISTRAL_NON_CHAT_RE = /(?:^mistral-ocr|embed)/i;
|
|
57
65
|
function parseMistralChatOnly(body, provider) {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GOOGLE_VARIANT_RE = void 0;
|
|
4
|
+
exports.stripGoogleVariant = stripGoogleVariant;
|
|
3
5
|
exports.stripProviderPrefix = stripProviderPrefix;
|
|
4
6
|
exports.stripDateSuffix = stripDateSuffix;
|
|
5
7
|
exports.buildAliasMap = buildAliasMap;
|
|
@@ -37,6 +39,10 @@ const PROVIDER_PREFIXES = [
|
|
|
37
39
|
];
|
|
38
40
|
const DATE_SUFFIX_RE = /-\d{4}-?\d{2}-?\d{2}$/;
|
|
39
41
|
const VERSION_SUFFIX_RE = /-\d{3}$/;
|
|
42
|
+
exports.GOOGLE_VARIANT_RE = /-(?:preview(?:-\d{2,4}){1,3}|exp-\d{4}|latest)$/;
|
|
43
|
+
function stripGoogleVariant(name) {
|
|
44
|
+
return name.replace(exports.GOOGLE_VARIANT_RE, '');
|
|
45
|
+
}
|
|
40
46
|
function stripProviderPrefix(name) {
|
|
41
47
|
for (const prefix of PROVIDER_PREFIXES) {
|
|
42
48
|
if (name.startsWith(prefix)) {
|
|
@@ -65,6 +71,10 @@ function buildAliasMap(canonicalNames) {
|
|
|
65
71
|
if (bareNoVersion !== bare && !map.has(bareNoVersion)) {
|
|
66
72
|
map.set(bareNoVersion, name);
|
|
67
73
|
}
|
|
74
|
+
const bareNoVariant = stripGoogleVariant(bare);
|
|
75
|
+
if (bareNoVariant !== bare && !map.has(bareNoVariant)) {
|
|
76
|
+
map.set(bareNoVariant, name);
|
|
77
|
+
}
|
|
68
78
|
for (const variant of (0, anthropic_model_id_1.buildAnthropicShortModelIdVariants)(bare)) {
|
|
69
79
|
if (!map.has(variant)) {
|
|
70
80
|
map.set(variant, name);
|
|
@@ -96,6 +106,12 @@ function resolveModelName(name, aliasMap) {
|
|
|
96
106
|
if (fromNoDate)
|
|
97
107
|
return fromNoDate;
|
|
98
108
|
}
|
|
109
|
+
const noVariant = stripGoogleVariant(stripped);
|
|
110
|
+
if (noVariant !== stripped) {
|
|
111
|
+
const fromNoVariant = aliasMap.get(noVariant);
|
|
112
|
+
if (fromNoVariant)
|
|
113
|
+
return fromNoVariant;
|
|
114
|
+
}
|
|
99
115
|
const dotNorm = normalizeDots(stripped);
|
|
100
116
|
if (dotNorm !== stripped) {
|
|
101
117
|
const fromDotNorm = aliasMap.get(dotNorm);
|
|
@@ -15,6 +15,7 @@ var ModelPricingCacheService_1;
|
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
16
|
exports.ModelPricingCacheService = void 0;
|
|
17
17
|
const common_1 = require("@nestjs/common");
|
|
18
|
+
const schedule_1 = require("@nestjs/schedule");
|
|
18
19
|
const model_name_normalizer_1 = require("./model-name-normalizer");
|
|
19
20
|
const pricing_sync_service_1 = require("../database/pricing-sync.service");
|
|
20
21
|
const models_dev_sync_service_1 = require("../database/models-dev-sync.service");
|
|
@@ -35,6 +36,9 @@ let ModelPricingCacheService = ModelPricingCacheService_1 = class ModelPricingCa
|
|
|
35
36
|
async onApplicationBootstrap() {
|
|
36
37
|
await this.reload();
|
|
37
38
|
}
|
|
39
|
+
async scheduledReload() {
|
|
40
|
+
await this.reload();
|
|
41
|
+
}
|
|
38
42
|
async reload() {
|
|
39
43
|
this.cache.clear();
|
|
40
44
|
const orCache = this.pricingSync.getAll();
|
|
@@ -115,7 +119,12 @@ let ModelPricingCacheService = ModelPricingCacheService_1 = class ModelPricingCa
|
|
|
115
119
|
validated: this.resolveValidatedForModelsDev(providerId, model.id),
|
|
116
120
|
source: 'models.dev',
|
|
117
121
|
};
|
|
118
|
-
this.cache.
|
|
122
|
+
const existing = this.cache.get(model.id);
|
|
123
|
+
const hasRealPricing = existing && (existing.input_price_per_token ?? 0) > 0;
|
|
124
|
+
const isZeroPricing = (model.inputPricePerToken ?? 0) === 0 && (model.outputPricePerToken ?? 0) === 0;
|
|
125
|
+
if (!hasRealPricing || !isZeroPricing) {
|
|
126
|
+
this.cache.set(model.id, pricingEntry);
|
|
127
|
+
}
|
|
119
128
|
for (const prefix of registryEntry.openRouterPrefixes) {
|
|
120
129
|
const prefixedKey = `${prefix}/${model.id}`;
|
|
121
130
|
if (this.cache.has(prefixedKey)) {
|
|
@@ -145,6 +154,12 @@ let ModelPricingCacheService = ModelPricingCacheService_1 = class ModelPricingCa
|
|
|
145
154
|
}
|
|
146
155
|
};
|
|
147
156
|
exports.ModelPricingCacheService = ModelPricingCacheService;
|
|
157
|
+
__decorate([
|
|
158
|
+
(0, schedule_1.Cron)('0 5 * * *'),
|
|
159
|
+
__metadata("design:type", Function),
|
|
160
|
+
__metadata("design:paramtypes", []),
|
|
161
|
+
__metadata("design:returntype", Promise)
|
|
162
|
+
], ModelPricingCacheService.prototype, "scheduledReload", null);
|
|
148
163
|
exports.ModelPricingCacheService = ModelPricingCacheService = ModelPricingCacheService_1 = __decorate([
|
|
149
164
|
(0, common_1.Injectable)(),
|
|
150
165
|
__param(1, (0, common_1.Optional)()),
|
|
@@ -28,7 +28,11 @@ function ThresholdAlertEmail(props) {
|
|
|
28
28
|
const accentColor = isSoft ? '#ea580c' : '#dc2626';
|
|
29
29
|
const accentBg = isSoft ? '#fff7ed' : '#fef2f2';
|
|
30
30
|
const accentBorder = isSoft ? '#fed7aa' : '#fecaca';
|
|
31
|
-
return ((0, jsx_runtime_1.jsxs)(components_1.Html, { children: [(0, jsx_runtime_1.jsx)(components_1.Head, {}), (0, jsx_runtime_1.
|
|
31
|
+
return ((0, jsx_runtime_1.jsxs)(components_1.Html, { children: [(0, jsx_runtime_1.jsx)(components_1.Head, {}), (0, jsx_runtime_1.jsx)(components_1.Preview, { children: isSoft
|
|
32
|
+
? `${agentName} exceeded ${metricType} threshold (${formatValue(actualValue, metricType)})`
|
|
33
|
+
: `${agentName} has been blocked — ${metricType} limit reached (${formatValue(actualValue, metricType)} / ${formatValue(threshold, metricType)})` }), (0, jsx_runtime_1.jsx)(components_1.Body, { style: body, children: (0, jsx_runtime_1.jsxs)(components_1.Container, { style: container, children: [(0, jsx_runtime_1.jsx)(components_1.Section, { style: logoSection, children: (0, jsx_runtime_1.jsx)(components_1.Img, { src: logoUrl, alt: "Manifest", width: "140", height: "32", style: logoImg }) }), (0, jsx_runtime_1.jsxs)(components_1.Section, { style: card, children: [(0, jsx_runtime_1.jsx)(components_1.Section, { style: alertBadgeContainer, children: (0, jsx_runtime_1.jsx)(components_1.Text, { style: { ...alertBadge, color: accentColor, backgroundColor: accentBg }, children: isSoft ? 'Warning' : 'Agent blocked' }) }), (0, jsx_runtime_1.jsx)(components_1.Text, { style: heading, children: isSoft
|
|
34
|
+
? `${agentName} exceeded the ${metricType} limit`
|
|
35
|
+
: `${agentName} has been blocked` }), (0, jsx_runtime_1.jsx)(components_1.Text, { style: paragraph, children: isSoft ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["Your agent ", (0, jsx_runtime_1.jsx)("strong", { children: agentName }), " has exceeded the", ' ', (0, jsx_runtime_1.jsx)("strong", { children: metricType }), " threshold for the current ", (0, jsx_runtime_1.jsx)("strong", { children: period }), ' ', "period."] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["Your agent ", (0, jsx_runtime_1.jsx)("strong", { children: agentName }), " has reached the", ' ', (0, jsx_runtime_1.jsx)("strong", { children: metricType }), " limit of", ' ', (0, jsx_runtime_1.jsx)("strong", { children: formatValue(threshold, metricType) }), " per", ' ', (0, jsx_runtime_1.jsx)("strong", { children: period }), ". New requests are blocked to protect your budget."] })) }), isSoft ? ((0, jsx_runtime_1.jsx)(components_1.Text, { style: paragraph, children: "Requests are still being processed normally." })) : ((0, jsx_runtime_1.jsx)(components_1.Section, { style: { ...hardLimitBox, backgroundColor: accentBg, borderColor: accentBorder }, children: (0, jsx_runtime_1.jsxs)(components_1.Text, { style: { ...hardLimitText, color: accentColor }, children: ["Requests are now blocked until the next period resets", periodResetDate ? ` on ${formatTimestamp(periodResetDate)}` : '', "."] }) })), (0, jsx_runtime_1.jsxs)(components_1.Section, { style: statsRow, children: [(0, jsx_runtime_1.jsxs)(components_1.Section, { style: statBox, children: [(0, jsx_runtime_1.jsx)(components_1.Text, { style: statLabel, children: "Threshold" }), (0, jsx_runtime_1.jsx)(components_1.Text, { style: statValue, children: formatValue(threshold, metricType) })] }), (0, jsx_runtime_1.jsxs)(components_1.Section, { style: { ...statBoxAlert, backgroundColor: accentBg, borderColor: accentBorder }, children: [(0, jsx_runtime_1.jsx)(components_1.Text, { style: statLabel, children: isSoft ? 'Actual usage' : 'Current usage' }), (0, jsx_runtime_1.jsx)(components_1.Text, { style: { ...statValueAlert, color: accentColor }, children: formatValue(actualValue, metricType) })] })] }), (0, jsx_runtime_1.jsxs)(components_1.Section, { style: metaRow, children: [(0, jsx_runtime_1.jsxs)(components_1.Text, { style: metaText, children: ["Period: ", period] }), (0, jsx_runtime_1.jsxs)(components_1.Text, { style: metaText, children: ["Triggered: ", formatTimestamp(timestamp)] })] }), (0, jsx_runtime_1.jsx)(components_1.Section, { style: ctaContainer, children: (0, jsx_runtime_1.jsx)(components_1.Button, { style: ctaButton, href: agentUrl, children: "View Agent Dashboard \u2192" }) })] }), (0, jsx_runtime_1.jsx)(components_1.Hr, { style: divider }), (0, jsx_runtime_1.jsxs)(components_1.Section, { style: footer, children: [(0, jsx_runtime_1.jsx)(components_1.Text, { style: footerNote, children: "You are receiving this because you set up a notification rule in Manifest." }), (0, jsx_runtime_1.jsxs)(components_1.Text, { style: footerMuted, children: ["\u00A9 2026 MNFST Inc. All rights reserved.", ' ', (0, jsx_runtime_1.jsx)(components_1.Link, { href: "https://manifest.build", style: footerLink, children: "manifest.build" })] })] })] }) })] }));
|
|
32
36
|
}
|
|
33
37
|
const brandBg = '#f8f6f1';
|
|
34
38
|
const brandCardBg = '#ffffff';
|
|
@@ -17,6 +17,7 @@ exports.NotificationsController = void 0;
|
|
|
17
17
|
const common_1 = require("@nestjs/common");
|
|
18
18
|
const current_user_decorator_1 = require("../auth/current-user.decorator");
|
|
19
19
|
const notification_rules_service_1 = require("./services/notification-rules.service");
|
|
20
|
+
const notification_log_service_1 = require("./services/notification-log.service");
|
|
20
21
|
const email_provider_config_service_1 = require("./services/email-provider-config.service");
|
|
21
22
|
const notification_cron_service_1 = require("./services/notification-cron.service");
|
|
22
23
|
const limit_check_service_1 = require("./services/limit-check.service");
|
|
@@ -24,12 +25,14 @@ const notification_rule_dto_1 = require("./dto/notification-rule.dto");
|
|
|
24
25
|
const set_email_provider_dto_1 = require("./dto/set-email-provider.dto");
|
|
25
26
|
let NotificationsController = NotificationsController_1 = class NotificationsController {
|
|
26
27
|
rulesService;
|
|
28
|
+
notificationLog;
|
|
27
29
|
emailProviderConfigService;
|
|
28
30
|
cronService;
|
|
29
31
|
limitCheck;
|
|
30
32
|
logger = new common_1.Logger(NotificationsController_1.name);
|
|
31
|
-
constructor(rulesService, emailProviderConfigService, cronService, limitCheck) {
|
|
33
|
+
constructor(rulesService, notificationLog, emailProviderConfigService, cronService, limitCheck) {
|
|
32
34
|
this.rulesService = rulesService;
|
|
35
|
+
this.notificationLog = notificationLog;
|
|
33
36
|
this.emailProviderConfigService = emailProviderConfigService;
|
|
34
37
|
this.cronService = cronService;
|
|
35
38
|
this.limitCheck = limitCheck;
|
|
@@ -64,6 +67,9 @@ let NotificationsController = NotificationsController_1 = class NotificationsCon
|
|
|
64
67
|
const triggered = await this.cronService.checkThresholds(user.id);
|
|
65
68
|
return { triggered, message: `${triggered} notification(s) triggered` };
|
|
66
69
|
}
|
|
70
|
+
async getLogs(agentName, user) {
|
|
71
|
+
return this.notificationLog.getLogsForAgent(user.id, agentName);
|
|
72
|
+
}
|
|
67
73
|
async listRules(agentName, user) {
|
|
68
74
|
return this.rulesService.listRules(user.id, agentName);
|
|
69
75
|
}
|
|
@@ -149,6 +155,14 @@ __decorate([
|
|
|
149
155
|
__metadata("design:paramtypes", [Object]),
|
|
150
156
|
__metadata("design:returntype", Promise)
|
|
151
157
|
], NotificationsController.prototype, "triggerCheck", null);
|
|
158
|
+
__decorate([
|
|
159
|
+
(0, common_1.Get)('logs'),
|
|
160
|
+
__param(0, (0, common_1.Query)('agent_name')),
|
|
161
|
+
__param(1, (0, current_user_decorator_1.CurrentUser)()),
|
|
162
|
+
__metadata("design:type", Function),
|
|
163
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
164
|
+
__metadata("design:returntype", Promise)
|
|
165
|
+
], NotificationsController.prototype, "getLogs", null);
|
|
152
166
|
__decorate([
|
|
153
167
|
(0, common_1.Get)(),
|
|
154
168
|
__param(0, (0, common_1.Query)('agent_name')),
|
|
@@ -185,6 +199,7 @@ __decorate([
|
|
|
185
199
|
exports.NotificationsController = NotificationsController = NotificationsController_1 = __decorate([
|
|
186
200
|
(0, common_1.Controller)('api/v1/notifications'),
|
|
187
201
|
__metadata("design:paramtypes", [notification_rules_service_1.NotificationRulesService,
|
|
202
|
+
notification_log_service_1.NotificationLogService,
|
|
188
203
|
email_provider_config_service_1.EmailProviderConfigService,
|
|
189
204
|
notification_cron_service_1.NotificationCronService,
|
|
190
205
|
limit_check_service_1.LimitCheckService])
|
|
@@ -85,9 +85,18 @@ let LimitCheckService = LimitCheckService_1 = class LimitCheckService {
|
|
|
85
85
|
const now = (0, notification_log_service_1.formatNotificationTimestamp)();
|
|
86
86
|
const providerConfig = await this.emailProviderConfig.getFullConfig(rule.user_id);
|
|
87
87
|
const email = await this.notificationLog.resolveUserEmail(rule.user_id, providerConfig?.notificationEmail);
|
|
88
|
-
|
|
88
|
+
await this.notificationLog.insertLog({
|
|
89
|
+
ruleId: rule.id,
|
|
90
|
+
periodStart,
|
|
91
|
+
periodEnd,
|
|
92
|
+
actualValue: actual,
|
|
93
|
+
thresholdValue: rule.threshold,
|
|
94
|
+
metricType: rule.metric_type,
|
|
95
|
+
agentName: rule.agent_name,
|
|
96
|
+
sentAt: now,
|
|
97
|
+
});
|
|
89
98
|
if (email) {
|
|
90
|
-
|
|
99
|
+
await this.emailService.sendThresholdAlert(email, {
|
|
91
100
|
agentName: rule.agent_name,
|
|
92
101
|
metricType: rule.metric_type,
|
|
93
102
|
threshold: rule.threshold,
|
|
@@ -99,18 +108,6 @@ let LimitCheckService = LimitCheckService_1 = class LimitCheckService {
|
|
|
99
108
|
periodResetDate: (0, period_util_1.computePeriodResetDate)(rule.period),
|
|
100
109
|
}, providerConfig ?? undefined);
|
|
101
110
|
}
|
|
102
|
-
if (emailSent || !email) {
|
|
103
|
-
await this.notificationLog.insertLog({
|
|
104
|
-
ruleId: rule.id,
|
|
105
|
-
periodStart,
|
|
106
|
-
periodEnd,
|
|
107
|
-
actualValue: actual,
|
|
108
|
-
thresholdValue: rule.threshold,
|
|
109
|
-
metricType: rule.metric_type,
|
|
110
|
-
agentName: rule.agent_name,
|
|
111
|
-
sentAt: now,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
111
|
}
|
|
115
112
|
async getCachedRules(tenantId, agentName) {
|
|
116
113
|
const key = `${tenantId}:${agentName}`;
|
|
@@ -102,9 +102,18 @@ let NotificationCronService = NotificationCronService_1 = class NotificationCron
|
|
|
102
102
|
const now = (0, notification_log_service_1.formatNotificationTimestamp)();
|
|
103
103
|
const fullConfig = await this.emailProviderConfigService.getFullConfig(rule.user_id);
|
|
104
104
|
const email = await this.notificationLog.resolveUserEmail(rule.user_id, fullConfig?.notificationEmail);
|
|
105
|
-
|
|
105
|
+
await this.notificationLog.insertLog({
|
|
106
|
+
ruleId: rule.id,
|
|
107
|
+
periodStart,
|
|
108
|
+
periodEnd,
|
|
109
|
+
actualValue: actual,
|
|
110
|
+
thresholdValue: rule.threshold,
|
|
111
|
+
metricType: rule.metric_type,
|
|
112
|
+
agentName: rule.agent_name,
|
|
113
|
+
sentAt: now,
|
|
114
|
+
});
|
|
106
115
|
if (email) {
|
|
107
|
-
emailSent = await this.emailService.sendThresholdAlert(email, {
|
|
116
|
+
const emailSent = await this.emailService.sendThresholdAlert(email, {
|
|
108
117
|
agentName: rule.agent_name,
|
|
109
118
|
metricType: rule.metric_type,
|
|
110
119
|
threshold: rule.threshold,
|
|
@@ -114,26 +123,14 @@ let NotificationCronService = NotificationCronService_1 = class NotificationCron
|
|
|
114
123
|
agentUrl: `${this.runtime.getAuthBaseUrl()}/agents/${encodeURIComponent(rule.agent_name)}`,
|
|
115
124
|
alertType: 'soft',
|
|
116
125
|
}, fullConfig ?? undefined);
|
|
126
|
+
if (!emailSent) {
|
|
127
|
+
this.logger.warn(`Failed to send alert for rule ${rule.id}, will retry next cron run`);
|
|
128
|
+
}
|
|
117
129
|
}
|
|
118
130
|
else {
|
|
119
131
|
this.logger.warn(`No email found for user ${rule.user_id}, skipping alert for rule ${rule.id}`);
|
|
120
132
|
}
|
|
121
|
-
|
|
122
|
-
await this.notificationLog.insertLog({
|
|
123
|
-
ruleId: rule.id,
|
|
124
|
-
periodStart,
|
|
125
|
-
periodEnd,
|
|
126
|
-
actualValue: actual,
|
|
127
|
-
thresholdValue: rule.threshold,
|
|
128
|
-
metricType: rule.metric_type,
|
|
129
|
-
agentName: rule.agent_name,
|
|
130
|
-
sentAt: now,
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
this.logger.warn(`Failed to send alert for rule ${rule.id}, will retry next cron run`);
|
|
135
|
-
}
|
|
136
|
-
return emailSent || !email;
|
|
133
|
+
return true;
|
|
137
134
|
}
|
|
138
135
|
};
|
|
139
136
|
exports.NotificationCronService = NotificationCronService;
|
|
@@ -29,8 +29,9 @@ let NotificationEmailService = NotificationEmailService_1 = class NotificationEm
|
|
|
29
29
|
const element = (0, threshold_alert_1.ThresholdAlertEmail)(props);
|
|
30
30
|
const html = await (0, render_1.render)(element);
|
|
31
31
|
const text = await (0, render_1.render)(element, { plainText: true });
|
|
32
|
-
const
|
|
33
|
-
|
|
32
|
+
const subject = props.alertType === 'soft'
|
|
33
|
+
? `Warning: ${props.agentName} exceeded ${props.metricType} threshold`
|
|
34
|
+
: `Blocked: ${props.agentName} reached ${props.metricType} limit`;
|
|
34
35
|
if (providerConfig) {
|
|
35
36
|
const defaultFrom = this.fromEmail;
|
|
36
37
|
const from = providerConfig.domain
|
|
@@ -51,6 +51,15 @@ let NotificationLogService = class NotificationLogService {
|
|
|
51
51
|
params.sentAt,
|
|
52
52
|
]);
|
|
53
53
|
}
|
|
54
|
+
async getLogsForAgent(userId, agentName) {
|
|
55
|
+
return this.ds.query(this.sql(`SELECT nl.id, nl.sent_at, nl.actual_value, nl.threshold_value,
|
|
56
|
+
nl.metric_type, nl.period_start, nl.period_end, nl.agent_name
|
|
57
|
+
FROM notification_logs nl
|
|
58
|
+
JOIN notification_rules nr ON nr.id = nl.rule_id
|
|
59
|
+
WHERE nr.user_id = $1 AND nl.agent_name = $2
|
|
60
|
+
ORDER BY nl.sent_at DESC
|
|
61
|
+
LIMIT 50`), [userId, agentName]);
|
|
62
|
+
}
|
|
54
63
|
async resolveUserEmail(userId, notificationEmail) {
|
|
55
64
|
if (notificationEmail)
|
|
56
65
|
return notificationEmail;
|
|
@@ -34,7 +34,7 @@ function extractSystemBlocks(messages) {
|
|
|
34
34
|
}
|
|
35
35
|
function toContentBlocks(content) {
|
|
36
36
|
if (typeof content === 'string')
|
|
37
|
-
return [{ type: 'text', text: content }];
|
|
37
|
+
return content ? [{ type: 'text', text: content }] : [];
|
|
38
38
|
if (Array.isArray(content)) {
|
|
39
39
|
return content
|
|
40
40
|
.filter((b) => b.type === 'text' && typeof b.text === 'string')
|
|
@@ -98,8 +98,6 @@ function toAnthropicRequest(body, _model, options) {
|
|
|
98
98
|
messages: converted,
|
|
99
99
|
max_tokens: body.max_tokens || 4096,
|
|
100
100
|
};
|
|
101
|
-
if (shouldCache)
|
|
102
|
-
result.cache_control = { type: 'ephemeral' };
|
|
103
101
|
if (systemBlocks.length > 0)
|
|
104
102
|
result.system = systemBlocks;
|
|
105
103
|
const tools = convertTools(body.tools);
|
|
@@ -4,37 +4,80 @@ exports.toResponsesRequest = toResponsesRequest;
|
|
|
4
4
|
exports.fromResponsesResponse = fromResponsesResponse;
|
|
5
5
|
exports.transformResponsesStreamChunk = transformResponsesStreamChunk;
|
|
6
6
|
const crypto_1 = require("crypto");
|
|
7
|
-
const
|
|
7
|
+
const chatgpt_helpers_1 = require("./chatgpt-helpers");
|
|
8
8
|
function toResponsesRequest(body, model) {
|
|
9
9
|
const messages = (body.messages ?? []);
|
|
10
|
-
const input =
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const input = [];
|
|
11
|
+
for (const message of messages) {
|
|
12
|
+
if (message.role === 'system' || message.role === 'developer')
|
|
13
|
+
continue;
|
|
14
|
+
if (message.role === 'assistant' &&
|
|
15
|
+
Array.isArray(message.tool_calls) &&
|
|
16
|
+
message.tool_calls.length > 0) {
|
|
17
|
+
const assistantText = (0, chatgpt_helpers_1.extractTextContent)(message.content);
|
|
18
|
+
if (assistantText) {
|
|
19
|
+
input.push({ role: 'assistant', content: (0, chatgpt_helpers_1.convertContent)(assistantText, 'assistant') });
|
|
20
|
+
}
|
|
21
|
+
input.push(...(0, chatgpt_helpers_1.convertAssistantToolCalls)(message.tool_calls));
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (message.role === 'tool' || message.role === 'function') {
|
|
25
|
+
input.push({
|
|
26
|
+
type: 'function_call_output',
|
|
27
|
+
call_id: typeof message.tool_call_id === 'string' ? message.tool_call_id : (0, crypto_1.randomUUID)(),
|
|
28
|
+
output: (0, chatgpt_helpers_1.extractTextContent)(message.content) ?? JSON.stringify(message.content ?? ''),
|
|
29
|
+
});
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
input.push({ role: message.role, content: (0, chatgpt_helpers_1.convertContent)(message.content, message.role) });
|
|
33
|
+
}
|
|
13
34
|
const request = {
|
|
14
35
|
model,
|
|
15
36
|
input,
|
|
16
37
|
stream: body.stream !== false,
|
|
17
38
|
store: false,
|
|
18
|
-
instructions: extractInstructions(messages),
|
|
39
|
+
instructions: (0, chatgpt_helpers_1.extractInstructions)(messages),
|
|
19
40
|
};
|
|
41
|
+
if (Array.isArray(body.tools)) {
|
|
42
|
+
request.tools = (0, chatgpt_helpers_1.convertTools)(body.tools);
|
|
43
|
+
}
|
|
20
44
|
return request;
|
|
21
45
|
}
|
|
22
46
|
function fromResponsesResponse(data, model) {
|
|
23
47
|
const output = (data.output ?? []);
|
|
24
48
|
let text = '';
|
|
49
|
+
const toolCalls = [];
|
|
25
50
|
for (const item of output) {
|
|
26
|
-
if (item.type
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
51
|
+
if (item.type === 'message') {
|
|
52
|
+
const content = item.content;
|
|
53
|
+
if (!content)
|
|
54
|
+
continue;
|
|
55
|
+
for (const part of content) {
|
|
56
|
+
if (part.type === 'output_text' && part.text)
|
|
57
|
+
text += part.text;
|
|
58
|
+
}
|
|
30
59
|
continue;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
60
|
+
}
|
|
61
|
+
if (item.type === 'function_call') {
|
|
62
|
+
toolCalls.push({
|
|
63
|
+
id: item.call_id ?? (0, crypto_1.randomUUID)(),
|
|
64
|
+
type: 'function',
|
|
65
|
+
function: {
|
|
66
|
+
name: item.name ?? '',
|
|
67
|
+
arguments: item.arguments ?? '{}',
|
|
68
|
+
},
|
|
69
|
+
});
|
|
34
70
|
}
|
|
35
71
|
}
|
|
36
72
|
const usage = data.usage ?? {};
|
|
37
73
|
const inputDetails = usage.input_tokens_details;
|
|
74
|
+
const message = {
|
|
75
|
+
role: 'assistant',
|
|
76
|
+
content: text || null,
|
|
77
|
+
};
|
|
78
|
+
if (toolCalls.length > 0) {
|
|
79
|
+
message.tool_calls = toolCalls;
|
|
80
|
+
}
|
|
38
81
|
return {
|
|
39
82
|
id: `chatcmpl-${(0, crypto_1.randomUUID)().replace(/-/g, '').slice(0, 29)}`,
|
|
40
83
|
object: 'chat.completion',
|
|
@@ -43,8 +86,8 @@ function fromResponsesResponse(data, model) {
|
|
|
43
86
|
choices: [
|
|
44
87
|
{
|
|
45
88
|
index: 0,
|
|
46
|
-
message
|
|
47
|
-
finish_reason: 'stop',
|
|
89
|
+
message,
|
|
90
|
+
finish_reason: toolCalls.length > 0 ? 'tool_calls' : 'stop',
|
|
48
91
|
},
|
|
49
92
|
],
|
|
50
93
|
usage: {
|
|
@@ -74,84 +117,75 @@ function transformResponsesStreamChunk(chunk, model) {
|
|
|
74
117
|
if (!eventType && !dataStr)
|
|
75
118
|
return null;
|
|
76
119
|
if (eventType === 'response.output_text.delta') {
|
|
77
|
-
const data = safeParse(dataStr);
|
|
120
|
+
const data = (0, chatgpt_helpers_1.safeParse)(dataStr);
|
|
78
121
|
if (!data)
|
|
79
122
|
return null;
|
|
80
123
|
const delta = typeof data.delta === 'string' ? data.delta : '';
|
|
81
|
-
return formatSSE({ delta: { content: delta }, finish_reason: null }, model);
|
|
82
|
-
}
|
|
83
|
-
if (eventType === 'response.completed') {
|
|
84
|
-
const data = safeParse(dataStr);
|
|
85
|
-
const respUsage = data?.response?.usage;
|
|
86
|
-
const respDetails = data?.response?.usage;
|
|
87
|
-
const cachedTokens = respDetails?.input_tokens_details?.cached_tokens ?? 0;
|
|
88
|
-
const usage = respUsage
|
|
89
|
-
? {
|
|
90
|
-
prompt_tokens: respUsage.input_tokens ?? 0,
|
|
91
|
-
completion_tokens: respUsage.output_tokens ?? 0,
|
|
92
|
-
total_tokens: respUsage.total_tokens ?? 0,
|
|
93
|
-
cache_read_tokens: cachedTokens,
|
|
94
|
-
cache_creation_tokens: 0,
|
|
95
|
-
}
|
|
96
|
-
: undefined;
|
|
97
|
-
const finish = formatSSE({ delta: {}, finish_reason: 'stop' }, model, usage);
|
|
98
|
-
return `${finish}\ndata: [DONE]\n\n`;
|
|
124
|
+
return (0, chatgpt_helpers_1.formatSSE)({ delta: { content: delta }, finish_reason: null }, model);
|
|
99
125
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const parts = [];
|
|
117
|
-
for (const message of messages) {
|
|
118
|
-
if (message.role !== 'system' && message.role !== 'developer')
|
|
119
|
-
continue;
|
|
120
|
-
parts.push(...extractTextParts(message.content));
|
|
126
|
+
if (eventType === 'response.function_call_arguments.delta') {
|
|
127
|
+
const data = (0, chatgpt_helpers_1.safeParse)(dataStr);
|
|
128
|
+
if (!data)
|
|
129
|
+
return null;
|
|
130
|
+
const delta = typeof data.delta === 'string' ? data.delta : '';
|
|
131
|
+
return (0, chatgpt_helpers_1.formatSSE)({
|
|
132
|
+
delta: {
|
|
133
|
+
tool_calls: [
|
|
134
|
+
{
|
|
135
|
+
index: typeof data.output_index === 'number' ? data.output_index : 0,
|
|
136
|
+
function: { arguments: delta },
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
finish_reason: null,
|
|
141
|
+
}, model);
|
|
121
142
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
143
|
+
if (eventType === 'response.output_item.added') {
|
|
144
|
+
const data = (0, chatgpt_helpers_1.safeParse)(dataStr);
|
|
145
|
+
if (!data)
|
|
146
|
+
return null;
|
|
147
|
+
const item = (0, chatgpt_helpers_1.isObjectRecord)(data.item) ? data.item : undefined;
|
|
148
|
+
if (item?.type !== 'function_call')
|
|
149
|
+
return null;
|
|
150
|
+
return (0, chatgpt_helpers_1.formatSSE)({
|
|
151
|
+
delta: {
|
|
152
|
+
tool_calls: [
|
|
153
|
+
{
|
|
154
|
+
index: typeof data.output_index === 'number' ? data.output_index : 0,
|
|
155
|
+
id: item.call_id ?? '',
|
|
156
|
+
type: 'function',
|
|
157
|
+
function: { name: item.name ?? '', arguments: '' },
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
finish_reason: null,
|
|
162
|
+
}, model);
|
|
140
163
|
}
|
|
141
|
-
|
|
142
|
-
return
|
|
164
|
+
if (eventType === 'response.completed') {
|
|
165
|
+
return handleCompletedEvent(dataStr, model);
|
|
143
166
|
}
|
|
167
|
+
return null;
|
|
144
168
|
}
|
|
145
|
-
function
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
169
|
+
function handleCompletedEvent(dataStr, model) {
|
|
170
|
+
const data = (0, chatgpt_helpers_1.safeParse)(dataStr);
|
|
171
|
+
const response = (0, chatgpt_helpers_1.isObjectRecord)(data?.response) ? data.response : undefined;
|
|
172
|
+
const responseUsage = response?.usage;
|
|
173
|
+
const inputDetails = responseUsage?.input_tokens_details;
|
|
174
|
+
const cachedTokens = inputDetails?.cached_tokens ?? 0;
|
|
175
|
+
const usage = responseUsage
|
|
176
|
+
? {
|
|
177
|
+
prompt_tokens: responseUsage.input_tokens ?? 0,
|
|
178
|
+
completion_tokens: responseUsage.output_tokens ?? 0,
|
|
179
|
+
total_tokens: responseUsage.total_tokens ?? 0,
|
|
180
|
+
cache_read_tokens: cachedTokens,
|
|
181
|
+
cache_creation_tokens: 0,
|
|
182
|
+
}
|
|
183
|
+
: undefined;
|
|
184
|
+
const responseOutput = Array.isArray(response?.output)
|
|
185
|
+
? response.output
|
|
186
|
+
: [];
|
|
187
|
+
const hasFunctionCalls = responseOutput.some((item) => item.type === 'function_call');
|
|
188
|
+
const finish = (0, chatgpt_helpers_1.formatSSE)({ delta: {}, finish_reason: hasFunctionCalls ? 'tool_calls' : 'stop' }, model, usage);
|
|
189
|
+
return `${finish}\ndata: [DONE]\n\n`;
|
|
156
190
|
}
|
|
157
191
|
//# sourceMappingURL=chatgpt-adapter.js.map
|