pi-provider-trace

Pi extension: transparent LLM provider HTTP/SSE wire trace + observability Web UI

Packages

Package details

extension

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

  1. Hack layer (opt-in via /trace on or pi --trace)
    Patches globalThis.fetch, tees response bodies, logs request / response_meta / sse_line, and folds provider usage from SSE into llm_usage. This is the practical way to get wire transparency while pi-ai uses global fetch.

  2. Official + extension events
    before_provider_requestprovider-payload.jsonl; message_end / turn_end for 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.jsonPI_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-theme in localStorage)
  • JSON/Markdown pre blocks: 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.fetch only.
  • Heuristic LLM URL filter in trace-fetch.ts.
  • Configured port must be free (EADDRINUSE otherwise).
  • 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 scores
  • GET /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=1 for local kind: observation lines (not Langfuse export)