@layer-ai/core 2.0.9 → 2.0.11

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.
@@ -0,0 +1,17 @@
1
+ -- Migration: 006_add_response_format_to_gates
2
+ -- Description: Add structured output support fields to gates table (OpenAI response_format feature)
3
+
4
+ ALTER TABLE gates
5
+ ADD COLUMN response_format_enabled BOOLEAN DEFAULT FALSE,
6
+ ADD COLUMN response_format_type VARCHAR(20),
7
+ ADD COLUMN response_format_schema JSONB;
8
+
9
+ -- Add index for querying gates with structured output enabled
10
+ CREATE INDEX idx_gates_response_format_enabled
11
+ ON gates(response_format_enabled)
12
+ WHERE response_format_enabled = TRUE;
13
+
14
+ -- Add comments for documentation
15
+ COMMENT ON COLUMN gates.response_format_enabled IS 'Whether structured output is enabled for this gate';
16
+ COMMENT ON COLUMN gates.response_format_type IS 'Response format type: text, json_object, or json_schema';
17
+ COMMENT ON COLUMN gates.response_format_schema IS 'JSON schema for json_schema response format type';
@@ -1 +1 @@
1
- {"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../../src/lib/db/postgres.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../../src/lib/db/postgres.ts"],"names":[],"mappings":"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"}
@@ -102,8 +102,8 @@ export const db = {
102
102
  return result.rows.map(toCamelCase);
103
103
  },
104
104
  async createGate(userId, data) {
105
- const result = await getPool().query(`INSERT INTO gates (user_id, name, description, task_type, model, system_prompt, allow_overrides, temperature, max_tokens, top_p, tags, routing_strategy, fallback_models, cost_weight, latency_weight, quality_weight, analysis_method, reanalysis_period, auto_apply_recommendations, task_analysis)
106
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20) RETURNING *`, [
105
+ const result = await getPool().query(`INSERT INTO gates (user_id, name, description, task_type, model, system_prompt, allow_overrides, temperature, max_tokens, top_p, tags, routing_strategy, fallback_models, cost_weight, latency_weight, quality_weight, analysis_method, reanalysis_period, auto_apply_recommendations, task_analysis, response_format_enabled, response_format_type, response_format_schema)
106
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23) RETURNING *`, [
107
107
  userId,
108
108
  data.name,
109
109
  data.description,
@@ -123,7 +123,10 @@ export const db = {
123
123
  data.analysisMethod || 'balanced',
124
124
  data.reanalysisPeriod || 'never',
125
125
  data.autoApplyRecommendations ?? false,
126
- data.taskAnalysis ? JSON.stringify(data.taskAnalysis) : null
126
+ data.taskAnalysis ? JSON.stringify(data.taskAnalysis) : null,
127
+ data.responseFormatEnabled ?? false,
128
+ data.responseFormatType || null,
129
+ data.responseFormatSchema ? JSON.stringify(data.responseFormatSchema) : null
127
130
  ]);
128
131
  return toCamelCase(result.rows[0]);
129
132
  },
@@ -152,6 +155,9 @@ export const db = {
152
155
  reanalysis_period = COALESCE($18, reanalysis_period),
153
156
  auto_apply_recommendations = COALESCE($19, auto_apply_recommendations),
154
157
  task_analysis = COALESCE($20, task_analysis),
158
+ response_format_enabled = COALESCE($21, response_format_enabled),
159
+ response_format_type = COALESCE($22, response_format_type),
160
+ response_format_schema = COALESCE($23, response_format_schema),
155
161
  updated_at = NOW()
156
162
  WHERE id = $1 RETURNING *`, [
157
163
  id,
@@ -174,6 +180,9 @@ export const db = {
174
180
  data.reanalysisPeriod,
175
181
  data.autoApplyRecommendations,
176
182
  data.taskAnalysis ? JSON.stringify(data.taskAnalysis) : null,
183
+ data.responseFormatEnabled,
184
+ data.responseFormatType,
185
+ data.responseFormatSchema ? JSON.stringify(data.responseFormatSchema) : null,
177
186
  ]);
178
187
  return result.rows[0] ? toCamelCase(result.rows[0]) : null;
179
188
  },
@@ -1 +1 @@
1
- {"version":3,"file":"gate-utils.d.ts","sourceRoot":"","sources":["../../src/lib/gate-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,GAAG,MAAM,EAAE,CAuD9E"}
1
+ {"version":3,"file":"gate-utils.d.ts","sourceRoot":"","sources":["../../src/lib/gate-utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,GAAG,MAAM,EAAE,CA0D9E"}
@@ -45,6 +45,9 @@ export function detectSignificantChanges(existing, updates) {
45
45
  systemPrompt: 'systemPrompt',
46
46
  reanalysisPeriod: 'reanalysisPeriod',
47
47
  autoApplyRecommendations: 'autoApplyRecommendations',
48
+ responseFormatEnabled: 'responseFormatEnabled',
49
+ responseFormatType: 'responseFormatType',
50
+ responseFormatSchema: 'responseFormatSchema',
48
51
  };
49
52
  for (const [field, displayName] of Object.entries(significantFields)) {
50
53
  if (hasChanged(field, existing[field], updates[field])) {
@@ -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;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAqPpC,eAAe,MAAM,CAAC"}
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;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAmTpC,eAAe,MAAM,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { Router } from 'express';
2
2
  import { db } from '../../lib/db/postgres.js';
3
3
  import { authenticate } from '../../middleware/auth.js';
4
- import { callAdapter, normalizeModelId } from '../../lib/provider-factory.js';
4
+ import { callAdapter, normalizeModelId, getProviderForModel, PROVIDER } from '../../lib/provider-factory.js';
5
5
  import { OverrideField } from '@layer-ai/sdk';
6
6
  const router = Router();
7
7
  // MARK:- Helper Functions
@@ -45,6 +45,42 @@ function resolveFinalRequest(gateConfig, request) {
45
45
  else if (chatData.topP !== undefined && !isOverrideAllowed(gateConfig.allowOverrides, OverrideField.TopP)) {
46
46
  chatData.topP = gateConfig.topP;
47
47
  }
48
+ // Apply structured output (response format) from gate config if enabled
49
+ if (gateConfig.responseFormatEnabled && gateConfig.responseFormatType) {
50
+ const modelProvider = getProviderForModel(finalModel);
51
+ if (modelProvider === PROVIDER.OPENAI) {
52
+ // OpenAI: Use native response_format support
53
+ if (gateConfig.responseFormatType === 'json_schema' && gateConfig.responseFormatSchema) {
54
+ chatData.responseFormat = {
55
+ type: 'json_schema',
56
+ json_schema: gateConfig.responseFormatSchema,
57
+ };
58
+ }
59
+ else {
60
+ chatData.responseFormat = gateConfig.responseFormatType; // 'text' or 'json_object'
61
+ }
62
+ }
63
+ else {
64
+ // Non-OpenAI providers: Beta mode - inject instructions into system prompt
65
+ if (gateConfig.responseFormatType !== 'text') {
66
+ let schemaInstructions = '';
67
+ if (gateConfig.responseFormatType === 'json_schema' && gateConfig.responseFormatSchema) {
68
+ // For json_schema mode, include the actual schema
69
+ schemaInstructions = `\n\n[STRUCTURED OUTPUT - BETA] You MUST respond with valid JSON matching this exact schema:\n${JSON.stringify(gateConfig.responseFormatSchema, null, 2)}\n\nIMPORTANT: Output ONLY the JSON object. Do not include any explanatory text, markdown formatting, or code blocks. Just the raw JSON.`;
70
+ }
71
+ else if (gateConfig.responseFormatType === 'json_object') {
72
+ // For json_object mode, just require valid JSON
73
+ schemaInstructions = `\n\n[STRUCTURED OUTPUT - BETA] You MUST respond with valid JSON only. Do not include any explanatory text, markdown formatting, or code blocks. Output should be a raw JSON object.`;
74
+ }
75
+ // Append to existing system prompt or create new one
76
+ chatData.systemPrompt = (chatData.systemPrompt || '') + schemaInstructions;
77
+ // Log info message about beta mode
78
+ console.log(`[Layer AI - Structured Output Beta] Gate "${gateConfig.name}" (ID: ${gateConfig.id}) ` +
79
+ `is using structured output with provider "${modelProvider}". This is a beta feature that relies on ` +
80
+ `prompt engineering and may not be as reliable as OpenAI's native support.`);
81
+ }
82
+ }
83
+ }
48
84
  return {
49
85
  ...request,
50
86
  type: 'chat',
@@ -168,6 +204,20 @@ router.post('/', authenticate, async (req, res) => {
168
204
  errorMessage: null,
169
205
  userAgent: req.headers['user-agent'] || null,
170
206
  ipAddress: req.ip || null,
207
+ requestPayload: {
208
+ gateId: request.gateId,
209
+ type: request.type,
210
+ model: request.model,
211
+ data: request.data,
212
+ metadata: request.metadata,
213
+ },
214
+ responsePayload: {
215
+ content: result.content,
216
+ model: result.model,
217
+ usage: result.usage,
218
+ cost: result.cost,
219
+ finishReason: result.finishReason,
220
+ },
171
221
  }).catch(err => console.error('Failed to log request:', err));
172
222
  // Return LayerResponse with additional metadata
173
223
  const response = {
@@ -195,6 +245,14 @@ router.post('/', authenticate, async (req, res) => {
195
245
  errorMessage,
196
246
  userAgent: req.headers['user-agent'] || null,
197
247
  ipAddress: req.ip || null,
248
+ requestPayload: request ? {
249
+ gateId: request.gateId,
250
+ type: request.type,
251
+ model: request.model,
252
+ data: request.data,
253
+ metadata: request.metadata,
254
+ } : null,
255
+ responsePayload: null,
198
256
  }).catch(err => console.error('Failed to log request:', err));
199
257
  console.error('Chat completion error:', error);
200
258
  res.status(500).json({ error: 'internal_error', message: errorMessage });
@@ -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;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AA8OpC,eAAe,MAAM,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;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAmQpC,eAAe,MAAM,CAAC"}
@@ -161,6 +161,19 @@ router.post('/', authenticate, async (req, res) => {
161
161
  errorMessage: null,
162
162
  userAgent: req.headers['user-agent'] || null,
163
163
  ipAddress: req.ip || null,
164
+ requestPayload: {
165
+ gateId: request.gateId,
166
+ type: request.type,
167
+ model: request.model,
168
+ data: request.data,
169
+ metadata: request.metadata,
170
+ },
171
+ responsePayload: {
172
+ embeddings: result.embeddings,
173
+ model: result.model,
174
+ usage: result.usage,
175
+ cost: result.cost,
176
+ },
164
177
  }).catch(err => console.error('Failed to log request:', err));
165
178
  // Return LayerResponse with additional metadata
166
179
  const response = {
@@ -188,6 +201,14 @@ router.post('/', authenticate, async (req, res) => {
188
201
  errorMessage,
189
202
  userAgent: req.headers['user-agent'] || null,
190
203
  ipAddress: req.ip || null,
204
+ requestPayload: request ? {
205
+ gateId: request.gateId,
206
+ type: request.type,
207
+ model: request.model,
208
+ data: request.data,
209
+ metadata: request.metadata,
210
+ } : null,
211
+ responsePayload: null,
191
212
  }).catch(err => console.error('Failed to log request:', err));
192
213
  console.error('Embeddings error:', error);
193
214
  res.status(500).json({ error: 'internal_error', message: errorMessage });
@@ -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;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAuOpC,eAAe,MAAM,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;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AA4PpC,eAAe,MAAM,CAAC"}
@@ -155,6 +155,19 @@ router.post('/', authenticate, async (req, res) => {
155
155
  errorMessage: null,
156
156
  userAgent: req.headers['user-agent'] || null,
157
157
  ipAddress: req.ip || null,
158
+ requestPayload: {
159
+ gateId: request.gateId,
160
+ type: request.type,
161
+ model: request.model,
162
+ data: request.data,
163
+ metadata: request.metadata,
164
+ },
165
+ responsePayload: {
166
+ images: result.images,
167
+ model: result.model,
168
+ usage: result.usage,
169
+ cost: result.cost,
170
+ },
158
171
  }).catch(err => console.error('Failed to log request:', err));
159
172
  // Return LayerResponse with additional metadata
160
173
  const response = {
@@ -182,6 +195,14 @@ router.post('/', authenticate, async (req, res) => {
182
195
  errorMessage,
183
196
  userAgent: req.headers['user-agent'] || null,
184
197
  ipAddress: req.ip || null,
198
+ requestPayload: request ? {
199
+ gateId: request.gateId,
200
+ type: request.type,
201
+ model: request.model,
202
+ data: request.data,
203
+ metadata: request.metadata,
204
+ } : null,
205
+ responsePayload: null,
185
206
  }).catch(err => console.error('Failed to log request:', err));
186
207
  console.error('Image generation error:', error);
187
208
  res.status(500).json({ error: 'internal_error', message: errorMessage });
@@ -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;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAgOpC,eAAe,MAAM,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;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAqPpC,eAAe,MAAM,CAAC"}
@@ -149,6 +149,19 @@ router.post('/', authenticate, async (req, res) => {
149
149
  errorMessage: null,
150
150
  userAgent: req.headers['user-agent'] || null,
151
151
  ipAddress: req.ip || null,
152
+ requestPayload: {
153
+ gateId: request.gateId,
154
+ type: request.type,
155
+ model: request.model,
156
+ data: request.data,
157
+ metadata: request.metadata,
158
+ },
159
+ responsePayload: {
160
+ ocr: result.ocr,
161
+ model: result.model,
162
+ usage: result.usage,
163
+ cost: result.cost,
164
+ },
152
165
  }).catch(err => console.error('Failed to log request:', err));
153
166
  // Return LayerResponse with additional metadata
154
167
  const response = {
@@ -176,6 +189,14 @@ router.post('/', authenticate, async (req, res) => {
176
189
  errorMessage,
177
190
  userAgent: req.headers['user-agent'] || null,
178
191
  ipAddress: req.ip || null,
192
+ requestPayload: request ? {
193
+ gateId: request.gateId,
194
+ type: request.type,
195
+ model: request.model,
196
+ data: request.data,
197
+ metadata: request.metadata,
198
+ } : null,
199
+ responsePayload: null,
179
200
  }).catch(err => console.error('Failed to log request:', err));
180
201
  console.error('OCR error:', error);
181
202
  res.status(500).json({ error: 'internal_error', message: errorMessage });
@@ -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;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AA4NpC,eAAe,MAAM,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;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAiPpC,eAAe,MAAM,CAAC"}
@@ -145,6 +145,19 @@ router.post('/', authenticate, async (req, res) => {
145
145
  errorMessage: null,
146
146
  userAgent: req.headers['user-agent'] || null,
147
147
  ipAddress: req.ip || null,
148
+ requestPayload: {
149
+ gateId: request.gateId,
150
+ type: request.type,
151
+ model: request.model,
152
+ data: request.data,
153
+ metadata: request.metadata,
154
+ },
155
+ responsePayload: {
156
+ audio: result.audio,
157
+ model: result.model,
158
+ usage: result.usage,
159
+ cost: result.cost,
160
+ },
148
161
  }).catch(err => console.error('Failed to log request:', err));
149
162
  // Return LayerResponse with additional metadata
150
163
  const response = {
@@ -172,6 +185,14 @@ router.post('/', authenticate, async (req, res) => {
172
185
  errorMessage,
173
186
  userAgent: req.headers['user-agent'] || null,
174
187
  ipAddress: req.ip || null,
188
+ requestPayload: request ? {
189
+ gateId: request.gateId,
190
+ type: request.type,
191
+ model: request.model,
192
+ data: request.data,
193
+ metadata: request.metadata,
194
+ } : null,
195
+ responsePayload: null,
175
196
  }).catch(err => console.error('Failed to log request:', err));
176
197
  console.error('TTS error:', error);
177
198
  res.status(500).json({ error: 'internal_error', message: errorMessage });
@@ -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;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAuOpC,eAAe,MAAM,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;AAOpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AA4PpC,eAAe,MAAM,CAAC"}
@@ -155,6 +155,19 @@ router.post('/', authenticate, async (req, res) => {
155
155
  errorMessage: null,
156
156
  userAgent: req.headers['user-agent'] || null,
157
157
  ipAddress: req.ip || null,
158
+ requestPayload: {
159
+ gateId: request.gateId,
160
+ type: request.type,
161
+ model: request.model,
162
+ data: request.data,
163
+ metadata: request.metadata,
164
+ },
165
+ responsePayload: {
166
+ videos: result.videos,
167
+ model: result.model,
168
+ usage: result.usage,
169
+ cost: result.cost,
170
+ },
158
171
  }).catch(err => console.error('Failed to log request:', err));
159
172
  // Return LayerResponse with additional metadata
160
173
  const response = {
@@ -182,6 +195,14 @@ router.post('/', authenticate, async (req, res) => {
182
195
  errorMessage,
183
196
  userAgent: req.headers['user-agent'] || null,
184
197
  ipAddress: req.ip || null,
198
+ requestPayload: request ? {
199
+ gateId: request.gateId,
200
+ type: request.type,
201
+ model: request.model,
202
+ data: request.data,
203
+ metadata: request.metadata,
204
+ } : null,
205
+ responsePayload: null,
185
206
  }).catch(err => console.error('Failed to log request:', err));
186
207
  console.error('Video generation error:', error);
187
208
  res.status(500).json({ error: 'internal_error', message: errorMessage });
@@ -1 +1 @@
1
- {"version":3,"file":"openai-adapter.d.ts","sourceRoot":"","sources":["../../../src/services/providers/openai-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EACL,YAAY,EACZ,aAAa,EACb,IAAI,EACJ,WAAW,EACX,SAAS,EACT,YAAY,EACZ,UAAU,EACV,SAAS,EACT,WAAW,EACX,YAAY,EACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAoB1E,qBAAa,aAAc,SAAQ,mBAAmB;IACpD,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAmB;IAE/C,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAQ1C;IAEF,SAAS,CAAC,mBAAmB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAIxD;IAEF,SAAS,CAAC,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAK1D;IAEF,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAQpD;IAEF,SAAS,CAAC,oBAAoB,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAG1D;IAEF,SAAS,CAAC,kBAAkB,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAGtD;IAEF,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAKpD;IAEF,SAAS,CAAC,mBAAmB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAOxD;IAEI,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;YAoB5D,UAAU;YA4GV,qBAAqB;YAuCrB,gBAAgB;YAkChB,kBAAkB;CA+BjC"}
1
+ {"version":3,"file":"openai-adapter.d.ts","sourceRoot":"","sources":["../../../src/services/providers/openai-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EACL,YAAY,EACZ,aAAa,EACb,IAAI,EACJ,WAAW,EACX,SAAS,EACT,YAAY,EACZ,UAAU,EACV,SAAS,EACT,WAAW,EACX,YAAY,EACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAoB1E,qBAAa,aAAc,SAAQ,mBAAmB;IACpD,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAmB;IAE/C,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAQ1C;IAEF,SAAS,CAAC,mBAAmB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAIxD;IAEF,SAAS,CAAC,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAK1D;IAEF,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAQpD;IAEF,SAAS,CAAC,oBAAoB,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAG1D;IAEF,SAAS,CAAC,kBAAkB,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAGtD;IAEF,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAKpD;IAEF,SAAS,CAAC,mBAAmB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAOxD;IAEI,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;YAoB5D,UAAU;YAoHV,qBAAqB;YAuCrB,gBAAgB;YAkChB,kBAAkB;CA+BjC"}
@@ -161,6 +161,12 @@ export class OpenAIAdapter extends BaseProviderAdapter {
161
161
  tools: chat.tools,
162
162
  ...(chat.toolChoice && { tool_choice: chat.toolChoice }),
163
163
  }),
164
+ // Structured output support: convert camelCase to snake_case
165
+ ...(chat.responseFormat && {
166
+ response_format: (typeof chat.responseFormat === 'string'
167
+ ? { type: chat.responseFormat }
168
+ : chat.responseFormat),
169
+ }),
164
170
  };
165
171
  const response = await client.chat.completions.create(openaiRequest);
166
172
  const choice = response.choices[0];
@@ -1 +1 @@
1
- {"version":3,"file":"task-analysis.d.ts","sourceRoot":"","sources":["../../src/services/task-analysis.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,YAAY,EAAmC,MAAM,eAAe,CAAC;AAqD9F,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GACA,OAAO,CAAC,YAAY,CAAC,CA6GvB"}
1
+ {"version":3,"file":"task-analysis.d.ts","sourceRoot":"","sources":["../../src/services/task-analysis.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,YAAY,EAAmC,MAAM,eAAe,CAAC;AA2D9F,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GACA,OAAO,CAAC,YAAY,CAAC,CAkHvB"}
@@ -20,8 +20,13 @@ AVAILABLE TASK TYPES:
20
20
 
21
21
  Return ONLY the task type as a single word, nothing else.`;
22
22
  try {
23
+ // Smart routing model - upgraded to Sonnet 4.5 for better recommendations
24
+ // Can be overridden via SMART_ROUTING_MODEL environment variable
25
+ // Default: claude-sonnet-4-5-20250929 (~$3/1M tokens vs Haiku ~$0.25/1M)
26
+ // Cost impact is minimal since smart routing is infrequent (gate creation/reanalysis)
27
+ const smartRoutingModel = process.env.SMART_ROUTING_MODEL || 'claude-sonnet-4-5-20250929';
23
28
  const response = await anthropic.messages.create({
24
- model: 'claude-haiku-4-5-20251001',
29
+ model: smartRoutingModel,
25
30
  max_tokens: 50,
26
31
  temperature: 0.0,
27
32
  messages: [{
@@ -101,8 +106,12 @@ Return JSON with:
101
106
  "reasoning": "why these models work for this task and user preferences"
102
107
  }`;
103
108
  try {
109
+ // Smart routing model - upgraded to Sonnet 4.5 for superior analysis quality
110
+ // Can be overridden via SMART_ROUTING_MODEL environment variable
111
+ // Default: claude-sonnet-4-5-20250929 for more nuanced model recommendations
112
+ const smartRoutingModel = process.env.SMART_ROUTING_MODEL || 'claude-sonnet-4-5-20250929';
104
113
  const response = await anthropic.messages.create({
105
- model: 'claude-haiku-4-5-20251001',
114
+ model: smartRoutingModel,
106
115
  max_tokens: 2000,
107
116
  temperature: 0.0,
108
117
  messages: [{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@layer-ai/core",
3
- "version": "2.0.9",
3
+ "version": "2.0.11",
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": "^2.5.2"
39
+ "@layer-ai/sdk": "^2.5.3"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/bcryptjs": "^2.4.6",