@layer-ai/core 0.9.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/routes/v1/gates.js +2 -2
- package/dist/routes/v2/complete.d.ts.map +1 -1
- package/dist/routes/v2/complete.js +127 -56
- package/dist/routes/v2/tests/test-byok-completion.js +1 -1
- package/dist/routes/v2/tests/test-complete-anthropic.js +4 -4
- package/dist/routes/v2/tests/test-complete-openai.js +7 -7
- package/dist/routes/v2/tests/test-complete-routing.js +5 -5
- package/dist/routes/v3/chat.d.ts +4 -0
- package/dist/routes/v3/chat.d.ts.map +1 -0
- package/dist/routes/v3/chat.js +203 -0
- package/dist/routes/v3/completions/chat.d.ts +4 -0
- package/dist/routes/v3/completions/chat.d.ts.map +1 -0
- package/dist/routes/v3/completions/chat.js +178 -0
- package/dist/routes/v3/completions/embed.d.ts +4 -0
- package/dist/routes/v3/completions/embed.d.ts.map +1 -0
- package/dist/routes/v3/completions/embed.js +94 -0
- package/dist/routes/v3/completions/image.d.ts +4 -0
- package/dist/routes/v3/completions/image.d.ts.map +1 -0
- package/dist/routes/v3/completions/image.js +155 -0
- package/dist/routes/v3/completions/ocr.d.ts +4 -0
- package/dist/routes/v3/completions/ocr.d.ts.map +1 -0
- package/dist/routes/v3/completions/ocr.js +94 -0
- package/dist/routes/v3/completions/tts.d.ts +4 -0
- package/dist/routes/v3/completions/tts.d.ts.map +1 -0
- package/dist/routes/v3/completions/tts.js +94 -0
- package/dist/routes/v3/completions/video.d.ts +4 -0
- package/dist/routes/v3/completions/video.d.ts.map +1 -0
- package/dist/routes/v3/completions/video.js +94 -0
- package/dist/services/providers/base-adapter.d.ts.map +1 -1
- package/dist/services/providers/base-adapter.js +5 -2
- package/dist/services/providers/tests/test-anthropic-adapter.js +4 -4
- package/dist/services/providers/tests/test-google-adapter.js +9 -9
- package/dist/services/providers/tests/test-mistral-adapter.js +11 -11
- package/dist/services/providers/tests/test-openai-adapter.js +8 -8
- package/package.json +2 -2
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { db } from '../../../lib/db/postgres.js';
|
|
3
|
+
import { authenticate } from '../../../middleware/auth.js';
|
|
4
|
+
import { callAdapter, normalizeModelId } from '../../../lib/provider-factory.js';
|
|
5
|
+
import { OverrideField } from '@layer-ai/sdk';
|
|
6
|
+
const router = Router();
|
|
7
|
+
function isOverrideAllowed(allowOverrides, field) {
|
|
8
|
+
if (allowOverrides === undefined || allowOverrides === null || allowOverrides === true)
|
|
9
|
+
return true;
|
|
10
|
+
if (allowOverrides === false)
|
|
11
|
+
return false;
|
|
12
|
+
return allowOverrides[field] ?? false;
|
|
13
|
+
}
|
|
14
|
+
function resolveFinalRequest(gateConfig, request) {
|
|
15
|
+
let finalModel = gateConfig.model;
|
|
16
|
+
if (request.model && isOverrideAllowed(gateConfig.allowOverrides, OverrideField.Model)) {
|
|
17
|
+
try {
|
|
18
|
+
finalModel = normalizeModelId(request.model);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
finalModel = gateConfig.model;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return { ...request, model: normalizeModelId(finalModel) };
|
|
25
|
+
}
|
|
26
|
+
function getModelsToTry(gateConfig, primaryModel) {
|
|
27
|
+
const modelsToTry = [primaryModel];
|
|
28
|
+
if (gateConfig.fallback1) {
|
|
29
|
+
try {
|
|
30
|
+
modelsToTry.push(normalizeModelId(gateConfig.fallback1));
|
|
31
|
+
}
|
|
32
|
+
catch (error) { }
|
|
33
|
+
}
|
|
34
|
+
if (gateConfig.fallback2) {
|
|
35
|
+
try {
|
|
36
|
+
modelsToTry.push(normalizeModelId(gateConfig.fallback2));
|
|
37
|
+
}
|
|
38
|
+
catch (error) { }
|
|
39
|
+
}
|
|
40
|
+
return modelsToTry;
|
|
41
|
+
}
|
|
42
|
+
async function executeWithRouting(gateConfig, request, userId) {
|
|
43
|
+
const modelsToTry = getModelsToTry(gateConfig, request.model);
|
|
44
|
+
let lastError = null;
|
|
45
|
+
for (let i = 0; i < modelsToTry.length; i++) {
|
|
46
|
+
const model = modelsToTry[i];
|
|
47
|
+
try {
|
|
48
|
+
const result = await callAdapter({ ...request, model }, userId);
|
|
49
|
+
return { result, modelUsed: model };
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
lastError = error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
throw lastError || new Error('All models failed');
|
|
56
|
+
}
|
|
57
|
+
router.post('/', authenticate, async (req, res) => {
|
|
58
|
+
const startTime = Date.now();
|
|
59
|
+
if (!req.userId) {
|
|
60
|
+
res.status(401).json({ error: 'unauthorized', message: 'Missing user ID' });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const userId = req.userId;
|
|
64
|
+
let gateConfig = null;
|
|
65
|
+
try {
|
|
66
|
+
const rawRequest = req.body;
|
|
67
|
+
if (!rawRequest.gateId || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(rawRequest.gateId)) {
|
|
68
|
+
res.status(400).json({ error: 'bad_request', message: 'Valid gateId (UUID) is required' });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (!rawRequest.data?.prompt || typeof rawRequest.data.prompt !== 'string' || !rawRequest.data.prompt.trim()) {
|
|
72
|
+
res.status(400).json({ error: 'bad_request', message: 'data.prompt is required' });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
gateConfig = await db.getGateByUserAndId(userId, rawRequest.gateId);
|
|
76
|
+
if (!gateConfig) {
|
|
77
|
+
res.status(404).json({ error: 'not_found', message: `Gate not found` });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const request = { gateId: rawRequest.gateId, type: 'video', data: rawRequest.data, model: rawRequest.model, metadata: rawRequest.metadata };
|
|
81
|
+
const finalRequest = resolveFinalRequest(gateConfig, request);
|
|
82
|
+
const { result, modelUsed } = await executeWithRouting(gateConfig, finalRequest, userId);
|
|
83
|
+
db.logRequest({ userId, gateId: gateConfig.id, model: modelUsed, promptTokens: result.usage?.promptTokens || 0, completionTokens: result.usage?.completionTokens || 0, totalTokens: result.usage?.totalTokens || 0, cost: result.cost || 0, latencyMs: Date.now() - startTime, success: true }).catch(() => { });
|
|
84
|
+
res.status(200).json(result);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
88
|
+
if (gateConfig) {
|
|
89
|
+
db.logRequest({ userId, gateId: gateConfig.id, model: gateConfig.model, promptTokens: 0, completionTokens: 0, totalTokens: 0, cost: 0, latencyMs: Date.now() - startTime, success: false, errorMessage }).catch(() => { });
|
|
90
|
+
}
|
|
91
|
+
res.status(500).json({ error: 'internal_server_error', message: errorMessage });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
export default router;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-adapter.d.ts","sourceRoot":"","sources":["../../../src/services/providers/base-adapter.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"base-adapter.d.ts","sourceRoot":"","sources":["../../../src/services/providers/base-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -82,9 +82,12 @@ export class BaseProviderAdapter {
|
|
|
82
82
|
}
|
|
83
83
|
calculateCost(model, promptTokens, completionTokens) {
|
|
84
84
|
const modelInfo = MODEL_REGISTRY[model];
|
|
85
|
-
if (!modelInfo || !('pricing' in modelInfo) || !modelInfo.pricing?.input
|
|
85
|
+
if (!modelInfo || !('pricing' in modelInfo) || !modelInfo.pricing?.input) {
|
|
86
86
|
return 0;
|
|
87
87
|
}
|
|
88
|
-
|
|
88
|
+
const pricing = modelInfo.pricing;
|
|
89
|
+
const inputCost = promptTokens / 1000000 * pricing.input;
|
|
90
|
+
const outputCost = ('output' in pricing && pricing.output) ? (completionTokens / 1000000 * pricing.output) : 0;
|
|
91
|
+
return inputCost + outputCost;
|
|
89
92
|
}
|
|
90
93
|
}
|
|
@@ -3,7 +3,7 @@ const adapter = new AnthropicAdapter();
|
|
|
3
3
|
async function testChatCompletion() {
|
|
4
4
|
console.log('Testing chat completion...');
|
|
5
5
|
const request = {
|
|
6
|
-
|
|
6
|
+
gateId: 'test-gate',
|
|
7
7
|
model: 'claude-sonnet-4-5-20250929',
|
|
8
8
|
type: 'chat',
|
|
9
9
|
data: {
|
|
@@ -25,7 +25,7 @@ async function testChatCompletion() {
|
|
|
25
25
|
async function testChatWithVision() {
|
|
26
26
|
console.log('Testing chat with vision...');
|
|
27
27
|
const request = {
|
|
28
|
-
|
|
28
|
+
gateId: 'test-gate',
|
|
29
29
|
model: 'claude-sonnet-4-5-20250929',
|
|
30
30
|
type: 'chat',
|
|
31
31
|
data: {
|
|
@@ -50,7 +50,7 @@ async function testToolCalls() {
|
|
|
50
50
|
console.log('Testing tool calls...');
|
|
51
51
|
// Step 1: Initial request with tool available
|
|
52
52
|
const request = {
|
|
53
|
-
|
|
53
|
+
gateId: 'test-gate',
|
|
54
54
|
model: 'claude-sonnet-4-5-20250929',
|
|
55
55
|
type: 'chat',
|
|
56
56
|
data: {
|
|
@@ -91,7 +91,7 @@ async function testToolCalls() {
|
|
|
91
91
|
console.log('Function arguments:', toolCall.function.arguments);
|
|
92
92
|
// Step 2: Send tool response back
|
|
93
93
|
const toolResponseRequest = {
|
|
94
|
-
|
|
94
|
+
gateId: 'test-gate',
|
|
95
95
|
model: 'claude-sonnet-4-5-20250929',
|
|
96
96
|
type: 'chat',
|
|
97
97
|
data: {
|
|
@@ -4,7 +4,7 @@ const adapter = new GoogleAdapter();
|
|
|
4
4
|
async function testChatCompletion() {
|
|
5
5
|
console.log('Testing chat completion...');
|
|
6
6
|
const request = {
|
|
7
|
-
|
|
7
|
+
gateId: 'test-gate',
|
|
8
8
|
model: 'gemini-2.5-flash',
|
|
9
9
|
type: 'chat',
|
|
10
10
|
data: {
|
|
@@ -26,7 +26,7 @@ async function testChatCompletion() {
|
|
|
26
26
|
async function testChatWithVision() {
|
|
27
27
|
console.log('Testing chat with vision...');
|
|
28
28
|
const request = {
|
|
29
|
-
|
|
29
|
+
gateId: 'test-gate',
|
|
30
30
|
model: 'gemini-2.5-flash',
|
|
31
31
|
type: 'chat',
|
|
32
32
|
data: {
|
|
@@ -52,7 +52,7 @@ async function testChatWithVision() {
|
|
|
52
52
|
async function testImageGeneration() {
|
|
53
53
|
console.log('Testing image generation...');
|
|
54
54
|
const request = {
|
|
55
|
-
|
|
55
|
+
gateId: 'test-gate',
|
|
56
56
|
model: 'imagen-4.0-generate-001',
|
|
57
57
|
type: 'image',
|
|
58
58
|
data: {
|
|
@@ -69,7 +69,7 @@ async function testImageGeneration() {
|
|
|
69
69
|
async function testEmbeddings() {
|
|
70
70
|
console.log('Testing embeddings...');
|
|
71
71
|
const request = {
|
|
72
|
-
|
|
72
|
+
gateId: 'test-gate',
|
|
73
73
|
model: 'text-embedding-004',
|
|
74
74
|
type: 'embeddings',
|
|
75
75
|
data: {
|
|
@@ -85,7 +85,7 @@ async function testToolCalling() {
|
|
|
85
85
|
console.log('Testing tool calling...');
|
|
86
86
|
// Step 1: Send message with tools available
|
|
87
87
|
const request = {
|
|
88
|
-
|
|
88
|
+
gateId: 'test-gate',
|
|
89
89
|
model: 'gemini-2.5-flash',
|
|
90
90
|
type: 'chat',
|
|
91
91
|
data: {
|
|
@@ -122,7 +122,7 @@ async function testToolCalling() {
|
|
|
122
122
|
console.log('Function arguments:', toolCall.function.arguments);
|
|
123
123
|
// Step 2: Send tool response back
|
|
124
124
|
const toolResponseRequest = {
|
|
125
|
-
|
|
125
|
+
gateId: 'test-gate',
|
|
126
126
|
model: 'gemini-2.5-flash',
|
|
127
127
|
type: 'chat',
|
|
128
128
|
data: {
|
|
@@ -149,7 +149,7 @@ async function testToolCalling() {
|
|
|
149
149
|
async function testEmbeddingsMultiple() {
|
|
150
150
|
console.log('Testing multiple embeddings...');
|
|
151
151
|
const request = {
|
|
152
|
-
|
|
152
|
+
gateId: 'test-gate',
|
|
153
153
|
model: 'text-embedding-004',
|
|
154
154
|
type: 'embeddings',
|
|
155
155
|
data: {
|
|
@@ -165,7 +165,7 @@ async function testEmbeddingsMultiple() {
|
|
|
165
165
|
async function testTextToSpeech() {
|
|
166
166
|
console.log('Testing text-to-speech...');
|
|
167
167
|
const request = {
|
|
168
|
-
|
|
168
|
+
gateId: 'test-gate',
|
|
169
169
|
model: 'gemini-2.5-flash-preview-tts',
|
|
170
170
|
type: 'tts',
|
|
171
171
|
data: {
|
|
@@ -182,7 +182,7 @@ async function testTextToSpeech() {
|
|
|
182
182
|
async function testVideoGeneration() {
|
|
183
183
|
console.log('Testing video generation (this may take a few minutes)...');
|
|
184
184
|
const request = {
|
|
185
|
-
|
|
185
|
+
gateId: 'test-gate',
|
|
186
186
|
model: 'veo-2.0-generate-001',
|
|
187
187
|
type: 'video',
|
|
188
188
|
data: {
|
|
@@ -6,7 +6,7 @@ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
6
6
|
async function testChatCompletion() {
|
|
7
7
|
console.log('--- Testing Chat Completion ---');
|
|
8
8
|
const request = {
|
|
9
|
-
|
|
9
|
+
gateId: 'test-gate',
|
|
10
10
|
type: 'chat',
|
|
11
11
|
model: 'mistral-small-latest',
|
|
12
12
|
data: {
|
|
@@ -31,7 +31,7 @@ async function testChatCompletion() {
|
|
|
31
31
|
async function testChatWithSystemPrompt() {
|
|
32
32
|
console.log('--- Testing Chat with System Prompt ---');
|
|
33
33
|
const request = {
|
|
34
|
-
|
|
34
|
+
gateId: 'test-gate',
|
|
35
35
|
type: 'chat',
|
|
36
36
|
model: 'mistral-small-latest',
|
|
37
37
|
data: {
|
|
@@ -54,7 +54,7 @@ async function testChatWithSystemPrompt() {
|
|
|
54
54
|
async function testChatWithTools() {
|
|
55
55
|
console.log('--- Testing Chat with Tools ---');
|
|
56
56
|
const request = {
|
|
57
|
-
|
|
57
|
+
gateId: 'test-gate',
|
|
58
58
|
type: 'chat',
|
|
59
59
|
model: 'mistral-small-latest',
|
|
60
60
|
data: {
|
|
@@ -102,7 +102,7 @@ async function testToolResponse() {
|
|
|
102
102
|
console.log('--- Testing Tool Response Flow ---');
|
|
103
103
|
// First, get the tool call
|
|
104
104
|
const initialRequest = {
|
|
105
|
-
|
|
105
|
+
gateId: 'test-gate',
|
|
106
106
|
type: 'chat',
|
|
107
107
|
model: 'mistral-small-latest',
|
|
108
108
|
data: {
|
|
@@ -143,7 +143,7 @@ async function testToolResponse() {
|
|
|
143
143
|
const toolCall = initialResponse.toolCalls[0];
|
|
144
144
|
await delay(2000);
|
|
145
145
|
const followUpRequest = {
|
|
146
|
-
|
|
146
|
+
gateId: 'test-gate',
|
|
147
147
|
type: 'chat',
|
|
148
148
|
model: 'mistral-small-latest',
|
|
149
149
|
data: {
|
|
@@ -175,7 +175,7 @@ async function testToolResponse() {
|
|
|
175
175
|
async function testEmbeddings() {
|
|
176
176
|
console.log('--- Testing Embeddings ---');
|
|
177
177
|
const request = {
|
|
178
|
-
|
|
178
|
+
gateId: 'test-gate',
|
|
179
179
|
type: 'embeddings',
|
|
180
180
|
model: 'mistral-embed',
|
|
181
181
|
data: {
|
|
@@ -193,7 +193,7 @@ async function testVisionCapability() {
|
|
|
193
193
|
console.log('--- Testing Vision Capability (Pixtral) ---');
|
|
194
194
|
// Use a public image URL for testing
|
|
195
195
|
const request = {
|
|
196
|
-
|
|
196
|
+
gateId: 'test-gate',
|
|
197
197
|
type: 'chat',
|
|
198
198
|
model: 'pixtral-large-2411',
|
|
199
199
|
data: {
|
|
@@ -224,7 +224,7 @@ async function testVisionCapability() {
|
|
|
224
224
|
async function testResponseFormat() {
|
|
225
225
|
console.log('--- Testing JSON Response Format ---');
|
|
226
226
|
const request = {
|
|
227
|
-
|
|
227
|
+
gateId: 'test-gate',
|
|
228
228
|
type: 'chat',
|
|
229
229
|
model: 'mistral-small-latest',
|
|
230
230
|
data: {
|
|
@@ -245,7 +245,7 @@ async function testResponseFormat() {
|
|
|
245
245
|
async function testMultiTurn() {
|
|
246
246
|
console.log('--- Testing Multi-turn Conversation ---');
|
|
247
247
|
const request = {
|
|
248
|
-
|
|
248
|
+
gateId: 'test-gate',
|
|
249
249
|
type: 'chat',
|
|
250
250
|
model: 'mistral-small-latest',
|
|
251
251
|
data: {
|
|
@@ -273,7 +273,7 @@ async function testMultiTurn() {
|
|
|
273
273
|
async function testOCR() {
|
|
274
274
|
console.log('--- Testing OCR Capability ---');
|
|
275
275
|
const request = {
|
|
276
|
-
|
|
276
|
+
gateId: 'test-gate',
|
|
277
277
|
type: 'ocr',
|
|
278
278
|
model: 'mistral-ocr-latest',
|
|
279
279
|
data: {
|
|
@@ -295,7 +295,7 @@ async function testOCR() {
|
|
|
295
295
|
async function testUnsupportedModality() {
|
|
296
296
|
console.log('--- Testing Unsupported Modality (Image Generation) ---');
|
|
297
297
|
const request = {
|
|
298
|
-
|
|
298
|
+
gateId: 'test-gate',
|
|
299
299
|
type: 'image',
|
|
300
300
|
model: 'mistral-large-latest',
|
|
301
301
|
data: {
|
|
@@ -3,7 +3,7 @@ const adapter = new OpenAIAdapter();
|
|
|
3
3
|
async function testChatCompletion() {
|
|
4
4
|
console.log('Testing chat completion...');
|
|
5
5
|
const request = {
|
|
6
|
-
|
|
6
|
+
gateId: 'test-gate',
|
|
7
7
|
model: 'gpt-4o-mini',
|
|
8
8
|
type: 'chat',
|
|
9
9
|
data: {
|
|
@@ -25,7 +25,7 @@ async function testChatCompletion() {
|
|
|
25
25
|
async function testChatWithVision() {
|
|
26
26
|
console.log('Testing chat with vision...');
|
|
27
27
|
const request = {
|
|
28
|
-
|
|
28
|
+
gateId: 'test-gate',
|
|
29
29
|
model: 'gpt-4o-mini',
|
|
30
30
|
type: 'chat',
|
|
31
31
|
data: {
|
|
@@ -50,7 +50,7 @@ async function testChatWithVision() {
|
|
|
50
50
|
async function testImageGeneration() {
|
|
51
51
|
console.log('Testing image generation...');
|
|
52
52
|
const request = {
|
|
53
|
-
|
|
53
|
+
gateId: 'test-gate',
|
|
54
54
|
model: 'dall-e-3',
|
|
55
55
|
type: 'image',
|
|
56
56
|
data: {
|
|
@@ -69,7 +69,7 @@ async function testImageGeneration() {
|
|
|
69
69
|
async function testEmbeddings() {
|
|
70
70
|
console.log('Testing embeddings...');
|
|
71
71
|
const request = {
|
|
72
|
-
|
|
72
|
+
gateId: 'test-gate',
|
|
73
73
|
model: 'text-embedding-3-small',
|
|
74
74
|
type: 'embeddings',
|
|
75
75
|
data: {
|
|
@@ -85,7 +85,7 @@ async function testEmbeddings() {
|
|
|
85
85
|
async function testTextToSpeech() {
|
|
86
86
|
console.log('Testing text-to-speech...');
|
|
87
87
|
const request = {
|
|
88
|
-
|
|
88
|
+
gateId: 'test-gate',
|
|
89
89
|
model: 'tts-1',
|
|
90
90
|
type: 'tts',
|
|
91
91
|
data: {
|
|
@@ -104,7 +104,7 @@ async function testToolCalling() {
|
|
|
104
104
|
console.log('Testing tool calling...');
|
|
105
105
|
// Step 1: Initial request with tool available
|
|
106
106
|
const request = {
|
|
107
|
-
|
|
107
|
+
gateId: 'test-gate',
|
|
108
108
|
model: 'gpt-4o-mini',
|
|
109
109
|
type: 'chat',
|
|
110
110
|
data: {
|
|
@@ -145,7 +145,7 @@ async function testToolCalling() {
|
|
|
145
145
|
console.log('Function arguments:', toolCall.function.arguments);
|
|
146
146
|
// Step 2: Send tool response back
|
|
147
147
|
const toolResponseRequest = {
|
|
148
|
-
|
|
148
|
+
gateId: 'test-gate',
|
|
149
149
|
model: 'gpt-4o-mini',
|
|
150
150
|
type: 'chat',
|
|
151
151
|
data: {
|
|
@@ -173,7 +173,7 @@ async function testContentAndToolCalls() {
|
|
|
173
173
|
console.log('Testing content + tool calls in same message...');
|
|
174
174
|
// This tests the fix we made - assistant messages can have BOTH content and toolCalls
|
|
175
175
|
const request = {
|
|
176
|
-
|
|
176
|
+
gateId: 'test-gate',
|
|
177
177
|
model: 'gpt-4o-mini',
|
|
178
178
|
type: 'chat',
|
|
179
179
|
data: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@layer-ai/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Core API routes and services for Layer AI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"nanoid": "^5.0.4",
|
|
37
37
|
"openai": "^4.24.0",
|
|
38
38
|
"pg": "^8.11.3",
|
|
39
|
-
"@layer-ai/sdk": "^1.
|
|
39
|
+
"@layer-ai/sdk": "^2.1.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/bcryptjs": "^2.4.6",
|