Skip to main content
When a coding agent misbehaves, the agent’s UI rarely tells you why. A tool call silently does nothing, a request fails with “provider error”, the model ignores your system prompt, or a short session costs far more than you expected. Most of the time the answer is sitting in the HTTP traffic between the agent and Venice, which you normally can’t see. In this guide, we’ll run a small proxy on your own machine that sits between the agent and the Venice API. The agent talks to the proxy, the proxy forwards everything to Venice unchanged, and every request and response gets written to a local log file you can search with jq.

See the real request

Model ID, messages, tools, and parameters exactly as the agent sent them

Streaming intact

Chunks are forwarded as they arrive, so the agent behaves normally

No dependencies

One file, Node.js 18 or later, nothing to install

How it works

The proxy forwards the full path and your Authorization header, so your API key stays in the agent’s config and every Venice endpoint works through it: /chat/completions, /responses, /models, /embeddings, and the rest. The only change you make to the agent is the base URL. For each request, the proxy logs:
  • The method, path, and request body, with your API key masked to its last four characters
  • The response status and body. Streamed responses are stored as a list of parsed chunks.
  • Token usage, from the usage object Venice returns
  • Total duration and time to first byte
  • x-venice-* and x-ratelimit-* response headers, such as remaining balance, rate-limit state, and model deprecation warnings
This is a debugging tool for your own machine. It binds to 127.0.0.1 only, has no authentication of its own, and writes prompts and code to disk in plain text. Don’t deploy it as a shared gateway. If you need one, see Building a Rust LLM Gateway.

Prerequisites


Setup

1

Create the proxy

Save this as venice-debug-proxy.mjs in a scratch directory:
venice-debug-proxy.mjs
There’s a few things worth pointing out here:
  • Streaming works normally. Each chunk from Venice is written to the agent the moment it arrives, and a copy is kept for the log. The agent sees the same token-by-token stream it would get from Venice directly.
  • Compression is handled for you. Node’s fetch decompresses the response, so the proxy drops content-encoding before passing headers on. Otherwise the agent would try to decompress plain text and fail.
  • Disconnects are passed on. If you cancel a turn in the agent, the proxy aborts the upstream request too, so Venice doesn’t keep generating tokens nobody reads.
2

Start it

You should see:
Set PORT or LOG_FILE in the environment to change either default.
3

Check it with curl

In a second terminal, send a request through the proxy:
The proxy prints one line per request:
That’s a lot of prompt tokens for “Say hello”. Most of them are Venice’s default system prompt, which is added to chat requests unless you set venice_parameters.include_venice_system_prompt to false. This is exactly the kind of thing the proxy makes visible.
4

Point your agent at the proxy

In your agent’s Venice settings, replace https://api.venice.ai with http://127.0.0.1:8787 and keep the rest of the URL as it is. The proxy forwards the full path, so whatever the agent’s guide tells you to enter still works.OpenCode’s bundled Venice provider and Kilo Code’s native Venice provider don’t expose a base URL, so switch to the manual or OpenAI-compatible provider while you debug.In OpenCode, give the debug provider its own ID, such as venice-debug, and run it with -m venice-debug/<model-id>. If you’ve saved a key with /connect, OpenCode sends that stored key for the venice provider ID even when your config sets apiKey.Use 127.0.0.1 rather than localhost. On some systems localhost resolves to the IPv6 address ::1, which the proxy isn’t listening on.
This doesn’t work with Cursor. Cursor sends custom-model requests from its own servers, which can’t reach a proxy on your machine.
5

Reproduce the problem

Use the agent as you normally would until the problem happens again, then look at the proxy’s terminal output and the log file.

Reading the logs

Each line in venice-debug.jsonl is one complete JSON object, so jq can slice it however you need. Show the most recent request and response:
Show only failed or interrupted requests:
Check which model, parameters, and tools the agent actually sent:
Rebuild the text of streamed chat completions:
Total tokens per model for the session:
Find the slowest requests:

What to look for


Without writing any code

If you’d rather click through traffic in a browser, mitmproxy can run as a reverse proxy in front of Venice:
Point the agent at http://127.0.0.1:8787/api/v1 the same way, then inspect each request in the mitmweb UI. The Node proxy is easier to script against and keeps a log you can grep later. mitmproxy is better for browsing a session interactively.

Keep the logs private

Venice doesn’t store your prompts or responses for normal inference (see Privacy), but this log file does. It contains your code, prompts, tool output, and model responses in plain text.
  • Run the proxy outside your project, or add venice-debug.jsonl to .gitignore.
  • Delete the log when you’ve finished debugging.
  • Don’t paste full log entries into public issues. Pull out the status, error, and the relevant part of response instead.
For E2EE models, the agent encrypts message content before it leaves your machine, so the log will show encrypted payloads rather than readable text.

Finishing up

When you’re done, stop the proxy with Ctrl+C and switch the agent’s base URL back to https://api.venice.ai/api/v1. If you forget, the agent will fail with a connection error as soon as the proxy isn’t running, which is at least easy to spot. Thanks for reading! Hopefully the next time an agent says “something went wrong”, you’ll be able to see exactly what went wrong.