Skip to content

Repository files navigation

pi-agent-proxy

An X-ray of what pi puts on the wire.

A zero-dependency pi native observer extension, so there is no HTTP proxy, no port, and no base-URL rewiring. It hooks pi's extension events instead:

The HTTP-proxy way pi-agent-proxy
Passes requests through verbatim before_provider_request → observes event.payload, returns undefined
Never touches the reply stream pi streams natively, extension stays out of it
Reassemble SSE to recover the reply message_end hands over the parsed assistant message + usage

Lifecycle

sequenceDiagram
    participant P as pi core
    participant X as pi-agent-proxy
    participant D as disk (.pi/pi-agent-proxy/SESSION/)

    P->>X: before_provider_request(payload)
    opt previous request still pending (no assistant message)
        X->>D: flush it marked *no reply captured*
    end
    X->>X: stash payload as pending
    X--)P: return undefined (observe only)
    P->>X: after_provider_response(status, headers)
    X->>X: attach to pending
    alt message_end(assistant message)
        X->>D: NNN-TIMESTAMP-MODEL.md + .json sidecar (0600)
    else hard failure / abort / shutdown
        X->>D: flushed on next request or session_shutdown
    end
Loading

Every provider request writes one readable Markdown document (plus a .json sidecar with the raw payload), opening with a size-ranked breakdown of where your context budget goes:

<audit>

**48,213 input tokens** charged on this call, per the response usage block.

- **tools**: 14 definitions, 61,204 bytes (~15,301 tokens)
- **system prompt**: 38,902 bytes (~9,725 tokens)
- **message history**: 412,338 bytes (~103,084 tokens)
- **envelope & params**: 1,842 bytes
- **total request**: 514,286 bytes

**Tool inventory, biggest first — trim from the top:**

| tool | bytes | ~tokens | % of request |
| --- | --: | --: | --: |
| read | 12,442 | ~3,110 | 2.4% |
| bash | 10,018 | ~2,504 | 1.9% |

followed by the full system prompt, every tool definition, the entire message history rendered as readable XML-ish blocks (<message>, <tool-use>, <tool-result>, <thinking>), and the assistant's reply with token/cost usage.

Install

pi install npm:pi-agent-proxy

Or straight from git:

pi install git:github.com/TheAkshitS/pi-agent-proxy

To try it without installing: pi -e git:github.com/TheAkshitS/pi-agent-proxy.

Or manually, symlink the cloned repo into pi's global extension directory:

git clone https://github.com/TheAkshitS/pi-agent-proxy
ln -s "$PWD/pi-agent-proxy" ~/.pi/agent/extensions/pi-agent-proxy

Then start pi normally (or /reload if it's already running). A footer status shows N logged once requests flow; failed requests are logged too (marked no reply captured).

Config & commands

  • PI_AGENT_PROXY_DIR — log root. Default: the working project's config dir, <cwd>/.pi/pi-agent-proxy/<session>/ (falls back to ~/.pi/agent/pi-agent-proxy/). Gitignore .pi/pi-agent-proxy/ in projects you use it in — each request dumps ~200KB.
  • /proxy-log — prints where the current session's logs live.

Files

Per request: 001-<timestamp>-<model>.md (readable document) and a .json sidecar with the raw provider payload (pretty-printed). Untrusted message/tool text in the .md has < escaped (\<) so logged content can't forge audit structure; fenced JSON blocks auto-lengthen so injected backticks can't break out.

Logs contain the full request payload — system prompt, tool results, file contents — in plaintext. Treat the log directory like session transcripts: files are written owner-only (0600, dirs 0700), keep it that way.

Dev

node test.ts  # self-check: region extraction + rendering across anthropic-messages,
              # openai-completions, openai-responses payloads (Node ≥23.6 runs TS natively)
npx tsc -p tsconfig.json

License

MIT

Credits

Inspired by Matt Pocock's provider-proxy gist.

About

A zero-dependency pi native observer extension, so there is no HTTP proxy, no port, and no base-URL rewiring

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages