pi-provider-trace
Pi extension: transparent LLM provider HTTP/SSE wire trace + observability Web UI
Package details
Install pi-provider-trace from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-provider-trace- Package
pi-provider-trace- Version
0.1.1- Published
- Jul 8, 2026
- Downloads
- not available
- Author
- dwsy
- License
- MIT
- Types
- extension
- Size
- 221.5 KB
- Dependencies
- 0 dependencies · 1 peer
Pi manifest JSON
{
"extensions": [
"./src/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-provider-trace
Pi extension for transparent LLM provider debugging: raw HTTP + SSE wire capture, Pi agent lifecycle events, and normalized usage / cost / cache hit rate—all per Pi session.
Tracing is off by default. Enable it only when you need visibility.
Why a hack (globalThis.fetch patch)?
Pi exposes official extension events that are great for billing, payload inspection, and session boundaries—but they are not equivalent to transparent wire-level debugging of LLM provider traffic. This extension targets DevTools/curl-style visibility: real URL/method/headers, response bodies, and line-by-line SSE, browsable per HTTP exchange in the Web UI.
Official hooks vs this extension
| Capability | Pi official | Enough without fetch patch? |
|---|---|---|
| Logical request payload | before_provider_request |
✅ Payload logging / rewrite |
| Status + response headers (before stream read) | after_provider_response |
✅ Meta only—no body |
| SSE / streaming body | ❌ Not exposed (pi-ai consumes the stream) | ❌ |
| Raw HTTP request (as on the wire / via proxy) | ❌ Only serialized payload object | ❌ |
| Tokens / cost / timing per assistant message | message_end |
✅ For accounting—not a packet trace |
| Session boundaries | session_start / session_shutdown |
✅ |
Timeline (turns, tools, /tree, /compact) |
Many separate pi.on events |
⚠️ No shared exchange id with HTTP |
after_provider_response is intentionally fired before the response stream is consumed—so official hooks cannot reproduce the Stream SSE tab (event types, deltas, reassembled text).
Two-layer design
Hack layer (opt-in via
/trace onorpi --trace)
PatchesglobalThis.fetch, tees response bodies, logsrequest/response_meta/sse_line, and folds provider usage from SSE intollm_usage. This is the practical way to get wire transparency while pi-ai uses globalfetch.Official + extension events
before_provider_request→provider-payload.jsonl;message_end/turn_endfor Pi-side usage; turns, tools, tree/compact hooks →pi_event, merged on the timeline by timestamp.
Payload + headers + per-turn usage only? Use Pi’s examples/extensions/provider-payload.ts—no fetch patch required.
Full SSE / wire troubleshooting? You need this extension’s hack layer—hence default off and explicit /trace on (patching fetch is invasive).
Hack-layer limits
- Only traffic through
globalThis.fetch; custom transports may be missed. - Heuristic LLM URL filter (
trace-fetch.ts). - Same family of idea as
pi-model-selector-x(runtime patch), but on the network layer, not TUI prototypes.
Features
| Layer | What you get |
|---|---|
| HTTP (hack) | Patches globalThis.fetch, tees response bodies, logs request/response/SSE lines without breaking pi-ai consumers |
| Pi events | Subscribes to extension lifecycle (input, turns, tools, before_provider_request, session tree/compact/switch/fork, etc.) as pi_event |
| Usage | Parses provider SSE (Anthropic, OpenAI Responses/Completions, …) and Pi message_end / turn_end usage → llm_usage |
| Web UI | Factory-style static UI (public/), configurable port (default 32211), session history, timeline, usage, download/delete |
| i18n | Auto zh (China TZ or zh browser lang), else en; manual override in UI (pi-trace-locale) |
Requirements
- Pi coding agent (
@earendil-works/pi-coding-agent)
npm install -g @earendil-works/pi-coding-agent
Installation
npm (recommended):
pi install npm:pi-provider-trace
Git:
pi install git:github.com/Dwsy/pi-provider-trace
If the extension is not auto-enabled, add to ~/.pi/agent/settings.json:
"+extensions/pi-provider-trace/src/index.ts"
Restart Pi after install or settings change.
Quick start
pi --trace # CLI: same as /trace on at session start (skip in --mode rpc)
/trace on # start capture (bound to current Pi session)
/trace ui # open http://127.0.0.1:32211/
/trace off # stop capture (logs remain on disk)
/trace path # show log root directory
Slash commands
| Command | Description |
|---|---|
/trace |
Status and help |
pi --trace |
Enable tracing when Pi starts + start Web UI (no auto browser) |
/trace on |
Enable capture + start Web UI (prints URL; does not open browser) |
/trace off |
Disable capture |
/trace ui |
Start Web UI (reuses server; does not open browser) |
/trace port [n] |
Show or set UI port (persisted to ui-config.json) |
/trace path |
Log root ~/.pi/provider-trace |
On-disk layout
~/.pi/provider-trace/
registry.json
sessions/<sessionKey>/
http-sse.jsonl
provider-payload.jsonl
- sessionKey: Pi session file stem, or
cwd-…without a session file. - Auth headers are redacted in logs.
Web UI port
Priority: runtime /trace port N (saved) → ~/.pi/provider-trace/ui-config.json → PI_PROVIDER_TRACE_UI_PORT → default 32211.
Web UI (http://127.0.0.1:<port>/)
Design: Factory theme — see docs/design/factory-style-reference.md. Static assets: public/index.html, public/css/*, public/js/* (ES modules, no npm); see public/js/README.md.
- Three columns: Pi sessions → HTTP exchanges → detail (stream / request headers & body / response / raw)
- Tabs: Overview, Timeline, Stream SSE, Usage, etc.
- Theme: light / dark / system (
pi-trace-themein localStorage) - JSON/Markdown
preblocks: lightweight highlight + copy button - Download JSONL / delete session traces
- Live updates:
/api/stream?session=<key>(history via/api/history)
Trace record kinds
kind |
Source |
|---|---|
request / response_meta / sse_line / error |
HTTP fetch patch |
pi_event |
Pi extension lifecycle (incl. /tree, /compact, switch/fork) |
llm_usage |
SSE fold + message_end / turn_end |
Cache hit rate: cacheRead / (input + cacheRead). Costs use pi-ai usage.cost when present.
Limitations
- Captures traffic via
globalThis.fetchonly. - Heuristic LLM URL filter in
trace-fetch.ts. - Configured port must be free (
EADDRINUSEotherwise). - UI is 127.0.0.1 only—logs may contain prompts; keep local.
Module map
src/index.ts · src/trace-fetch.ts · public/ (HTML/CSS/JS) · src/web-ui.ts · src/logger.ts
Observability API
GET /api/metrics?session=— trace + generation metrics (Langfuse-aligned fields, local only)GET/POST /api/scores?session=— numeric scoresGET /api/media?session=&exchange=— multimodal refs- Architecture:
docs/observability-architecture.md,src/observability/processors/
Langfuse production export: future work, not in this release. Stub only — see
docs/future-langfuse.md.
- Optional
PI_PROVIDER_TRACE_WRITE_OBSERVATION=1for localkind: observationlines (not Langfuse export)