RunanywhereAI / RunanywhereAI/wally

Anthropic shim opens a new TLS connection for every request (~541 ms per turn)

Open
#80 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

important P2
Dominant language
C++
Stars
1.5k
Forks
86
Avg merge
6h 53m
Merged PRs (30d)
50

Description

Release blocker. ~541 ms is added to every request an agent makes through wally, before a single byte of the request is sent.

Problem

The Anthropic→OpenAI shim builds a fresh httplib::Client for every request to the hosted endpoint: inside the streaming sink in src/anthropic/messages.cpp (HandleStreaming, httplib::Client client(*origin) ~L183) and again in HandleNonStreaming (~L119). Each one opens a new TCP connection and completes a new TLS handshake, streams one response, and is destroyed.

Against the regional load balancer that handshake was measured at ~541 ms (InferenceInfra .claude/rules/terraform-safety.md, 2026-09-06; InferenceInfra #418 measured ~556 ms per new connection from Delhi, and nothing on reused connections). Claude Code makes several requests per user turn once ANTHROPIC_BASE_URL points at the shim — the main completion plus the small side calls — and every one pays it. Claude Code → shim is loopback and unaffected; the shim → inference.runanywhere.ai leg is where the cost lands.

Why it blocks release

It is the largest piece of time-to-first-token a customer feels that has nothing to do with the GPU, on every turn. It also makes the regional-TLS question (InferenceInfra #299) look worse than it is: once the connection is reused, that handshake is paid once per session instead of once per request.

Fix

  1. Keep long-lived httplib::Clients on the shim's Runtime, set_keep_alive(true). An httplib::Client serialises requests on its one socket, so use a small pool — one per concurrent stream — and reuse across turns.
  2. Reconnect lazily: if a request fails on a stale socket (the ALB keeps idle client connections ~10 minutes), retry once on a fresh one. Never retry a request that has started streaming.
  3. Enable TLS session resumption on the client so a reconnect is one round-trip.
  4. Same pattern in src/harness/codex.cpp / opencode.cpp only if they own an HTTP client of their own; if they hand the tool a base URL and the tool's client talks directly, they are unaffected.

Done when

A packet capture of a second request in the same session shows no TLS handshake, and the per-turn TTFT in a real agent session drops by roughly the handshake time.

Related: the cancel-on-close issue (same file), InferenceInfra #299.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read src/anthropic/messages.cpp at HandleStreaming and HandleNonStreaming, then trace how the shim Runtime owns outbound clients. Check the related client paths in src/harness/codex.cpp and opencode.cpp only if they create HTTP clients. Done means a second request reuses the connection without a TLS handshake, stale sockets reconnect safely, and real-agent per-turn TTFT drops by roughly the handshake time.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend-api-design, networking, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.