pi-langfuse 1.0.0 → 1.2.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.
@@ -0,0 +1,68 @@
1
+ # Langfuse 追踪逻辑优化方案
2
+
3
+ ## 1. 背景与目标
4
+ 根据之前的建议,我们需要进一步优化 Pi-Langfuse 扩展的上报逻辑,使得在 Langfuse 控制台中观察 Agent 执行过程时更加细致、层级分明且数据完备。
5
+ 本次优化包含 5 个核心点:引入 Turn 级别的 Span、精准追踪 TTFT(首字响应时间)、处理 Provider 请求异常、上报 System Prompt,以及完善 Session 的边缘生命周期和上下文压缩(Compact)处理。
6
+
7
+ ## 2. 现状分析
8
+ - **层级结构**:目前 `llm-generation` 和 `tool` 是平级挂载在根 Trace 下,多轮对话时瀑布图非常扁平。
9
+ - **TTFT**:尚未记录 `completionStartTime`,无法在 Langfuse 中直观看到首字耗时。
10
+ - **异常闭环**:LLM Provider 发生 4xx/5xx HTTP 错误时,`message_end` 可能不触发,导致 Generation 无法正常闭合。
11
+ - **上下文完备性**:`before_agent_start` 仅提取了 user prompt,缺少 System Prompt,不利于后期 Debug。
12
+ - **Session 生命周期**:仅处理了 `session_start` 和 `session_shutdown`,忽略了 `/new`, `/resume`, `/fork`, `/compact` 等高级会话操作引发的状态混乱问题。
13
+
14
+ ## 3. 具体修改方案
15
+
16
+ ### 3.1 引入 Turn-Level Span (层级结构优化)
17
+ 将一轮对话(Turn)包装为一个 Span,使其成为 Generation 和 Tool 的父节点。
18
+ - **`src/types.ts`**:
19
+ - 在 `AgentState` 接口中增加 `activeTurn?: LangfuseObservation` 字段。
20
+ - **`src/handlers/turn.ts` (新建)**:
21
+ - 实现 `startTurnObservation(event)`:调用 `state.agentState.root.startObservation("turn", {...}, { asType: "span" })` 并赋值给 `activeTurn`。
22
+ - 实现 `finishTurnObservation(event)`:结束 `activeTurn` 并将其置空。
23
+ - **`src/handlers/generation.ts` & `src/handlers/tool.ts`**:
24
+ - 在创建 `llm-generation` 和 `tool` 观察节点时,优先判断 `state.agentState.activeTurn` 是否存在,若存在则调用 `activeTurn.startObservation`,否则降级使用 `root.startObservation`。
25
+ - **`index.ts`**:
26
+ - 注册 `turn_start` 事件,调用 `startTurnObservation`。
27
+ - 在现有的 `turn_end` 监听器中,除了处理 Fallback Generation,还需要调用 `finishTurnObservation`。
28
+
29
+ ### 3.2 精准追踪 TTFT (首字生成时间)
30
+ 记录模型流式输出第一块 Chunk 的时间,用于计算 TTFT。
31
+ - **`src/types.ts`**:
32
+ - 在 `GenerationState` 中增加 `ttftRecorded?: boolean` 标志位。
33
+ - **`src/handlers/generation.ts`**:
34
+ - 新增 `recordTTFT(event)` 函数:获取当前 `activeGeneration`,若 `ttftRecorded` 为 false/undefined,则调用 `generation.observation.update({ completionStartTime: new Date() })`,并标记 `ttftRecorded = true`。
35
+ - **`index.ts`**:
36
+ - 在 `message_update` 事件监听器中,除了原有的提取逻辑外,新增调用 `recordTTFT(event)`。
37
+
38
+ ### 3.3 异常流闭环:Provider 请求级错误处理
39
+ 防止因 Provider HTTP 请求失败导致 Generation 永远处于开启状态。
40
+ - **`src/handlers/generation.ts`**:
41
+ - 修改 `updateGenerationMetadata(event)` 函数。在提取完 metadata 后,检查 `metadata.status`。
42
+ - 如果 `status >= 400` 或者存在明确的 error 信息,立刻将该 Generation 的状态设为 `level: "ERROR"`,附加 `statusMessage`,并调用 `.end()` 提前闭合它,同时设置 `ended = true`。
43
+
44
+ ### 3.4 完善上下文信息:上报 System Prompt
45
+ 将 System Prompt 纳入 Trace 的元数据或输入中,方便回溯。
46
+ - **`src/handlers/agent.ts`**:
47
+ - 修改 `startAgentRun(event, ctx)`。
48
+ - 增加 `const systemPrompt = await ctx.getSystemPrompt();`。
49
+ - 在 `root` Trace 的 `metadata` 中增加 `systemPrompt: truncate(systemPrompt, MAX_TOOL_PAYLOAD_LENGTH)`。
50
+
51
+ ### 3.5 Session 边缘生命周期与 Compact 处理
52
+ 完善 Pi 扩展 API 提供的各类会话切换与上下文管理事件。
53
+ - **`index.ts`**:
54
+ - 增加 `session_before_switch` 和 `session_before_fork` 的事件监听。当触发这些事件时,表明当前会话即将被替换,调用 `closeDanglingObservations("Session switched or forked")` 提前闭合所有挂起的节点,并调用 `resetRunState()`。
55
+ - 增加 `session_compact` 事件监听。如果当前 `state.agentState.root` 存在,调用 `root.startObservation("session_compact", { level: "DEFAULT", statusMessage: "Context was compacted" }, { asType: "span" }).end()`,在 Trace 中记录下压缩动作发生的时机。
56
+
57
+ ## 4. 假设与决策
58
+ - **决策**: Turn Span 的命名直接使用 `"turn"`,类型使用 `span`,这样在 Langfuse 的甘特图中能清晰地包裹住内部的 Generation 和 Tool。
59
+ - **决策**: TTFT 使用系统当前时间 `new Date()`。尽管存在微小的事件传递延迟,但在 Node.js 环境下已足够精确。
60
+ - **假设**: `ctx.getSystemPrompt()` 是异步方法,在 `before_agent_start` 和 `agent_start` 中可以通过 `await` 正常获取。
61
+ - **决策**: 对于 Session Lifecycle 的处理,统一视作强行终止当前 Agent Run 的执行,因此复用 `closeDanglingObservations` 逻辑以保证不会出现悬空(Dangling)的 Trace/Span。
62
+
63
+ ## 5. 验收标准
64
+ 1. 在代码中实现上述 5 项修改,且不破坏现有 TypeScript 编译。
65
+ 2. 运行 Pi Agent 进行一次多轮对话(调用工具),能够在 Langfuse 观察到 `Trace -> Turn -> Generation/Tool` 的层级结构。
66
+ 3. Langfuse 的 Generation 详情中能够看到 `Time to First Token (TTFT)`。
67
+ 4. Trace 的 Metadata 中包含 `systemPrompt` 字段。
68
+ 5. 通过 `/new` 或 `/compact` 时,控制台不报挂起节点相关的警告。
@@ -0,0 +1,78 @@
1
+ # Pi-Langfuse 代码重构与拆分计划
2
+
3
+ ## 摘要 (Summary)
4
+ 将当前长达 1105 行的单文件 `index.ts` 重构并按功能职责拆分至 `src/` 目录下的多个模块中。保留根目录的 `index.ts` 作为 Pi 扩展的纯入口文件。此举将极大提升代码的可读性和可维护性。
5
+
6
+ ## 当前状态分析 (Current State Analysis)
7
+ 目前 `index.ts` 是一个单文件巨石(Monolith),包含了以下所有逻辑:
8
+ 1. 本地与环境变量配置读取
9
+ 2. TypeScript 接口声明(`Config`, `AgentState`, `LangfuseObservation` 等)
10
+ 3. 全局可变状态(如 `agentState`, `currentSessionId`, 各类计数器)
11
+ 4. Langfuse SDK 的懒加载与生命周期管理
12
+ 5. 数据格式化、截断与负载提取工具函数
13
+ 6. Agent、Generation 和 Tool 各自的观测事件处理器
14
+ 7. Pi 扩展命令注册与生命周期事件监听
15
+
16
+ 所有逻辑混合在一起,导致状态变更难以追踪,且由于闭包共享了大量模块级状态,修改代码容易引入隐藏的副作用。
17
+
18
+ ## 提议更改 (Proposed Changes)
19
+
20
+ ### 1. 更新项目配置
21
+ - 修改 `tsconfig.json`:在 `include` 中增加 `"src/**/*.ts"`,以包含新的源码目录。
22
+ - **依赖引用规范**:由于 `tsconfig.json` 配置了 `"moduleResolution": "NodeNext"`,所有内部文件导入必须显式带有 `.js` 后缀(例如 `import { state } from "./state.js"`)。
23
+
24
+ ### 2. 建立 `src/` 目录结构并拆分职责
25
+ 计划新建如下文件与目录:
26
+
27
+ - **`src/types.ts`**
28
+ - **内容**:提取所有的 Interface 和 Type 定义。
29
+ - **包含**:`Config`, `LangfuseObservation`, `ObservationUpdate`, `LangfuseScoreClient`, `LangfuseRuntime`, `GenerationState`, `ToolState`, `AgentState`。
30
+
31
+ - **`src/constants.ts`**
32
+ - **内容**:提取所有魔法数字和常量配置。
33
+ - **包含**:`EXT_DIR`, `CONFIG_PATH`, `DEFAULT_LANGFUSE_HOST`, `MAX_STRING_LENGTH` 等。
34
+
35
+ - **`src/state.ts`**
36
+ - **内容**:统一管理所有全局可变状态。
37
+ - **实现方式**:将原来的 `let agentState`, `let currentSessionId` 等包裹在一个 `export const state = { ... }` 对象中,确保跨模块引用时状态一致。
38
+ - **包含函数**:`resetRunState`, `computeEvaluationScores`。
39
+
40
+ - **`src/utils.ts`**
41
+ - **内容**:集中存放与状态无关的纯工具函数。
42
+ - **包含**:`truncate`, `tryParseJson`, `shapePayload`, `safeSerialize`,以及一系列解析函数(`extractTextContent`, `extractToolCalls`, `getToolCallId` 等)。
43
+
44
+ - **`src/config.ts`**
45
+ - **内容**:负责配置读取与持久化,以及与 Pi UI 的交互提示。
46
+ - **包含**:`loadConfigFromFile`, `loadConfigFromEnv`, `saveConfig`, `ensureConfig`, `promptForConfig`。
47
+
48
+ - **`src/langfuse.ts`**
49
+ - **内容**:Langfuse SDK 客户端封装。
50
+ - **包含**:`getRuntime` (单例模式加载 SDK)、`shutdownRuntime`、`sendScore`。
51
+
52
+ - **`src/handlers/agent.ts`**
53
+ - **内容**:Agent 生命周期的事件逻辑。
54
+ - **包含**:`startAgentRun`, `finishAgentRun`, `updateTraceIO`。
55
+
56
+ - **`src/handlers/generation.ts`**
57
+ - **内容**:模型生成 (Generation) 相关的生命周期逻辑。
58
+ - **包含**:`getOpenGeneration`, `startGeneration`, `updateGenerationMetadata`, `finishGenerationFromMessage`, `createFallbackGenerationFromTurn`。
59
+
60
+ - **`src/handlers/tool.ts`**
61
+ - **内容**:工具调用 (Tool) 相关的逻辑。
62
+ - **包含**:`startToolObservation`, `finishToolObservation`, `closeDanglingObservations`。
63
+
64
+ ### 3. 精简根目录 `index.ts`
65
+ - **内容**:将其转换为纯粹的事件路由中心。
66
+ - **改动**:删除原有的业务实现,改为从 `src/` 各个模块导入必要的 handler。保留默认导出的扩展注册函数 `export default async function (pi: ExtensionAPI)`,并在其中通过 `pi.on` 和 `pi.registerCommand` 将事件委派给对应的处理函数。
67
+
68
+ ## 假设与决策 (Assumptions & Decisions)
69
+ - **零行为变更**:本次重构仅做结构上的梳理,不修改任何核心逻辑、状态变更时机或事件 payload 的生成规则,从而保证与当前 Langfuse 的数据对接一致。
70
+ - **状态管理**:采用共享的 `state` 单例对象替代原本的顶层变量,以最少的改动适配多文件架构。
71
+ - **兼容性**:保留根目录的 `index.ts` 以兼容现有的 `package.json` 中的 `pi.extensions` 配置,无需修改发布行为。
72
+
73
+ ## 验证步骤 (Verification steps)
74
+ 1. 运行 `npm run typecheck` 确认代码拆分后无 TypeScript 编译及引入报错。
75
+ 2. 开启 Pi CLI (`pi "test prompt"`) 并挂载该本地扩展,验证:
76
+ - 配置初始化弹窗或环境变量读取是否正常工作。
77
+ - 工具调用、LLM 生成以及会话结束时的逻辑是否无异常抛出。
78
+ 3. 登录 Langfuse 控制面板,核对新产生的 trace 数据结构(agent、generation、tool observations 及打分数据)是否完整,未出现状态泄漏或丢失。
package/AGENTS.md CHANGED
@@ -1,57 +1,48 @@
1
- # AGENTS.md
1
+ # Pi Langfuse Extension - Agents & Architecture
2
2
 
