@layer-ai/core 2.0.49 → 2.0.51
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/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/db/migrations/011_allow_nullable_request_fields.sql +8 -0
- package/dist/lib/spending-jobs.d.ts +13 -7
- package/dist/lib/spending-jobs.d.ts.map +1 -1
- package/dist/lib/spending-jobs.js +61 -57
- package/dist/routes/v1/chat-completions.d.ts.map +1 -1
- package/dist/routes/v1/chat-completions.js +12 -4
- package/dist/routes/v1/messages.d.ts.map +1 -1
- package/dist/routes/v1/messages.js +15 -5
- package/dist/routes/v2/complete.d.ts.map +1 -1
- package/dist/routes/v2/complete.js +27 -9
- package/dist/routes/v3/chat.d.ts.map +1 -1
- package/dist/routes/v3/chat.js +12 -4
- package/dist/routes/v3/embeddings.d.ts.map +1 -1
- package/dist/routes/v3/embeddings.js +21 -7
- package/dist/routes/v3/image.d.ts.map +1 -1
- package/dist/routes/v3/image.js +12 -4
- package/dist/routes/v3/ocr.d.ts.map +1 -1
- package/dist/routes/v3/ocr.js +12 -4
- package/dist/routes/v3/tts.d.ts.map +1 -1
- package/dist/routes/v3/tts.js +12 -4
- package/dist/routes/v3/video.d.ts.map +1 -1
- package/dist/routes/v3/video.js +12 -4
- package/dist/services/providers/anthropic-adapter.js +3 -3
- package/dist/services/providers/google-adapter.js +3 -3
- package/dist/services/providers/mistral-adapter.js +3 -3
- package/dist/services/providers/openai-adapter.js +3 -3
- package/dist/services/task-analysis.js +1 -1
- package/package.json +3 -1
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,6 @@ export * from './services/task-analysis.js';
|
|
|
23
23
|
export { initializeRegistry, getRegistry, getModel, hasModel, getModelEntries } from './lib/registry.js';
|
|
24
24
|
export { PROVIDER, PROVIDERS, type Provider, callAdapter, normalizeModelId, getProviderForModel } from './lib/provider-factory.js';
|
|
25
25
|
export { spendingTracker } from './lib/spending-tracker.js';
|
|
26
|
-
export {
|
|
26
|
+
export { spendingWorker } from './lib/spending-jobs.js';
|
|
27
27
|
export { gateSpendingTracker } from './lib/gate-spending-tracker.js';
|
|
28
28
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGpE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGpE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG3C,OAAO,EAAE,EAAE,EAAE,MAAM,sBAAsB,CAAC;AAC1C,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,eAAO,MAAM,gBAAgB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,MAAM,CAGrE,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,IAAI,CAG3E,CAAC;AAGF,cAAc,6BAA6B,CAAC;AAG5C,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzG,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAGnI,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGpE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGpE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG3C,OAAO,EAAE,EAAE,EAAE,MAAM,sBAAsB,CAAC;AAC1C,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,eAAO,MAAM,gBAAgB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,MAAM,CAGrE,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,IAAI,CAG3E,CAAC;AAGF,cAAc,6BAA6B,CAAC;AAG5C,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzG,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAGnI,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -39,5 +39,5 @@ export { initializeRegistry, getRegistry, getModel, hasModel, getModelEntries }
|
|
|
39
39
|
export { PROVIDER, PROVIDERS, callAdapter, normalizeModelId, getProviderForModel } from './lib/provider-factory.js';
|
|
40
40
|
// Spending Management
|
|
41
41
|
export { spendingTracker } from './lib/spending-tracker.js';
|
|
42
|
-
export {
|
|
42
|
+
export { spendingWorker } from './lib/spending-jobs.js';
|
|
43
43
|
export { gateSpendingTracker } from './lib/gate-spending-tracker.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-- Allow nullable fields for failed requests (validation errors before model selection)
|
|
2
|
+
ALTER TABLE requests ALTER COLUMN model_requested DROP NOT NULL;
|
|
3
|
+
ALTER TABLE requests ALTER COLUMN model_used DROP NOT NULL;
|
|
4
|
+
ALTER TABLE requests ALTER COLUMN prompt_tokens SET DEFAULT 0;
|
|
5
|
+
ALTER TABLE requests ALTER COLUMN completion_tokens SET DEFAULT 0;
|
|
6
|
+
ALTER TABLE requests ALTER COLUMN total_tokens SET DEFAULT 0;
|
|
7
|
+
ALTER TABLE requests ALTER COLUMN cost_usd SET DEFAULT 0;
|
|
8
|
+
ALTER TABLE requests ALTER COLUMN latency_ms SET DEFAULT 0;
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
declare class SpendingWorker {
|
|
2
|
+
private isRunning;
|
|
3
|
+
private syncTask;
|
|
4
|
+
private resetTask;
|
|
5
|
+
start(): void;
|
|
6
|
+
stop(): void;
|
|
7
|
+
private syncSpendingJob;
|
|
8
|
+
private resetSpendingPeriodsJob;
|
|
9
|
+
private resetGateSpendingPeriodsJob;
|
|
10
|
+
private resetUsageCountersJob;
|
|
11
|
+
}
|
|
12
|
+
export declare const spendingWorker: SpendingWorker;
|
|
13
|
+
export {};
|
|
8
14
|
//# sourceMappingURL=spending-jobs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spending-jobs.d.ts","sourceRoot":"","sources":["../../src/lib/spending-jobs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spending-jobs.d.ts","sourceRoot":"","sources":["../../src/lib/spending-jobs.ts"],"names":[],"mappings":"AAKA,cAAM,cAAc;IAClB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,SAAS,CAAmC;IAEpD,KAAK;IAkBL,IAAI;YAUU,eAAe;YAiBf,uBAAuB;YAwBvB,2BAA2B;YAuB3B,qBAAqB;CAUpC;AAED,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
|
|
@@ -1,98 +1,102 @@
|
|
|
1
|
+
import * as cron from 'node-cron';
|
|
1
2
|
import { db } from './db/postgres.js';
|
|
2
3
|
import { cache } from './db/redis.js';
|
|
3
4
|
import { spendingTracker } from './spending-tracker.js';
|
|
4
|
-
|
|
5
|
+
class SpendingWorker {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.isRunning = false;
|
|
8
|
+
this.syncTask = null;
|
|
9
|
+
this.resetTask = null;
|
|
10
|
+
}
|
|
11
|
+
start() {
|
|
12
|
+
console.log('[Spending Worker] Starting scheduled jobs');
|
|
13
|
+
// Sync Redis to DB every 5 minutes (offset :02 to avoid other workers)
|
|
14
|
+
this.syncTask = cron.schedule('2/5 * * * *', async () => {
|
|
15
|
+
await this.syncSpendingJob();
|
|
16
|
+
});
|
|
17
|
+
// Check for billing period resets every hour at :20
|
|
18
|
+
this.resetTask = cron.schedule('20 * * * *', async () => {
|
|
19
|
+
await this.resetSpendingPeriodsJob();
|
|
20
|
+
await this.resetGateSpendingPeriodsJob();
|
|
21
|
+
await this.resetUsageCountersJob();
|
|
22
|
+
});
|
|
23
|
+
console.log('[Spending Worker] Cron schedules activated');
|
|
24
|
+
}
|
|
25
|
+
stop() {
|
|
26
|
+
if (this.syncTask) {
|
|
27
|
+
this.syncTask.stop();
|
|
28
|
+
}
|
|
29
|
+
if (this.resetTask) {
|
|
30
|
+
this.resetTask.stop();
|
|
31
|
+
}
|
|
32
|
+
console.log('[Spending Worker] Stopped');
|
|
33
|
+
}
|
|
5
34
|
async syncSpendingJob() {
|
|
6
|
-
|
|
35
|
+
if (this.isRunning) {
|
|
36
|
+
console.log('[Spending Worker] Sync already in progress, skipping');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this.isRunning = true;
|
|
7
40
|
try {
|
|
41
|
+
console.log('[Spending Worker] Starting periodic sync...');
|
|
8
42
|
await spendingTracker.syncAllSpending();
|
|
9
43
|
}
|
|
10
44
|
catch (error) {
|
|
11
|
-
console.error('[Spending
|
|
45
|
+
console.error('[Spending Worker] Sync failed:', error);
|
|
12
46
|
}
|
|
13
|
-
|
|
47
|
+
finally {
|
|
48
|
+
this.isRunning = false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
14
51
|
async resetSpendingPeriodsJob() {
|
|
15
|
-
console.log('[Spending
|
|
52
|
+
console.log('[Spending Worker] Checking for billing periods to reset...');
|
|
16
53
|
try {
|
|
17
54
|
const usersToReset = await db.getUsersToResetSpending();
|
|
18
55
|
if (usersToReset.length === 0) {
|
|
19
|
-
console.log('[Spending
|
|
56
|
+
console.log('[Spending Worker] No users need reset');
|
|
20
57
|
return;
|
|
21
58
|
}
|
|
22
|
-
console.log(`[Spending
|
|
59
|
+
console.log(`[Spending Worker] Resetting ${usersToReset.length} users`);
|
|
23
60
|
for (const userId of usersToReset) {
|
|
24
61
|
await db.resetUserSpending(userId);
|
|
25
62
|
await cache.invalidateUserSpending(userId);
|
|
26
|
-
console.log(`[Spending
|
|
63
|
+
console.log(`[Spending Worker] Reset user ${userId}`);
|
|
27
64
|
}
|
|
28
|
-
console.log('[Spending
|
|
65
|
+
console.log('[Spending Worker] Reset complete');
|
|
29
66
|
}
|
|
30
67
|
catch (error) {
|
|
31
|
-
console.error('[Spending
|
|
68
|
+
console.error('[Spending Worker] Reset failed:', error);
|
|
32
69
|
}
|
|
33
|
-
}
|
|
70
|
+
}
|
|
34
71
|
async resetGateSpendingPeriodsJob() {
|
|
35
|
-
console.log('[Spending
|
|
72
|
+
console.log('[Spending Worker] Checking for gate spending periods to reset...');
|
|
36
73
|
try {
|
|
37
74
|
const gatesToReset = await db.getGatesToResetSpending();
|
|
38
75
|
if (gatesToReset.length === 0) {
|
|
39
|
-
console.log('[Spending
|
|
76
|
+
console.log('[Spending Worker] No gates need reset');
|
|
40
77
|
return;
|
|
41
78
|
}
|
|
42
|
-
console.log(`[Spending
|
|
79
|
+
console.log(`[Spending Worker] Resetting ${gatesToReset.length} gates`);
|
|
43
80
|
for (const gateId of gatesToReset) {
|
|
44
81
|
await db.resetGateSpending(gateId);
|
|
45
|
-
console.log(`[Spending
|
|
82
|
+
console.log(`[Spending Worker] Reset gate ${gateId}`);
|
|
46
83
|
}
|
|
47
|
-
console.log('[Spending
|
|
84
|
+
console.log('[Spending Worker] Gate reset complete');
|
|
48
85
|
}
|
|
49
86
|
catch (error) {
|
|
50
|
-
console.error('[Spending
|
|
87
|
+
console.error('[Spending Worker] Gate reset failed:', error);
|
|
51
88
|
}
|
|
52
|
-
}
|
|
89
|
+
}
|
|
53
90
|
async resetUsageCountersJob() {
|
|
54
|
-
console.log('[Spending
|
|
91
|
+
console.log('[Spending Worker] Checking for usage counters to reset...');
|
|
55
92
|
try {
|
|
56
93
|
await db.resetDailyUsage();
|
|
57
94
|
await db.resetMonthlyUsage();
|
|
58
|
-
console.log('[Spending
|
|
95
|
+
console.log('[Spending Worker] Usage counters reset complete');
|
|
59
96
|
}
|
|
60
97
|
catch (error) {
|
|
61
|
-
console.error('[Spending
|
|
98
|
+
console.error('[Spending Worker] Usage counter reset failed:', error);
|
|
62
99
|
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
setInterval(() => {
|
|
67
|
-
this.syncSpendingJob().catch(err => {
|
|
68
|
-
console.error('[Spending Job] Sync interval error:', err);
|
|
69
|
-
});
|
|
70
|
-
}, 5 * 60 * 1000);
|
|
71
|
-
// Check for billing period resets every hour
|
|
72
|
-
setInterval(() => {
|
|
73
|
-
this.resetSpendingPeriodsJob().catch(err => {
|
|
74
|
-
console.error('[Spending Job] Reset interval error:', err);
|
|
75
|
-
});
|
|
76
|
-
this.resetGateSpendingPeriodsJob().catch(err => {
|
|
77
|
-
console.error('[Spending Job] Gate reset interval error:', err);
|
|
78
|
-
});
|
|
79
|
-
this.resetUsageCountersJob().catch(err => {
|
|
80
|
-
console.error('[Spending Job] Usage counter reset interval error:', err);
|
|
81
|
-
});
|
|
82
|
-
}, 60 * 60 * 1000);
|
|
83
|
-
// Run once on startup
|
|
84
|
-
this.syncSpendingJob().catch(err => {
|
|
85
|
-
console.error('[Spending Job] Initial sync error:', err);
|
|
86
|
-
});
|
|
87
|
-
this.resetSpendingPeriodsJob().catch(err => {
|
|
88
|
-
console.error('[Spending Job] Initial reset error:', err);
|
|
89
|
-
});
|
|
90
|
-
this.resetGateSpendingPeriodsJob().catch(err => {
|
|
91
|
-
console.error('[Spending Job] Initial gate reset error:', err);
|
|
92
|
-
});
|
|
93
|
-
this.resetUsageCountersJob().catch(err => {
|
|
94
|
-
console.error('[Spending Job] Initial usage counter reset error:', err);
|
|
95
|
-
});
|
|
96
|
-
console.log('[Spending Job] Scheduled jobs started');
|
|
97
|
-
},
|
|
98
|
-
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export const spendingWorker = new SpendingWorker();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-completions.d.ts","sourceRoot":"","sources":["../../../src/routes/v1/chat-completions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAapD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"chat-completions.d.ts","sourceRoot":"","sources":["../../../src/routes/v1/chat-completions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAapD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AA0TpC,eAAe,MAAM,CAAC"}
|
|
@@ -44,9 +44,11 @@ router.post('/', async (req, res) => {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
if (!gateId) {
|
|
47
|
+
const msg = 'Missing required field: gateId (provide in request body, X-Layer-Gate-Id header, or as part of model field)';
|
|
48
|
+
db.logRequest({ userId, gateId: null, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: openaiReq, responsePayload: null }).catch(() => { });
|
|
47
49
|
const error = {
|
|
48
50
|
error: {
|
|
49
|
-
message:
|
|
51
|
+
message: msg,
|
|
50
52
|
type: 'invalid_request_error',
|
|
51
53
|
param: 'gateId',
|
|
52
54
|
code: 'missing_field',
|
|
@@ -57,9 +59,11 @@ router.post('/', async (req, res) => {
|
|
|
57
59
|
}
|
|
58
60
|
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(gateId);
|
|
59
61
|
if (!isUUID) {
|
|
62
|
+
const msg = 'gateId must be a valid UUID';
|
|
63
|
+
db.logRequest({ userId, gateId, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: openaiReq, responsePayload: null }).catch(() => { });
|
|
60
64
|
const error = {
|
|
61
65
|
error: {
|
|
62
|
-
message:
|
|
66
|
+
message: msg,
|
|
63
67
|
type: 'invalid_request_error',
|
|
64
68
|
param: 'gateId',
|
|
65
69
|
code: 'invalid_format',
|
|
@@ -70,9 +74,11 @@ router.post('/', async (req, res) => {
|
|
|
70
74
|
}
|
|
71
75
|
gateConfig = await db.getGateByUserAndId(userId, gateId);
|
|
72
76
|
if (!gateConfig) {
|
|
77
|
+
const msg = `Gate with ID "${gateId}" not found`;
|
|
78
|
+
db.logRequest({ userId, gateId, gateName: null, modelRequested: openaiReq.model || null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: openaiReq, responsePayload: null }).catch(() => { });
|
|
73
79
|
const error = {
|
|
74
80
|
error: {
|
|
75
|
-
message:
|
|
81
|
+
message: msg,
|
|
76
82
|
type: 'invalid_request_error',
|
|
77
83
|
param: 'gateId',
|
|
78
84
|
code: 'not_found',
|
|
@@ -82,9 +88,11 @@ router.post('/', async (req, res) => {
|
|
|
82
88
|
return;
|
|
83
89
|
}
|
|
84
90
|
if (!openaiReq.messages || !Array.isArray(openaiReq.messages) || openaiReq.messages.length === 0) {
|
|
91
|
+
const msg = 'Missing required field: messages (must be a non-empty array)';
|
|
92
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: openaiReq.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: openaiReq, responsePayload: null }).catch(() => { });
|
|
85
93
|
const error = {
|
|
86
94
|
error: {
|
|
87
|
-
message:
|
|
95
|
+
message: msg,
|
|
88
96
|
type: 'invalid_request_error',
|
|
89
97
|
param: 'messages',
|
|
90
98
|
code: 'missing_field',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/routes/v1/messages.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAapD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/routes/v1/messages.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAapD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAmVpC,eAAe,MAAM,CAAC"}
|
|
@@ -43,11 +43,13 @@ router.post('/', async (req, res) => {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
if (!gateId) {
|
|
46
|
+
const msg = 'Missing required field: gateId (provide in request body, X-Layer-Gate-Id header, or as part of model field)';
|
|
47
|
+
db.logRequest({ userId, gateId: null, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: anthropicReq, responsePayload: null }).catch(() => { });
|
|
46
48
|
const error = {
|
|
47
49
|
type: 'error',
|
|
48
50
|
error: {
|
|
49
51
|
type: 'invalid_request_error',
|
|
50
|
-
message:
|
|
52
|
+
message: msg,
|
|
51
53
|
},
|
|
52
54
|
};
|
|
53
55
|
res.status(400).json(error);
|
|
@@ -55,11 +57,13 @@ router.post('/', async (req, res) => {
|
|
|
55
57
|
}
|
|
56
58
|
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(gateId);
|
|
57
59
|
if (!isUUID) {
|
|
60
|
+
const msg = 'gateId must be a valid UUID';
|
|
61
|
+
db.logRequest({ userId, gateId, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: anthropicReq, responsePayload: null }).catch(() => { });
|
|
58
62
|
const error = {
|
|
59
63
|
type: 'error',
|
|
60
64
|
error: {
|
|
61
65
|
type: 'invalid_request_error',
|
|
62
|
-
message:
|
|
66
|
+
message: msg,
|
|
63
67
|
},
|
|
64
68
|
};
|
|
65
69
|
res.status(400).json(error);
|
|
@@ -67,33 +71,39 @@ router.post('/', async (req, res) => {
|
|
|
67
71
|
}
|
|
68
72
|
gateConfig = await db.getGateByUserAndId(userId, gateId);
|
|
69
73
|
if (!gateConfig) {
|
|
74
|
+
const msg = `Gate with ID "${gateId}" not found`;
|
|
75
|
+
db.logRequest({ userId, gateId, gateName: null, modelRequested: anthropicReq.model || null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: anthropicReq, responsePayload: null }).catch(() => { });
|
|
70
76
|
const error = {
|
|
71
77
|
type: 'error',
|
|
72
78
|
error: {
|
|
73
79
|
type: 'not_found_error',
|
|
74
|
-
message:
|
|
80
|
+
message: msg,
|
|
75
81
|
},
|
|
76
82
|
};
|
|
77
83
|
res.status(404).json(error);
|
|
78
84
|
return;
|
|
79
85
|
}
|
|
80
86
|
if (!anthropicReq.messages || !Array.isArray(anthropicReq.messages) || anthropicReq.messages.length === 0) {
|
|
87
|
+
const msg = 'Missing required field: messages (must be a non-empty array)';
|
|
88
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: anthropicReq.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: anthropicReq, responsePayload: null }).catch(() => { });
|
|
81
89
|
const error = {
|
|
82
90
|
type: 'error',
|
|
83
91
|
error: {
|
|
84
92
|
type: 'invalid_request_error',
|
|
85
|
-
message:
|
|
93
|
+
message: msg,
|
|
86
94
|
},
|
|
87
95
|
};
|
|
88
96
|
res.status(400).json(error);
|
|
89
97
|
return;
|
|
90
98
|
}
|
|
91
99
|
if (!anthropicReq.max_tokens) {
|
|
100
|
+
const msg = 'Missing required field: max_tokens';
|
|
101
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: anthropicReq.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: anthropicReq, responsePayload: null }).catch(() => { });
|
|
92
102
|
const error = {
|
|
93
103
|
type: 'error',
|
|
94
104
|
error: {
|
|
95
105
|
type: 'invalid_request_error',
|
|
96
|
-
message:
|
|
106
|
+
message: msg,
|
|
97
107
|
},
|
|
98
108
|
};
|
|
99
109
|
res.status(400).json(error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/complete.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AASpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../../src/routes/v2/complete.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AASpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAwWpC,eAAe,MAAM,CAAC"}
|
|
@@ -169,17 +169,23 @@ router.post('/', async (req, res) => {
|
|
|
169
169
|
try {
|
|
170
170
|
const rawRequest = req.body;
|
|
171
171
|
if (!rawRequest.gateId) {
|
|
172
|
-
|
|
172
|
+
const msg = 'Missing required field: gateId';
|
|
173
|
+
db.logRequest({ userId, gateId: null, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
174
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
173
175
|
return;
|
|
174
176
|
}
|
|
175
177
|
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(rawRequest.gateId);
|
|
176
178
|
if (!isUUID) {
|
|
177
|
-
|
|
179
|
+
const msg = 'gateId must be a valid UUID. Gate names are no longer supported.';
|
|
180
|
+
db.logRequest({ userId, gateId: rawRequest.gateId, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
181
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
178
182
|
return;
|
|
179
183
|
}
|
|
180
184
|
gateConfig = await db.getGateByUserAndId(userId, rawRequest.gateId);
|
|
181
185
|
if (!gateConfig) {
|
|
182
|
-
|
|
186
|
+
const msg = `Gate with ID "${rawRequest.gateId}" not found`;
|
|
187
|
+
db.logRequest({ userId, gateId: rawRequest.gateId, gateName: null, modelRequested: rawRequest.model || null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
188
|
+
res.status(404).json({ error: 'not_found', message: msg });
|
|
183
189
|
return;
|
|
184
190
|
}
|
|
185
191
|
// Default to gate's taskType, allow override via request.type
|
|
@@ -200,37 +206,49 @@ router.post('/', async (req, res) => {
|
|
|
200
206
|
switch (request.type) {
|
|
201
207
|
case 'chat':
|
|
202
208
|
if (!request.data.messages || !Array.isArray(request.data.messages) || request.data.messages.length === 0) {
|
|
203
|
-
|
|
209
|
+
const msg = 'Missing required field: data.messages';
|
|
210
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
211
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
204
212
|
return;
|
|
205
213
|
}
|
|
206
214
|
break;
|
|
207
215
|
case 'image':
|
|
208
216
|
if (!request.data.prompt) {
|
|
209
|
-
|
|
217
|
+
const msg = 'Missing required field: data.prompt';
|
|
218
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
219
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
210
220
|
return;
|
|
211
221
|
}
|
|
212
222
|
break;
|
|
213
223
|
case 'video':
|
|
214
224
|
if (!request.data.prompt) {
|
|
215
|
-
|
|
225
|
+
const msg = 'Missing required field: data.prompt';
|
|
226
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
227
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
216
228
|
return;
|
|
217
229
|
}
|
|
218
230
|
break;
|
|
219
231
|
case 'embeddings':
|
|
220
232
|
if (!request.data.input) {
|
|
221
|
-
|
|
233
|
+
const msg = 'Missing required field: data.input';
|
|
234
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
235
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
222
236
|
return;
|
|
223
237
|
}
|
|
224
238
|
break;
|
|
225
239
|
case 'tts':
|
|
226
240
|
if (!request.data.input) {
|
|
227
|
-
|
|
241
|
+
const msg = 'Missing required field: data.input';
|
|
242
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
243
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
228
244
|
return;
|
|
229
245
|
}
|
|
230
246
|
break;
|
|
231
247
|
case 'ocr':
|
|
232
248
|
if (!request.data.documentUrl && !request.data.imageUrl && !request.data.base64) {
|
|
233
|
-
|
|
249
|
+
const msg = 'Missing required field: data must contain one of documentUrl, imageUrl, or base64';
|
|
250
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
251
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
234
252
|
return;
|
|
235
253
|
}
|
|
236
254
|
break;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/chat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAGpD,OAAO,KAAK,EAAE,YAAY,EAAiB,IAAI,EAA+C,MAAM,eAAe,CAAC;AAIpH,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAiBpC,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,IAAI,EAChB,OAAO,EAAE,YAAY,GACpB,YAAY,CAiFd;
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/chat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAGpD,OAAO,KAAK,EAAE,YAAY,EAAiB,IAAI,EAA+C,MAAM,eAAe,CAAC;AAIpH,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAiBpC,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,IAAI,EAChB,OAAO,EAAE,YAAY,GACpB,YAAY,CAiFd;AAgXD,eAAe,MAAM,CAAC"}
|
package/dist/routes/v3/chat.js
CHANGED
|
@@ -195,22 +195,30 @@ router.post('/', async (req, res) => {
|
|
|
195
195
|
try {
|
|
196
196
|
const rawRequest = req.body;
|
|
197
197
|
if (!rawRequest.gateId) {
|
|
198
|
-
|
|
198
|
+
const msg = 'Missing required field: gateId';
|
|
199
|
+
db.logRequest({ userId, gateId: null, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
200
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
199
201
|
return;
|
|
200
202
|
}
|
|
201
203
|
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(rawRequest.gateId);
|
|
202
204
|
if (!isUUID) {
|
|
203
|
-
|
|
205
|
+
const msg = 'gateId must be a valid UUID';
|
|
206
|
+
db.logRequest({ userId, gateId: rawRequest.gateId, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
207
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
204
208
|
return;
|
|
205
209
|
}
|
|
206
210
|
gateConfig = await db.getGateByUserAndId(userId, rawRequest.gateId);
|
|
207
211
|
if (!gateConfig) {
|
|
208
|
-
|
|
212
|
+
const msg = `Gate with ID "${rawRequest.gateId}" not found`;
|
|
213
|
+
db.logRequest({ userId, gateId: rawRequest.gateId, gateName: null, modelRequested: rawRequest.model || null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
214
|
+
res.status(404).json({ error: 'not_found', message: msg });
|
|
209
215
|
return;
|
|
210
216
|
}
|
|
211
217
|
// Validate chat-specific fields
|
|
212
218
|
if (!rawRequest.data?.messages || !Array.isArray(rawRequest.data.messages) || rawRequest.data.messages.length === 0) {
|
|
213
|
-
|
|
219
|
+
const msg = 'Missing required field: data.messages (must be a non-empty array)';
|
|
220
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
221
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
214
222
|
return;
|
|
215
223
|
}
|
|
216
224
|
// Warn if gate is configured for a different task type
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/embeddings.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/embeddings.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAiRpC,eAAe,MAAM,CAAC"}
|
|
@@ -95,37 +95,51 @@ router.post('/', async (req, res) => {
|
|
|
95
95
|
try {
|
|
96
96
|
const rawRequest = req.body;
|
|
97
97
|
if (!rawRequest.gateId) {
|
|
98
|
-
|
|
98
|
+
const msg = 'Missing required field: gateId';
|
|
99
|
+
db.logRequest({ userId, gateId: null, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
100
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
99
101
|
return;
|
|
100
102
|
}
|
|
101
103
|
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(rawRequest.gateId);
|
|
102
104
|
if (!isUUID) {
|
|
103
|
-
|
|
105
|
+
const msg = 'gateId must be a valid UUID';
|
|
106
|
+
db.logRequest({ userId, gateId: rawRequest.gateId, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
107
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
104
108
|
return;
|
|
105
109
|
}
|
|
106
110
|
gateConfig = await db.getGateByUserAndId(userId, rawRequest.gateId);
|
|
107
111
|
if (!gateConfig) {
|
|
108
|
-
|
|
112
|
+
const msg = `Gate with ID "${rawRequest.gateId}" not found`;
|
|
113
|
+
db.logRequest({ userId, gateId: rawRequest.gateId, gateName: null, modelRequested: rawRequest.model || null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
114
|
+
res.status(404).json({ error: 'not_found', message: msg });
|
|
109
115
|
return;
|
|
110
116
|
}
|
|
111
117
|
// Validate embeddings-specific fields
|
|
112
118
|
if (!rawRequest.data?.input) {
|
|
113
|
-
|
|
119
|
+
const msg = 'Missing required field: data.input';
|
|
120
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
121
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
114
122
|
return;
|
|
115
123
|
}
|
|
116
124
|
// Validate input is string or array of strings
|
|
117
125
|
const input = rawRequest.data.input;
|
|
118
126
|
if (typeof input !== 'string' && !Array.isArray(input)) {
|
|
119
|
-
|
|
127
|
+
const msg = 'data.input must be a string or array of strings';
|
|
128
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
129
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
120
130
|
return;
|
|
121
131
|
}
|
|
122
132
|
if (Array.isArray(input)) {
|
|
123
133
|
if (input.length === 0) {
|
|
124
|
-
|
|
134
|
+
const msg = 'data.input array must not be empty';
|
|
135
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
136
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
125
137
|
return;
|
|
126
138
|
}
|
|
127
139
|
if (!input.every(item => typeof item === 'string')) {
|
|
128
|
-
|
|
140
|
+
const msg = 'data.input array must contain only strings';
|
|
141
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
142
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
129
143
|
return;
|
|
130
144
|
}
|
|
131
145
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/image.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/image.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAoQpC,eAAe,MAAM,CAAC"}
|
package/dist/routes/v3/image.js
CHANGED
|
@@ -105,22 +105,30 @@ router.post('/', async (req, res) => {
|
|
|
105
105
|
try {
|
|
106
106
|
const rawRequest = req.body;
|
|
107
107
|
if (!rawRequest.gateId) {
|
|
108
|
-
|
|
108
|
+
const msg = 'Missing required field: gateId';
|
|
109
|
+
db.logRequest({ userId, gateId: null, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
110
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
109
111
|
return;
|
|
110
112
|
}
|
|
111
113
|
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(rawRequest.gateId);
|
|
112
114
|
if (!isUUID) {
|
|
113
|
-
|
|
115
|
+
const msg = 'gateId must be a valid UUID';
|
|
116
|
+
db.logRequest({ userId, gateId: rawRequest.gateId, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
117
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
114
118
|
return;
|
|
115
119
|
}
|
|
116
120
|
gateConfig = await db.getGateByUserAndId(userId, rawRequest.gateId);
|
|
117
121
|
if (!gateConfig) {
|
|
118
|
-
|
|
122
|
+
const msg = `Gate with ID "${rawRequest.gateId}" not found`;
|
|
123
|
+
db.logRequest({ userId, gateId: rawRequest.gateId, gateName: null, modelRequested: rawRequest.model || null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
124
|
+
res.status(404).json({ error: 'not_found', message: msg });
|
|
119
125
|
return;
|
|
120
126
|
}
|
|
121
127
|
// Validate image-specific fields
|
|
122
128
|
if (!rawRequest.data?.prompt || typeof rawRequest.data.prompt !== 'string' || rawRequest.data.prompt.trim().length === 0) {
|
|
123
|
-
|
|
129
|
+
const msg = 'Missing required field: data.prompt (must be a non-empty string)';
|
|
130
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
131
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
124
132
|
return;
|
|
125
133
|
}
|
|
126
134
|
// Warn if gate is configured for a different task type
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ocr.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/ocr.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"ocr.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/ocr.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AA6PpC,eAAe,MAAM,CAAC"}
|
package/dist/routes/v3/ocr.js
CHANGED
|
@@ -95,25 +95,33 @@ router.post('/', async (req, res) => {
|
|
|
95
95
|
try {
|
|
96
96
|
const rawRequest = req.body;
|
|
97
97
|
if (!rawRequest.gateId) {
|
|
98
|
-
|
|
98
|
+
const msg = 'Missing required field: gateId';
|
|
99
|
+
db.logRequest({ userId, gateId: null, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
100
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
99
101
|
return;
|
|
100
102
|
}
|
|
101
103
|
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(rawRequest.gateId);
|
|
102
104
|
if (!isUUID) {
|
|
103
|
-
|
|
105
|
+
const msg = 'gateId must be a valid UUID';
|
|
106
|
+
db.logRequest({ userId, gateId: rawRequest.gateId, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
107
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
104
108
|
return;
|
|
105
109
|
}
|
|
106
110
|
gateConfig = await db.getGateByUserAndId(userId, rawRequest.gateId);
|
|
107
111
|
if (!gateConfig) {
|
|
108
|
-
|
|
112
|
+
const msg = `Gate with ID "${rawRequest.gateId}" not found`;
|
|
113
|
+
db.logRequest({ userId, gateId: rawRequest.gateId, gateName: null, modelRequested: rawRequest.model || null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
114
|
+
res.status(404).json({ error: 'not_found', message: msg });
|
|
109
115
|
return;
|
|
110
116
|
}
|
|
111
117
|
// Validate OCR-specific fields - must have one of documentUrl, imageUrl, or base64
|
|
112
118
|
const data = rawRequest.data;
|
|
113
119
|
if (!data || (!data.documentUrl && !data.imageUrl && !data.base64)) {
|
|
120
|
+
const msg = 'Missing required field: data must contain one of documentUrl, imageUrl, or base64';
|
|
121
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
114
122
|
res.status(400).json({
|
|
115
123
|
error: 'bad_request',
|
|
116
|
-
message:
|
|
124
|
+
message: msg
|
|
117
125
|
});
|
|
118
126
|
return;
|
|
119
127
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tts.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/tts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"tts.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/tts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAyPpC,eAAe,MAAM,CAAC"}
|
package/dist/routes/v3/tts.js
CHANGED
|
@@ -95,22 +95,30 @@ router.post('/', async (req, res) => {
|
|
|
95
95
|
try {
|
|
96
96
|
const rawRequest = req.body;
|
|
97
97
|
if (!rawRequest.gateId) {
|
|
98
|
-
|
|
98
|
+
const msg = 'Missing required field: gateId';
|
|
99
|
+
db.logRequest({ userId, gateId: null, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
100
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
99
101
|
return;
|
|
100
102
|
}
|
|
101
103
|
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(rawRequest.gateId);
|
|
102
104
|
if (!isUUID) {
|
|
103
|
-
|
|
105
|
+
const msg = 'gateId must be a valid UUID';
|
|
106
|
+
db.logRequest({ userId, gateId: rawRequest.gateId, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
107
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
104
108
|
return;
|
|
105
109
|
}
|
|
106
110
|
gateConfig = await db.getGateByUserAndId(userId, rawRequest.gateId);
|
|
107
111
|
if (!gateConfig) {
|
|
108
|
-
|
|
112
|
+
const msg = `Gate with ID "${rawRequest.gateId}" not found`;
|
|
113
|
+
db.logRequest({ userId, gateId: rawRequest.gateId, gateName: null, modelRequested: rawRequest.model || null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
114
|
+
res.status(404).json({ error: 'not_found', message: msg });
|
|
109
115
|
return;
|
|
110
116
|
}
|
|
111
117
|
// Validate TTS-specific fields
|
|
112
118
|
if (!rawRequest.data?.input || typeof rawRequest.data.input !== 'string' || rawRequest.data.input.trim().length === 0) {
|
|
113
|
-
|
|
119
|
+
const msg = 'Missing required field: data.input (must be a non-empty string)';
|
|
120
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
121
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
114
122
|
return;
|
|
115
123
|
}
|
|
116
124
|
// Warn if gate is configured for a different task type
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/video.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../../src/routes/v3/video.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAMpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAoQpC,eAAe,MAAM,CAAC"}
|
package/dist/routes/v3/video.js
CHANGED
|
@@ -105,22 +105,30 @@ router.post('/', async (req, res) => {
|
|
|
105
105
|
try {
|
|
106
106
|
const rawRequest = req.body;
|
|
107
107
|
if (!rawRequest.gateId) {
|
|
108
|
-
|
|
108
|
+
const msg = 'Missing required field: gateId';
|
|
109
|
+
db.logRequest({ userId, gateId: null, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
110
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
109
111
|
return;
|
|
110
112
|
}
|
|
111
113
|
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(rawRequest.gateId);
|
|
112
114
|
if (!isUUID) {
|
|
113
|
-
|
|
115
|
+
const msg = 'gateId must be a valid UUID';
|
|
116
|
+
db.logRequest({ userId, gateId: rawRequest.gateId, gateName: null, modelRequested: null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
117
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
114
118
|
return;
|
|
115
119
|
}
|
|
116
120
|
gateConfig = await db.getGateByUserAndId(userId, rawRequest.gateId);
|
|
117
121
|
if (!gateConfig) {
|
|
118
|
-
|
|
122
|
+
const msg = `Gate with ID "${rawRequest.gateId}" not found`;
|
|
123
|
+
db.logRequest({ userId, gateId: rawRequest.gateId, gateName: null, modelRequested: rawRequest.model || null, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
124
|
+
res.status(404).json({ error: 'not_found', message: msg });
|
|
119
125
|
return;
|
|
120
126
|
}
|
|
121
127
|
// Validate video-specific fields
|
|
122
128
|
if (!rawRequest.data?.prompt || typeof rawRequest.data.prompt !== 'string' || rawRequest.data.prompt.trim().length === 0) {
|
|
123
|
-
|
|
129
|
+
const msg = 'Missing required field: data.prompt (must be a non-empty string)';
|
|
130
|
+
db.logRequest({ userId, gateId: gateConfig.id, gateName: gateConfig.name, modelRequested: rawRequest.model || gateConfig.model, modelUsed: null, promptTokens: 0, completionTokens: 0, totalTokens: 0, costUsd: 0, latencyMs: Date.now() - startTime, success: false, errorMessage: msg, userAgent: req.headers['user-agent'] || null, ipAddress: req.ip || null, requestPayload: rawRequest, responsePayload: null }).catch(() => { });
|
|
131
|
+
res.status(400).json({ error: 'bad_request', message: msg });
|
|
124
132
|
return;
|
|
125
133
|
}
|
|
126
134
|
// Warn if gate is configured for a different task type
|
|
@@ -9,7 +9,7 @@ function getAnthropicClient(apiKey) {
|
|
|
9
9
|
}
|
|
10
10
|
if (!anthropic) {
|
|
11
11
|
anthropic = new Anthropic({
|
|
12
|
-
apiKey: process.env.
|
|
12
|
+
apiKey: process.env.LAYER_PLATFORM_ANTHROPIC_API_KEY,
|
|
13
13
|
});
|
|
14
14
|
}
|
|
15
15
|
return anthropic;
|
|
@@ -52,7 +52,7 @@ export class AnthropicAdapter extends BaseProviderAdapter {
|
|
|
52
52
|
return super.mapToolChoice(choice);
|
|
53
53
|
}
|
|
54
54
|
async call(request, userId) {
|
|
55
|
-
const resolved = await resolveApiKey(this.provider, userId, process.env.
|
|
55
|
+
const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_ANTHROPIC_API_KEY);
|
|
56
56
|
switch (request.type) {
|
|
57
57
|
case 'chat':
|
|
58
58
|
return this.handleChat(request, resolved.key, resolved.usedPlatformKey);
|
|
@@ -69,7 +69,7 @@ export class AnthropicAdapter extends BaseProviderAdapter {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
async *callStream(request, userId) {
|
|
72
|
-
const resolved = await resolveApiKey(this.provider, userId, process.env.
|
|
72
|
+
const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_ANTHROPIC_API_KEY);
|
|
73
73
|
switch (request.type) {
|
|
74
74
|
case 'chat':
|
|
75
75
|
yield* this.handleChatStream(request, resolved.key, resolved.usedPlatformKey);
|
|
@@ -9,7 +9,7 @@ function getGoogleClient(apiKey) {
|
|
|
9
9
|
return new GoogleGenAI({ apiKey });
|
|
10
10
|
}
|
|
11
11
|
if (!client) {
|
|
12
|
-
client = new GoogleGenAI({ apiKey: process.env.
|
|
12
|
+
client = new GoogleGenAI({ apiKey: process.env.LAYER_PLATFORM_GOOGLE_API_KEY || '' });
|
|
13
13
|
}
|
|
14
14
|
return client;
|
|
15
15
|
}
|
|
@@ -56,7 +56,7 @@ export class GoogleAdapter extends BaseProviderAdapter {
|
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
async call(request, userId) {
|
|
59
|
-
const resolved = await resolveApiKey(this.provider, userId, process.env.
|
|
59
|
+
const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_GOOGLE_API_KEY);
|
|
60
60
|
switch (request.type) {
|
|
61
61
|
case 'chat':
|
|
62
62
|
return this.handleChat(request, resolved.key, resolved.usedPlatformKey);
|
|
@@ -73,7 +73,7 @@ export class GoogleAdapter extends BaseProviderAdapter {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
async *callStream(request, userId) {
|
|
76
|
-
const resolved = await resolveApiKey(this.provider, userId, process.env.
|
|
76
|
+
const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_GOOGLE_API_KEY);
|
|
77
77
|
switch (request.type) {
|
|
78
78
|
case 'chat':
|
|
79
79
|
yield* this.handleChatStream(request, resolved.key, resolved.usedPlatformKey);
|
|
@@ -12,7 +12,7 @@ function getMistralClient(apiKey) {
|
|
|
12
12
|
// Otherwise use singleton with platform key
|
|
13
13
|
if (!client) {
|
|
14
14
|
client = new Mistral({
|
|
15
|
-
apiKey: process.env.
|
|
15
|
+
apiKey: process.env.LAYER_PLATFORM_MISTRAL_API_KEY || '',
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
return client;
|
|
@@ -46,7 +46,7 @@ export class MistralAdapter extends BaseProviderAdapter {
|
|
|
46
46
|
}
|
|
47
47
|
async call(request, userId) {
|
|
48
48
|
// Resolve API key (BYOK → Platform key)
|
|
49
|
-
const resolved = await resolveApiKey(this.provider, userId, process.env.
|
|
49
|
+
const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_MISTRAL_API_KEY);
|
|
50
50
|
switch (request.type) {
|
|
51
51
|
case 'chat':
|
|
52
52
|
return this.handleChat(request, resolved.key, resolved.usedPlatformKey);
|
|
@@ -65,7 +65,7 @@ export class MistralAdapter extends BaseProviderAdapter {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
async *callStream(request, userId) {
|
|
68
|
-
const resolved = await resolveApiKey(this.provider, userId, process.env.
|
|
68
|
+
const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_MISTRAL_API_KEY);
|
|
69
69
|
switch (request.type) {
|
|
70
70
|
case 'chat':
|
|
71
71
|
yield* this.handleChatStream(request, resolved.key, resolved.usedPlatformKey);
|
|
@@ -9,7 +9,7 @@ function getOpenAIClient(apiKey) {
|
|
|
9
9
|
}
|
|
10
10
|
if (!openai) {
|
|
11
11
|
openai = new OpenAI({
|
|
12
|
-
apiKey: process.env.
|
|
12
|
+
apiKey: process.env.LAYER_PLATFORM_OPENAI_API_KEY,
|
|
13
13
|
});
|
|
14
14
|
}
|
|
15
15
|
return openai;
|
|
@@ -71,7 +71,7 @@ export class OpenAIAdapter extends BaseProviderAdapter {
|
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
73
|
async call(request, userId) {
|
|
74
|
-
const resolved = await resolveApiKey(this.provider, userId, process.env.
|
|
74
|
+
const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_OPENAI_API_KEY);
|
|
75
75
|
switch (request.type) {
|
|
76
76
|
case 'chat':
|
|
77
77
|
return this.handleChat(request, resolved.key, resolved.usedPlatformKey);
|
|
@@ -88,7 +88,7 @@ export class OpenAIAdapter extends BaseProviderAdapter {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
async *callStream(request, userId) {
|
|
91
|
-
const resolved = await resolveApiKey(this.provider, userId, process.env.
|
|
91
|
+
const resolved = await resolveApiKey(this.provider, userId, process.env.LAYER_PLATFORM_OPENAI_API_KEY);
|
|
92
92
|
switch (request.type) {
|
|
93
93
|
case 'chat':
|
|
94
94
|
yield* this.handleChatStream(request, resolved.key, resolved.usedPlatformKey);
|
|
@@ -53,7 +53,7 @@ Return ONLY the task type as a single word, nothing else.`;
|
|
|
53
53
|
}
|
|
54
54
|
export async function analyzeTask(description, userPreferences) {
|
|
55
55
|
const anthropic = new Anthropic({
|
|
56
|
-
apiKey: process.env.
|
|
56
|
+
apiKey: process.env.LAYER_PLATFORM_ANTHROPIC_API_KEY
|
|
57
57
|
});
|
|
58
58
|
const costWeight = userPreferences?.costWeight ?? 0.33;
|
|
59
59
|
const latencyWeight = userPreferences?.latencyWeight ?? 0.33;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@layer-ai/core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.51",
|
|
4
4
|
"description": "Core API routes and services for Layer AI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"ioredis": "^5.3.2",
|
|
35
35
|
"jsonwebtoken": "^9.0.2",
|
|
36
36
|
"nanoid": "^5.0.4",
|
|
37
|
+
"node-cron": "^4.2.1",
|
|
37
38
|
"openai": "^4.24.0",
|
|
38
39
|
"pg": "^8.11.3",
|
|
39
40
|
"@layer-ai/sdk": "^2.5.14"
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"@types/express": "^4.17.21",
|
|
44
45
|
"@types/jsonwebtoken": "^9.0.5",
|
|
45
46
|
"@types/node": "^20.10.4",
|
|
47
|
+
"@types/node-cron": "^3.0.11",
|
|
46
48
|
"@types/pg": "^8.10.9",
|
|
47
49
|
"typescript": "^5.3.3"
|
|
48
50
|
},
|