oh-langfuse 0.1.34 → 0.1.36
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
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.36`
|
|
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 启动链路里嵌套运行 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`
|
|
@@ -55,22 +55,23 @@ npx oh-langfuse@latest auto-update codex
|
|
|
55
55
|
|
|
56
56
|
## Skill 使用量统计
|
|
57
57
|
|
|
58
|
-
工具会为每次识别到的 skill
|
|
58
|
+
工具会为每次识别到的 skill 使用额外写入一条通用 observation,skill 名称放在 metadata 中:
|
|
59
59
|
|
|
60
60
|
```text
|
|
61
|
-
Skill Use
|
|
61
|
+
Observation Name: Skill Use
|
|
62
|
+
metadata.skill_name: <skill_name>
|
|
63
|
+
metadata.skill_use_count: 1
|
|
62
64
|
```
|
|
63
65
|
|
|
64
|
-
Dashboard
|
|
66
|
+
Dashboard 中统计全部 skill 使用量可配置:
|
|
65
67
|
|
|
66
68
|
```text
|
|
67
69
|
View: Observations
|
|
68
70
|
Metric: Count
|
|
69
|
-
Filter: Observation Name
|
|
70
|
-
Breakdown Dimension: Observation Name
|
|
71
|
+
Filter: Observation Name equals Skill Use
|
|
71
72
|
```
|
|
72
73
|
|
|
73
|
-
`AI Interaction` 仍然保留 `skill_use_count`、`skill_names`、`skill_names_json` 和 `skill_names_csv`,用于查看单次交互的效率汇总。为避免极端情况下产生过多 observation,OpenCode 每次交互最多记录 20 个去重后的 skill 使用事件。
|
|
74
|
+
如果当前 Langfuse Dashboard 支持 metadata 维度,可用 `metadata.skill_name` 做 Breakdown 来看各 skill 使用量;否则可用 Metrics API 或导出数据按 `metadata.skill_name` 聚合。`AI Interaction` 仍然保留 `skill_use_count`、`skill_names`、`skill_names_json` 和 `skill_names_csv`,用于查看单次交互的效率汇总。为避免极端情况下产生过多 observation,OpenCode 每次交互最多记录 20 个去重后的 skill 使用事件。
|
|
74
75
|
|
|
75
76
|
本地开发运行:
|
|
76
77
|
|
package/codex_langfuse_notify.py
CHANGED
package/langfuse_hook.py
CHANGED
package/package.json
CHANGED
|
@@ -86,6 +86,13 @@ async function main() {
|
|
|
86
86
|
const message = installedVersion
|
|
87
87
|
? `oh-langfuse ${target} runtime update available: ${installedVersion} -> ${latest}.`
|
|
88
88
|
: `oh-langfuse ${target} runtime may need update. Latest package: ${latest}.`;
|
|
89
|
+
const updateCommand = `npx oh-langfuse@latest update ${target}`;
|
|
90
|
+
|
|
91
|
+
if (args["notify-only"] || args.notifyOnly) {
|
|
92
|
+
console.log(`[INFO] ${message}`);
|
|
93
|
+
console.log(`[INFO] To update safely, close the agent and run: ${updateCommand}`);
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
89
96
|
|
|
90
97
|
if (args.yes || args.y) {
|
|
91
98
|
console.log(`[INFO] ${message}`);
|
|
@@ -94,7 +101,7 @@ async function main() {
|
|
|
94
101
|
}
|
|
95
102
|
|
|
96
103
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
97
|
-
console.log(`[INFO] ${message} Run:
|
|
104
|
+
console.log(`[INFO] ${message} Run: ${updateCommand}`);
|
|
98
105
|
return 0;
|
|
99
106
|
}
|
|
100
107
|
|
|
@@ -468,7 +468,7 @@ function getPatchedLangfuseDistIndexJs() {
|
|
|
468
468
|
" };",
|
|
469
469
|
" const emitSkillUseSpans = ({ skillNames, sessionId, messageId, interactionId }) => {",
|
|
470
470
|
" for (const skillName of skillNames.slice(0, MAX_SKILL_USE_SPANS_PER_INTERACTION)) {",
|
|
471
|
-
" const span = metricsTracer.startSpan(
|
|
471
|
+
" const span = metricsTracer.startSpan('Skill Use');",
|
|
472
472
|
' span.setAttribute("oh.langfuse.source", "opencode");',
|
|
473
473
|
' span.setAttribute("oh.langfuse.user_id", userId || "");',
|
|
474
474
|
' span.setAttribute("oh.langfuse.metrics_schema_version", "1.0");',
|
|
@@ -595,7 +595,7 @@ function writeWindowsLauncherCmd(opencodeDir, { publicKey, secretKey, baseUrl, u
|
|
|
595
595
|
if (userId) cmd.push(`set LANGFUSE_USER_ID=${userId}`);
|
|
596
596
|
cmd.push("where npx >nul 2>nul");
|
|
597
597
|
cmd.push("if %ERRORLEVEL% EQU 0 (");
|
|
598
|
-
cmd.push(" call npx -y oh-langfuse@latest auto-update opencode --skip-check");
|
|
598
|
+
cmd.push(" call npx -y oh-langfuse@latest auto-update opencode --skip-check --notify-only");
|
|
599
599
|
cmd.push(")");
|
|
600
600
|
cmd.push('if exist "%USERPROFILE%\\.opencode\\bin\\opencode.exe" (');
|
|
601
601
|
cmd.push(' "%USERPROFILE%\\.opencode\\bin\\opencode.exe" %*');
|
|
@@ -623,7 +623,7 @@ function writeOpencodeCommandShim(opencodeDir, { publicKey, secretKey, baseUrl,
|
|
|
623
623
|
if (userId) cmd.push(`set LANGFUSE_USER_ID=${userId}`);
|
|
624
624
|
cmd.push("where npx >nul 2>nul");
|
|
625
625
|
cmd.push("if %ERRORLEVEL% EQU 0 (");
|
|
626
|
-
cmd.push(" call npx -y oh-langfuse@latest auto-update opencode --skip-check");
|
|
626
|
+
cmd.push(" call npx -y oh-langfuse@latest auto-update opencode --skip-check --notify-only");
|
|
627
627
|
cmd.push(")");
|
|
628
628
|
cmd.push(`call ${cmdQuote(realOpencodeCli)} %*`);
|
|
629
629
|
cmd.push("exit /b %ERRORLEVEL%");
|
|
@@ -642,7 +642,7 @@ function writeOpencodeCommandShim(opencodeDir, { publicKey, secretKey, baseUrl,
|
|
|
642
642
|
`export LANGFUSE_BASEURL=${shQuote(baseUrl)}`,
|
|
643
643
|
userId ? `export LANGFUSE_USER_ID=${shQuote(userId)}` : null,
|
|
644
644
|
'if command -v npx >/dev/null 2>&1; then',
|
|
645
|
-
' npx -y oh-langfuse@latest auto-update opencode --skip-check || true',
|
|
645
|
+
' npx -y oh-langfuse@latest auto-update opencode --skip-check --notify-only || true',
|
|
646
646
|
"fi",
|
|
647
647
|
`exec ${shQuote(realOpencodeCli)} "$@"`,
|
|
648
648
|
""
|
|
@@ -664,7 +664,7 @@ function writeUnixLauncherSh(opencodeDir, { publicKey, secretKey, baseUrl, userI
|
|
|
664
664
|
`export LANGFUSE_BASEURL=${shQuote(baseUrl)}`,
|
|
665
665
|
userId ? `export LANGFUSE_USER_ID=${shQuote(userId)}` : null,
|
|
666
666
|
'if command -v npx >/dev/null 2>&1; then',
|
|
667
|
-
' npx -y oh-langfuse@latest auto-update opencode --skip-check || true',
|
|
667
|
+
' npx -y oh-langfuse@latest auto-update opencode --skip-check --notify-only || true',
|
|
668
668
|
"fi",
|
|
669
669
|
'if [ -x "$HOME/.opencode/bin/opencode" ]; then',
|
|
670
670
|
' exec "$HOME/.opencode/bin/opencode" "$@"',
|
|
@@ -980,7 +980,14 @@ async function main() {
|
|
|
980
980
|
};
|
|
981
981
|
const merged = deepMerge(existing, desired);
|
|
982
982
|
writeJsonPretty(opencodeJsonPath, merged);
|
|
983
|
-
|
|
983
|
+
let realOpencodeCli = resolveOpencodeCli(args.cmd);
|
|
984
|
+
const shimDir = path.join(opencodeDir, "bin");
|
|
985
|
+
if (realOpencodeCli) {
|
|
986
|
+
const relativeToShim = path.relative(path.resolve(shimDir), path.resolve(realOpencodeCli));
|
|
987
|
+
if (relativeToShim && !relativeToShim.startsWith("..") && !path.isAbsolute(relativeToShim)) {
|
|
988
|
+
realOpencodeCli = "";
|
|
989
|
+
}
|
|
990
|
+
}
|
|
984
991
|
console.log(`已更新:${opencodeJsonPath}`);
|
|
985
992
|
|
|
986
993
|
const launcher = writeWindowsLauncherCmd(opencodeDir, { publicKey, secretKey, baseUrl, userId });
|