3
3
  ## Project Overview
4
4
 
5
- This repository contains a Pi Coding Agent extension that forwards session activity to Langfuse for observability. The runtime is intentionally small:
5
+ This repository contains a Pi Coding Agent extension that integrates with Langfuse to provide deep observability into agent sessions. By hooking into Pi's Extension API, it forwards telemetry data (traces, spans, and LLM generations) to Langfuse, enabling developers to monitor token usage, cost, tool execution success rates, and conversational context.
6
6
 
7
- - `index.ts`: extension entrypoint, event listeners, trace/span/generation lifecycle, and scoring
8
- - `package.json`: package metadata for Pi/NPM
9
- - `config.json`: local credentials file for manual development only, ignored by git
10
- - `.agents/skills/langfuse/SKILL.md`: local skill instructions for Langfuse-related workflows
7
+ ## Architecture & Event Mapping
11
8
 
12
- ## How The Extension Works
9
+ The extension leverages the `@earendil-works/pi-coding-agent` Extension API to intercept lifecycle events and maps them to Langfuse's hierarchical observability model: **Trace** -> **Span** / **Generation**.
13
10
 
14
- The extension listens to Pi lifecycle events and maps them into Langfuse objects:
11
+ ### 1. Trace Level (Agent Run)
12
+ The root of the observability tree is a **Trace**, representing a single user prompt and the agent's complete execution to fulfill it.
15
13
 
