pi-langfuse 1.4.2 → 1.4.4
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 +104 -248
- package/README_CN.md +108 -248
- package/image.png +0 -0
- package/index.ts +5 -3
- package/package.json +2 -1
- package/src/capture-policy.ts +141 -0
- package/src/config.ts +21 -12
- package/src/constants.ts +1 -0
- package/src/handlers/agent.ts +61 -29
- package/src/handlers/generation.ts +58 -59
- package/src/handlers/tool.ts +40 -27
- package/src/handlers/turn.ts +23 -21
- package/src/langfuse.ts +78 -17
- package/src/observation.ts +21 -0
- package/src/redaction.ts +115 -0
- package/src/state.ts +25 -2
- package/src/types.ts +3 -0
- package/src/utils.ts +54 -5
- package/types/langfuse-runtime-shims.d.ts +49 -0
package/README.md
CHANGED
|
@@ -5,34 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
[**English**](./README.md) | [**简体中文**](./README_CN.md)
|
|
7
7
|
|
|
8
|
-
Langfuse observability extension for [Pi Coding Agent](https://github.com/earendil-works/pi-coding-agent).
|
|
8
|
+
Langfuse observability extension for [Pi Coding Agent](https://github.com/earendil-works/pi-coding-agent). It sends complete Pi runs to [Langfuse](https://langfuse.com) so the prompt, agent workflow, LLM generations, tool calls, final response, usage, cost, and health scores appear in one trace.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## What This Adds to Pi
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- **Per-Request Generations**: Records a separate `generation` observation for every provider request, including the actual provider payload instead of only the original prompt.
|
|
19
|
-
- **Final Message Capture**: Uses finalized assistant messages for generation and root outputs, so Langfuse shows what the user actually saw in Pi.
|
|
20
|
-
- **Tool Observability**: Creates Langfuse `tool` observations for every tool call, including arguments, results, error states, and payload/latency metrics.
|
|
21
|
-
- **Parallel Tool Safety**: Correlates tool observations by `toolCallId`, avoiding result mix-ups when Pi runs tools concurrently.
|
|
22
|
-
- **Session Correlation**: Groups traces from the same Pi session under a shared Langfuse session ID.
|
|
23
|
-
- **Cost and Token Tracking**: Records usage and cost details on each generation when Pi/provider payloads expose them.
|
|
24
|
-
- **Evaluation Scores**: Automatically computes and sends tool success rates, error counts, and session health metrics.
|
|
25
|
-
- **Defensive Payload Shaping**: Parses JSON-like strings when possible, limits object depth, and truncates large payloads before upload.
|
|
26
|
-
|
|
27
|
-
## Highlights
|
|
28
|
-
|
|
29
|
-
`pi-langfuse` is designed to make a Pi run readable as an agent workflow, not just a bag of logs:
|
|
30
|
-
|
|
31
|
-
- The trace input/output mirrors the root `agent` observation, making the run understandable from the Langfuse trace list and detail view.
|
|
32
|
-
- 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.
|
|
33
|
-
- 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.
|
|
34
|
-
- Shutdown and interrupted runs flush pending telemetry and mark unfinished observations as cancelled/warning instead of silently losing the trace.
|
|
35
|
-
- Agent-end runtime shutdown is deferred so Langfuse flushing does not block Pi's visible turn completion.
|
|
12
|
+
- One Langfuse trace per user prompt, grouped by Pi session.
|
|
13
|
+
- Root `agent`, per-request `generation`, and per-tool `tool` observations.
|
|
14
|
+
- Final assistant output capture, tool error visibility, and trace-level scores.
|
|
15
|
+
- Privacy controls for inputs, outputs, tool I/O, system prompt, and cwd.
|
|
16
|
+
- Secret redaction and local path hashing before upload.
|
|
17
|
+
- REST fallback for self-hosted Langfuse setups where OTel spans arrive but traces do not materialize.
|
|
36
18
|
|
|
37
19
|
## Prerequisites
|
|
38
20
|
|
|
@@ -40,55 +22,42 @@ Langfuse provides open-source observability for LLM applications. This extension
|
|
|
40
22
|
- **Pi Coding Agent** installed and configured
|
|
41
23
|
- A **Langfuse** account ([cloud](https://cloud.langfuse.com) or self-hosted)
|
|
42
24
|
|
|
43
|
-
##
|
|
25
|
+
## Quick Start
|
|
44
26
|
|
|
45
|
-
|
|
27
|
+
1. Install the extension:
|
|
46
28
|
|
|
47
|
-
```bash
|
|
48
|
-
pi install npm:pi-langfuse
|
|
49
|
-
```
|
|
29
|
+
```bash
|
|
30
|
+
pi install npm:pi-langfuse
|
|
31
|
+
```
|
|
50
32
|
|
|
51
|
-
Pi
|
|
33
|
+
2. Run Pi once. If no credentials are configured yet, Pi prompts for:
|
|
34
|
+
- Langfuse public key, starting with `pk-lf-...`
|
|
35
|
+
- Langfuse secret key, starting with `sk-lf-...`
|
|
36
|
+
- Langfuse host, defaulting to `https://cloud.langfuse.com`
|
|
52
37
|
|
|
53
|
-
|
|
38
|
+
3. Run Pi normally:
|
|
54
39
|
|
|
55
|
-
```bash
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
npm install
|
|
59
|
-
```
|
|
40
|
+
```bash
|
|
41
|
+
pi "Explain the architecture of Redis"
|
|
42
|
+
```
|
|
60
43
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
pi link /path/to/pi-langfuse
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Or run Pi from the project directory — Pi auto-discovers extensions in the current directory's `package.json`.
|
|
44
|
+
4. Open Langfuse and inspect the new trace.
|
|
68
45
|
|
|
69
46
|
## Configuration
|
|
70
47
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
There are three ways to configure the extension:
|
|
48
|
+
Langfuse API keys are available in **Langfuse Cloud** -> **Settings** -> **API Keys**.
|
|
74
49
|
|
|
75
|
-
### Method 1: Interactive setup
|
|
50
|
+
### Method 1: Interactive setup
|
|
76
51
|
|
|
77
|
-
Run any `pi` command with the extension loaded. On first run without configuration, Pi
|
|
52
|
+
Run any `pi` command with the extension loaded. On first run without configuration, Pi prompts in the CLI or TUI and saves the result to `~/.pi/agent/pi-langfuse/config.json`.
|
|
78
53
|
|
|
79
|
-
|
|
80
|
-
2. **Langfuse secret key** — starts with `sk-lf-...`
|
|
81
|
-
3. **Langfuse host** — defaults to `https://cloud.langfuse.com`
|
|
54
|
+
To run setup again:
|
|
82
55
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
To re-run setup at any time:
|
|
86
|
-
|
|
87
|
-
```
|
|
56
|
+
```text
|
|
88
57
|
/langfuse-setup
|
|
89
58
|
```
|
|
90
59
|
|
|
91
|
-
### Method 2: Environment variables
|
|
60
|
+
### Method 2: Environment variables
|
|
92
61
|
|
|
93
62
|
Set these before starting Pi:
|
|
94
63
|
|
|
@@ -98,238 +67,125 @@ export LANGFUSE_SECRET_KEY="sk-lf-xxxx"
|
|
|
98
67
|
export LANGFUSE_BASE_URL="https://cloud.langfuse.com" # optional; LANGFUSE_HOST is also supported
|
|
99
68
|
```
|
|
100
69
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
### Method 3: Persistent config.json
|
|
70
|
+
Saved config takes precedence. Environment variables are only used when `~/.pi/agent/pi-langfuse/config.json` is missing or incomplete.
|
|
104
71
|
|
|
105
|
-
|
|
72
|
+
Privacy controls can also be set through environment variables:
|
|
106
73
|
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
"publicKey": "pk-lf-xxxx",
|
|
110
|
-
"secretKey": "sk-lf-xxxx",
|
|
111
|
-
"host": "https://cloud.langfuse.com"
|
|
112
|
-
}
|
|
74
|
+
```bash
|
|
75
|
+
export LANGFUSE_PRIVACY_PRESET="full-debug"
|
|
113
76
|
```
|
|
114
77
|
|
|
115
|
-
|
|
78
|
+
Available presets:
|
|
116
79
|
|
|
117
|
-
|
|
80
|
+
| Preset | Captures |
|
|
81
|
+
|--------|----------|
|
|
82
|
+
| `metadata-only` | Metadata only; omits inputs, outputs, tool I/O, system prompt, and cwd |
|
|
83
|
+
| `prompts-only` | Prompt/provider inputs plus metadata |
|
|
84
|
+
| `conversations` | Inputs and assistant outputs, but omits tool I/O, system prompt, and cwd |
|
|
85
|
+
| `full-debug` | Full trace detail; this is the default |
|
|
118
86
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
Run Pi as usual — the extension auto-loads and traces every agent run:
|
|
87
|
+
Fine-grained flags override presets:
|
|
122
88
|
|
|
123
89
|
```bash
|
|
124
|
-
|
|
90
|
+
export LANGFUSE_CAPTURE_INPUTS=true
|
|
91
|
+
export LANGFUSE_CAPTURE_OUTPUTS=true
|
|
92
|
+
export LANGFUSE_CAPTURE_TOOL_IO=false
|
|
93
|
+
export LANGFUSE_CAPTURE_SYSTEM_PROMPT=false
|
|
94
|
+
export LANGFUSE_CAPTURE_CWD=false
|
|
125
95
|
```
|
|
126
96
|
|
|
127
|
-
|
|
97
|
+
All captured payloads are redacted before upload. The extension masks common API keys, bearer tokens, passwords, cookies, private keys, Langfuse keys, GitHub/npm/AWS-style tokens, and local absolute paths.
|
|
128
98
|
|
|
129
|
-
###
|
|
99
|
+
### Method 3: Persistent `config.json`
|
|
130
100
|
|
|
131
|
-
|
|
132
|
-
|
|
101
|
+
Create or update `~/.pi/agent/pi-langfuse/config.json`:
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"publicKey": "pk-lf-xxxx",
|
|
106
|
+
"secretKey": "sk-lf-xxxx",
|
|
107
|
+
"host": "https://cloud.langfuse.com",
|
|
108
|
+
"privacyPreset": "conversations"
|
|
109
|
+
}
|
|
133
110
|
```
|
|
134
111
|
|
|
135
|
-
|
|
112
|
+
Fine-grained capture flags can also be persisted:
|
|
136
113
|
|
|
137
|
-
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"publicKey": "pk-lf-xxxx",
|
|
117
|
+
"secretKey": "sk-lf-xxxx",
|
|
118
|
+
"host": "https://cloud.langfuse.com",
|
|
119
|
+
"capture": {
|
|
120
|
+
"LANGFUSE_PRIVACY_PRESET": "metadata-only",
|
|
121
|
+
"LANGFUSE_CAPTURE_INPUTS": "true"
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
138
125
|
|
|
139
|
-
|
|
126
|
+
> **Security**: Keep `~/.pi/agent/pi-langfuse/config.json` private. Never commit API keys to version control.
|
|
140
127
|
|
|
141
|
-
##
|
|
128
|
+
## Verify the Extension
|
|
142
129
|
|
|
143
|
-
|
|
130
|
+
Check that Pi has loaded the package:
|
|
144
131
|
|
|
145
132
|
```bash
|
|
146
|
-
|
|
147
|
-
git clone <your-repo-url>
|
|
148
|
-
cd pi-langfuse
|
|
149
|
-
npm install
|
|
150
|
-
|
|
151
|
-
# Type-check your changes
|
|
152
|
-
npm run typecheck
|
|
153
|
-
|
|
154
|
-
# Test with Pi
|
|
155
|
-
pi "test prompt"
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### Project structure
|
|
159
|
-
|
|
160
|
-
```
|
|
161
|
-
pi-langfuse/
|
|
162
|
-
├── index.ts # Extension entrypoint and core logic
|
|
163
|
-
├── package.json # Package metadata
|
|
164
|
-
├── tsconfig.json # TypeScript configuration
|
|
165
|
-
├── types/
|
|
166
|
-
│ ├── pi-coding-agent.d.ts # Pi extension API types
|
|
167
|
-
│ └── node-shims.d.ts # Node.js module shims
|
|
168
|
-
├── .agents/
|
|
169
|
-
│ └── skills/
|
|
170
|
-
│ └── langfuse/
|
|
171
|
-
│ └── SKILL.md # Langfuse CLI skill for data queries
|
|
172
|
-
├── AGENTS.md # Developer guide (extended)
|
|
173
|
-
├── README.md # This file
|
|
174
|
-
├── README_CN.md # Chinese translation
|
|
175
|
-
└── AGENTS_CN.md # Developer guide (Chinese)
|
|
133
|
+
pi list
|
|
176
134
|
```
|
|
177
135
|
|
|
178
|
-
|
|
136
|
+
`pi-langfuse` should appear in the installed package list.
|
|
179
137
|
|
|
180
|
-
|
|
138
|
+
## What Appears in Langfuse
|
|
181
139
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
140
|
+
- Each Pi session gets its own Langfuse session ID.
|
|
141
|
+
- Each user prompt within that session becomes a separate trace.
|
|
142
|
+
- The trace contains the final assistant output shown in Pi.
|
|
143
|
+
- Tool runs appear as tool observations with arguments, results, and error state.
|
|
144
|
+
- LLM requests appear as generation observations, including usage and cost when the provider exposes them.
|
|
145
|
+
- Trace-level scores include tool counts, tool success rate, and whether the run had errors.
|
|
186
146
|
|
|
187
|
-
|
|
147
|
+
The package also includes a Langfuse CLI skill, so Langfuse data can be queried directly from Pi:
|
|
188
148
|
|
|
189
|
-
```
|
|
190
|
-
Trace (name: "pi-agent")
|
|
191
|
-
├── Session ID: <pi-session-id>
|
|
192
|
-
├── input: user prompt, images/context summary when present
|
|
193
|
-
├── output: final assistant response
|
|
194
|
-
└── Agent observation (name: "pi-agent", type: agent)
|
|
195
|
-
├── input: current user prompt
|
|
196
|
-
├── output: final assistant response
|
|
197
|
-
├── Generation observation (name: "llm-generation", type: generation)
|
|
198
|
-
│ ├── input: provider request payload / message history
|
|
199
|
-
│ ├── output: finalized assistant message or tool-call message
|
|
200
|
-
│ ├── model, usageDetails, costDetails
|
|
201
|
-
│ └── metadata: provider/request details
|
|
202
|
-
└── Tool observation (name: "<tool-name>", type: tool)
|
|
203
|
-
├── input: tool parameters
|
|
204
|
-
├── output: tool result
|
|
205
|
-
└── metadata: toolCallId, isError
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
## What Gets Tracked
|
|
209
|
-
|
|
210
|
-
### Trace Level
|
|
211
|
-
| Field | Description |
|
|
212
|
-
|-------|-------------|
|
|
213
|
-
| `input` | User prompt, with images/context summary when available |
|
|
214
|
-
| `output` | Final assistant response shown in Pi |
|
|
215
|
-
| `sessionId` | Pi session identifier |
|
|
216
|
-
| `metadata.model` | Model identifier (e.g., "MiniMax-M2.7") |
|
|
217
|
-
| `metadata.provider` | LLM provider name |
|
|
218
|
-
| `metadata.cwd` | Working directory |
|
|
219
|
-
|
|
220
|
-
### Agent Observation (Root Workflow)
|
|
221
|
-
| Field | Description |
|
|
222
|
-
|-------|-------------|
|
|
223
|
-
| `type` | `agent` |
|
|
224
|
-
| `name` | `pi-agent` |
|
|
225
|
-
| `input` | Current user prompt payload |
|
|
226
|
-
| `output` | Final assistant response |
|
|
227
|
-
| `metadata.sessionId` | Pi session identifier |
|
|
228
|
-
| `metadata.cwd` | Working directory |
|
|
229
|
-
| `metadata.model` | Selected model when available |
|
|
230
|
-
| `metadata.provider` | Provider when available |
|
|
231
|
-
|
|
232
|
-
### Evaluation Scores (Trace Level)
|
|
233
|
-
|
|
234
|
-
| Score Name | Type | Description |
|
|
235
|
-
|------------|------|-------------|
|
|
236
|
-
| `tool_call_count` | number | Total tool calls in session |
|
|
237
|
-
| `turn_count` | number | Number of assistant turns |
|
|
238
|
-
| `total_tool_errors` | number | Tools that returned errors |
|
|
239
|
-
| `tool_success_rate` | float (0-1) | Ratio of successful tool calls |
|
|
240
|
-
| `session_had_errors` | 0 or 1 | Whether any tool errored |
|
|
241
|
-
|
|
242
|
-
### Generation Observations (LLM Calls)
|
|
243
|
-
| Field | Description |
|
|
244
|
-
|-------|-------------|
|
|
245
|
-
| `type` | `generation` |
|
|
246
|
-
| `name` | `llm-generation` |
|
|
247
|
-
| `input` | Actual provider request payload / message history |
|
|
248
|
-
| `output` | Finalized assistant message, including tool-call payloads for tool-calling turns |
|
|
249
|
-
| `model` | Model identifier (e.g., "MiniMax-M2.7") |
|
|
250
|
-
| `usageDetails.input` | Input token count |
|
|
251
|
-
| `usageDetails.output` | Output token count |
|
|
252
|
-
| `usageDetails.total` | Total token count |
|
|
253
|
-
| `costDetails.total` | Total cost in USD |
|
|
254
|
-
| `costDetails.input` | Input cost in USD |
|
|
255
|
-
| `costDetails.output` | Output cost in USD |
|
|
256
|
-
| `metadata.provider` | Provider name |
|
|
257
|
-
| `metadata.requestId` | Provider/Pi request identifier when available |
|
|
258
|
-
| `metadata.status` | HTTP/provider status when available |
|
|
259
|
-
|
|
260
|
-
### Tool Observations
|
|
261
|
-
| Field | Description |
|
|
262
|
-
|-------|-------------|
|
|
263
|
-
| `type` | `tool` |
|
|
264
|
-
| `name` | Tool name (e.g., "bash", "read") |
|
|
265
|
-
| `input` | Tool parameters |
|
|
266
|
-
| `output` | Tool result, shaped and truncated for readability |
|
|
267
|
-
| `metadata.toolCallId` | Stable Pi tool call identifier |
|
|
268
|
-
| `metadata.isError` | Whether the tool failed |
|
|
269
|
-
| `metadata.durationMs` | Approximate tool runtime in milliseconds |
|
|
270
|
-
| `metadata.inputBytes` | UTF-8 byte size of the shaped tool input payload |
|
|
271
|
-
| `metadata.outputBytes` | UTF-8 byte size of the shaped tool output payload |
|
|
272
|
-
| `level` | `ERROR` for failed tool calls, otherwise `DEFAULT` |
|
|
273
|
-
|
|
274
|
-
### Observation-Level Scores
|
|
275
|
-
| Score Name | Description |
|
|
276
|
-
|------------|-------------|
|
|
277
|
-
| `tool_is_error` | Value 1 assigned to individual tool observations that errored |
|
|
278
|
-
|
|
279
|
-
## Langfuse Dashboard
|
|
280
|
-
|
|
281
|
-
After running, check your Langfuse project for:
|
|
282
|
-
|
|
283
|
-
1. **Traces** — All pi agent runs with I/O
|
|
284
|
-
2. **Sessions** — Traces grouped by session ID
|
|
285
|
-
3. **Observations** — Tool calls and LLM generations
|
|
286
|
-
4. **Scores** — Evaluation metrics (tool errors, success rate, etc.)
|
|
287
|
-
5. **Model Usage** — Usage breakdown by model
|
|
288
|
-
|
|
289
|
-
You can also monitor your Langfuse data directly from the terminal using the built-in Langfuse skill:
|
|
290
|
-
|
|
291
|
-
```
|
|
149
|
+
```text
|
|
292
150
|
/pi-langfuse-langfuse <your-query>
|
|
293
151
|
```
|
|
294
152
|
|
|
295
153
|
## Troubleshooting
|
|
296
154
|
|
|
297
155
|
### No traces appearing?
|
|
298
|
-
|
|
299
|
-
-
|
|
300
|
-
-
|
|
301
|
-
-
|
|
156
|
+
|
|
157
|
+
- Verify the API keys and run `/langfuse-setup` again if needed.
|
|
158
|
+
- Confirm the Langfuse project is active and accepts writes.
|
|
159
|
+
- Confirm the keys have write permission.
|
|
160
|
+
- Look for `📊 Langfuse:` log messages in Pi output.
|
|
302
161
|
|
|
303
162
|
### Extension not loading?
|
|
163
|
+
|
|
304
164
|
```bash
|
|
305
|
-
pi list
|
|
306
|
-
pi install npm:pi-langfuse
|
|
165
|
+
pi list
|
|
166
|
+
pi install npm:pi-langfuse
|
|
307
167
|
```
|
|
308
168
|
|
|
309
|
-
### "Missing config"
|
|
310
|
-
- The extension needs credentials. Use the interactive `/langfuse-setup` command
|
|
311
|
-
- Or set `LANGFUSE_PUBLIC_KEY` and `LANGFUSE_SECRET_KEY` environment variables
|
|
169
|
+
### "Missing config" on startup?
|
|
312
170
|
|
|
313
|
-
|
|
314
|
-
-
|
|
315
|
-
- Check the Langfuse traces API for raw observation data
|
|
316
|
-
- The `model` field in generations comes from provider events, finalized assistant messages, `model_select`, or `ctx.model`
|
|
171
|
+
- Run `/langfuse-setup`.
|
|
172
|
+
- Or set `LANGFUSE_PUBLIC_KEY` and `LANGFUSE_SECRET_KEY` before starting Pi.
|
|
317
173
|
|
|
318
|
-
###
|
|
319
|
-
|
|
320
|
-
-
|
|
174
|
+
### Model or cost not showing?
|
|
175
|
+
|
|
176
|
+
- Some providers do not expose cost information.
|
|
177
|
+
- Inspect the raw observation data in Langfuse traces.
|
|
178
|
+
- The `model` field can come from provider events, finalized assistant messages, `model_select`, or `ctx.model`.
|
|
321
179
|
|
|
322
|
-
|
|
180
|
+
### API key errors?
|
|
323
181
|
|
|
324
|
-
-
|
|
325
|
-
-
|
|
326
|
-
-
|
|
327
|
-
- [@opentelemetry/sdk-node](https://www.npmjs.com/package/@opentelemetry/sdk-node) — Node OpenTelemetry SDK
|
|
328
|
-
- [@earendil-works/pi-coding-agent](https://www.npmjs.com/package/@earendil-works/pi-coding-agent) — Pi extension API (peer dependency)
|
|
182
|
+
- Public keys start with `pk-lf-`.
|
|
183
|
+
- Secret keys start with `sk-lf-`.
|
|
184
|
+
- For self-hosted deployments, verify the host URL.
|
|
329
185
|
|
|
330
|
-
##
|
|
186
|
+
## Development Docs
|
|
331
187
|
|
|
332
|
-
|
|
188
|
+
Development setup, source installation, runtime architecture, trace model, tracked fields, and validation steps are documented in [DEVELOPMENT.md](./DEVELOPMENT.md) and [DEVELOPMENT_CN.md](./DEVELOPMENT_CN.md).
|
|
333
189
|
|
|
334
190
|
## License
|
|
335
191
|
|