@rynfar/meridian 1.34.0 → 1.35.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/README.md +15 -9
- package/dist/{cli-1qv75efv.js → cli-0kfa6j99.js} +1319 -136
- package/dist/cli-p9swy5t3.js +67 -0
- package/dist/cli.js +8 -8
- package/dist/{profileCli-5e3p99k0.js → profileCli-5f15dx7k.js} +1 -1
- package/dist/{profilePage-9nkbct3w.js → profilePage-e90fq8ye.js} +1 -1
- package/dist/{profiles-ntgacztq.js → profiles-edzz1ffd.js} +1 -1
- package/dist/proxy/adapters/pi.d.ts.map +1 -1
- package/dist/proxy/sanitize.d.ts +26 -0
- package/dist/proxy/sanitize.d.ts.map +1 -0
- package/dist/proxy/server.d.ts.map +1 -1
- package/dist/proxy/types.d.ts +2 -0
- package/dist/proxy/types.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/{setup-5x116vbs.js → setup-v5pnqe04.js} +1 -1
- package/dist/telemetry/index.d.ts +9 -4
- package/dist/telemetry/index.d.ts.map +1 -1
- package/dist/telemetry/logStore.d.ts +4 -25
- package/dist/telemetry/logStore.d.ts.map +1 -1
- package/dist/telemetry/percentiles.d.ts +12 -0
- package/dist/telemetry/percentiles.d.ts.map +1 -0
- package/dist/telemetry/prometheus.d.ts +10 -0
- package/dist/telemetry/prometheus.d.ts.map +1 -0
- package/dist/telemetry/routes.d.ts.map +1 -1
- package/dist/telemetry/sqlite.d.ts +7 -0
- package/dist/telemetry/sqlite.d.ts.map +1 -0
- package/dist/telemetry/store.d.ts +3 -3
- package/dist/telemetry/store.d.ts.map +1 -1
- package/dist/telemetry/types.d.ts +51 -0
- package/dist/telemetry/types.d.ts.map +1 -1
- package/dist/{tokenRefresh-ywwpe8k2.js → tokenRefresh-y7d1qvb3.js} +1 -1
- package/package.json +3 -2
- package/plugin/meridian.ts +4 -1
- package/dist/cli-a05ws7rb.js +0 -18
|
@@ -20,9 +20,1133 @@ import {
|
|
|
20
20
|
setActiveProfile
|
|
21
21
|
} from "./cli-vdp9s10c.js";
|
|
22
22
|
import {
|
|
23
|
+
__commonJS,
|
|
24
|
+
__esm,
|
|
23
25
|
__export,
|
|
24
|
-
__require
|
|
25
|
-
|
|
26
|
+
__require,
|
|
27
|
+
__toCommonJS,
|
|
28
|
+
__toESM
|
|
29
|
+
} from "./cli-p9swy5t3.js";
|
|
30
|
+
|
|
31
|
+
// src/telemetry/percentiles.ts
|
|
32
|
+
function computePercentiles(values) {
|
|
33
|
+
if (values.length === 0)
|
|
34
|
+
return { p50: 0, p95: 0, p99: 0, min: 0, max: 0, avg: 0 };
|
|
35
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
36
|
+
const sum = sorted.reduce((a, b) => a + b, 0);
|
|
37
|
+
return {
|
|
38
|
+
p50: sorted[Math.floor(sorted.length * 0.5)],
|
|
39
|
+
p95: sorted[Math.floor(sorted.length * 0.95)],
|
|
40
|
+
p99: sorted[Math.floor(sorted.length * 0.99)],
|
|
41
|
+
min: sorted[0],
|
|
42
|
+
max: sorted[sorted.length - 1],
|
|
43
|
+
avg: Math.round(sum / sorted.length)
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function computeSummary(metrics, windowMs) {
|
|
47
|
+
if (metrics.length === 0) {
|
|
48
|
+
const emptyPhase = { p50: 0, p95: 0, p99: 0, min: 0, max: 0, avg: 0 };
|
|
49
|
+
return {
|
|
50
|
+
windowMs,
|
|
51
|
+
totalRequests: 0,
|
|
52
|
+
errorCount: 0,
|
|
53
|
+
requestsPerMinute: 0,
|
|
54
|
+
queueWait: emptyPhase,
|
|
55
|
+
proxyOverhead: emptyPhase,
|
|
56
|
+
ttfb: emptyPhase,
|
|
57
|
+
upstreamDuration: emptyPhase,
|
|
58
|
+
totalDuration: emptyPhase,
|
|
59
|
+
byModel: {},
|
|
60
|
+
byMode: {},
|
|
61
|
+
tokenUsage: {
|
|
62
|
+
totalInputTokens: 0,
|
|
63
|
+
totalOutputTokens: 0,
|
|
64
|
+
totalCacheReadTokens: 0,
|
|
65
|
+
totalCacheCreationTokens: 0,
|
|
66
|
+
avgCacheHitRate: 0,
|
|
67
|
+
cacheMissOnResumeCount: 0
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const errorCount = metrics.filter((m) => m.error !== null).length;
|
|
72
|
+
const oldest = metrics[metrics.length - 1].timestamp;
|
|
73
|
+
const newest = metrics[0].timestamp;
|
|
74
|
+
const spanMs = Math.max(newest - oldest, 1);
|
|
75
|
+
const requestsPerMinute = metrics.length / spanMs * 60000;
|
|
76
|
+
const queueWaits = metrics.map((m) => m.queueWaitMs);
|
|
77
|
+
const overheads = metrics.map((m) => m.proxyOverheadMs);
|
|
78
|
+
const ttfbs = metrics.filter((m) => m.ttfbMs !== null).map((m) => m.ttfbMs);
|
|
79
|
+
const upstreams = metrics.map((m) => m.upstreamDurationMs);
|
|
80
|
+
const totals = metrics.map((m) => m.totalDurationMs);
|
|
81
|
+
const byModel = {};
|
|
82
|
+
for (const m of metrics) {
|
|
83
|
+
const modelKey = m.requestModel || m.model;
|
|
84
|
+
const entry = byModel[modelKey] ??= { count: 0, totalMs: 0 };
|
|
85
|
+
entry.count++;
|
|
86
|
+
entry.totalMs += m.totalDurationMs;
|
|
87
|
+
}
|
|
88
|
+
const byMode = {};
|
|
89
|
+
for (const m of metrics) {
|
|
90
|
+
const entry = byMode[m.mode] ??= { count: 0, totalMs: 0 };
|
|
91
|
+
entry.count++;
|
|
92
|
+
entry.totalMs += m.totalDurationMs;
|
|
93
|
+
}
|
|
94
|
+
let totalInputTokens = 0;
|
|
95
|
+
let totalOutputTokens = 0;
|
|
96
|
+
let totalCacheReadTokens = 0;
|
|
97
|
+
let totalCacheCreationTokens = 0;
|
|
98
|
+
let cacheHitRateSum = 0;
|
|
99
|
+
let cacheHitRateCount = 0;
|
|
100
|
+
let cacheMissOnResumeCount = 0;
|
|
101
|
+
for (const m of metrics) {
|
|
102
|
+
totalInputTokens += m.inputTokens ?? 0;
|
|
103
|
+
totalOutputTokens += m.outputTokens ?? 0;
|
|
104
|
+
totalCacheReadTokens += m.cacheReadInputTokens ?? 0;
|
|
105
|
+
totalCacheCreationTokens += m.cacheCreationInputTokens ?? 0;
|
|
106
|
+
if (m.cacheHitRate !== undefined) {
|
|
107
|
+
cacheHitRateSum += m.cacheHitRate;
|
|
108
|
+
cacheHitRateCount++;
|
|
109
|
+
}
|
|
110
|
+
if (m.isResume && m.cacheHitRate !== undefined && m.cacheHitRate === 0) {
|
|
111
|
+
cacheMissOnResumeCount++;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
windowMs,
|
|
116
|
+
totalRequests: metrics.length,
|
|
117
|
+
errorCount,
|
|
118
|
+
requestsPerMinute: Math.round(requestsPerMinute * 100) / 100,
|
|
119
|
+
queueWait: computePercentiles(queueWaits),
|
|
120
|
+
proxyOverhead: computePercentiles(overheads),
|
|
121
|
+
ttfb: ttfbs.length > 0 ? computePercentiles(ttfbs) : { p50: 0, p95: 0, p99: 0, min: 0, max: 0, avg: 0 },
|
|
122
|
+
upstreamDuration: computePercentiles(upstreams),
|
|
123
|
+
totalDuration: computePercentiles(totals),
|
|
124
|
+
byModel: Object.fromEntries(Object.entries(byModel).map(([k, v]) => [k, { count: v.count, avgTotalMs: Math.round(v.totalMs / v.count) }])),
|
|
125
|
+
byMode: Object.fromEntries(Object.entries(byMode).map(([k, v]) => [k, { count: v.count, avgTotalMs: Math.round(v.totalMs / v.count) }])),
|
|
126
|
+
tokenUsage: {
|
|
127
|
+
totalInputTokens,
|
|
128
|
+
totalOutputTokens,
|
|
129
|
+
totalCacheReadTokens,
|
|
130
|
+
totalCacheCreationTokens,
|
|
131
|
+
avgCacheHitRate: cacheHitRateCount > 0 ? Math.round(cacheHitRateSum / cacheHitRateCount * 100) / 100 : 0,
|
|
132
|
+
cacheMissOnResumeCount
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
var init_percentiles = () => {};
|
|
137
|
+
|
|
138
|
+
// node_modules/@neon-rs/load/dist/index.js
|
|
139
|
+
var require_dist = __commonJS((exports) => {
|
|
140
|
+
var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
|
|
141
|
+
if (k2 === undefined)
|
|
142
|
+
k2 = k;
|
|
143
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
144
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
145
|
+
desc = { enumerable: true, get: function() {
|
|
146
|
+
return m[k];
|
|
147
|
+
} };
|
|
148
|
+
}
|
|
149
|
+
Object.defineProperty(o, k2, desc);
|
|
150
|
+
} : function(o, m, k, k2) {
|
|
151
|
+
if (k2 === undefined)
|
|
152
|
+
k2 = k;
|
|
153
|
+
o[k2] = m[k];
|
|
154
|
+
});
|
|
155
|
+
var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
|
|
156
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
157
|
+
} : function(o, v) {
|
|
158
|
+
o["default"] = v;
|
|
159
|
+
});
|
|
160
|
+
var __importStar = exports && exports.__importStar || function(mod) {
|
|
161
|
+
if (mod && mod.__esModule)
|
|
162
|
+
return mod;
|
|
163
|
+
var result = {};
|
|
164
|
+
if (mod != null) {
|
|
165
|
+
for (var k in mod)
|
|
166
|
+
if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k))
|
|
167
|
+
__createBinding(result, mod, k);
|
|
168
|
+
}
|
|
169
|
+
__setModuleDefault(result, mod);
|
|
170
|
+
return result;
|
|
171
|
+
};
|
|
172
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
173
|
+
exports.load = exports.currentTarget = undefined;
|
|
174
|
+
var path = __importStar(__require("path"));
|
|
175
|
+
var fs = __importStar(__require("fs"));
|
|
176
|
+
function currentTarget() {
|
|
177
|
+
let os = null;
|
|
178
|
+
switch (process.platform) {
|
|
179
|
+
case "android":
|
|
180
|
+
switch (process.arch) {
|
|
181
|
+
case "arm":
|
|
182
|
+
return "android-arm-eabi";
|
|
183
|
+
case "arm64":
|
|
184
|
+
return "android-arm64";
|
|
185
|
+
}
|
|
186
|
+
os = "Android";
|
|
187
|
+
break;
|
|
188
|
+
case "win32":
|
|
189
|
+
switch (process.arch) {
|
|
190
|
+
case "x64":
|
|
191
|
+
return "win32-x64-msvc";
|
|
192
|
+
case "arm64":
|
|
193
|
+
return "win32-arm64-msvc";
|
|
194
|
+
case "ia32":
|
|
195
|
+
return "win32-ia32-msvc";
|
|
196
|
+
}
|
|
197
|
+
os = "Windows";
|
|
198
|
+
break;
|
|
199
|
+
case "darwin":
|
|
200
|
+
switch (process.arch) {
|
|
201
|
+
case "x64":
|
|
202
|
+
return "darwin-x64";
|
|
203
|
+
case "arm64":
|
|
204
|
+
return "darwin-arm64";
|
|
205
|
+
}
|
|
206
|
+
os = "macOS";
|
|
207
|
+
break;
|
|
208
|
+
case "linux":
|
|
209
|
+
switch (process.arch) {
|
|
210
|
+
case "x64":
|
|
211
|
+
case "arm64":
|
|
212
|
+
return isGlibc() ? `linux-${process.arch}-gnu` : `linux-${process.arch}-musl`;
|
|
213
|
+
case "arm":
|
|
214
|
+
return "linux-arm-gnueabihf";
|
|
215
|
+
}
|
|
216
|
+
os = "Linux";
|
|
217
|
+
break;
|
|
218
|
+
case "freebsd":
|
|
219
|
+
if (process.arch === "x64") {
|
|
220
|
+
return "freebsd-x64";
|
|
221
|
+
}
|
|
222
|
+
os = "FreeBSD";
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
if (os) {
|
|
226
|
+
throw new Error(`Neon: unsupported ${os} architecture: ${process.arch}`);
|
|
227
|
+
}
|
|
228
|
+
throw new Error(`Neon: unsupported system: ${process.platform}`);
|
|
229
|
+
}
|
|
230
|
+
exports.currentTarget = currentTarget;
|
|
231
|
+
function isGlibc() {
|
|
232
|
+
const report = process.report?.getReport();
|
|
233
|
+
if (typeof report !== "object" || !report || !("header" in report)) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
const header = report.header;
|
|
237
|
+
return typeof header === "object" && !!header && "glibcVersionRuntime" in header;
|
|
238
|
+
}
|
|
239
|
+
function load(dirname2) {
|
|
240
|
+
const m = path.join(dirname2, "index.node");
|
|
241
|
+
return fs.existsSync(m) ? __require(m) : null;
|
|
242
|
+
}
|
|
243
|
+
exports.load = load;
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// node_modules/detect-libc/lib/process.js
|
|
247
|
+
var require_process = __commonJS((exports, module) => {
|
|
248
|
+
var isLinux = () => process.platform === "linux";
|
|
249
|
+
var report = null;
|
|
250
|
+
var getReport = () => {
|
|
251
|
+
if (!report) {
|
|
252
|
+
report = isLinux() && process.report ? process.report.getReport() : {};
|
|
253
|
+
}
|
|
254
|
+
return report;
|
|
255
|
+
};
|
|
256
|
+
module.exports = { isLinux, getReport };
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// node_modules/detect-libc/lib/filesystem.js
|
|
260
|
+
var require_filesystem = __commonJS((exports, module) => {
|
|
261
|
+
var fs = __require("fs");
|
|
262
|
+
var LDD_PATH = "/usr/bin/ldd";
|
|
263
|
+
var readFileSync2 = (path) => fs.readFileSync(path, "utf-8");
|
|
264
|
+
var readFile = (path) => new Promise((resolve2, reject) => {
|
|
265
|
+
fs.readFile(path, "utf-8", (err, data) => {
|
|
266
|
+
if (err) {
|
|
267
|
+
reject(err);
|
|
268
|
+
} else {
|
|
269
|
+
resolve2(data);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
module.exports = {
|
|
274
|
+
LDD_PATH,
|
|
275
|
+
readFileSync: readFileSync2,
|
|
276
|
+
readFile
|
|
277
|
+
};
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// node_modules/detect-libc/lib/detect-libc.js
|
|
281
|
+
var require_detect_libc = __commonJS((exports, module) => {
|
|
282
|
+
var childProcess = __require("child_process");
|
|
283
|
+
var { isLinux, getReport } = require_process();
|
|
284
|
+
var { LDD_PATH, readFile, readFileSync: readFileSync2 } = require_filesystem();
|
|
285
|
+
var cachedFamilyFilesystem;
|
|
286
|
+
var cachedVersionFilesystem;
|
|
287
|
+
var command = "getconf GNU_LIBC_VERSION 2>&1 || true; ldd --version 2>&1 || true";
|
|
288
|
+
var commandOut = "";
|
|
289
|
+
var safeCommand = () => {
|
|
290
|
+
if (!commandOut) {
|
|
291
|
+
return new Promise((resolve2) => {
|
|
292
|
+
childProcess.exec(command, (err, out) => {
|
|
293
|
+
commandOut = err ? " " : out;
|
|
294
|
+
resolve2(commandOut);
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
return commandOut;
|
|
299
|
+
};
|
|
300
|
+
var safeCommandSync = () => {
|
|
301
|
+
if (!commandOut) {
|
|
302
|
+
try {
|
|
303
|
+
commandOut = childProcess.execSync(command, { encoding: "utf8" });
|
|
304
|
+
} catch (_err) {
|
|
305
|
+
commandOut = " ";
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return commandOut;
|
|
309
|
+
};
|
|
310
|
+
var GLIBC = "glibc";
|
|
311
|
+
var RE_GLIBC_VERSION = /GLIBC\s(\d+\.\d+)/;
|
|
312
|
+
var MUSL = "musl";
|
|
313
|
+
var GLIBC_ON_LDD = GLIBC.toUpperCase();
|
|
314
|
+
var MUSL_ON_LDD = MUSL.toLowerCase();
|
|
315
|
+
var isFileMusl = (f) => f.includes("libc.musl-") || f.includes("ld-musl-");
|
|
316
|
+
var familyFromReport = () => {
|
|
317
|
+
const report = getReport();
|
|
318
|
+
if (report.header && report.header.glibcVersionRuntime) {
|
|
319
|
+
return GLIBC;
|
|
320
|
+
}
|
|
321
|
+
if (Array.isArray(report.sharedObjects)) {
|
|
322
|
+
if (report.sharedObjects.some(isFileMusl)) {
|
|
323
|
+
return MUSL;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return null;
|
|
327
|
+
};
|
|
328
|
+
var familyFromCommand = (out) => {
|
|
329
|
+
const [getconf, ldd1] = out.split(/[\r\n]+/);
|
|
330
|
+
if (getconf && getconf.includes(GLIBC)) {
|
|
331
|
+
return GLIBC;
|
|
332
|
+
}
|
|
333
|
+
if (ldd1 && ldd1.includes(MUSL)) {
|
|
334
|
+
return MUSL;
|
|
335
|
+
}
|
|
336
|
+
return null;
|
|
337
|
+
};
|
|
338
|
+
var getFamilyFromLddContent = (content) => {
|
|
339
|
+
if (content.includes(MUSL_ON_LDD)) {
|
|
340
|
+
return MUSL;
|
|
341
|
+
}
|
|
342
|
+
if (content.includes(GLIBC_ON_LDD)) {
|
|
343
|
+
return GLIBC;
|
|
344
|
+
}
|
|
345
|
+
return null;
|
|
346
|
+
};
|
|
347
|
+
var familyFromFilesystem = async () => {
|
|
348
|
+
if (cachedFamilyFilesystem !== undefined) {
|
|
349
|
+
return cachedFamilyFilesystem;
|
|
350
|
+
}
|
|
351
|
+
cachedFamilyFilesystem = null;
|
|
352
|
+
try {
|
|
353
|
+
const lddContent = await readFile(LDD_PATH);
|
|
354
|
+
cachedFamilyFilesystem = getFamilyFromLddContent(lddContent);
|
|
355
|
+
} catch (e) {}
|
|
356
|
+
return cachedFamilyFilesystem;
|
|
357
|
+
};
|
|
358
|
+
var familyFromFilesystemSync = () => {
|
|
359
|
+
if (cachedFamilyFilesystem !== undefined) {
|
|
360
|
+
return cachedFamilyFilesystem;
|
|
361
|
+
}
|
|
362
|
+
cachedFamilyFilesystem = null;
|
|
363
|
+
try {
|
|
364
|
+
const lddContent = readFileSync2(LDD_PATH);
|
|
365
|
+
cachedFamilyFilesystem = getFamilyFromLddContent(lddContent);
|
|
366
|
+
} catch (e) {}
|
|
367
|
+
return cachedFamilyFilesystem;
|
|
368
|
+
};
|
|
369
|
+
var family = async () => {
|
|
370
|
+
let family2 = null;
|
|
371
|
+
if (isLinux()) {
|
|
372
|
+
family2 = await familyFromFilesystem();
|
|
373
|
+
if (!family2) {
|
|
374
|
+
family2 = familyFromReport();
|
|
375
|
+
}
|
|
376
|
+
if (!family2) {
|
|
377
|
+
const out = await safeCommand();
|
|
378
|
+
family2 = familyFromCommand(out);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return family2;
|
|
382
|
+
};
|
|
383
|
+
var familySync = () => {
|
|
384
|
+
let family2 = null;
|
|
385
|
+
if (isLinux()) {
|
|
386
|
+
family2 = familyFromFilesystemSync();
|
|
387
|
+
if (!family2) {
|
|
388
|
+
family2 = familyFromReport();
|
|
389
|
+
}
|
|
390
|
+
if (!family2) {
|
|
391
|
+
const out = safeCommandSync();
|
|
392
|
+
family2 = familyFromCommand(out);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return family2;
|
|
396
|
+
};
|
|
397
|
+
var isNonGlibcLinux = async () => isLinux() && await family() !== GLIBC;
|
|
398
|
+
var isNonGlibcLinuxSync = () => isLinux() && familySync() !== GLIBC;
|
|
399
|
+
var versionFromFilesystem = async () => {
|
|
400
|
+
if (cachedVersionFilesystem !== undefined) {
|
|
401
|
+
return cachedVersionFilesystem;
|
|
402
|
+
}
|
|
403
|
+
cachedVersionFilesystem = null;
|
|
404
|
+
try {
|
|
405
|
+
const lddContent = await readFile(LDD_PATH);
|
|
406
|
+
const versionMatch = lddContent.match(RE_GLIBC_VERSION);
|
|
407
|
+
if (versionMatch) {
|
|
408
|
+
cachedVersionFilesystem = versionMatch[1];
|
|
409
|
+
}
|
|
410
|
+
} catch (e) {}
|
|
411
|
+
return cachedVersionFilesystem;
|
|
412
|
+
};
|
|
413
|
+
var versionFromFilesystemSync = () => {
|
|
414
|
+
if (cachedVersionFilesystem !== undefined) {
|
|
415
|
+
return cachedVersionFilesystem;
|
|
416
|
+
}
|
|
417
|
+
cachedVersionFilesystem = null;
|
|
418
|
+
try {
|
|
419
|
+
const lddContent = readFileSync2(LDD_PATH);
|
|
420
|
+
const versionMatch = lddContent.match(RE_GLIBC_VERSION);
|
|
421
|
+
if (versionMatch) {
|
|
422
|
+
cachedVersionFilesystem = versionMatch[1];
|
|
423
|
+
}
|
|
424
|
+
} catch (e) {}
|
|
425
|
+
return cachedVersionFilesystem;
|
|
426
|
+
};
|
|
427
|
+
var versionFromReport = () => {
|
|
428
|
+
const report = getReport();
|
|
429
|
+
if (report.header && report.header.glibcVersionRuntime) {
|
|
430
|
+
return report.header.glibcVersionRuntime;
|
|
431
|
+
}
|
|
432
|
+
return null;
|
|
433
|
+
};
|
|
434
|
+
var versionSuffix = (s) => s.trim().split(/\s+/)[1];
|
|
435
|
+
var versionFromCommand = (out) => {
|
|
436
|
+
const [getconf, ldd1, ldd2] = out.split(/[\r\n]+/);
|
|
437
|
+
if (getconf && getconf.includes(GLIBC)) {
|
|
438
|
+
return versionSuffix(getconf);
|
|
439
|
+
}
|
|
440
|
+
if (ldd1 && ldd2 && ldd1.includes(MUSL)) {
|
|
441
|
+
return versionSuffix(ldd2);
|
|
442
|
+
}
|
|
443
|
+
return null;
|
|
444
|
+
};
|
|
445
|
+
var version = async () => {
|
|
446
|
+
let version2 = null;
|
|
447
|
+
if (isLinux()) {
|
|
448
|
+
version2 = await versionFromFilesystem();
|
|
449
|
+
if (!version2) {
|
|
450
|
+
version2 = versionFromReport();
|
|
451
|
+
}
|
|
452
|
+
if (!version2) {
|
|
453
|
+
const out = await safeCommand();
|
|
454
|
+
version2 = versionFromCommand(out);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
return version2;
|
|
458
|
+
};
|
|
459
|
+
var versionSync = () => {
|
|
460
|
+
let version2 = null;
|
|
461
|
+
if (isLinux()) {
|
|
462
|
+
version2 = versionFromFilesystemSync();
|
|
463
|
+
if (!version2) {
|
|
464
|
+
version2 = versionFromReport();
|
|
465
|
+
}
|
|
466
|
+
if (!version2) {
|
|
467
|
+
const out = safeCommandSync();
|
|
468
|
+
version2 = versionFromCommand(out);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
return version2;
|
|
472
|
+
};
|
|
473
|
+
module.exports = {
|
|
474
|
+
GLIBC,
|
|
475
|
+
MUSL,
|
|
476
|
+
family,
|
|
477
|
+
familySync,
|
|
478
|
+
isNonGlibcLinux,
|
|
479
|
+
isNonGlibcLinuxSync,
|
|
480
|
+
version,
|
|
481
|
+
versionSync
|
|
482
|
+
};
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
// node_modules/libsql/auth.js
|
|
486
|
+
var require_auth = __commonJS((exports, module) => {
|
|
487
|
+
var Authorization = {
|
|
488
|
+
ALLOW: 0,
|
|
489
|
+
DENY: 1
|
|
490
|
+
};
|
|
491
|
+
module.exports = Authorization;
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
// node_modules/libsql/sqlite-error.js
|
|
495
|
+
var require_sqlite_error = __commonJS((exports, module) => {
|
|
496
|
+
var descriptor = { value: "SqliteError", writable: true, enumerable: false, configurable: true };
|
|
497
|
+
function SqliteError(message, code, rawCode) {
|
|
498
|
+
if (new.target !== SqliteError) {
|
|
499
|
+
return new SqliteError(message, code);
|
|
500
|
+
}
|
|
501
|
+
if (typeof code !== "string") {
|
|
502
|
+
throw new TypeError("Expected second argument to be a string");
|
|
503
|
+
}
|
|
504
|
+
Error.call(this, message);
|
|
505
|
+
descriptor.value = "" + message;
|
|
506
|
+
Object.defineProperty(this, "message", descriptor);
|
|
507
|
+
Error.captureStackTrace(this, SqliteError);
|
|
508
|
+
this.code = code;
|
|
509
|
+
this.rawCode = rawCode;
|
|
510
|
+
}
|
|
511
|
+
Object.setPrototypeOf(SqliteError, Error);
|
|
512
|
+
Object.setPrototypeOf(SqliteError.prototype, Error.prototype);
|
|
513
|
+
Object.defineProperty(SqliteError.prototype, "name", descriptor);
|
|
514
|
+
module.exports = SqliteError;
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
// node_modules/libsql/index.js
|
|
518
|
+
var require_libsql = __commonJS((exports, module) => {
|
|
519
|
+
var __dirname = "/home/runner/work/meridian/meridian/node_modules/libsql";
|
|
520
|
+
var { load, currentTarget } = require_dist();
|
|
521
|
+
var { familySync, GLIBC, MUSL } = require_detect_libc();
|
|
522
|
+
function requireNative() {
|
|
523
|
+
if (process.env.LIBSQL_JS_DEV) {
|
|
524
|
+
return load(__dirname);
|
|
525
|
+
}
|
|
526
|
+
let target = currentTarget();
|
|
527
|
+
if (familySync() == GLIBC) {
|
|
528
|
+
switch (target) {
|
|
529
|
+
case "linux-x64-musl":
|
|
530
|
+
target = "linux-x64-gnu";
|
|
531
|
+
break;
|
|
532
|
+
case "linux-arm64-musl":
|
|
533
|
+
target = "linux-arm64-gnu";
|
|
534
|
+
break;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (target === "linux-arm-gnueabihf" && familySync() == MUSL) {
|
|
538
|
+
target = "linux-arm-musleabihf";
|
|
539
|
+
}
|
|
540
|
+
return __require(`@libsql/${target}`);
|
|
541
|
+
}
|
|
542
|
+
var {
|
|
543
|
+
databaseOpen,
|
|
544
|
+
databaseOpenWithSync,
|
|
545
|
+
databaseInTransaction,
|
|
546
|
+
databaseInterrupt,
|
|
547
|
+
databaseClose,
|
|
548
|
+
databaseSyncSync,
|
|
549
|
+
databaseSyncUntilSync,
|
|
550
|
+
databaseExecSync,
|
|
551
|
+
databasePrepareSync,
|
|
552
|
+
databaseDefaultSafeIntegers,
|
|
553
|
+
databaseAuthorizer,
|
|
554
|
+
databaseLoadExtension,
|
|
555
|
+
databaseMaxWriteReplicationIndex,
|
|
556
|
+
statementRaw,
|
|
557
|
+
statementIsReader,
|
|
558
|
+
statementGet,
|
|
559
|
+
statementRun,
|
|
560
|
+
statementInterrupt,
|
|
561
|
+
statementRowsSync,
|
|
562
|
+
statementColumns,
|
|
563
|
+
statementSafeIntegers,
|
|
564
|
+
rowsNext
|
|
565
|
+
} = requireNative();
|
|
566
|
+
var Authorization = require_auth();
|
|
567
|
+
var SqliteError = require_sqlite_error();
|
|
568
|
+
function convertError(err) {
|
|
569
|
+
if (err.libsqlError) {
|
|
570
|
+
return new SqliteError(err.message, err.code, err.rawCode);
|
|
571
|
+
}
|
|
572
|
+
return err;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
class Database {
|
|
576
|
+
constructor(path, opts) {
|
|
577
|
+
const encryptionCipher = opts?.encryptionCipher ?? "aes256cbc";
|
|
578
|
+
if (opts && opts.syncUrl) {
|
|
579
|
+
var authToken = "";
|
|
580
|
+
if (opts.syncAuth) {
|
|
581
|
+
console.warn("Warning: The `syncAuth` option is deprecated, please use `authToken` option instead.");
|
|
582
|
+
authToken = opts.syncAuth;
|
|
583
|
+
} else if (opts.authToken) {
|
|
584
|
+
authToken = opts.authToken;
|
|
585
|
+
}
|
|
586
|
+
const encryptionKey = opts?.encryptionKey ?? "";
|
|
587
|
+
const syncPeriod = opts?.syncPeriod ?? 0;
|
|
588
|
+
const readYourWrites = opts?.readYourWrites ?? true;
|
|
589
|
+
const offline = opts?.offline ?? false;
|
|
590
|
+
const remoteEncryptionKey = opts?.remoteEncryptionKey ?? "";
|
|
591
|
+
this.db = databaseOpenWithSync(path, opts.syncUrl, authToken, encryptionCipher, encryptionKey, syncPeriod, readYourWrites, offline, remoteEncryptionKey);
|
|
592
|
+
} else {
|
|
593
|
+
const authToken2 = opts?.authToken ?? "";
|
|
594
|
+
const encryptionKey = opts?.encryptionKey ?? "";
|
|
595
|
+
const timeout = opts?.timeout ?? 0;
|
|
596
|
+
const remoteEncryptionKey = opts?.remoteEncryptionKey ?? "";
|
|
597
|
+
this.db = databaseOpen(path, authToken2, encryptionCipher, encryptionKey, timeout, remoteEncryptionKey);
|
|
598
|
+
}
|
|
599
|
+
this.memory = path === ":memory:";
|
|
600
|
+
this.readonly = false;
|
|
601
|
+
this.name = "";
|
|
602
|
+
this.open = true;
|
|
603
|
+
const db = this.db;
|
|
604
|
+
Object.defineProperties(this, {
|
|
605
|
+
inTransaction: {
|
|
606
|
+
get() {
|
|
607
|
+
return databaseInTransaction(db);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
sync() {
|
|
613
|
+
return databaseSyncSync.call(this.db);
|
|
614
|
+
}
|
|
615
|
+
syncUntil(replicationIndex) {
|
|
616
|
+
return databaseSyncUntilSync.call(this.db, replicationIndex);
|
|
617
|
+
}
|
|
618
|
+
prepare(sql) {
|
|
619
|
+
try {
|
|
620
|
+
const stmt = databasePrepareSync.call(this.db, sql);
|
|
621
|
+
return new Statement(stmt);
|
|
622
|
+
} catch (err) {
|
|
623
|
+
throw convertError(err);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
transaction(fn) {
|
|
627
|
+
if (typeof fn !== "function")
|
|
628
|
+
throw new TypeError("Expected first argument to be a function");
|
|
629
|
+
const db = this;
|
|
630
|
+
const wrapTxn = (mode) => {
|
|
631
|
+
return (...bindParameters) => {
|
|
632
|
+
db.exec("BEGIN " + mode);
|
|
633
|
+
try {
|
|
634
|
+
const result = fn(...bindParameters);
|
|
635
|
+
db.exec("COMMIT");
|
|
636
|
+
return result;
|
|
637
|
+
} catch (err) {
|
|
638
|
+
db.exec("ROLLBACK");
|
|
639
|
+
throw err;
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
};
|
|
643
|
+
const properties = {
|
|
644
|
+
default: { value: wrapTxn("") },
|
|
645
|
+
deferred: { value: wrapTxn("DEFERRED") },
|
|
646
|
+
immediate: { value: wrapTxn("IMMEDIATE") },
|
|
647
|
+
exclusive: { value: wrapTxn("EXCLUSIVE") },
|
|
648
|
+
database: { value: this, enumerable: true }
|
|
649
|
+
};
|
|
650
|
+
Object.defineProperties(properties.default.value, properties);
|
|
651
|
+
Object.defineProperties(properties.deferred.value, properties);
|
|
652
|
+
Object.defineProperties(properties.immediate.value, properties);
|
|
653
|
+
Object.defineProperties(properties.exclusive.value, properties);
|
|
654
|
+
return properties.default.value;
|
|
655
|
+
}
|
|
656
|
+
pragma(source, options) {
|
|
657
|
+
if (options == null)
|
|
658
|
+
options = {};
|
|
659
|
+
if (typeof source !== "string")
|
|
660
|
+
throw new TypeError("Expected first argument to be a string");
|
|
661
|
+
if (typeof options !== "object")
|
|
662
|
+
throw new TypeError("Expected second argument to be an options object");
|
|
663
|
+
const simple = options["simple"];
|
|
664
|
+
const stmt = this.prepare(`PRAGMA ${source}`, this, true);
|
|
665
|
+
return simple ? stmt.pluck().get() : stmt.all();
|
|
666
|
+
}
|
|
667
|
+
backup(filename, options) {
|
|
668
|
+
throw new Error("not implemented");
|
|
669
|
+
}
|
|
670
|
+
serialize(options) {
|
|
671
|
+
throw new Error("not implemented");
|
|
672
|
+
}
|
|
673
|
+
function(name, options, fn) {
|
|
674
|
+
if (options == null)
|
|
675
|
+
options = {};
|
|
676
|
+
if (typeof options === "function") {
|
|
677
|
+
fn = options;
|
|
678
|
+
options = {};
|
|
679
|
+
}
|
|
680
|
+
if (typeof name !== "string")
|
|
681
|
+
throw new TypeError("Expected first argument to be a string");
|
|
682
|
+
if (typeof fn !== "function")
|
|
683
|
+
throw new TypeError("Expected last argument to be a function");
|
|
684
|
+
if (typeof options !== "object")
|
|
685
|
+
throw new TypeError("Expected second argument to be an options object");
|
|
686
|
+
if (!name)
|
|
687
|
+
throw new TypeError("User-defined function name cannot be an empty string");
|
|
688
|
+
throw new Error("not implemented");
|
|
689
|
+
}
|
|
690
|
+
aggregate(name, options) {
|
|
691
|
+
if (typeof name !== "string")
|
|
692
|
+
throw new TypeError("Expected first argument to be a string");
|
|
693
|
+
if (typeof options !== "object" || options === null)
|
|
694
|
+
throw new TypeError("Expected second argument to be an options object");
|
|
695
|
+
if (!name)
|
|
696
|
+
throw new TypeError("User-defined function name cannot be an empty string");
|
|
697
|
+
throw new Error("not implemented");
|
|
698
|
+
}
|
|
699
|
+
table(name, factory) {
|
|
700
|
+
if (typeof name !== "string")
|
|
701
|
+
throw new TypeError("Expected first argument to be a string");
|
|
702
|
+
if (!name)
|
|
703
|
+
throw new TypeError("Virtual table module name cannot be an empty string");
|
|
704
|
+
throw new Error("not implemented");
|
|
705
|
+
}
|
|
706
|
+
authorizer(rules) {
|
|
707
|
+
databaseAuthorizer.call(this.db, rules);
|
|
708
|
+
}
|
|
709
|
+
loadExtension(...args) {
|
|
710
|
+
databaseLoadExtension.call(this.db, ...args);
|
|
711
|
+
}
|
|
712
|
+
maxWriteReplicationIndex() {
|
|
713
|
+
return databaseMaxWriteReplicationIndex.call(this.db);
|
|
714
|
+
}
|
|
715
|
+
exec(sql) {
|
|
716
|
+
try {
|
|
717
|
+
databaseExecSync.call(this.db, sql);
|
|
718
|
+
} catch (err) {
|
|
719
|
+
throw convertError(err);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
interrupt() {
|
|
723
|
+
databaseInterrupt.call(this.db);
|
|
724
|
+
}
|
|
725
|
+
close() {
|
|
726
|
+
databaseClose.call(this.db);
|
|
727
|
+
this.open = false;
|
|
728
|
+
}
|
|
729
|
+
defaultSafeIntegers(toggle) {
|
|
730
|
+
databaseDefaultSafeIntegers.call(this.db, toggle ?? true);
|
|
731
|
+
return this;
|
|
732
|
+
}
|
|
733
|
+
unsafeMode(...args) {
|
|
734
|
+
throw new Error("not implemented");
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
class Statement {
|
|
739
|
+
constructor(stmt) {
|
|
740
|
+
this.stmt = stmt;
|
|
741
|
+
this.pluckMode = false;
|
|
742
|
+
}
|
|
743
|
+
raw(raw2) {
|
|
744
|
+
statementRaw.call(this.stmt, raw2 ?? true);
|
|
745
|
+
return this;
|
|
746
|
+
}
|
|
747
|
+
pluck(pluckMode) {
|
|
748
|
+
this.pluckMode = pluckMode ?? true;
|
|
749
|
+
return this;
|
|
750
|
+
}
|
|
751
|
+
get reader() {
|
|
752
|
+
return statementIsReader.call(this.stmt);
|
|
753
|
+
}
|
|
754
|
+
run(...bindParameters) {
|
|
755
|
+
try {
|
|
756
|
+
if (bindParameters.length == 1 && typeof bindParameters[0] === "object") {
|
|
757
|
+
return statementRun.call(this.stmt, bindParameters[0]);
|
|
758
|
+
} else {
|
|
759
|
+
return statementRun.call(this.stmt, bindParameters.flat());
|
|
760
|
+
}
|
|
761
|
+
} catch (err) {
|
|
762
|
+
throw convertError(err);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
get(...bindParameters) {
|
|
766
|
+
try {
|
|
767
|
+
if (bindParameters.length == 1 && typeof bindParameters[0] === "object") {
|
|
768
|
+
return statementGet.call(this.stmt, bindParameters[0]);
|
|
769
|
+
} else {
|
|
770
|
+
return statementGet.call(this.stmt, bindParameters.flat());
|
|
771
|
+
}
|
|
772
|
+
} catch (err) {
|
|
773
|
+
throw convertError(err);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
iterate(...bindParameters) {
|
|
777
|
+
var rows = undefined;
|
|
778
|
+
if (bindParameters.length == 1 && typeof bindParameters[0] === "object") {
|
|
779
|
+
rows = statementRowsSync.call(this.stmt, bindParameters[0]);
|
|
780
|
+
} else {
|
|
781
|
+
rows = statementRowsSync.call(this.stmt, bindParameters.flat());
|
|
782
|
+
}
|
|
783
|
+
const iter = {
|
|
784
|
+
nextRows: Array(100),
|
|
785
|
+
nextRowIndex: 100,
|
|
786
|
+
next() {
|
|
787
|
+
try {
|
|
788
|
+
if (this.nextRowIndex === 100) {
|
|
789
|
+
rowsNext.call(rows, this.nextRows);
|
|
790
|
+
this.nextRowIndex = 0;
|
|
791
|
+
}
|
|
792
|
+
const row = this.nextRows[this.nextRowIndex];
|
|
793
|
+
this.nextRows[this.nextRowIndex] = undefined;
|
|
794
|
+
if (!row) {
|
|
795
|
+
return { done: true };
|
|
796
|
+
}
|
|
797
|
+
this.nextRowIndex++;
|
|
798
|
+
return { value: row, done: false };
|
|
799
|
+
} catch (err) {
|
|
800
|
+
throw convertError(err);
|
|
801
|
+
}
|
|
802
|
+
},
|
|
803
|
+
[Symbol.iterator]() {
|
|
804
|
+
return this;
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
return iter;
|
|
808
|
+
}
|
|
809
|
+
all(...bindParameters) {
|
|
810
|
+
try {
|
|
811
|
+
const result = [];
|
|
812
|
+
for (const row of this.iterate(...bindParameters)) {
|
|
813
|
+
if (this.pluckMode) {
|
|
814
|
+
result.push(row[Object.keys(row)[0]]);
|
|
815
|
+
} else {
|
|
816
|
+
result.push(row);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
return result;
|
|
820
|
+
} catch (err) {
|
|
821
|
+
throw convertError(err);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
interrupt() {
|
|
825
|
+
statementInterrupt.call(this.stmt);
|
|
826
|
+
}
|
|
827
|
+
columns() {
|
|
828
|
+
return statementColumns.call(this.stmt);
|
|
829
|
+
}
|
|
830
|
+
safeIntegers(toggle) {
|
|
831
|
+
statementSafeIntegers.call(this.stmt, toggle ?? true);
|
|
832
|
+
return this;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
module.exports = Database;
|
|
836
|
+
module.exports.Authorization = Authorization;
|
|
837
|
+
module.exports.SqliteError = SqliteError;
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
// src/telemetry/sqlite.ts
|
|
841
|
+
var exports_sqlite = {};
|
|
842
|
+
__export(exports_sqlite, {
|
|
843
|
+
createSqliteStores: () => createSqliteStores
|
|
844
|
+
});
|
|
845
|
+
function openDatabase(dbPath) {
|
|
846
|
+
const db = new import_libsql.default(dbPath);
|
|
847
|
+
db.pragma("journal_mode = WAL");
|
|
848
|
+
db.pragma("synchronous = NORMAL");
|
|
849
|
+
db.exec(METRICS_SCHEMA);
|
|
850
|
+
db.exec(LOGS_SCHEMA);
|
|
851
|
+
return db;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
class SqliteTelemetryStore {
|
|
855
|
+
db;
|
|
856
|
+
retentionMs;
|
|
857
|
+
insertCount = 0;
|
|
858
|
+
insertStmt;
|
|
859
|
+
countStmt;
|
|
860
|
+
constructor(db, retentionDays) {
|
|
861
|
+
this.db = db;
|
|
862
|
+
this.retentionMs = retentionDays * 24 * 60 * 60 * 1000;
|
|
863
|
+
this.insertStmt = db.prepare(`
|
|
864
|
+
INSERT INTO metrics (
|
|
865
|
+
request_id, timestamp, adapter, model, request_model, mode,
|
|
866
|
+
is_resume, is_passthrough, lineage_type,
|
|
867
|
+
has_deferred_tools, deferred_tool_count, tool_count, discovered_tools, session_discovered_count,
|
|
868
|
+
message_count, sdk_session_id,
|
|
869
|
+
status, queue_wait_ms, proxy_overhead_ms, ttfb_ms,
|
|
870
|
+
upstream_duration_ms, total_duration_ms, content_blocks, text_events, error,
|
|
871
|
+
input_tokens, output_tokens, cache_read_input_tokens,
|
|
872
|
+
cache_creation_input_tokens, cache_hit_rate
|
|
873
|
+
) VALUES (
|
|
874
|
+
@requestId, @timestamp, @adapter, @model, @requestModel, @mode,
|
|
875
|
+
@isResume, @isPassthrough, @lineageType,
|
|
876
|
+
@hasDeferredTools, @deferredToolCount, @toolCount, @discoveredTools, @sessionDiscoveredCount,
|
|
877
|
+
@messageCount, @sdkSessionId,
|
|
878
|
+
@status, @queueWaitMs, @proxyOverheadMs, @ttfbMs,
|
|
879
|
+
@upstreamDurationMs, @totalDurationMs, @contentBlocks, @textEvents, @error,
|
|
880
|
+
@inputTokens, @outputTokens, @cacheReadInputTokens,
|
|
881
|
+
@cacheCreationInputTokens, @cacheHitRate
|
|
882
|
+
)
|
|
883
|
+
`);
|
|
884
|
+
this.countStmt = db.prepare("SELECT COUNT(*) as cnt FROM metrics");
|
|
885
|
+
}
|
|
886
|
+
record(metric) {
|
|
887
|
+
try {
|
|
888
|
+
this.insertStmt.run({
|
|
889
|
+
requestId: metric.requestId,
|
|
890
|
+
timestamp: metric.timestamp,
|
|
891
|
+
adapter: metric.adapter ?? null,
|
|
892
|
+
model: metric.model,
|
|
893
|
+
requestModel: metric.requestModel ?? null,
|
|
894
|
+
mode: metric.mode,
|
|
895
|
+
isResume: metric.isResume ? 1 : 0,
|
|
896
|
+
isPassthrough: metric.isPassthrough ? 1 : 0,
|
|
897
|
+
lineageType: metric.lineageType ?? null,
|
|
898
|
+
hasDeferredTools: metric.hasDeferredTools ? 1 : metric.hasDeferredTools === false ? 0 : null,
|
|
899
|
+
deferredToolCount: metric.deferredToolCount ?? null,
|
|
900
|
+
toolCount: metric.toolCount ?? null,
|
|
901
|
+
discoveredTools: metric.discoveredTools ? JSON.stringify(metric.discoveredTools) : null,
|
|
902
|
+
sessionDiscoveredCount: metric.sessionDiscoveredCount ?? null,
|
|
903
|
+
messageCount: metric.messageCount ?? null,
|
|
904
|
+
sdkSessionId: metric.sdkSessionId ?? null,
|
|
905
|
+
status: metric.status,
|
|
906
|
+
queueWaitMs: metric.queueWaitMs,
|
|
907
|
+
proxyOverheadMs: metric.proxyOverheadMs,
|
|
908
|
+
ttfbMs: metric.ttfbMs ?? null,
|
|
909
|
+
upstreamDurationMs: metric.upstreamDurationMs,
|
|
910
|
+
totalDurationMs: metric.totalDurationMs,
|
|
911
|
+
contentBlocks: metric.contentBlocks,
|
|
912
|
+
textEvents: metric.textEvents,
|
|
913
|
+
error: metric.error ?? null,
|
|
914
|
+
inputTokens: metric.inputTokens ?? null,
|
|
915
|
+
outputTokens: metric.outputTokens ?? null,
|
|
916
|
+
cacheReadInputTokens: metric.cacheReadInputTokens ?? null,
|
|
917
|
+
cacheCreationInputTokens: metric.cacheCreationInputTokens ?? null,
|
|
918
|
+
cacheHitRate: metric.cacheHitRate ?? null
|
|
919
|
+
});
|
|
920
|
+
} catch (err) {
|
|
921
|
+
console.error("[telemetry] SQLite write failed, skipping:", err);
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
if (++this.insertCount % CLEANUP_INTERVAL === 0) {
|
|
925
|
+
this.cleanup();
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
get size() {
|
|
929
|
+
try {
|
|
930
|
+
return this.countStmt.get().cnt;
|
|
931
|
+
} catch {
|
|
932
|
+
return 0;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
getRecent(options = {}) {
|
|
936
|
+
const { limit = 50, since, model } = options;
|
|
937
|
+
const conditions = [];
|
|
938
|
+
const params = { limit };
|
|
939
|
+
if (since !== undefined) {
|
|
940
|
+
conditions.push("timestamp >= @since");
|
|
941
|
+
params.since = since;
|
|
942
|
+
}
|
|
943
|
+
if (model !== undefined) {
|
|
944
|
+
conditions.push("model = @model");
|
|
945
|
+
params.model = model;
|
|
946
|
+
}
|
|
947
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
948
|
+
const sql = `SELECT * FROM metrics ${where} ORDER BY timestamp DESC, id DESC LIMIT @limit`;
|
|
949
|
+
try {
|
|
950
|
+
const rows = this.db.prepare(sql).all(params);
|
|
951
|
+
return rows.map(rowToMetric);
|
|
952
|
+
} catch {
|
|
953
|
+
return [];
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
getLastForSession(sdkSessionId) {
|
|
957
|
+
try {
|
|
958
|
+
const row = this.db.prepare(`SELECT * FROM metrics WHERE sdk_session_id = ? AND error IS NULL ORDER BY timestamp DESC, id DESC LIMIT 1`).get(sdkSessionId);
|
|
959
|
+
return row ? rowToMetric(row) : undefined;
|
|
960
|
+
} catch {
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
summarize(windowMs = 60 * 60 * 1000) {
|
|
965
|
+
const since = Date.now() - windowMs;
|
|
966
|
+
const metrics = this.getRecent({ limit: 1e5, since });
|
|
967
|
+
return computeSummary(metrics, windowMs);
|
|
968
|
+
}
|
|
969
|
+
clear() {
|
|
970
|
+
try {
|
|
971
|
+
this.db.exec("DELETE FROM metrics");
|
|
972
|
+
} catch {}
|
|
973
|
+
}
|
|
974
|
+
cleanup() {
|
|
975
|
+
try {
|
|
976
|
+
const cutoff = Date.now() - this.retentionMs;
|
|
977
|
+
this.db.prepare("DELETE FROM metrics WHERE timestamp < ?").run(cutoff);
|
|
978
|
+
this.db.prepare("DELETE FROM diagnostic_logs WHERE timestamp < ?").run(cutoff);
|
|
979
|
+
this.db.pragma("wal_checkpoint(TRUNCATE)");
|
|
980
|
+
} catch (err) {
|
|
981
|
+
console.error("[telemetry] SQLite cleanup failed:", err);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
class SqliteDiagnosticLogStore {
|
|
987
|
+
db;
|
|
988
|
+
insertStmt;
|
|
989
|
+
constructor(db) {
|
|
990
|
+
this.db = db;
|
|
991
|
+
this.insertStmt = db.prepare(`
|
|
992
|
+
INSERT INTO diagnostic_logs (timestamp, level, category, request_id, message)
|
|
993
|
+
VALUES (@timestamp, @level, @category, @requestId, @message)
|
|
994
|
+
`);
|
|
995
|
+
}
|
|
996
|
+
log(entry) {
|
|
997
|
+
try {
|
|
998
|
+
this.insertStmt.run({
|
|
999
|
+
timestamp: Date.now(),
|
|
1000
|
+
level: entry.level,
|
|
1001
|
+
category: entry.category,
|
|
1002
|
+
requestId: entry.requestId ?? null,
|
|
1003
|
+
message: entry.message
|
|
1004
|
+
});
|
|
1005
|
+
} catch (err) {
|
|
1006
|
+
console.error("[telemetry] SQLite log write failed:", err);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
session(message, requestId) {
|
|
1010
|
+
this.log({ level: "info", category: "session", message, requestId });
|
|
1011
|
+
}
|
|
1012
|
+
lineage(message, requestId) {
|
|
1013
|
+
this.log({ level: "warn", category: "lineage", message, requestId });
|
|
1014
|
+
}
|
|
1015
|
+
error(message, requestId) {
|
|
1016
|
+
this.log({ level: "error", category: "error", message, requestId });
|
|
1017
|
+
}
|
|
1018
|
+
getRecent(options = {}) {
|
|
1019
|
+
const { limit = 100, since, category } = options;
|
|
1020
|
+
const conditions = [];
|
|
1021
|
+
const params = { limit };
|
|
1022
|
+
if (since !== undefined) {
|
|
1023
|
+
conditions.push("timestamp >= @since");
|
|
1024
|
+
params.since = since;
|
|
1025
|
+
}
|
|
1026
|
+
if (category !== undefined) {
|
|
1027
|
+
conditions.push("category = @category");
|
|
1028
|
+
params.category = category;
|
|
1029
|
+
}
|
|
1030
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1031
|
+
const sql = `SELECT * FROM diagnostic_logs ${where} ORDER BY timestamp DESC, id DESC LIMIT @limit`;
|
|
1032
|
+
try {
|
|
1033
|
+
const rows = this.db.prepare(sql).all(params);
|
|
1034
|
+
return rows.map((r) => ({
|
|
1035
|
+
timestamp: r.timestamp,
|
|
1036
|
+
level: r.level,
|
|
1037
|
+
category: r.category,
|
|
1038
|
+
requestId: r.request_id ?? undefined,
|
|
1039
|
+
message: r.message
|
|
1040
|
+
}));
|
|
1041
|
+
} catch {
|
|
1042
|
+
return [];
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
clear() {
|
|
1046
|
+
try {
|
|
1047
|
+
this.db.exec("DELETE FROM diagnostic_logs");
|
|
1048
|
+
} catch {}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
function rowToMetric(r) {
|
|
1052
|
+
return {
|
|
1053
|
+
requestId: r.request_id,
|
|
1054
|
+
timestamp: r.timestamp,
|
|
1055
|
+
adapter: r.adapter ?? undefined,
|
|
1056
|
+
model: r.model,
|
|
1057
|
+
requestModel: r.request_model ?? undefined,
|
|
1058
|
+
mode: r.mode,
|
|
1059
|
+
isResume: r.is_resume === 1,
|
|
1060
|
+
isPassthrough: r.is_passthrough === 1,
|
|
1061
|
+
lineageType: r.lineage_type ?? undefined,
|
|
1062
|
+
hasDeferredTools: r.has_deferred_tools === 1 ? true : r.has_deferred_tools === 0 ? false : undefined,
|
|
1063
|
+
deferredToolCount: r.deferred_tool_count ?? undefined,
|
|
1064
|
+
toolCount: r.tool_count ?? undefined,
|
|
1065
|
+
discoveredTools: r.discovered_tools ? JSON.parse(r.discovered_tools) : undefined,
|
|
1066
|
+
sessionDiscoveredCount: r.session_discovered_count ?? undefined,
|
|
1067
|
+
messageCount: r.message_count ?? undefined,
|
|
1068
|
+
sdkSessionId: r.sdk_session_id ?? undefined,
|
|
1069
|
+
status: r.status,
|
|
1070
|
+
queueWaitMs: r.queue_wait_ms,
|
|
1071
|
+
proxyOverheadMs: r.proxy_overhead_ms,
|
|
1072
|
+
ttfbMs: r.ttfb_ms ?? null,
|
|
1073
|
+
upstreamDurationMs: r.upstream_duration_ms,
|
|
1074
|
+
totalDurationMs: r.total_duration_ms,
|
|
1075
|
+
contentBlocks: r.content_blocks,
|
|
1076
|
+
textEvents: r.text_events,
|
|
1077
|
+
error: r.error ?? null,
|
|
1078
|
+
inputTokens: r.input_tokens ?? undefined,
|
|
1079
|
+
outputTokens: r.output_tokens ?? undefined,
|
|
1080
|
+
cacheReadInputTokens: r.cache_read_input_tokens ?? undefined,
|
|
1081
|
+
cacheCreationInputTokens: r.cache_creation_input_tokens ?? undefined,
|
|
1082
|
+
cacheHitRate: r.cache_hit_rate ?? undefined
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
function createSqliteStores(dbPath, retentionDays) {
|
|
1086
|
+
const db = openDatabase(dbPath);
|
|
1087
|
+
return {
|
|
1088
|
+
telemetry: new SqliteTelemetryStore(db, retentionDays),
|
|
1089
|
+
diagnostics: new SqliteDiagnosticLogStore(db),
|
|
1090
|
+
close: () => {
|
|
1091
|
+
try {
|
|
1092
|
+
db.close();
|
|
1093
|
+
} catch {}
|
|
1094
|
+
}
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
var import_libsql, METRICS_SCHEMA = `
|
|
1098
|
+
CREATE TABLE IF NOT EXISTS metrics (
|
|
1099
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1100
|
+
request_id TEXT NOT NULL,
|
|
1101
|
+
timestamp INTEGER NOT NULL,
|
|
1102
|
+
adapter TEXT,
|
|
1103
|
+
model TEXT NOT NULL,
|
|
1104
|
+
request_model TEXT,
|
|
1105
|
+
mode TEXT NOT NULL,
|
|
1106
|
+
is_resume INTEGER NOT NULL,
|
|
1107
|
+
is_passthrough INTEGER NOT NULL,
|
|
1108
|
+
lineage_type TEXT,
|
|
1109
|
+
has_deferred_tools INTEGER,
|
|
1110
|
+
deferred_tool_count INTEGER,
|
|
1111
|
+
tool_count INTEGER,
|
|
1112
|
+
discovered_tools TEXT,
|
|
1113
|
+
session_discovered_count INTEGER,
|
|
1114
|
+
message_count INTEGER,
|
|
1115
|
+
sdk_session_id TEXT,
|
|
1116
|
+
status INTEGER NOT NULL,
|
|
1117
|
+
queue_wait_ms REAL NOT NULL,
|
|
1118
|
+
proxy_overhead_ms REAL NOT NULL,
|
|
1119
|
+
ttfb_ms REAL,
|
|
1120
|
+
upstream_duration_ms REAL NOT NULL,
|
|
1121
|
+
total_duration_ms REAL NOT NULL,
|
|
1122
|
+
content_blocks INTEGER NOT NULL,
|
|
1123
|
+
text_events INTEGER NOT NULL,
|
|
1124
|
+
error TEXT,
|
|
1125
|
+
input_tokens INTEGER,
|
|
1126
|
+
output_tokens INTEGER,
|
|
1127
|
+
cache_read_input_tokens INTEGER,
|
|
1128
|
+
cache_creation_input_tokens INTEGER,
|
|
1129
|
+
cache_hit_rate REAL
|
|
1130
|
+
);
|
|
1131
|
+
CREATE INDEX IF NOT EXISTS idx_metrics_ts ON metrics(timestamp);
|
|
1132
|
+
CREATE INDEX IF NOT EXISTS idx_metrics_model ON metrics(model);
|
|
1133
|
+
CREATE INDEX IF NOT EXISTS idx_metrics_session_success ON metrics(sdk_session_id, timestamp DESC, id DESC);
|
|
1134
|
+
`, LOGS_SCHEMA = `
|
|
1135
|
+
CREATE TABLE IF NOT EXISTS diagnostic_logs (
|
|
1136
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1137
|
+
timestamp INTEGER NOT NULL,
|
|
1138
|
+
level TEXT NOT NULL,
|
|
1139
|
+
category TEXT NOT NULL,
|
|
1140
|
+
request_id TEXT,
|
|
1141
|
+
message TEXT NOT NULL
|
|
1142
|
+
);
|
|
1143
|
+
CREATE INDEX IF NOT EXISTS idx_logs_ts ON diagnostic_logs(timestamp);
|
|
1144
|
+
CREATE INDEX IF NOT EXISTS idx_logs_cat ON diagnostic_logs(category);
|
|
1145
|
+
`, CLEANUP_INTERVAL = 1000;
|
|
1146
|
+
var init_sqlite = __esm(() => {
|
|
1147
|
+
init_percentiles();
|
|
1148
|
+
import_libsql = __toESM(require_libsql(), 1);
|
|
1149
|
+
});
|
|
26
1150
|
|
|
27
1151
|
// node_modules/hono/dist/compose.js
|
|
28
1152
|
var compose = (middleware, onError, onNotFound) => {
|
|
@@ -2187,7 +3311,8 @@ var DEFAULT_PROXY_CONFIG = {
|
|
|
2187
3311
|
idleTimeoutSeconds: 120,
|
|
2188
3312
|
silent: false,
|
|
2189
3313
|
profiles: undefined,
|
|
2190
|
-
defaultProfile: undefined
|
|
3314
|
+
defaultProfile: undefined,
|
|
3315
|
+
version: undefined
|
|
2191
3316
|
};
|
|
2192
3317
|
|
|
2193
3318
|
// src/env.ts
|
|
@@ -2198,6 +3323,13 @@ function envBool(suffix) {
|
|
|
2198
3323
|
const val = env(suffix);
|
|
2199
3324
|
return val === "1" || val === "true" || val === "yes";
|
|
2200
3325
|
}
|
|
3326
|
+
function envInt(suffix, defaultValue) {
|
|
3327
|
+
const val = env(suffix);
|
|
3328
|
+
if (!val)
|
|
3329
|
+
return defaultValue;
|
|
3330
|
+
const parsed = parseInt(val, 10);
|
|
3331
|
+
return Number.isFinite(parsed) ? parsed : defaultValue;
|
|
3332
|
+
}
|
|
2201
3333
|
|
|
2202
3334
|
// src/proxy/server.ts
|
|
2203
3335
|
import { exec as execCallback2 } from "child_process";
|
|
@@ -6270,7 +7402,12 @@ function stripMcpPrefix(toolName) {
|
|
|
6270
7402
|
return toolName;
|
|
6271
7403
|
}
|
|
6272
7404
|
|
|
7405
|
+
// src/telemetry/index.ts
|
|
7406
|
+
import { join } from "node:path";
|
|
7407
|
+
import { homedir } from "node:os";
|
|
7408
|
+
|
|
6273
7409
|
// src/telemetry/store.ts
|
|
7410
|
+
init_percentiles();
|
|
6274
7411
|
var DEFAULT_CAPACITY = 1000;
|
|
6275
7412
|
function getCapacity() {
|
|
6276
7413
|
const raw2 = process.env.MERIDIAN_TELEMETRY_SIZE ?? process.env.CLAUDE_PROXY_TELEMETRY_SIZE;
|
|
@@ -6282,7 +7419,7 @@ function getCapacity() {
|
|
|
6282
7419
|
return parsed;
|
|
6283
7420
|
}
|
|
6284
7421
|
|
|
6285
|
-
class
|
|
7422
|
+
class MemoryTelemetryStore {
|
|
6286
7423
|
buffer;
|
|
6287
7424
|
head = 0;
|
|
6288
7425
|
count = 0;
|
|
@@ -6329,94 +7466,7 @@ class TelemetryStore {
|
|
|
6329
7466
|
summarize(windowMs = 60 * 60 * 1000) {
|
|
6330
7467
|
const since = Date.now() - windowMs;
|
|
6331
7468
|
const metrics = this.getRecent({ limit: this.capacity, since });
|
|
6332
|
-
|
|
6333
|
-
const emptyPhase = { p50: 0, p95: 0, p99: 0, min: 0, max: 0, avg: 0 };
|
|
6334
|
-
return {
|
|
6335
|
-
windowMs,
|
|
6336
|
-
totalRequests: 0,
|
|
6337
|
-
errorCount: 0,
|
|
6338
|
-
requestsPerMinute: 0,
|
|
6339
|
-
queueWait: emptyPhase,
|
|
6340
|
-
proxyOverhead: emptyPhase,
|
|
6341
|
-
ttfb: emptyPhase,
|
|
6342
|
-
upstreamDuration: emptyPhase,
|
|
6343
|
-
totalDuration: emptyPhase,
|
|
6344
|
-
byModel: {},
|
|
6345
|
-
byMode: {},
|
|
6346
|
-
tokenUsage: {
|
|
6347
|
-
totalInputTokens: 0,
|
|
6348
|
-
totalOutputTokens: 0,
|
|
6349
|
-
totalCacheReadTokens: 0,
|
|
6350
|
-
totalCacheCreationTokens: 0,
|
|
6351
|
-
avgCacheHitRate: 0,
|
|
6352
|
-
cacheMissOnResumeCount: 0
|
|
6353
|
-
}
|
|
6354
|
-
};
|
|
6355
|
-
}
|
|
6356
|
-
const errorCount = metrics.filter((m) => m.error !== null).length;
|
|
6357
|
-
const oldest = metrics[metrics.length - 1].timestamp;
|
|
6358
|
-
const newest = metrics[0].timestamp;
|
|
6359
|
-
const spanMs = Math.max(newest - oldest, 1);
|
|
6360
|
-
const requestsPerMinute = metrics.length / spanMs * 60000;
|
|
6361
|
-
const queueWaits = metrics.map((m) => m.queueWaitMs);
|
|
6362
|
-
const overheads = metrics.map((m) => m.proxyOverheadMs);
|
|
6363
|
-
const ttfbs = metrics.filter((m) => m.ttfbMs !== null).map((m) => m.ttfbMs);
|
|
6364
|
-
const upstreams = metrics.map((m) => m.upstreamDurationMs);
|
|
6365
|
-
const totals = metrics.map((m) => m.totalDurationMs);
|
|
6366
|
-
const byModel = {};
|
|
6367
|
-
for (const m of metrics) {
|
|
6368
|
-
const modelKey = m.requestModel || m.model;
|
|
6369
|
-
const entry = byModel[modelKey] ??= { count: 0, totalMs: 0 };
|
|
6370
|
-
entry.count++;
|
|
6371
|
-
entry.totalMs += m.totalDurationMs;
|
|
6372
|
-
}
|
|
6373
|
-
const byMode = {};
|
|
6374
|
-
for (const m of metrics) {
|
|
6375
|
-
const entry = byMode[m.mode] ??= { count: 0, totalMs: 0 };
|
|
6376
|
-
entry.count++;
|
|
6377
|
-
entry.totalMs += m.totalDurationMs;
|
|
6378
|
-
}
|
|
6379
|
-
let totalInputTokens = 0;
|
|
6380
|
-
let totalOutputTokens = 0;
|
|
6381
|
-
let totalCacheReadTokens = 0;
|
|
6382
|
-
let totalCacheCreationTokens = 0;
|
|
6383
|
-
let cacheHitRateSum = 0;
|
|
6384
|
-
let cacheHitRateCount = 0;
|
|
6385
|
-
let cacheMissOnResumeCount = 0;
|
|
6386
|
-
for (const m of metrics) {
|
|
6387
|
-
totalInputTokens += m.inputTokens ?? 0;
|
|
6388
|
-
totalOutputTokens += m.outputTokens ?? 0;
|
|
6389
|
-
totalCacheReadTokens += m.cacheReadInputTokens ?? 0;
|
|
6390
|
-
totalCacheCreationTokens += m.cacheCreationInputTokens ?? 0;
|
|
6391
|
-
if (m.cacheHitRate !== undefined) {
|
|
6392
|
-
cacheHitRateSum += m.cacheHitRate;
|
|
6393
|
-
cacheHitRateCount++;
|
|
6394
|
-
}
|
|
6395
|
-
if (m.isResume && m.cacheHitRate !== undefined && m.cacheHitRate === 0) {
|
|
6396
|
-
cacheMissOnResumeCount++;
|
|
6397
|
-
}
|
|
6398
|
-
}
|
|
6399
|
-
return {
|
|
6400
|
-
windowMs,
|
|
6401
|
-
totalRequests: metrics.length,
|
|
6402
|
-
errorCount,
|
|
6403
|
-
requestsPerMinute: Math.round(requestsPerMinute * 100) / 100,
|
|
6404
|
-
queueWait: computePercentiles(queueWaits),
|
|
6405
|
-
proxyOverhead: computePercentiles(overheads),
|
|
6406
|
-
ttfb: ttfbs.length > 0 ? computePercentiles(ttfbs) : { p50: 0, p95: 0, p99: 0, min: 0, max: 0, avg: 0 },
|
|
6407
|
-
upstreamDuration: computePercentiles(upstreams),
|
|
6408
|
-
totalDuration: computePercentiles(totals),
|
|
6409
|
-
byModel: Object.fromEntries(Object.entries(byModel).map(([k, v]) => [k, { count: v.count, avgTotalMs: Math.round(v.totalMs / v.count) }])),
|
|
6410
|
-
byMode: Object.fromEntries(Object.entries(byMode).map(([k, v]) => [k, { count: v.count, avgTotalMs: Math.round(v.totalMs / v.count) }])),
|
|
6411
|
-
tokenUsage: {
|
|
6412
|
-
totalInputTokens,
|
|
6413
|
-
totalOutputTokens,
|
|
6414
|
-
totalCacheReadTokens,
|
|
6415
|
-
totalCacheCreationTokens,
|
|
6416
|
-
avgCacheHitRate: cacheHitRateCount > 0 ? Math.round(cacheHitRateSum / cacheHitRateCount * 100) / 100 : 0,
|
|
6417
|
-
cacheMissOnResumeCount
|
|
6418
|
-
}
|
|
6419
|
-
};
|
|
7469
|
+
return computeSummary(metrics, windowMs);
|
|
6420
7470
|
}
|
|
6421
7471
|
clear() {
|
|
6422
7472
|
this.buffer = new Array(this.capacity).fill(null);
|
|
@@ -6424,25 +7474,12 @@ class TelemetryStore {
|
|
|
6424
7474
|
this.count = 0;
|
|
6425
7475
|
}
|
|
6426
7476
|
}
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
return { p50: 0, p95: 0, p99: 0, min: 0, max: 0, avg: 0 };
|
|
6430
|
-
const sorted = [...values].sort((a, b) => a - b);
|
|
6431
|
-
const sum = sorted.reduce((a, b) => a + b, 0);
|
|
6432
|
-
return {
|
|
6433
|
-
p50: sorted[Math.floor(sorted.length * 0.5)],
|
|
6434
|
-
p95: sorted[Math.floor(sorted.length * 0.95)],
|
|
6435
|
-
p99: sorted[Math.floor(sorted.length * 0.99)],
|
|
6436
|
-
min: sorted[0],
|
|
6437
|
-
max: sorted[sorted.length - 1],
|
|
6438
|
-
avg: Math.round(sum / sorted.length)
|
|
6439
|
-
};
|
|
6440
|
-
}
|
|
6441
|
-
var telemetryStore = new TelemetryStore;
|
|
7477
|
+
var telemetryStore = new MemoryTelemetryStore;
|
|
7478
|
+
|
|
6442
7479
|
// src/telemetry/logStore.ts
|
|
6443
7480
|
var DEFAULT_CAPACITY2 = 500;
|
|
6444
7481
|
|
|
6445
|
-
class
|
|
7482
|
+
class MemoryDiagnosticLogStore {
|
|
6446
7483
|
buffer;
|
|
6447
7484
|
head = 0;
|
|
6448
7485
|
count = 0;
|
|
@@ -6488,7 +7525,7 @@ class DiagnosticLogStore {
|
|
|
6488
7525
|
this.count = 0;
|
|
6489
7526
|
}
|
|
6490
7527
|
}
|
|
6491
|
-
var diagnosticLog = new
|
|
7528
|
+
var diagnosticLog = new MemoryDiagnosticLogStore;
|
|
6492
7529
|
// src/telemetry/routes.ts
|
|
6493
7530
|
import { existsSync, readFileSync } from "node:fs";
|
|
6494
7531
|
import { resolve, dirname } from "node:path";
|
|
@@ -6866,7 +7903,7 @@ function createTelemetryRoutes() {
|
|
|
6866
7903
|
const limit = Number.parseInt(c.req.query("limit") || "50", 10);
|
|
6867
7904
|
const since = c.req.query("since") ? Number.parseInt(c.req.query("since"), 10) : undefined;
|
|
6868
7905
|
const model = c.req.query("model") || undefined;
|
|
6869
|
-
const requests =
|
|
7906
|
+
const requests = telemetryStore2.getRecent({
|
|
6870
7907
|
limit: Math.min(limit, 500),
|
|
6871
7908
|
since,
|
|
6872
7909
|
model
|
|
@@ -6875,14 +7912,14 @@ function createTelemetryRoutes() {
|
|
|
6875
7912
|
});
|
|
6876
7913
|
routes.get("/summary", (c) => {
|
|
6877
7914
|
const windowMs = Number.parseInt(c.req.query("window") || "3600000", 10);
|
|
6878
|
-
const summary =
|
|
7915
|
+
const summary = telemetryStore2.summarize(windowMs);
|
|
6879
7916
|
return c.json(summary);
|
|
6880
7917
|
});
|
|
6881
7918
|
routes.get("/logs", (c) => {
|
|
6882
7919
|
const limit = Number.parseInt(c.req.query("limit") || "100", 10);
|
|
6883
7920
|
const since = c.req.query("since") ? Number.parseInt(c.req.query("since"), 10) : undefined;
|
|
6884
7921
|
const category = c.req.query("category") || undefined;
|
|
6885
|
-
const logs =
|
|
7922
|
+
const logs = diagnosticLog2.getRecent({
|
|
6886
7923
|
limit: Math.min(limit, 500),
|
|
6887
7924
|
since,
|
|
6888
7925
|
category
|
|
@@ -7014,6 +8051,95 @@ refresh();setInterval(refresh,10000);
|
|
|
7014
8051
|
</script>
|
|
7015
8052
|
</body>
|
|
7016
8053
|
</html>`;
|
|
8054
|
+
|
|
8055
|
+
// src/telemetry/index.ts
|
|
8056
|
+
init_percentiles();
|
|
8057
|
+
|
|
8058
|
+
// src/telemetry/prometheus.ts
|
|
8059
|
+
var DURATION_BUCKETS = [10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 1e4, 30000];
|
|
8060
|
+
var PHASES = [
|
|
8061
|
+
{ key: "queue_wait", extract: (m) => m.queueWaitMs },
|
|
8062
|
+
{ key: "proxy_overhead", extract: (m) => m.proxyOverheadMs },
|
|
8063
|
+
{ key: "ttfb", extract: (m) => m.ttfbMs },
|
|
8064
|
+
{ key: "upstream", extract: (m) => m.upstreamDurationMs },
|
|
8065
|
+
{ key: "total", extract: (m) => m.totalDurationMs }
|
|
8066
|
+
];
|
|
8067
|
+
function escapeLabelValue(v) {
|
|
8068
|
+
return v.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n");
|
|
8069
|
+
}
|
|
8070
|
+
function formatLabels(labels) {
|
|
8071
|
+
return Object.entries(labels).map(([k, v]) => `${k}="${escapeLabelValue(v)}"`).join(",");
|
|
8072
|
+
}
|
|
8073
|
+
function renderPrometheusMetrics(store) {
|
|
8074
|
+
const metrics = store.getRecent({ limit: 1e4 });
|
|
8075
|
+
const lines = [];
|
|
8076
|
+
lines.push("# HELP meridian_requests_total Total proxy requests");
|
|
8077
|
+
lines.push("# TYPE meridian_requests_total counter");
|
|
8078
|
+
const counters = new Map;
|
|
8079
|
+
for (const m of metrics) {
|
|
8080
|
+
const key = `${m.model}\x00${m.mode}\x00${m.status}`;
|
|
8081
|
+
counters.set(key, (counters.get(key) ?? 0) + 1);
|
|
8082
|
+
}
|
|
8083
|
+
for (const [key, count] of counters) {
|
|
8084
|
+
const [model, mode, status] = key.split("\x00");
|
|
8085
|
+
lines.push(`meridian_requests_total{${formatLabels({ model, mode, status })}} ${count}`);
|
|
8086
|
+
}
|
|
8087
|
+
lines.push("");
|
|
8088
|
+
lines.push("# HELP meridian_request_duration_ms Request duration by phase in milliseconds");
|
|
8089
|
+
lines.push("# TYPE meridian_request_duration_ms histogram");
|
|
8090
|
+
for (const phase of PHASES) {
|
|
8091
|
+
const values = [];
|
|
8092
|
+
for (const m of metrics) {
|
|
8093
|
+
const v = phase.extract(m);
|
|
8094
|
+
if (v !== null)
|
|
8095
|
+
values.push(v);
|
|
8096
|
+
}
|
|
8097
|
+
const phaseLabel = `phase="${escapeLabelValue(phase.key)}"`;
|
|
8098
|
+
for (const le of DURATION_BUCKETS) {
|
|
8099
|
+
const count = values.filter((v) => v <= le).length;
|
|
8100
|
+
lines.push(`meridian_request_duration_ms_bucket{${phaseLabel},le="${le}"} ${count}`);
|
|
8101
|
+
}
|
|
8102
|
+
lines.push(`meridian_request_duration_ms_bucket{${phaseLabel},le="+Inf"} ${values.length}`);
|
|
8103
|
+
const sum = values.reduce((a, b) => a + b, 0);
|
|
8104
|
+
lines.push(`meridian_request_duration_ms_sum{${phaseLabel}} ${sum}`);
|
|
8105
|
+
lines.push(`meridian_request_duration_ms_count{${phaseLabel}} ${values.length}`);
|
|
8106
|
+
}
|
|
8107
|
+
lines.push("");
|
|
8108
|
+
return lines.join(`
|
|
8109
|
+
`);
|
|
8110
|
+
}
|
|
8111
|
+
|
|
8112
|
+
// src/telemetry/index.ts
|
|
8113
|
+
init_sqlite();
|
|
8114
|
+
function getDefaultDbPath() {
|
|
8115
|
+
return join(homedir(), ".config", "meridian", "telemetry.db");
|
|
8116
|
+
}
|
|
8117
|
+
function createStores() {
|
|
8118
|
+
if (!envBool("TELEMETRY_PERSIST")) {
|
|
8119
|
+
return {
|
|
8120
|
+
telemetry: new MemoryTelemetryStore,
|
|
8121
|
+
diagnostics: new MemoryDiagnosticLogStore
|
|
8122
|
+
};
|
|
8123
|
+
}
|
|
8124
|
+
try {
|
|
8125
|
+
const { createSqliteStores: createSqliteStores2 } = (init_sqlite(), __toCommonJS(exports_sqlite));
|
|
8126
|
+
const dbPath = env("TELEMETRY_DB") ?? getDefaultDbPath();
|
|
8127
|
+
const retention = envInt("TELEMETRY_RETENTION_DAYS", 7);
|
|
8128
|
+
const stores = createSqliteStores2(dbPath, retention);
|
|
8129
|
+
console.error(`[telemetry] SQLite persistence enabled: ${dbPath} (${retention}d retention)`);
|
|
8130
|
+
return { telemetry: stores.telemetry, diagnostics: stores.diagnostics };
|
|
8131
|
+
} catch {
|
|
8132
|
+
console.warn("[telemetry] MERIDIAN_TELEMETRY_PERSIST is set but libsql is not installed. Run: npm install libsql");
|
|
8133
|
+
return {
|
|
8134
|
+
telemetry: new MemoryTelemetryStore,
|
|
8135
|
+
diagnostics: new MemoryDiagnosticLogStore
|
|
8136
|
+
};
|
|
8137
|
+
}
|
|
8138
|
+
}
|
|
8139
|
+
var stores = createStores();
|
|
8140
|
+
var telemetryStore2 = stores.telemetry;
|
|
8141
|
+
var diagnosticLog2 = stores.diagnostics;
|
|
8142
|
+
|
|
7017
8143
|
// src/proxy/errors.ts
|
|
7018
8144
|
function classifyError(errMsg) {
|
|
7019
8145
|
const lower = errMsg.toLowerCase();
|
|
@@ -7121,7 +8247,7 @@ function isExtraUsageRequiredError(errMsg) {
|
|
|
7121
8247
|
import { exec as execCallback } from "child_process";
|
|
7122
8248
|
import { existsSync as existsSync2 } from "fs";
|
|
7123
8249
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7124
|
-
import { join, dirname as dirname2 } from "path";
|
|
8250
|
+
import { join as join2, dirname as dirname2 } from "path";
|
|
7125
8251
|
import { promisify } from "util";
|
|
7126
8252
|
var exec = promisify(execCallback);
|
|
7127
8253
|
var AUTH_STATUS_CACHE_TTL_MS = 60000;
|
|
@@ -7263,7 +8389,7 @@ async function resolveClaudeExecutableAsync() {
|
|
|
7263
8389
|
if (runningUnderBun) {
|
|
7264
8390
|
try {
|
|
7265
8391
|
const sdkPath = fileURLToPath2(import.meta.resolve("@anthropic-ai/claude-agent-sdk"));
|
|
7266
|
-
const sdkCliJs =
|
|
8392
|
+
const sdkCliJs = join2(dirname2(sdkPath), "cli.js");
|
|
7267
8393
|
if (existsSync2(sdkCliJs)) {
|
|
7268
8394
|
cachedClaudePath = sdkCliJs;
|
|
7269
8395
|
return sdkCliJs;
|
|
@@ -7281,7 +8407,7 @@ async function resolveClaudeExecutableAsync() {
|
|
|
7281
8407
|
if (!runningUnderBun) {
|
|
7282
8408
|
try {
|
|
7283
8409
|
const sdkPath = fileURLToPath2(import.meta.resolve("@anthropic-ai/claude-agent-sdk"));
|
|
7284
|
-
const sdkCliJs =
|
|
8410
|
+
const sdkCliJs = join2(dirname2(sdkPath), "cli.js");
|
|
7285
8411
|
if (existsSync2(sdkCliJs)) {
|
|
7286
8412
|
cachedClaudePath = sdkCliJs;
|
|
7287
8413
|
return sdkCliJs;
|
|
@@ -8109,6 +9235,9 @@ var piAdapter = {
|
|
|
8109
9235
|
buildSdkAgents(_body, _mcpToolNames) {
|
|
8110
9236
|
return {};
|
|
8111
9237
|
},
|
|
9238
|
+
supportsThinking() {
|
|
9239
|
+
return true;
|
|
9240
|
+
},
|
|
8112
9241
|
buildSdkHooks(_body, _sdkAgents) {
|
|
8113
9242
|
return;
|
|
8114
9243
|
},
|
|
@@ -14126,6 +15255,49 @@ function formatUsageSummary(usage) {
|
|
|
14126
15255
|
return `${parts.join(" ")}${cacheTag}`;
|
|
14127
15256
|
}
|
|
14128
15257
|
|
|
15258
|
+
// src/proxy/sanitize.ts
|
|
15259
|
+
var ORCHESTRATION_TAGS = [
|
|
15260
|
+
"system-reminder",
|
|
15261
|
+
"env",
|
|
15262
|
+
"system_information",
|
|
15263
|
+
"current_working_directory",
|
|
15264
|
+
"operating_system",
|
|
15265
|
+
"default_shell",
|
|
15266
|
+
"home_directory",
|
|
15267
|
+
"task_metadata",
|
|
15268
|
+
"tool_exec",
|
|
15269
|
+
"tool_output",
|
|
15270
|
+
"skill_content",
|
|
15271
|
+
"skill_files",
|
|
15272
|
+
"directories",
|
|
15273
|
+
"available_skills",
|
|
15274
|
+
"thinking"
|
|
15275
|
+
];
|
|
15276
|
+
var PAIRED_TAG_PATTERNS = ORCHESTRATION_TAGS.map((tag) => new RegExp(`<${tag}\\b[^>]*>[\\s\\S]*?<\\/${tag}>`, "gi"));
|
|
15277
|
+
var SELF_CLOSING_TAG_PATTERNS = ORCHESTRATION_TAGS.map((tag) => new RegExp(`<${tag}\\b[^>]*\\/>`, "gi"));
|
|
15278
|
+
var NON_XML_PATTERNS = [
|
|
15279
|
+
/<!--\s*OMO_INTERNAL_INITIATOR\s*-->/gi,
|
|
15280
|
+
/\[SYSTEM DIRECTIVE: OH-MY-OPENCODE[^\]]*\]/gi,
|
|
15281
|
+
/⚙\s*background_output\s*\[task_id=[^\]]*\]\n?/g,
|
|
15282
|
+
/\n?---\nFiles changed:[^\n]*(?:\n(?: [-•*] [^\n]*))*\n?/g
|
|
15283
|
+
];
|
|
15284
|
+
var ALL_PATTERNS = [
|
|
15285
|
+
...PAIRED_TAG_PATTERNS,
|
|
15286
|
+
...SELF_CLOSING_TAG_PATTERNS,
|
|
15287
|
+
...NON_XML_PATTERNS
|
|
15288
|
+
];
|
|
15289
|
+
function sanitizeTextContent(text) {
|
|
15290
|
+
let result = text;
|
|
15291
|
+
for (const pattern of ALL_PATTERNS) {
|
|
15292
|
+
pattern.lastIndex = 0;
|
|
15293
|
+
result = result.replace(pattern, "");
|
|
15294
|
+
}
|
|
15295
|
+
result = result.replace(/\n{3,}/g, `
|
|
15296
|
+
|
|
15297
|
+
`);
|
|
15298
|
+
return result.trim();
|
|
15299
|
+
}
|
|
15300
|
+
|
|
14129
15301
|
// src/proxy/session/lineage.ts
|
|
14130
15302
|
import { createHash as createHash2 } from "crypto";
|
|
14131
15303
|
var MIN_SUFFIX_FOR_COMPACTION = 2;
|
|
@@ -14222,7 +15394,7 @@ function verifyLineage(cached, messages, cacheKey2, cache) {
|
|
|
14222
15394
|
if (suffixOverlap >= MIN_SUFFIX_FOR_COMPACTION && cached.messageHashes.length >= MIN_STORED_FOR_COMPACTION && suffixStartInIncoming > 0) {
|
|
14223
15395
|
const compactionMsg = `Compaction detected (key=${cacheKey2.slice(0, 8)}…): suffix overlap ${suffixOverlap}/${cached.messageHashes.length}. Allowing resume.`;
|
|
14224
15396
|
console.error(`[PROXY] ${compactionMsg}`);
|
|
14225
|
-
|
|
15397
|
+
diagnosticLog2.lineage(compactionMsg);
|
|
14226
15398
|
cached.lineageHash = computeLineageHash(messages);
|
|
14227
15399
|
cached.messageHashes = incomingHashes;
|
|
14228
15400
|
cached.messageCount = messages.length;
|
|
@@ -14240,13 +15412,13 @@ function verifyLineage(cached, messages, cacheKey2, cache) {
|
|
|
14240
15412
|
}
|
|
14241
15413
|
const undoMsg = `Undo detected (key=${cacheKey2.slice(0, 8)}…): prefix overlap ${prefixOverlap}/${cached.messageHashes.length}, rollback UUID: ${rollbackUuid || "none (legacy session)"}.`;
|
|
14242
15414
|
console.error(`[PROXY] ${undoMsg}`);
|
|
14243
|
-
|
|
15415
|
+
diagnosticLog2.lineage(undoMsg);
|
|
14244
15416
|
return { type: "undo", session: cached, prefixOverlap, rollbackUuid };
|
|
14245
15417
|
}
|
|
14246
15418
|
if (prefixOverlap > 0 && messages.length > cached.messageCount) {
|
|
14247
15419
|
const modifiedMsg = `Modified continuation (key=${cacheKey2.slice(0, 8)}…): prefix overlap ${prefixOverlap}/${cached.messageHashes.length}, incoming ${messages.length} msgs. Allowing resume.`;
|
|
14248
15420
|
console.error(`[PROXY] ${modifiedMsg}`);
|
|
14249
|
-
|
|
15421
|
+
diagnosticLog2.lineage(modifiedMsg);
|
|
14250
15422
|
cached.lineageHash = computeLineageHash(messages.slice(0, messages.length));
|
|
14251
15423
|
cached.messageHashes = incomingHashes;
|
|
14252
15424
|
cached.messageCount = messages.length;
|
|
@@ -14333,8 +15505,8 @@ import {
|
|
|
14333
15505
|
unlinkSync,
|
|
14334
15506
|
writeFileSync
|
|
14335
15507
|
} from "node:fs";
|
|
14336
|
-
import { homedir } from "node:os";
|
|
14337
|
-
import { join as
|
|
15508
|
+
import { homedir as homedir2 } from "node:os";
|
|
15509
|
+
import { join as join3 } from "node:path";
|
|
14338
15510
|
var DEFAULT_MAX_STORED_SESSIONS = 1e4;
|
|
14339
15511
|
var STALE_LOCK_THRESHOLD_MS = 30000;
|
|
14340
15512
|
function getMaxStoredSessions() {
|
|
@@ -14385,11 +15557,11 @@ function getStorePath() {
|
|
|
14385
15557
|
if (!existsSync3(dir)) {
|
|
14386
15558
|
mkdirSync(dir, { recursive: true });
|
|
14387
15559
|
}
|
|
14388
|
-
return
|
|
15560
|
+
return join3(dir, "sessions.json");
|
|
14389
15561
|
}
|
|
14390
15562
|
function getDefaultCacheDir() {
|
|
14391
|
-
const newDir =
|
|
14392
|
-
const oldDir =
|
|
15563
|
+
const newDir = join3(homedir2(), ".cache", "meridian");
|
|
15564
|
+
const oldDir = join3(homedir2(), ".cache", "opencode-claude-max-proxy");
|
|
14393
15565
|
if (existsSync3(newDir))
|
|
14394
15566
|
return newDir;
|
|
14395
15567
|
if (existsSync3(oldDir)) {
|
|
@@ -14777,11 +15949,11 @@ function buildFreshPrompt(messages, stripCacheControl) {
|
|
|
14777
15949
|
const role = m.role === "assistant" ? "Assistant" : "Human";
|
|
14778
15950
|
let content;
|
|
14779
15951
|
if (typeof m.content === "string") {
|
|
14780
|
-
content = m.content;
|
|
15952
|
+
content = sanitizeTextContent(m.content);
|
|
14781
15953
|
} else if (Array.isArray(m.content)) {
|
|
14782
15954
|
content = m.content.map((block) => {
|
|
14783
15955
|
if (block.type === "text" && block.text)
|
|
14784
|
-
return block.text;
|
|
15956
|
+
return sanitizeTextContent(block.text);
|
|
14785
15957
|
if (block.type === "tool_use")
|
|
14786
15958
|
return `[Tool Use: ${block.name}(${JSON.stringify(block.input)})]`;
|
|
14787
15959
|
if (block.type === "tool_result")
|
|
@@ -14821,7 +15993,7 @@ function checkTokenHealth(requestId, sdkSessionId, usage, turnNumber, isResume,
|
|
|
14821
15993
|
isResume,
|
|
14822
15994
|
isPassthrough
|
|
14823
15995
|
};
|
|
14824
|
-
const prevMetric =
|
|
15996
|
+
const prevMetric = telemetryStore2.getLastForSession(sdkSessionId);
|
|
14825
15997
|
const previous = prevMetric ? {
|
|
14826
15998
|
requestId: prevMetric.requestId,
|
|
14827
15999
|
turnNumber: turnNumber - 1,
|
|
@@ -14840,7 +16012,7 @@ function checkTokenHealth(requestId, sdkSessionId, usage, turnNumber, isResume,
|
|
|
14840
16012
|
console.error(line);
|
|
14841
16013
|
}
|
|
14842
16014
|
for (const a of anomalies) {
|
|
14843
|
-
|
|
16015
|
+
diagnosticLog2.log({
|
|
14844
16016
|
level: a.severity === "critical" ? "error" : "warn",
|
|
14845
16017
|
category: "token",
|
|
14846
16018
|
message: `${requestId} ${a.type}: ${a.detail}`,
|
|
@@ -14851,6 +16023,7 @@ function checkTokenHealth(requestId, sdkSessionId, usage, turnNumber, isResume,
|
|
|
14851
16023
|
}
|
|
14852
16024
|
function createProxyServer(config = {}) {
|
|
14853
16025
|
const finalConfig = { ...DEFAULT_PROXY_CONFIG, ...config };
|
|
16026
|
+
const serverVersion = finalConfig.version ?? "unknown";
|
|
14854
16027
|
restoreActiveProfile(finalConfig.profiles);
|
|
14855
16028
|
const sessionDiscoveredTools = new Map;
|
|
14856
16029
|
const app = new Hono2;
|
|
@@ -14862,7 +16035,7 @@ function createProxyServer(config = {}) {
|
|
|
14862
16035
|
status: "ok",
|
|
14863
16036
|
service: "meridian",
|
|
14864
16037
|
format: "anthropic",
|
|
14865
|
-
endpoints: ["/v1/messages", "/messages", "/v1/chat/completions", "/v1/models", "/telemetry", "/health"]
|
|
16038
|
+
endpoints: ["/v1/messages", "/messages", "/v1/chat/completions", "/v1/models", "/telemetry", "/metrics", "/health"]
|
|
14866
16039
|
});
|
|
14867
16040
|
}
|
|
14868
16041
|
return c.html(landingHtml);
|
|
@@ -14985,14 +16158,14 @@ function createProxyServer(config = {}) {
|
|
|
14985
16158
|
const toolCount = body.tools?.length ?? 0;
|
|
14986
16159
|
const requestLogLine = `${requestMeta.requestId} adapter=${adapter.name} model=${model} stream=${stream2} tools=${toolCount} lineage=${lineageType} session=${resumeSessionId?.slice(0, 8) || "new"}${isUndo && undoRollbackUuid ? ` rollback=${undoRollbackUuid.slice(0, 8)}` : ""}${agentMode ? ` agent=${agentMode}` : ""} active=${activeSessions}/${MAX_CONCURRENT_SESSIONS} msgCount=${msgCount}`;
|
|
14987
16160
|
console.error(`[PROXY] ${requestLogLine} msgs=${msgSummary}`);
|
|
14988
|
-
|
|
16161
|
+
diagnosticLog2.session(`${requestLogLine}`, requestMeta.requestId);
|
|
14989
16162
|
if (lineageResult.type === "diverged" && profileSessionId) {
|
|
14990
16163
|
const recovery = lookupSessionRecovery(profileSessionId);
|
|
14991
16164
|
if (recovery) {
|
|
14992
16165
|
const prevId = recovery.previousClaudeSessionId || recovery.claudeSessionId;
|
|
14993
16166
|
const recoveryMsg = `${requestMeta.requestId} SESSION RECOVERY: previous conversation available. Run: claude --resume ${prevId}`;
|
|
14994
16167
|
console.error(`[PROXY] ${recoveryMsg}`);
|
|
14995
|
-
|
|
16168
|
+
diagnosticLog2.session(recoveryMsg, requestMeta.requestId);
|
|
14996
16169
|
}
|
|
14997
16170
|
}
|
|
14998
16171
|
claudeLog("request.received", {
|
|
@@ -15081,11 +16254,11 @@ function createProxyServer(config = {}) {
|
|
|
15081
16254
|
const role = m.role === "assistant" ? "Assistant" : "Human";
|
|
15082
16255
|
let content;
|
|
15083
16256
|
if (typeof m.content === "string") {
|
|
15084
|
-
content = m.content;
|
|
16257
|
+
content = sanitizeTextContent(m.content);
|
|
15085
16258
|
} else if (Array.isArray(m.content)) {
|
|
15086
16259
|
content = m.content.map((block) => {
|
|
15087
16260
|
if (block.type === "text" && block.text)
|
|
15088
|
-
return block.text;
|
|
16261
|
+
return sanitizeTextContent(block.text);
|
|
15089
16262
|
if (block.type === "tool_use")
|
|
15090
16263
|
return `[Tool Use: ${block.name}(${JSON.stringify(block.input)})]`;
|
|
15091
16264
|
if (block.type === "tool_result")
|
|
@@ -15425,7 +16598,7 @@ Subprocess stderr: ${stderrOutput}`;
|
|
|
15425
16598
|
});
|
|
15426
16599
|
const nonStreamQueueWaitMs = requestMeta.queueStartedAt - requestMeta.queueEnteredAt;
|
|
15427
16600
|
checkTokenHealth(requestMeta.requestId, currentSessionId || resumeSessionId, lastUsage, allMessages.length, isResume, passthrough);
|
|
15428
|
-
|
|
16601
|
+
telemetryStore2.record({
|
|
15429
16602
|
requestId: requestMeta.requestId,
|
|
15430
16603
|
timestamp: Date.now(),
|
|
15431
16604
|
adapter: adapter.name,
|
|
@@ -15923,7 +17096,7 @@ data: {"type":"message_stop"}
|
|
|
15923
17096
|
});
|
|
15924
17097
|
const streamQueueWaitMs = requestMeta.queueStartedAt - requestMeta.queueEnteredAt;
|
|
15925
17098
|
checkTokenHealth(requestMeta.requestId, currentSessionId || resumeSessionId, lastUsage, allMessages.length, isResume, passthrough);
|
|
15926
|
-
|
|
17099
|
+
telemetryStore2.record({
|
|
15927
17100
|
requestId: requestMeta.requestId,
|
|
15928
17101
|
timestamp: Date.now(),
|
|
15929
17102
|
adapter: adapter.name,
|
|
@@ -16042,7 +17215,7 @@ data: ${JSON.stringify({
|
|
|
16042
17215
|
const classified = classifyError(errMsg);
|
|
16043
17216
|
claudeLog("proxy.error", { error: errMsg, classified: classified.type });
|
|
16044
17217
|
const errorQueueWaitMs = requestMeta.queueStartedAt - requestMeta.queueEnteredAt;
|
|
16045
|
-
|
|
17218
|
+
telemetryStore2.record({
|
|
16046
17219
|
requestId: requestMeta.requestId,
|
|
16047
17220
|
timestamp: Date.now(),
|
|
16048
17221
|
adapter: adapter.name,
|
|
@@ -16086,6 +17259,12 @@ data: ${JSON.stringify({
|
|
|
16086
17259
|
app.post("/v1/messages", (c) => handleWithQueue(c, "/v1/messages"));
|
|
16087
17260
|
app.post("/messages", (c) => handleWithQueue(c, "/messages"));
|
|
16088
17261
|
app.route("/telemetry", createTelemetryRoutes());
|
|
17262
|
+
app.get("/metrics", (c) => {
|
|
17263
|
+
const body = renderPrometheusMetrics(telemetryStore2);
|
|
17264
|
+
return c.body(body, 200, {
|
|
17265
|
+
"Content-Type": "text/plain; version=0.0.4; charset=utf-8"
|
|
17266
|
+
});
|
|
17267
|
+
});
|
|
16089
17268
|
app.get("/health", async (c) => {
|
|
16090
17269
|
try {
|
|
16091
17270
|
const healthProfile = resolveProfile(finalConfig.profiles, finalConfig.defaultProfile);
|
|
@@ -16094,6 +17273,7 @@ data: ${JSON.stringify({
|
|
|
16094
17273
|
if (!auth) {
|
|
16095
17274
|
return c.json({
|
|
16096
17275
|
status: "degraded",
|
|
17276
|
+
version: serverVersion,
|
|
16097
17277
|
error: "Could not verify auth status",
|
|
16098
17278
|
mode: envBool("PASSTHROUGH") ? "passthrough" : "internal"
|
|
16099
17279
|
});
|
|
@@ -16101,12 +17281,14 @@ data: ${JSON.stringify({
|
|
|
16101
17281
|
if (!auth.loggedIn) {
|
|
16102
17282
|
return c.json({
|
|
16103
17283
|
status: "unhealthy",
|
|
17284
|
+
version: serverVersion,
|
|
16104
17285
|
error: "Not logged in. Run: claude login",
|
|
16105
17286
|
auth: { loggedIn: false }
|
|
16106
17287
|
}, 503);
|
|
16107
17288
|
}
|
|
16108
17289
|
return c.json({
|
|
16109
17290
|
status: "healthy",
|
|
17291
|
+
version: serverVersion,
|
|
16110
17292
|
auth: {
|
|
16111
17293
|
loggedIn: true,
|
|
16112
17294
|
email: auth.email,
|
|
@@ -16118,6 +17300,7 @@ data: ${JSON.stringify({
|
|
|
16118
17300
|
} catch {
|
|
16119
17301
|
return c.json({
|
|
16120
17302
|
status: "degraded",
|
|
17303
|
+
version: serverVersion,
|
|
16121
17304
|
error: "Could not verify auth status",
|
|
16122
17305
|
mode: envBool("PASSTHROUGH") ? "passthrough" : "internal"
|
|
16123
17306
|
});
|
|
@@ -16145,7 +17328,7 @@ data: ${JSON.stringify({
|
|
|
16145
17328
|
});
|
|
16146
17329
|
});
|
|
16147
17330
|
app.get("/profiles", async (c) => {
|
|
16148
|
-
const { profilePageHtml } = await import("./profilePage-
|
|
17331
|
+
const { profilePageHtml } = await import("./profilePage-e90fq8ye.js");
|
|
16149
17332
|
return c.html(profilePageHtml);
|
|
16150
17333
|
});
|
|
16151
17334
|
app.post("/profiles/active", async (c) => {
|