16
- 1. `session_start` captures a stable session id
17
- 2. `before_agent_start` creates a trace for the user prompt
18
- 3. `tool_call` / `tool_result` create and close tool spans
19
- 4. `turn_end` records LLM usage/cost metadata as a generation
20
- 5. `agent_end` finalizes the trace and publishes aggregate evaluation scores
21
- 6. `session_shutdown` flushes any remaining state
14
+ - `before_agent_start` / `agent_start`: Initializes the `pi-agent` **Trace**. Captures the initial prompt, working directory (`cwd`), and session ID.
15
+ - `agent_end`: Finalizes the trace, captures the final assistant output, and submits evaluation scores (e.g., tool call count, success rate).
22
16
 
23
- The code is stateful by design. Changes to trace/session bookkeeping should be reviewed carefully because multiple Pi hooks share the same module-level state.
17
+ ### 2. Generation Level (LLM Calls)
18
+ Every time the agent communicates with an LLM provider, a **Generation** is recorded to track token usage, costs, and latency.
24
19
 
25
- ## Local Development
20
+ - `before_provider_request`: Starts the `llm-generation` observation.
21
+ - `after_provider_response`: Updates the generation with HTTP status and provider metadata.
22
+ - `message_update`: Tracks streaming text (can be used to track Time-To-First-Token).
23
+ - `message_end`: Ends the generation, extracting `usageDetails` (input/output tokens, cache metrics) and `costDetails`.
24
+ - `turn_end`: Handles fallback generation logging if standard message events miss the completion.
26
25
 
