@layer-ai/core 0.8.9 → 0.8.10

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,6 @@
1
+ /**
2
+ * Detects which significant fields have changed between existing and new gate configurations.
3
+ * Returns array of field names that changed. Only tracks fields that warrant a history snapshot.
4
+ */
5
+ export declare function detectSignificantChanges(existing: any, updates: any): string[];
6
+ //# sourceMappingURL=gate-utils.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Detects which significant fields have changed between existing and new gate configurations.
3
+ * Returns array of field names that changed. Only tracks fields that warrant a history snapshot.
4
+ */
5
+ export function detectSignificantChanges(existing, updates) {
6
+ const changedFields = [];
7
+ const normalizeArray = (val) => {
8
+ if (Array.isArray(val))
9
+ return JSON.stringify(val.sort());
10
+ if (typeof val === 'string') {
11
+ try {
12
+ const parsed = JSON.parse(val);
13
+ return JSON.stringify(Array.isArray(parsed) ? parsed.sort() : parsed);
14
+ }
15
+ catch {
16
+ return val;
17
+ }
18
+ }
19
+ return JSON.stringify(val || []);
20
+ };
21
+ const hasChanged = (field, existingVal, newVal) => {
22
+ if (newVal === undefined)
23
+ return false;
24
+ if (field === 'fallbackModels') {
25
+ return normalizeArray(existingVal) !== normalizeArray(newVal);
26
+ }
27
+ const normalizedExisting = existingVal ?? null;
28
+ const normalizedNew = newVal ?? null;
29
+ return normalizedExisting !== normalizedNew;
30
+ };
31
+ const significantFields = {
32
+ name: 'name',
33
+ description: 'description',
34
+ model: 'model',
35
+ fallbackModels: 'fallbackModels',
36
+ routingStrategy: 'routingStrategy',
37
+ temperature: 'temperature',
38
+ maxTokens: 'maxTokens',
39
+ topP: 'topP',
40
+ costWeight: 'costWeight',
41
+ latencyWeight: 'latencyWeight',
42
+ qualityWeight: 'qualityWeight',
43
+ analysisMethod: 'analysisMethod',
44
+ taskType: 'taskType',
45
+ systemPrompt: 'systemPrompt',
46
+ reanalysisPeriod: 'reanalysisPeriod',
47
+ autoApplyRecommendations: 'autoApplyRecommendations',
48
+ };
49
+ for (const [field, displayName] of Object.entries(significantFields)) {
50
+ if (hasChanged(field, existing[field], updates[field])) {
51
+ changedFields.push(displayName);
52
+ }
53
+ }
54
+ return changedFields;
55
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"gates.d.ts","sourceRoot":"","sources":["../../../src/routes/v1/gates.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AAQpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AA6fpC,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"gates.d.ts","sourceRoot":"","sources":["../../../src/routes/v1/gates.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AASpD,QAAA,MAAM,MAAM,EAAE,UAAqB,CAAC;AAsiBpC,eAAe,MAAM,CAAC"}
@@ -4,6 +4,7 @@ import { cache } from '../../lib/db/redis.js';
4
4
  import { authenticate } from '../../middleware/auth.js';
5
5
  import { callAdapter } from '../../lib/provider-factory.js';
6
6
  import { MODEL_REGISTRY } from '@layer-ai/sdk';
7
+ import { detectSignificantChanges } from '../../lib/gate-utils.js';
7
8
  const router = Router();
8
9
  // All routes require authentication (SDK auth with Bearer token)
9
10
  router.use(authenticate);
@@ -118,7 +119,7 @@ router.patch('/name/:name', async (req, res) => {
118
119
  return;
119
120
  }
120
121
  try {
121
- const { description, taskType, model, systemPrompt, allowOverrides, temperature, maxTokens, topP, tags, routingStrategy, fallbackModels, costWeight, latencyWeight, qualityWeight, analysisMethod, reanalysisPeriod, taskAnalysis } = req.body;
122
+ const { description, taskType, model, systemPrompt, allowOverrides, temperature, maxTokens, topP, tags, routingStrategy, fallbackModels, costWeight, latencyWeight, qualityWeight, analysisMethod, reanalysisPeriod, taskAnalysis, autoApplyRecommendations } = req.body;
122
123
  const existing = await db.getGateByUserAndName(req.userId, req.params.name);
123
124
  if (!existing) {
124
125
  res.status(404).json({ error: 'not_found', message: 'Gate not found' });
@@ -128,6 +129,24 @@ router.patch('/name/:name', async (req, res) => {
128
129
  res.status(400).json({ error: 'bad_request', message: `Unsupported model: ${model}` });
129
130
  return;
130
131
  }
132
+ // Detect significant changes before updating
133
+ const changedFields = detectSignificantChanges(existing, {
134
+ description,
135
+ taskType,
136
+ model,
137
+ systemPrompt,
138
+ temperature,
139
+ maxTokens,
140
+ topP,
141
+ routingStrategy,
142
+ fallbackModels,
143
+ costWeight,
144
+ latencyWeight,
145
+ qualityWeight,
146
+ analysisMethod,
147
+ reanalysisPeriod,
148
+ autoApplyRecommendations,
149
+ });
131
150
  const updated = await db.updateGate(existing.id, {
132
151
  description,
133
152
  taskType,
@@ -146,15 +165,16 @@ router.patch('/name/:name', async (req, res) => {
146
165
  analysisMethod,
147
166
  reanalysisPeriod,
148
167
  taskAnalysis,
168
+ autoApplyRecommendations,
149
169
  });
150
- // Create history snapshot after update with the updated values
151
- if (updated) {
152
- await db.createGateHistory(existing.id, updated, 'user');
170
+ // Only create history snapshot if significant changes were detected
171
+ if (updated && changedFields.length > 0) {
172
+ await db.createGateHistory(existing.id, updated, 'user', changedFields);
173
+ // Log manual update activity with specific changed fields
174
+ await db.createActivityLog(existing.id, req.userId, 'manual_update', {
175
+ changedFields
176
+ });
153
177
  }
154
- // Log manual update activity
155
- await db.createActivityLog(existing.id, req.userId, 'manual_update', {
156
- changedFields: Object.keys(req.body)
157
- });
158
178
  await cache.invalidateGate(req.userId, existing.name);
159
179
  res.json(updated);
160
180
  }
@@ -170,7 +190,7 @@ router.patch('/:id', async (req, res) => {
170
190
  return;
171
191
  }
172
192
  try {
173
- const { name, description, taskType, model, systemPrompt, allowOverrides, temperature, maxTokens, topP, tags, routingStrategy, fallbackModels, costWeight, latencyWeight, qualityWeight, analysisMethod, reanalysisPeriod, taskAnalysis } = req.body;
193
+ const { name, description, taskType, model, systemPrompt, allowOverrides, temperature, maxTokens, topP, tags, routingStrategy, fallbackModels, costWeight, latencyWeight, qualityWeight, analysisMethod, reanalysisPeriod, taskAnalysis, autoApplyRecommendations } = req.body;
174
194
  const existing = await db.getGateById(req.params.id);
175
195
  if (!existing) {
176
196
  res.status(404).json({ error: 'not_found', message: 'Gate not found' });
@@ -184,6 +204,25 @@ router.patch('/:id', async (req, res) => {
184
204
  res.status(400).json({ error: 'bad_request', message: `Unsupported model: ${model}` });
185
205
  return;
186
206
  }
207
+ // Detect significant changes before updating
208
+ const changedFields = detectSignificantChanges(existing, {
209
+ name,
210
+ description,
211
+ taskType,
212
+ model,
213
+ systemPrompt,
214
+ temperature,
215
+ maxTokens,
216
+ topP,
217
+ routingStrategy,
218
+ fallbackModels,
219
+ costWeight,
220
+ latencyWeight,
221
+ qualityWeight,
222
+ analysisMethod,
223
+ reanalysisPeriod,
224
+ autoApplyRecommendations,
225
+ });
187
226
  const updated = await db.updateGate(req.params.id, {
188
227
  name,
189
228
  description,
@@ -203,15 +242,16 @@ router.patch('/:id', async (req, res) => {
203
242
  analysisMethod,
204
243
  reanalysisPeriod,
205
244
  taskAnalysis,
245
+ autoApplyRecommendations,
206
246
  });
207
- // Create history snapshot after update with the updated values
208
- if (updated) {
209
- await db.createGateHistory(req.params.id, updated, 'user');
247
+ // Only create history snapshot if significant changes were detected
248
+ if (updated && changedFields.length > 0) {
249
+ await db.createGateHistory(req.params.id, updated, 'user', changedFields);
250
+ // Log manual update activity with specific changed fields
251
+ await db.createActivityLog(req.params.id, req.userId, 'manual_update', {
252
+ changedFields
253
+ });
210
254
  }
211
- // Log manual update activity
212
- await db.createActivityLog(req.params.id, req.userId, 'manual_update', {
213
- changedFields: Object.keys(req.body)
214
- });
215
255
  await cache.invalidateGate(req.userId, existing.name);
216
256
  res.json(updated);
217
257
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@layer-ai/core",
3
- "version": "0.8.9",
3
+ "version": "0.8.10",
4
4
  "description": "Core API routes and services for Layer AI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",