oh-langfuse 0.1.36 → 0.1.38
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 +2 -2
- package/package.json +1 -1
- package/scripts/opencode-langfuse-setup.mjs +30 -23
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`oh-langfuse` 是用于给 Claude Code、OpenCode 和 Codex 配置 Langfuse 追踪的命令行工具。它提供交互式安装向导,也支持 `setup` / `check` 直接命令,方便在用户机器上安装、修复和校验配置。
|
|
4
4
|
|
|
5
|
-
当前 npm 版本:`0.1.
|
|
5
|
+
当前 npm 版本:`0.1.38`
|
|
6
6
|
|
|
7
7
|
## 能做什么
|
|
8
8
|
|
|
@@ -40,7 +40,7 @@ npx oh-langfuse@latest check codex
|
|
|
40
40
|
|
|
41
41
|
OpenCode 生成的 `launch-opencode-langfuse.*` 会在启动 agent 前执行一次更新检测:如果 npm 上的 `oh-langfuse@latest` 高于本机 runtime 版本,会提示是否更新;用户确认后才会运行 `npx oh-langfuse@latest update opencode`。Claude Code 和 Codex 也会生成对应 launcher:
|
|
42
42
|
|
|
43
|
-
OpenCode setup 还会生成 `~/.config/opencode/bin/opencode` / `opencode.cmd` 命令包装器,并把该目录写入用户 PATH。新开终端后直接运行 `opencode
|
|
43
|
+
OpenCode setup 还会生成 `~/.config/opencode/bin/opencode` / `opencode.cmd` 命令包装器,并把该目录写入用户 PATH。新开终端后直接运行 `opencode`,会先用轻量脚本检测 `oh-langfuse` runtime 是否需要更新,再转发到真实 OpenCode CLI。为了避免 Windows 下在 agent 启动链路里嵌套运行 Node/npm installer 导致启动崩溃,`opencode` 命令只做检测和提示;需要更新时请关闭 agent 后运行提示中的 `npx oh-langfuse@latest update opencode`。
|
|
44
44
|
|
|
45
45
|
- `~/.claude/launch-claude-langfuse.cmd` / `~/.claude/launch-claude-langfuse.sh`
|
|
46
46
|
- `~/.codex/launch-codex-langfuse.cmd` / `~/.codex/launch-codex-langfuse.sh`
|
package/package.json
CHANGED
|
@@ -400,7 +400,6 @@ function getPatchedLangfuseDistIndexJs() {
|
|
|
400
400
|
" const knownSkillNames = await collectKnownSkillNames();",
|
|
401
401
|
" const messageTextById = new Map();",
|
|
402
402
|
" const skillNamesByMessageId = new Map();",
|
|
403
|
-
" const skillNamesBySessionId = new Map();",
|
|
404
403
|
" const toolCallIdsByMessageId = new Map();",
|
|
405
404
|
" const toolCallIdsBySessionId = new Map();",
|
|
406
405
|
" const toolResultIdsByMessageId = new Map();",
|
|
@@ -448,15 +447,6 @@ function getPatchedLangfuseDistIndexJs() {
|
|
|
448
447
|
" }",
|
|
449
448
|
" for (const name of names) set.add(name);",
|
|
450
449
|
" };",
|
|
451
|
-
" const rememberSessionSkillNames = (sessionId, names) => {",
|
|
452
|
-
" if (!sessionId || !names.length) return;",
|
|
453
|
-
" let set = skillNamesBySessionId.get(sessionId);",
|
|
454
|
-
" if (!set) {",
|
|
455
|
-
" set = new Set();",
|
|
456
|
-
" skillNamesBySessionId.set(sessionId, set);",
|
|
457
|
-
" }",
|
|
458
|
-
" for (const name of names) set.add(name);",
|
|
459
|
-
" };",
|
|
460
450
|
" const rememberToolActivity = (map, key, activity, kind) => {",
|
|
461
451
|
" if (!key || !activity?.[kind]) return;",
|
|
462
452
|
" let set = map.get(key);",
|
|
@@ -490,9 +480,9 @@ function getPatchedLangfuseDistIndexJs() {
|
|
|
490
480
|
" const partType = part?.type ?? '';",
|
|
491
481
|
" const sessionId = pickEventString(part?.sessionID, part?.sessionId, payload?.sessionID, payload?.sessionId, payload?.session?.id);",
|
|
492
482
|
" const messageId = pickEventString(part?.messageID, part?.messageId, payload?.messageID, payload?.messageId, payload?.message?.id);",
|
|
493
|
-
" const
|
|
483
|
+
" const skillDetectionSources = [part?.state?.input, part?.input, payload?.input, part?.state?.metadata, payload?.metadata, part?.state?.file, part?.file];",
|
|
484
|
+
" const eventSkillNames = detectOpencodeSkillNames(skillDetectionSources, knownSkillNames);",
|
|
494
485
|
" rememberSkillNames(messageId, eventSkillNames);",
|
|
495
|
-
" rememberSessionSkillNames(sessionId, eventSkillNames);",
|
|
496
486
|
" const toolActivity = countOpencodeToolActivity(event);",
|
|
497
487
|
" rememberToolActivity(toolCallIdsByMessageId, messageId, toolActivity, 'toolCallCount');",
|
|
498
488
|
" rememberToolActivity(toolCallIdsBySessionId, sessionId, toolActivity, 'toolCallCount');",
|
|
@@ -510,7 +500,7 @@ function getPatchedLangfuseDistIndexJs() {
|
|
|
510
500
|
" const tokenAvailable = [tokenMetrics.input, tokenMetrics.output, total, tokenMetrics.cacheRead, tokenMetrics.reasoning].some((value) => value !== undefined);",
|
|
511
501
|
" const span = metricsTracer.startSpan('AI Interaction');",
|
|
512
502
|
" const text = messageTextById.get(messageId) || '';",
|
|
513
|
-
" const skillNames = [...
|
|
503
|
+
" const skillNames = [...(skillNamesByMessageId.get(messageId) ?? [])];",
|
|
514
504
|
" const toolCallCount = Math.max(new Set([...(toolCallIdsByMessageId.get(messageId) ?? []), ...(toolCallIdsBySessionId.get(sessionId) ?? [])]).size, skillNames.length);",
|
|
515
505
|
" const toolResultCount = Math.max(new Set([...(toolResultIdsByMessageId.get(messageId) ?? []), ...(toolResultIdsBySessionId.get(sessionId) ?? [])]).size, skillNames.length);",
|
|
516
506
|
' span.setAttribute("oh.langfuse.source", "opencode");',
|
|
@@ -542,7 +532,6 @@ function getPatchedLangfuseDistIndexJs() {
|
|
|
542
532
|
" emitSkillUseSpans({ skillNames, sessionId, messageId, interactionId });",
|
|
543
533
|
" messageTextById.delete(messageId);",
|
|
544
534
|
" skillNamesByMessageId.delete(messageId);",
|
|
545
|
-
" skillNamesBySessionId.delete(sessionId);",
|
|
546
535
|
" toolCallIdsByMessageId.delete(messageId);",
|
|
547
536
|
" toolCallIdsBySessionId.delete(sessionId);",
|
|
548
537
|
" toolResultIdsByMessageId.delete(messageId);",
|
|
@@ -588,15 +577,13 @@ function syncPluginPackageToLocalPlugins({ pkgDir, pluginDest, pluginsDir }) {
|
|
|
588
577
|
function writeWindowsLauncherCmd(opencodeDir, { publicKey, secretKey, baseUrl, userId }) {
|
|
589
578
|
if (process.platform !== "win32") return null;
|
|
590
579
|
const p = path.join(opencodeDir, "launch-opencode-langfuse.cmd");
|
|
591
|
-
|
|
580
|
+
writeWindowsUpdateCheckScript(opencodeDir);
|
|
581
|
+
const cmd = ["@echo off", "REM Auto-generated by scripts/opencode-langfuse-setup.mjs"];
|
|
592
582
|
cmd.push(`set LANGFUSE_PUBLIC_KEY=${publicKey}`);
|
|
593
583
|
cmd.push(`set LANGFUSE_SECRET_KEY=${secretKey}`);
|
|
594
584
|
cmd.push(`set LANGFUSE_BASEURL=${baseUrl}`);
|
|
595
585
|
if (userId) cmd.push(`set LANGFUSE_USER_ID=${userId}`);
|
|
596
|
-
cmd.push(
|
|
597
|
-
cmd.push("if %ERRORLEVEL% EQU 0 (");
|
|
598
|
-
cmd.push(" call npx -y oh-langfuse@latest auto-update opencode --skip-check --notify-only");
|
|
599
|
-
cmd.push(")");
|
|
586
|
+
cmd.push('powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0oh-langfuse-opencode-update-check.ps1"');
|
|
600
587
|
cmd.push('if exist "%USERPROFILE%\\.opencode\\bin\\opencode.exe" (');
|
|
601
588
|
cmd.push(' "%USERPROFILE%\\.opencode\\bin\\opencode.exe" %*');
|
|
602
589
|
cmd.push(" exit /b %ERRORLEVEL%");
|
|
@@ -610,21 +597,41 @@ function shQuote(s) {
|
|
|
610
597
|
return `'${String(s).replace(/'/g, "'\"'\"'")}'`;
|
|
611
598
|
}
|
|
612
599
|
|
|
600
|
+
function writeWindowsUpdateCheckScript(dir) {
|
|
601
|
+
if (process.platform !== "win32") return null;
|
|
602
|
+
ensureDir(dir);
|
|
603
|
+
const p = path.join(dir, "oh-langfuse-opencode-update-check.ps1");
|
|
604
|
+
const ps = [
|
|
605
|
+
"$ErrorActionPreference = 'SilentlyContinue'",
|
|
606
|
+
"$statePath = Join-Path $env:USERPROFILE '.config\\oh-langfuse\\runtime.json'",
|
|
607
|
+
"if (-not (Test-Path -LiteralPath $statePath)) { exit 0 }",
|
|
608
|
+
"$state = Get-Content -LiteralPath $statePath -Raw | ConvertFrom-Json",
|
|
609
|
+
"$installed = $state.targets.opencode.packageVersion",
|
|
610
|
+
"$meta = Invoke-RestMethod -UseBasicParsing -Uri 'https://registry.npmjs.org/oh-langfuse' -TimeoutSec 3",
|
|
611
|
+
"$latest = $meta.'dist-tags'.latest",
|
|
612
|
+
"if ($installed -and $latest -and ([version]$latest -gt [version]$installed)) {",
|
|
613
|
+
" Write-Host \"[INFO] oh-langfuse opencode runtime update available: $installed -> $latest\"",
|
|
614
|
+
" Write-Host '[INFO] Close OpenCode and run: npx oh-langfuse@latest update opencode'",
|
|
615
|
+
"}",
|
|
616
|
+
""
|
|
617
|
+
].join("\r\n");
|
|
618
|
+
fs.writeFileSync(p, ps, "utf8");
|
|
619
|
+
return p;
|
|
620
|
+
}
|
|
621
|
+
|
|
613
622
|
function writeOpencodeCommandShim(opencodeDir, { publicKey, secretKey, baseUrl, userId, realOpencodeCli }) {
|
|
614
623
|
const shimDir = path.join(opencodeDir, "bin");
|
|
615
624
|
ensureDir(shimDir);
|
|
616
625
|
if (process.platform === "win32") {
|
|
617
626
|
const shim = path.join(shimDir, "opencode.cmd");
|
|
627
|
+
writeWindowsUpdateCheckScript(shimDir);
|
|
618
628
|
const cmd = ["@echo off", "REM Auto-generated by scripts/opencode-langfuse-setup.mjs"];
|
|
619
629
|
cmd.push("set OH_LANGFUSE_OPENCODE_SHIM=1");
|
|
620
630
|
cmd.push(`set LANGFUSE_PUBLIC_KEY=${publicKey}`);
|
|
621
631
|
cmd.push(`set LANGFUSE_SECRET_KEY=${secretKey}`);
|
|
622
632
|
cmd.push(`set LANGFUSE_BASEURL=${baseUrl}`);
|
|
623
633
|
if (userId) cmd.push(`set LANGFUSE_USER_ID=${userId}`);
|
|
624
|
-
cmd.push(
|
|
625
|
-
cmd.push("if %ERRORLEVEL% EQU 0 (");
|
|
626
|
-
cmd.push(" call npx -y oh-langfuse@latest auto-update opencode --skip-check --notify-only");
|
|
627
|
-
cmd.push(")");
|
|
634
|
+
cmd.push('powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0oh-langfuse-opencode-update-check.ps1"');
|
|
628
635
|
cmd.push(`call ${cmdQuote(realOpencodeCli)} %*`);
|
|
629
636
|
cmd.push("exit /b %ERRORLEVEL%");
|
|
630
637
|
fs.writeFileSync(shim, cmd.join("\r\n") + "\r\n", "utf8");
|