oh-langfuse 0.1.75 → 0.1.77
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/bin/cli.js +11 -9
- package/package.json +1 -1
- package/scripts/opencode-langfuse-setup.mjs +1434 -1434
- package/scripts/real-self-verify.mjs +45 -40
- package/scripts/resolve-opencode-cli.mjs +15 -11
|
@@ -258,7 +258,7 @@ function basicAuth(publicKey, secretKey) {
|
|
|
258
258
|
return `Basic ${Buffer.from(`${publicKey}:${secretKey}`, "utf8").toString("base64")}`;
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
-
async function langfuseGet(config, pathname, params = {}) {
|
|
261
|
+
async function langfuseGet(config, pathname, params = {}) {
|
|
262
262
|
const url = new URL(`${apiBase(config.baseUrl)}${pathname}`);
|
|
263
263
|
for (const [key, value] of Object.entries(params)) {
|
|
264
264
|
if (value !== undefined && value !== null && String(value) !== "") url.searchParams.set(key, String(value));
|
|
@@ -278,17 +278,22 @@ async function langfuseGet(config, pathname, params = {}) {
|
|
|
278
278
|
error.status = response.status;
|
|
279
279
|
throw error;
|
|
280
280
|
}
|
|
281
|
-
return await response.json();
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
281
|
+
return await response.json();
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function isLangfuseQueryShapeError(error) {
|
|
285
|
+
if (!error) return false;
|
|
286
|
+
return error.status === 400 || error.status === 422;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
async function langfuseGetLenient(config, pathname, params = {}) {
|
|
290
|
+
try {
|
|
291
|
+
return await langfuseGet(config, pathname, params);
|
|
292
|
+
} catch (error) {
|
|
293
|
+
if (!isLangfuseQueryShapeError(error)) throw error;
|
|
294
|
+
const fallback = {};
|
|
295
|
+
for (const key of ["limit", "page", "userId", "fields"]) {
|
|
296
|
+
if (params[key] !== undefined) fallback[key] = params[key];
|
|
292
297
|
}
|
|
293
298
|
return await langfuseGet(config, pathname, fallback);
|
|
294
299
|
}
|
|
@@ -407,18 +412,18 @@ function expectedAgentTurnName(target) {
|
|
|
407
412
|
async function observationsForTrace(config, traceId, since) {
|
|
408
413
|
if (!traceId) return [];
|
|
409
414
|
const params = { limit: 100, fields: "core,basic,usage", traceId };
|
|
410
|
-
try {
|
|
411
|
-
return dataArray(await langfuseGet(config, "/v2/observations", params));
|
|
412
|
-
} catch (error) {
|
|
413
|
-
if (error
|
|
414
|
-
}
|
|
415
|
-
try {
|
|
416
|
-
return dataArray(await langfuseGet(config, "/observations", { limit: 100, traceId }));
|
|
417
|
-
} catch (error) {
|
|
418
|
-
if (error
|
|
419
|
-
}
|
|
420
|
-
const fallback = dataArray(await langfuseGetLenient(config, "/observations", { limit: 100, fromTimestamp: since.toISOString() }));
|
|
421
|
-
return fallback.filter((item) => item.traceId === traceId || item.trace_id === traceId);
|
|
415
|
+
try {
|
|
416
|
+
return dataArray(await langfuseGet(config, "/v2/observations", params));
|
|
417
|
+
} catch (error) {
|
|
418
|
+
if (!isLangfuseQueryShapeError(error) && error.status !== 404) throw error;
|
|
419
|
+
}
|
|
420
|
+
try {
|
|
421
|
+
return dataArray(await langfuseGet(config, "/observations", { limit: 100, traceId }));
|
|
422
|
+
} catch (error) {
|
|
423
|
+
if (!isLangfuseQueryShapeError(error)) throw error;
|
|
424
|
+
}
|
|
425
|
+
const fallback = dataArray(await langfuseGetLenient(config, "/observations", { limit: 100, fromTimestamp: since.toISOString() }));
|
|
426
|
+
return fallback.filter((item) => item.traceId === traceId || item.trace_id === traceId);
|
|
422
427
|
}
|
|
423
428
|
|
|
424
429
|
function mergeMetricCandidates(items) {
|
|
@@ -439,12 +444,12 @@ async function recentMetricCandidates(config, since) {
|
|
|
439
444
|
const candidates = [];
|
|
440
445
|
for (const pathname of ["/traces"]) {
|
|
441
446
|
for (const params of [{ ...baseParams, userId: config.userId }, baseParams]) {
|
|
442
|
-
try {
|
|
443
|
-
candidates.push(...dataArray(await langfuseGetLenient(config, pathname, params)));
|
|
444
|
-
} catch (error) {
|
|
445
|
-
if (error.name === "AbortError" || error.status === 404) continue;
|
|
446
|
-
throw error;
|
|
447
|
-
}
|
|
447
|
+
try {
|
|
448
|
+
candidates.push(...dataArray(await langfuseGetLenient(config, pathname, params)));
|
|
449
|
+
} catch (error) {
|
|
450
|
+
if (error.name === "AbortError" || error.status === 404 || isLangfuseQueryShapeError(error)) continue;
|
|
451
|
+
throw error;
|
|
452
|
+
}
|
|
448
453
|
}
|
|
449
454
|
}
|
|
450
455
|
return mergeMetricCandidates(candidates);
|
|
@@ -564,12 +569,12 @@ async function findLangfuseMarker(config, marker, { since, target }) {
|
|
|
564
569
|
|
|
565
570
|
for (const params of traceQueries) {
|
|
566
571
|
let traces;
|
|
567
|
-
try {
|
|
568
|
-
traces = await langfuseGetLenient(config, "/traces", params);
|
|
569
|
-
} catch (error) {
|
|
570
|
-
if (error.status === 404) continue;
|
|
571
|
-
throw error;
|
|
572
|
-
}
|
|
572
|
+
try {
|
|
573
|
+
traces = await langfuseGetLenient(config, "/traces", params);
|
|
574
|
+
} catch (error) {
|
|
575
|
+
if (error.status === 404 || isLangfuseQueryShapeError(error)) continue;
|
|
576
|
+
throw error;
|
|
577
|
+
}
|
|
573
578
|
for (const trace of dataArray(traces)) {
|
|
574
579
|
if (containsMarker(trace, marker)) return { kind: "trace-list", target, id: idOf(trace), item: trace };
|
|
575
580
|
}
|
|
@@ -597,10 +602,10 @@ async function findLangfuseMarker(config, marker, { since, target }) {
|
|
|
597
602
|
for (const observation of dataArray(observations)) {
|
|
598
603
|
if (containsMarker(observation, marker)) return { kind: pathname, target, id: idOf(observation), item: observation };
|
|
599
604
|
}
|
|
600
|
-
} catch (error) {
|
|
601
|
-
if (error.status === 404 || error
|
|
602
|
-
throw error;
|
|
603
|
-
}
|
|
605
|
+
} catch (error) {
|
|
606
|
+
if (error.status === 404 || isLangfuseQueryShapeError(error)) continue;
|
|
607
|
+
throw error;
|
|
608
|
+
}
|
|
604
609
|
}
|
|
605
610
|
|
|
606
611
|
return null;
|
|
@@ -29,23 +29,27 @@ export function resolveOpencodeCli(preferred) {
|
|
|
29
29
|
const home = os.homedir();
|
|
30
30
|
|
|
31
31
|
/** @type {string[]} */
|
|
32
|
-
const candidates = [];
|
|
33
|
-
if (process.platform === "win32") {
|
|
34
|
-
candidates.push(path.join(home, ".opencode", "bin", "opencode.exe"));
|
|
35
|
-
candidates.push(path.join(home, ".opencode", "bin", "opencode.cmd"));
|
|
36
|
-
candidates.push(path.join(home, "bin", "opencode.exe"));
|
|
37
|
-
if (process.env.LOCALAPPDATA) {
|
|
38
|
-
candidates.push(path.join(process.env.LOCALAPPDATA, "Programs", "opencode", "opencode.exe"));
|
|
39
|
-
}
|
|
32
|
+
const candidates = [];
|
|
33
|
+
if (process.platform === "win32") {
|
|
34
|
+
candidates.push(path.join(home, ".opencode", "bin", "opencode.exe"));
|
|
40
35
|
if (process.env.APPDATA) {
|
|
41
|
-
candidates.push(path.join(process.env.APPDATA, "npm", "opencode.cmd"));
|
|
42
|
-
candidates.push(path.join(process.env.APPDATA, "npm", "opencode"));
|
|
43
36
|
candidates.push(path.join(process.env.APPDATA, "npm", "node_modules", "opencode-ai", "node_modules", "opencode-windows-x64", "bin", "opencode.exe"));
|
|
44
37
|
candidates.push(path.join(process.env.APPDATA, "npm", "node_modules", "opencode-ai", "node_modules", "opencode-windows-x64-baseline", "bin", "opencode.exe"));
|
|
45
38
|
candidates.push(path.join(process.env.APPDATA, "npm", "node_modules", "opencode-windows-x64", "bin", "opencode.exe"));
|
|
46
39
|
candidates.push(path.join(process.env.APPDATA, "npm", "node_modules", "opencode-windows-x64-baseline", "bin", "opencode.exe"));
|
|
47
40
|
}
|
|
48
|
-
|
|
41
|
+
if (process.env.LOCALAPPDATA) {
|
|
42
|
+
candidates.push(path.join(process.env.LOCALAPPDATA, "Programs", "opencode", "opencode.exe"));
|
|
43
|
+
}
|
|
44
|
+
candidates.push(path.join(home, ".config", "opencode", "bin", "opencode.exe"));
|
|
45
|
+
candidates.push(path.join(home, ".config", "opencode", "bin", "opencode.cmd"));
|
|
46
|
+
candidates.push(path.join(home, ".opencode", "bin", "opencode.cmd"));
|
|
47
|
+
candidates.push(path.join(home, "bin", "opencode.exe"));
|
|
48
|
+
if (process.env.APPDATA) {
|
|
49
|
+
candidates.push(path.join(process.env.APPDATA, "npm", "opencode.cmd"));
|
|
50
|
+
candidates.push(path.join(process.env.APPDATA, "npm", "opencode"));
|
|
51
|
+
}
|
|
52
|
+
candidates.push(path.join(home, "scoop", "shims", "opencode.exe"));
|
|
49
53
|
} else {
|
|
50
54
|
candidates.push(path.join(home, ".opencode", "bin", "opencode"));
|
|
51
55
|
candidates.push(path.join(home, ".local", "bin", "opencode"));
|