27
- Recommended environment:
26
+ ### 3. Span Level (Tool Executions)
27
+ When the LLM decides to use a registered tool (e.g., bash, file read), a **Span** is created under the root trace.
28
28
 
29
- - Node.js `>=22` as declared in `package.json`
30
- - A local `config.json` with Langfuse credentials
29
+ - `tool_execution_start` / `tool_call`: Starts a `tool` span, logging the tool name and its input parameters (truncated for safety).
30
+ - `tool_result` / `tool_execution_end`: Finalizes the tool span. If the tool fails, the span's level is marked as `ERROR` and the error message is recorded.
31
31
 
32
- Typical workflow:
32
+ ### 4. Session & Lifecycle Management
33
+ - `session_start`: Captures the stable session ID from Pi (`ctx.sessionManager.getSessionFile()`).
34
+ - `session_shutdown`: Cleans up and flushes dangling observations (e.g., if the user abruptly exits via `Ctrl+C`).
33
35
 
34
- ```bash
35
- npm install
36
- pi "test prompt"
37
- ```
36
+ ## Development & Testing
38
37
 
39
- There is currently no dedicated test suite or `npm` script. When changing behavior, validate by running Pi with the extension enabled and confirming traces, spans, generations, and scores appear in Langfuse.
38
+ 1. **Prerequisites**: Node.js `>=22` and a local `config.json` with Langfuse credentials (`LANGFUSE_PUBLIC_KEY`, `LANGFUSE_SECRET_KEY`, `LANGFUSE_HOST`).
39
+ 2. **Run**:
40
+ ```bash
41
+ npm install
42
+ pi -e ./index.ts "your test prompt"
43
+ ```
44
+ 3. **Validation**: Open your Langfuse dashboard to verify that Traces, Generations, and Tool Spans are accurately grouped, and that token usage/costs are populated.
40
45
 
41
- ## Editing Guidance
42
-
43
- - Prefer small, behavior-preserving changes in `index.ts`; most bugs here are lifecycle or observability-shape bugs rather than UI issues.
44
- - Keep credential material out of version control. `config.json` should stay local.
45
- - When logging tool input/output, be mindful of payload size and serialization failures.
46
- - If you add new Langfuse fields, verify them against current official docs because the SDK surface evolves.
47
- - Avoid hard-coding install-layout assumptions when importing SDK files unless Pi requires it.
48
-
49
- ## Review Focus Areas
50
-
51
- When reviewing or extending this project, pay extra attention to:
52
-
53
- - Trace lifecycle consistency across `before_agent_start`, `agent_end`, and `session_shutdown`
54
- - Correct score attribution at trace level vs observation level
55
- - Defensive handling of unexpected event payload shapes
56
- - Truncation/redaction strategy for large tool payloads
57
- - Compatibility between the installed Langfuse SDK version and any manually declared local TypeScript interfaces
46
+ ## Design Constraints
47
+ - **Statefulness**: The extension maintains module-level state (`state.ts`) because multiple Pi hooks share the same context across an agent run.
48
+ - **Data Safety**: Large tool payloads and circular references are aggressively truncated/shaped to prevent serialization crashes and excessive network overhead.
package/README.md CHANGED
@@ -1,6 +1,11 @@
1
1
  # pi-langfuse
