T3 Chat Router & Wire Protocol Research: t3router & pi-t3chat (2026)
This document provides the line-verified reverse-engineering specification of vibheksoni/t3router (~/dev/t3router, commit 5314bbbf0af66e724e3e07ffd458ef5919d1eed1) and vibheksoni/pi-t3chat (~/dev/pi-t3chat, commit b39873245362c33f68a9a3e044423f69769069f9). It documents the POST https://t3.chat/api/chat wire contract, Chrome 136 TLS impersonation (rquest::Impersonate::Chrome136), WorkOS x-workos-session automatic rotation, the /assets/*.js regex bundle scraper (eval_js_number vs parseFloat), all 6 tRPC endpoints, poll_credit_delta, ToolCallTranslator, ToolRefusalDetector, and the 3-tool lazy MCP wrapper (list_mcps, list_mcp_tools, call_mcp).
1. Repository & Module Inventory
Section titled “1. Repository & Module Inventory”1.1 vibheksoni/t3router (~/dev/t3router — Rust 2021)
Section titled “1.1 vibheksoni/t3router (~/dev/t3router — Rust 2021)”src/lib.rs&src/t3/mod.rs:1-10: Declarespub mod client; pub mod config; pub mod history; pub mod message; pub mod models; pub mod repl; pub mod session; pub mod usage;(with zeropub usere-exports inmod.rs).src/t3/config.rs:1-58: DefinesReasoningEffort(Low,Medium,High,Default=Medium) andConfig(include_search: bool,reasoning_effort: ReasoningEffort).src/t3/client.rs:174-792: DefinesChatResponse(message: Message,thread_id: String,model: String,credits_before: Option<f64>,credits_after: Option<f64>,credits_deducted: Option<f64>,finish_reason: Option<String>),SseAccumulator,poll_credit_delta, andClient(new,warmup,init,refresh_session,send,send_stream,send_with_credits,send_with_credits_stream,send_with_image_download,finalize_credits,parse_response,new_conversation,resume_conversation,append_message,get_messages,clear_messages,download_image,get_thread_id).src/t3/models.rs:1-665:ModelsClient,ModelInfo,ModelCost,AttachmentSupport,ModelStatus,ModelBenchmarkEntry,BenchmarkMetric,parse_models_from_bundle,eval_js_number.src/t3/usage.rs:1-415:UsageClient,CustomerData,SubscriptionData,PricingData,CreditPack,TopUpInfo,SessionInfo(session_id,created_at,expires_at,ip_address,user_agent),UsageSummary,extract_trpc_result.src/t3/session.rs:1-114:SavedSession,SavedMessage,default_session_path()(readsT3CHAT_SESSION_PATHbefore falling back to~/.t3chat_session.json),save_session(&SavedSession),load_session().src/t3/repl.rs:36-45, 176-254: Interactive REPL supporting/help,/new,/resume,/save,/model [name],/credits, and/quit(alias/exit). (Implementation note:repl.rs:250callspoll_credit_deltaa second time afterclient.send_with_credits_streamalready invoked it atclient.rs:744.)src/bin/t3chat.rs: Full CLI binary supporting--list-models,--status,--benchmarks,--usage,--credits,--effort,--search,--save,--resume, and interactive REPL mode.
1.2 vibheksoni/pi-t3chat (~/dev/pi-t3chat — TypeScript)
Section titled “1.2 vibheksoni/pi-t3chat (~/dev/pi-t3chat — TypeScript)”index.ts:118-191: Pi coding-agent extension entrypoint registering flags--t3chat-loginand--t3chat-cookiesand slash commands/t3chat-status,/t3chat-logout, and/t3chat-refresh.auth.ts: Playwright browser login (loginWithBrowser),~/.pi/agent/t3chat-auth.jsonpersistence (chmod 0o600), andrefreshSession(auth.getActiveSessions).catalog.ts:147-276: ExportsgetCachedCatalog(L262) andclearCachedCatalog(L276), wrapping internalfetchCatalog(L231, scanning up to 12 JS chunks in parallel viachunkPaths.slice(0, 12)).config.ts:1-28: Exportstype ReasoningEffort,interface ChatConfig,defaultConfig(), andbuildConfigObject().chat.ts:59-108&sse.ts:1-95:chat.tsdefinesT3_BASE_URL = "https://t3.chat",mapSSEEvent(L85–108), andstreamT3Chat;sse.tsdefinesSSEEvent(text-delta,reasoning-delta,finish-step,finish,error) andparseSSEStream.tools.ts:1-310:ToolRegistry,ToolCallTranslator,ToolCallDeltaAccumulator, andToolRefusalDetector.mcp.ts:1-210: Lazy MCP wrapper (list_mcps,list_mcp_tools,call_mcp,MAX_WRAPPER_ROUNDS = 6).proxy.ts:40-48, 704-733: Localhost OpenAI-compatible HTTP proxy (T3_PROXY_HOST = "127.0.0.1",T3_PROXY_PORT = 42101, fallback toserver.listen(0)onEADDRINUSE) exportingstartProxy,stopProxy,PROXY_SECRET(32-byte random hex verified viacrypto.timingSafeEqual),proxyCredentials, andsetProxyCredentials.tokens.ts,usage.ts,log.ts:1-32:log.tsexportssetNotifier,logInfo,logWarn,logErrorwith a pre-session_bufferqueue.
2. POST https://t3.chat/api/chat Wire Contract & WorkOS Rotation
Section titled “2. POST https://t3.chat/api/chat Wire Contract & WorkOS Rotation”- TLS Fingerprint (
t3router/src/t3/client.rs:205): Usesrquest::Impersonate::Chrome136to satisfy Cloudflare JA3/JA4/HTTP2 checks. - Automatic Session Rotation (
client.rs:235-252&pi-t3chat/auth.ts:112-160): CallsGET https://t3.chat/api/trpc/auth.getActiveSessions?batch=1&input=%7B%220%22%3A%7B%22json%22%3Anull%2C%22meta%22%3A%7B%22values%22%3A%5B%22undefined%22%5D%7D%7D%7D. If the response carriesx-workos-sessionorset-cookie: wos-session=..., the client hot-swapswos-sessionin memory and persists it. - Request Payload (
POST https://t3.chat/api/chat):{"messages": [{"id": "<uuid-v4>","role": "user","parts": [{ "type": "text", "text": "..." }],"attachments": []}],"threadMetadata": { "id": "<thread-uuid-v4>" },"responseMessageId": "<response-uuid-v4>","model": "claude-sonnet-4-6","convexSessionId": "<session-uuid-v4>","modelParams": {"reasoningEffort": "medium","includeSearch": false},"preferences": {"name": "","occupation": "","selectedTraits": [],"additionalInfo": ""},"userInfo": { "timezone": "America/Los_Angeles" },"isEphemeral": false} - SSE Event Stream (
client.rs:60-170,sse.ts:1-95): Emitsdata: {"type":"reasoning-delta","delta":"..."},data: {"type":"text-delta","delta":"..."},data: {"type":"finish-step",...}(mapped tonullbymapSSEEventinchat.ts:104-105),data: {"type":"finish","finishReason":"stop"}, anddata: [DONE].
3. Dynamic JS Bundle Scraper & tRPC Procedures
Section titled “3. Dynamic JS Bundle Scraper & tRPC Procedures”3.1 /assets/*.js Scraper Differences (t3router/src/t3/models.rs vs pi-t3chat/catalog.ts)
Section titled “3.1 /assets/*.js Scraper Differences (t3router/src/t3/models.rs vs pi-t3chat/catalog.ts)”Both scrapers fetch https://t3.chat/, extract /assets/[^"]+\.js[^"]*, locate the chunk containing usdCostPerToken and modelToInternalId, and extract model entries:
t3router/src/t3/models.rs:437-662:eval_js_number(L647–662) explicitly evaluates/1e6and/1e3division expressions inusdCostPerToken: { input: 3/1e6, output: 15/1e6 }.- Handles both
features: new Set([...])andfeatures: [...](L437–449).
pi-t3chat/catalog.ts:147-253:- Scans up to 12 chunks in parallel (
chunkPaths.slice(0, 12)viaPromise.all), filters out image-only models (features.every(f => f === "images")) and retired models (retiredOn), and parsesusdCostPerTokenwithparseFloat(costMatch[1])(which drops/1e6suffixes).
- Scans up to 12 chunks in parallel (
3.2 tRPC Endpoints & Header Differences (t3router/src/t3/usage.rs vs pi-t3chat/usage.ts)
Section titled “3.2 tRPC Endpoints & Header Differences (t3router/src/t3/usage.rs vs pi-t3chat/usage.ts)”auth.getActiveSessions:Client::refresh_session(client.rs:237-246) sendstrpc-accept: application/jsonl, whereasUsageClient::get_active_sessions(usage.rs:397-408) sendsx-trpc-source: web-clientwithouttrpc-accept.getCustomerData: ReturnscreditsRemaining,totalCredits,NextCreditRefill,TopUpInfo.getSubscriptionData:t3router(usage.rs:367-368) sendsx-trpc-batch: true+trpc-accept: application/jsonl;pi-t3chat(usage.ts:204) callstrpcCall(cookies, "getSubscriptionData", null, false).getPricingProducts:t3router(usage.rs:309) sends{"0":{"json":{"sessionId":null},"meta":{"values":{"sessionId":["undefined"]}}}};pi-t3chat(usage.ts:214) sends{"0":{"json":null,"meta":{"values":["undefined"]}}}.getModelStatuses&getAllModelBenchmarks(t3router/src/t3/models.rs:212-345): Returns livestatus(operational,degraded,outage) and benchmark scores across Artificial Analysis, LiveBench, SweBench, SnitchBench, SkateBench, etc.
3.3 Post-Turn Credit Delta Polling (t3router/src/t3/client.rs:770-792)
Section titled “3.3 Post-Turn Credit Delta Polling (t3router/src/t3/client.rs:770-792)”poll_credit_deltaloopsfor attempt in 0..8, sleeping200msonly whenattempt + 1 < 8(7 sleeps =1.4smax sleep). If none of the 8 loop checks observes(before - after).abs() > 0.000_1, line 786 performs a 9th unconditionalusage_client.get_balance().await.ok()call and returns(final_after, final_after.map(|after| before - after)).
4. Coding-Agent Tool Emulation, Refusal Auto-Correction & Lazy MCP (pi-t3chat)
Section titled “4. Coding-Agent Tool Emulation, Refusal Auto-Correction & Lazy MCP (pi-t3chat)”ToolCallTranslator(tools.ts:45-210): Serializes OpenAI tool definitions into system prompt instructions requiring```tool:<exact_tool_name>\n{...}\n```fenced blocks.ToolRefusalDetector(tools.ts:265-305): Detects false refusals in the first 350 characters whentools.length > 0,toolCallsFound === 0, andtext.length < 700using two exact regexes (tools.ts:270-271):REFUSAL_RE = /\b(can't|cannot|can not|don't have|do not have|unable to|not able to|no access|without access|can't actually|cannot actually)\b/iCAPABILITY_RE = /\b(tool|terminal|shell|command|run|execute|file|filesystem|browse|browser|web search|search|calendar|schedule|environment)\b/i- When both match (
!retriedRefusal),proxy.tsdiscards the refusal and retries once with a corrective system reminder listing the available tool names.
- Lazy MCP Wrapper (
mcp.ts:1-210): Collapses allmcp__<server>__<tool>tools into 3 lightweight meta-tools (list_mcps,list_mcp_tools,call_mcp) resolved locally inproxy.tsup toMAX_WRAPPER_ROUNDS = 6.