2
2
 
3
- Langfuse observability extension for [Pi Coding Agent](https://github.com/earendil-works/pi-coding-agent). Sends traces to [Langfuse](https://langfuse.com) for monitoring tokens, costs, latency, and tool calls.
3
+ [![npm version](https://img.shields.io/npm/v/pi-langfuse)](https://www.npmjs.com/package/pi-langfuse)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ [**English**](./README.md) | [**简体中文**](./README_CN.md)
7
+
8
+ Langfuse observability extension for [Pi Coding Agent](https://github.com/earendil-works/pi-coding-agent). Sends complete Pi agent runs to [Langfuse](https://langfuse.com) so you can inspect the user prompt, root agent workflow, every LLM generation, every tool call, final assistant response, usage, cost, and health scores in one trace.
4
9
 
5
10
  ## Why Langfuse?
6
11
 
@@ -8,113 +13,319 @@ Langfuse provides open-source observability for LLM applications. This extension
8
13
 
9
14
  ## Features
10
15
 
11
- - **Hierarchical Tracing**: Maps user prompts to per-turn spans and nested tool executions for deep visibility.
12
- - **LLM Metadata**: Automatically records model name, provider, token usage, and API costs per turn.
13
- - **Tool Observability**: Detailed logs for every tool call, including arguments, results, and error states.
14
- - **Session Correlation**: Groups all prompts from the same Pi session into a single Langfuse session.
15
- - **Cost Tracking**: Records input/output/total costs in USD per generation.
16
- - **Token Usage**: Tracks input and output tokens per turn.
16
+ - **Complete Agent Traces**: Creates one trace per user prompt with a root `agent` observation containing the prompt input and final assistant output.
17
+ - **Per-Request Generations**: Records a separate `generation` observation for every provider request, including the actual provider payload instead of only the original prompt.
18
+ - **Final Message Capture**: Uses finalized assistant messages for generation and root outputs, so Langfuse shows what the user actually saw in Pi.
19
+ - **Tool Observability**: Creates Langfuse `tool` observations for every tool call, including arguments, results, and error states.
20
+ - **Parallel Tool Safety**: Correlates tool observations by `toolCallId`, avoiding result mix-ups when Pi runs tools concurrently.
21
+ - **Session Correlation**: Groups traces from the same Pi session under a shared Langfuse session ID.
22
+ - **Cost and Token Tracking**: Records usage and cost details on each generation when Pi/provider payloads expose them.
23
+ - **Evaluation Scores**: Automatically computes and sends tool success rates, error counts, and session health metrics.
24
+ - **Defensive Payload Shaping**: Parses JSON-like strings when possible, limits object depth, and truncates large payloads before upload.
25
+
26
+ ## Highlights
27
+
28
+ `pi-langfuse` is designed to make a Pi run readable as an agent workflow, not just a bag of logs:
29
+
30
+ - The trace input/output mirrors the root `agent` observation, making the run understandable from the Langfuse trace list and detail view.
31
+ - The first generation in a tool-using run can show the assistant's tool-call message, the tool observation shows execution I/O, and the follow-up generation shows the final natural-language answer.
32
+ - Tool failures are marked on the tool observation and reflected in trace-level scores, while later generations still preserve the tool error result in their input history.
33
+ - Shutdown and interrupted runs flush pending telemetry and mark unfinished observations as cancelled/warning instead of silently losing the trace.
17
34
 
18
- ## Quick Install
35
+ ## Prerequisites
36
+
37
+ - **Node.js** >= 22
38
+ - **Pi Coding Agent** installed and configured
39
+ - A **Langfuse** account ([cloud](https://cloud.langfuse.com) or self-hosted)
40
+
41
+ ## Installation
42
+
43
+ ### Option 1: Install via npm (recommended for users)
19
44
 
20
- ### Via npm (recommended)
21
45
  ```bash
22
46
  pi install npm:pi-langfuse
23
47
  ```
24
48
 
49
+ Pi will download the package and register it as an extension.
50
+
51
+ ### Option 2: Install from local source (recommended for development)
52
+
53
+ ```bash
54
+ git clone <your-repo-url>
55
+ cd pi-langfuse
56
+ npm install
57
+ ```
58
+
59
+ Then tell Pi to use it:
60
+
61
+ ```bash
62
+ pi link /path/to/pi-langfuse
63
+ ```
64
+
65
+ Or run Pi from the project directory — Pi auto-discovers extensions in the current directory's `package.json`.
66
+
25
67
  ## Configuration
26
68
 
27
- Get your keys from [Langfuse Cloud](https://cloud.langfuse.com) → Settings → API Keys.
69
+ You need Langfuse API keys. Get them from **Langfuse Cloud****Settings****API Keys**.
28
70
 
29
- On first run, Pi will prompt in the CLI/TUI for:
71
+ There are three ways to configure the extension:
30
72
 
31
- - `LANGFUSE_PUBLIC_KEY`
32
- - `LANGFUSE_SECRET_KEY`
33
- - `LANGFUSE_HOST` (optional, defaults to `https://cloud.langfuse.com`)
73
+ ### Method 1: Interactive setup (easiest)
34
74
 
35
- The extension stores this locally in its own `config.json`, which is ignored by git.
75
+ Run any `pi` command with the extension loaded. On first run without configuration, Pi will prompt you in the CLI or TUI for:
36
76
 
37
- You can also preconfigure it with environment variables instead of using the interactive prompt.
77
+ 1. **Langfuse public key** starts with `pk-lf-...`
78
+ 2. **Langfuse secret key** — starts with `sk-lf-...`
79
+ 3. **Langfuse host** — defaults to `https://cloud.langfuse.com`
38
80
 
39
- To rerun setup later, use:
81
+ The extension saves these to a local `config.json` (ignored by git).
40
82
 
41
- ```bash
83
+ To re-run setup at any time:
84
+
85
+ ```
42
86
  /langfuse-setup
43
87
  ```
44
88
 
89
+ ### Method 2: Environment variables
90
+
91
+ Set these before starting Pi:
92
+
93
+ ```bash
94
+ export LANGFUSE_PUBLIC_KEY="pk-lf-xxxx"
95
+ export LANGFUSE_SECRET_KEY="sk-lf-xxxx"
96
+ export LANGFUSE_BASE_URL="https://cloud.langfuse.com" # optional; LANGFUSE_HOST is also supported
97
+ ```
98
+
99
+ The extension checks the local `config.json` first, then falls back to environment variables.
100
+
101
+ ### Method 3: Local config.json (development only)
102
+
103
+ For local development, create a `config.json` in the project root:
104
+
105
+ ```json
106
+ {
107
+ "publicKey": "pk-lf-xxxx",
108
+ "secretKey": "sk-lf-xxxx",
109
+ "host": "https://cloud.langfuse.com"
110
+ }
111
+ ```
112
+
113
+ > **⚠️ Security**: `config.json` is not tracked by git. Never commit API keys to version control.
114
+
45
115
  ## Usage
46
116
 
47
- ### Run pi with tracing enabled
117
+ ### Basic usage
118
+
119
+ Run Pi as usual — the extension auto-loads and traces every agent run:
48
120
 
49
121
  ```bash
50
- pi "your prompt"
122
+ pi "Explain the architecture of Redis"
51
123
  ```
52
124
 
53
- Pi auto-loads the extension. All sessions will be traced to Langfuse.
125
+ After the session ends, check your [Langfuse dashboard](https://cloud.langfuse.com) for the trace.
126
+
127
+ ### Verify the extension is loaded
128
+
129
+ ```bash
130
+ pi list
131
+ ```
132
+
133
+ You should see `pi-langfuse` in the list of installed packages.
134
+
135
+ ### Multiple sessions
136
+
137
+ Each Pi session gets its own Langfuse session ID. Each user prompt within that Pi session becomes a separate Langfuse trace grouped under the same session.
138
+
139
+ ## Development Setup
140
+
141
+ If you're contributing to this extension:
142
+
143
+ ```bash
144
+ # Clone and install dependencies
145
+ git clone <your-repo-url>
146
+ cd pi-langfuse
147
+ npm install
148
+
149
+ # Type-check your changes
150
+ npm run typecheck
151
+
152
+ # Test with Pi
153
+ pi "test prompt"
154
+ ```
155
+
156
+ ### Project structure
157
+
158
+ ```
159
+ pi-langfuse/
160
+ ├── index.ts # Extension entrypoint and core logic
161
+ ├── package.json # Package metadata
162
+ ├── tsconfig.json # TypeScript configuration
163
+ ├── config.json # Local credentials (git-ignored)
164
+ ├── types/
165
+ │ ├── pi-coding-agent.d.ts # Pi extension API types
166
+ │ └── node-shims.d.ts # Node.js module shims
167
+ ├── .agents/
168
+ │ └── skills/
169
+ │ └── langfuse/
170
+ │ └── SKILL.md # Langfuse CLI skill for data queries
171
+ ├── AGENTS.md # Developer guide (extended)
172
+ ├── README.md # This file
173
+ ├── README_CN.md # Chinese translation
174
+ └── AGENTS_CN.md # Developer guide (Chinese)
175
+ ```
176
+
177
+ ### Validation
178
+
179
+ There is no dedicated test suite yet. To validate changes:
180
+
181
+ 1. Run `npm run typecheck` for TypeScript errors
182
+ 2. Start Pi with the extension enabled
183
+ 3. Run a few prompts
184
+ 4. Confirm traces, the root agent observation, tool observations, generations, and evaluation scores appear in your Langfuse project
54
185
 
55
186
  ## Trace Model
56
187
 
57
188
  ```
58
189
  Trace (name: "pi-agent")
59
190
  ├── Session ID: <pi-session-id>
60
- ├── Metadata: model, provider, cwd
61
- └── Span (name: "tool:<name>")
62
- └── Input/Output logs
63
-
64
- Generation (name: "llm-response")
65
- ├── Model: MiniMax-M2.7
66
- ├── Usage: input/output tokens
67
- └── Cost: input/output/total USD
191
+ ├── input: user prompt, images/context summary when present
192
+ ├── output: final assistant response
193
+ └── Agent observation (name: "pi-agent", type: agent)
194
+ ├── input: current user prompt
195
+ ├── output: final assistant response
196
+ ├── Generation observation (name: "llm-generation", type: generation)
197
+ ├── input: provider request payload / message history
198
+ │ ├── output: finalized assistant message or tool-call message
199
+ │ ├── model, usageDetails, costDetails
200
+ │ └── metadata: provider/request details
201
+ └── Tool observation (name: "<tool-name>", type: tool)
202
+ ├── input: tool parameters
203
+ ├── output: tool result
204
+ └── metadata: toolCallId, isError
68
205
  ```
69
206
 
70
207
  ## What Gets Tracked
71
208
 
72
209
  ### Trace Level
73
- - `input` - User prompt
74
- - `output` - Assistant response
75
- - `sessionId` - Pi session identifier
76
- - `metadata` - Model, provider, cwd
210
+ | Field | Description |
211
+ |-------|-------------|
212
+ | `input` | User prompt, with images/context summary when available |
213
+ | `output` | Final assistant response shown in Pi |
214
+ | `sessionId` | Pi session identifier |
215
+ | `metadata.model` | Model identifier (e.g., "MiniMax-M2.7") |
216
+ | `metadata.provider` | LLM provider name |
217
+ | `metadata.cwd` | Working directory |
218
+
219
+ ### Agent Observation (Root Workflow)
220
+ | Field | Description |
221
+ |-------|-------------|
222
+ | `type` | `agent` |
223
+ | `name` | `pi-agent` |
224
+ | `input` | Current user prompt payload |
225
+ | `output` | Final assistant response |
226
+ | `metadata.sessionId` | Pi session identifier |
227
+ | `metadata.cwd` | Working directory |
228
+ | `metadata.model` | Selected model when available |
229
+ | `metadata.provider` | Provider when available |
230
+
231
+ ### Evaluation Scores (Trace Level)
232
+
233
+ | Score Name | Type | Description |
234
+ |------------|------|-------------|
235
+ | `tool_call_count` | number | Total tool calls in session |
236
+ | `turn_count` | number | Number of assistant turns |
237
+ | `total_tool_errors` | number | Tools that returned errors |
238
+ | `tool_success_rate` | float (0-1) | Ratio of successful tool calls |
239
+ | `session_had_errors` | 0 or 1 | Whether any tool errored |
77
240
 
78
241
  ### Generation Observations (LLM Calls)
79
- - `model` - Model identifier (e.g., "MiniMax-M2.7")
80
- - `usage` - Token counts (input/output/total)
81
- - `costDetails` - Cost breakdown in USD
82
-
83
- ### Span Observations (Tool Calls)
84
- - `name` - Tool name (e.g., "tool:bash")
85
- - `input` - Tool parameters (JSON)
86
- - `output` - Tool result
87
- - `metadata.isError` - Whether tool failed
242
+ | Field | Description |
243
+ |-------|-------------|
244
+ | `type` | `generation` |
245
+ | `name` | `llm-generation` |
246
+ | `input` | Actual provider request payload / message history |
247
+ | `output` | Finalized assistant message, including tool-call payloads for tool-calling turns |
248
+ | `model` | Model identifier (e.g., "MiniMax-M2.7") |
249
+ | `usageDetails.input` | Input token count |
250
+ | `usageDetails.output` | Output token count |
251
+ | `usageDetails.total` | Total token count |
252
+ | `costDetails.total` | Total cost in USD |
253
+ | `costDetails.input` | Input cost in USD |
254
+ | `costDetails.output` | Output cost in USD |
255
+ | `metadata.provider` | Provider name |
256
+ | `metadata.requestId` | Provider/Pi request identifier when available |
257
+ | `metadata.status` | HTTP/provider status when available |
258
+
259
+ ### Tool Observations
260
+ | Field | Description |
261
+ |-------|-------------|
262
+ | `type` | `tool` |
263
+ | `name` | Tool name (e.g., "bash", "read") |
264
+ | `input` | Tool parameters |
265
+ | `output` | Tool result, shaped and truncated for readability |
266
+ | `metadata.toolCallId` | Stable Pi tool call identifier |
267
+ | `metadata.isError` | Whether the tool failed |
268
+ | `level` | `ERROR` for failed tool calls, otherwise `DEFAULT` |
269
+
270
+ ### Observation-Level Scores
271
+ | Score Name | Description |
272
+ |------------|-------------|
273
+ | `tool_is_error` | Value 1 assigned to individual tool observations that errored |
88
274
 
89
275
  ## Langfuse Dashboard
90
276
 
91
277
  After running, check your Langfuse project for:
92
278
 
93
- 1. **Traces** - All pi agent runs with I/O
94
- 2. **Sessions** - Traces grouped by session ID
95
- 3. **Observations** - Tool calls and LLM generations
96
- 4. **Scores** - Evaluation metrics such as tool errors and success rate
97
- 5. **Model Usage** - Usage breakdown by model
279
+ 1. **Traces** All pi agent runs with I/O
280
+ 2. **Sessions** Traces grouped by session ID
281
+ 3. **Observations** Tool calls and LLM generations
282
+ 4. **Scores** Evaluation metrics (tool errors, success rate, etc.)
283
+ 5. **Model Usage** Usage breakdown by model
284
+
285
+ You can also monitor your Langfuse data directly from the terminal using the built-in Langfuse skill:
286
+
287
+ ```
288
+ /pi-langfuse-langfuse <your-query>
289
+ ```
98
290
 
99
291
  ## Troubleshooting
100
292
 
101
- **No traces appearing?**
102
- - Verify API keys are correct in `config.json`
103
- - Check Langfuse project is active
104
- - Ensure API keys have write permissions
293
+ ### No traces appearing?
294
+ - Verify API keys are correct run `/langfuse-setup` to re-configure
295
+ - Check your Langfuse project is active and has write capacity
296
+ - Ensure API keys have write permissions (not read-only)
297
+ - Look for `📊 Langfuse:` log messages in the Pi output
298
+
299
+ ### Extension not loading?
300
+ ```bash
301
+ pi list # Verify pi-langfuse is installed
302
+ pi install npm:pi-langfuse # Reinstall if missing
303
+ ```
304
+
305
+ ### "Missing config" message on startup?
306
+ - The extension needs credentials. Use the interactive `/langfuse-setup` command
307
+ - Or set `LANGFUSE_PUBLIC_KEY` and `LANGFUSE_SECRET_KEY` environment variables
105
308
 
106
- **Extension not loading?**
107
- - Run `pi list` to check installed packages
108
- - Try restarting pi
309
+ ### Model/cost not showing?
310
+ - Not all providers expose cost information
311
+ - Check the Langfuse traces API for raw observation data
312
+ - The `model` field in generations comes from provider events, finalized assistant messages, `model_select`, or `ctx.model`
109
313
 
110
- **Model/cost not showing?**
111
- - Not all providers expose cost info
112
- - Check Langfuse traces API for raw observation data
314
+ ### API key errors?
315
+ - Langfuse public keys start with `pk-lf-`, secret keys with `sk-lf-`
316
+ - If self-hosting, verify your host URL is correct
113
317
 
114
318
  ## Dependencies
115
319
 
116
- - [langfuse](https://www.npmjs.com/package/langfuse) - Langfuse SDK
117
- - [@earendil-works/pi-coding-agent](https://www.npmjs.com/package/@earendil-works/pi-coding-agent) - Pi extension API
320
+ - [@langfuse/tracing](https://www.npmjs.com/package/@langfuse/tracing) Langfuse observation API for `agent`, `generation`, and `tool` traces
321
+ - [@langfuse/otel](https://www.npmjs.com/package/@langfuse/otel) OpenTelemetry span processor for exporting traces to Langfuse
322
+ - [@langfuse/client](https://www.npmjs.com/package/@langfuse/client) — Langfuse API client used for scores
323
+ - [@opentelemetry/sdk-node](https://www.npmjs.com/package/@opentelemetry/sdk-node) — Node OpenTelemetry SDK
324
+ - [@earendil-works/pi-coding-agent](https://www.npmjs.com/package/@earendil-works/pi-coding-agent) — Pi extension API (peer dependency)
325
+
326
+ ## About Langfuse Skill
327
+
328
+ This package includes a Langfuse CLI skill (at `.agents/skills/langfuse/`) that lets you query Langfuse data directly from Pi. Use it to look up traces, prompts, datasets, and scores without leaving the terminal. The skill is auto-registered when the extension is installed globally.
118
329
 
119
330
  ## License
120
331