| name | codexcont-middleware |
| description | Continue-thinking middleware that detects and handles reasoning truncation in Codex/OpenAI Responses-compatible APIs |
| triggers | ["set up CodexCont proxy","configure continuation middleware","handle reasoning truncation","proxy OpenAI Codex requests","extend thinking limits","configure CodexCont authentication","debug truncated reasoning","fold streaming responses"] |
CodexCont Middleware
Skill by ara.so — Codex Skills collection.
CodexCont is a Starlette-based proxy middleware that sits between coding agents and OpenAI Responses-compatible APIs. It automatically detects reasoning truncation (when reasoning_tokens == 518 * n - 2), silently continues the thinking process, and folds multiple upstream streaming responses into one coherent downstream response.
Installation
Prerequisites
- Python >= 3.12
uv package manager recommended
Setup
git clone https://github.com/neteroster/CodexCont.git
cd CodexCont
uv sync
cp config.example.toml config.toml
uv run python run.py
Alternative: Direct virtual environment usage
.venv/Scripts/python.exe run.py
.venv/bin/python run.py
Configuration
Basic Configuration Structure
Edit config.toml:
[server]
host = "127.0.0.1"
port = 8787
[upstream]
url = "https://chatgpt.com/backend-api/codex/responses"
mode = "header"
[auth]
mode = "passthrough"
access_token = ""
chatgpt_account_id = ""
[continue]
enabled = true
method = "commentary"
continue_tool_name = "continue_thinking"
max_rounds = 8
max_reasoning_tokens = 50000
tier_gate_low = 1
tier_gate_high = 100
[repair_followup]
mode = "off"
Upstream Mode
header mode (recommended): Allows per-request upstream override via Responses-API-Base header:
import httpx
response = httpx.post(
"http://127.0.0.1:8787/v1/responses",
headers={
"Responses-API-Base": "https://api.openai.com/v1",
"Authorization": f"Bearer {os.getenv('OPENAI_API_KEY')}"
},
json=payload
)
fixed mode: Always uses the configured upstream.url.
Authentication Modes
passthrough: Forward client auth headers only:
[auth]
mode = "passthrough"
inject: Override with configured credentials:
[auth]
mode = "inject"
access_token = "your-token-here"
chatgpt_account_id = "org-xxxxx"
passthrough_then_inject: Use client auth if present, fallback to config:
[auth]
mode = "passthrough_then_inject"
access_token = "your-fallback-token"
Security: The proxy will reject requests with Responses-API-Base header when inject mode would leak configured credentials to unknown URLs.
Continuation Methods
commentary (recommended): Uses hidden phase commentary to continue thinking:
[continue]
method = "commentary"
tool_pair: Legacy mode using synthetic tool calls:
[continue]
method = "tool_pair"
continue_tool_name = "continue_thinking"
Safety Limits
[continue]
max_rounds = 8
max_reasoning_tokens = 50000
tier_gate_low = 1
tier_gate_high = 100
Usage Examples
Basic Proxy Client
import httpx
import os
import json
async def query_with_continuation(prompt: str):
"""Query through CodexCont proxy with automatic continuation."""
payload = {
"model": "gpt-4",
"messages": [
{"role": "user", "content": prompt}
],
"stream": True,
"reasoning": True
}
async with httpx.AsyncClient() as client:
async with client.stream(
"POST",
"http://127.0.0.1:8787/v1/responses",
headers={
"Authorization": f"Bearer {os.getenv('OPENAI_API_KEY')}",
"Content-Type": "application/json"
},
json=payload,
timeout=300.0
) as response:
async for line in response.aiter_lines():
if line.startswith("data: "):
data = line[6:]
if data.strip() == "[DONE]":
break
event = json.loads(data)
if event.get("type") == "response.reasoning_item.delta":
print(f"Reasoning: {event.get('delta', {}).get('content', '')}")
elif event.get("type") == "response.message.delta":
print(f"Output: {event.get('delta', {}).get('content', '')}")
elif event.get("type") == "response.done":
metadata = event.get("response", {}).get("metadata", {})
rounds = metadata.get("proxy_rounds", [])
print(f"\nCompleted in {len(rounds)} round(s)")
for i, r in enumerate(rounds):
print(f" Round {i+1}: {r.get('reasoning_tokens')} tokens (tier {r.get('tier')})")
Synchronous Client
import requests
import os
def simple_query(prompt: str):
"""Simple synchronous query through proxy."""
response = requests.post(
"http://127.0.0.1:8787/v1/responses",
headers={
"Authorization": f"Bearer {os.getenv('OPENAI_API_KEY')}"
},
json={
"model": "gpt-4",
"messages": [{"role": "user", "content": prompt}],
"stream": True
},
stream=True
)
for line in response.iter_lines():
if line:
line_str = line.decode('utf-8')
if line_str.startswith("data: "):
data = line_str[6:]
if data.strip() != "[DONE]":
print(data)
Override Upstream URL
import httpx
import os
async def query_different_endpoint(prompt: str):
"""Query a different Responses-compatible endpoint."""
async with httpx.AsyncClient() as client:
response = await client.post(
"http://127.0.0.1:8787/v1/responses",
headers={
"Responses-API-Base": "https://api.openai.com/v1",
"Authorization": f"Bearer {os.getenv('OPENAI_API_KEY')}"
},
json={
"model": "gpt-4",
"messages": [{"role": "user", "content": prompt}],
"stream": True
}
)
return response
Disable Continuation for Specific Request
payload = {
"model": "gpt-4",
"messages": [{"role": "user", "content": "Quick question"}],
"stream": True,
"reasoning": False
}
Understanding Continuation Behavior
Truncation Detection
The middleware detects truncation when:
usage.output_tokens_details.reasoning_tokens == 518 * n - 2 (for integer n)
- Reasoning content appears encrypted/truncated
- Token count is within tier gates (
tier_gate_low <= n <= tier_gate_high)
- Safety limits not exceeded (
max_rounds, max_reasoning_tokens)
Response Metadata
The final response includes proxy metadata:
{
"type": "response.done",
"response": {
"metadata": {
"proxy_rounds": [
{"reasoning_tokens": 516, "tier": 1},
{"reasoning_tokens": 1034, "tier": 2}
],
"proxy_billed_usage": {
"input_tokens": 150,
"output_tokens": 1550,
"reasoning_tokens": 1550
},
"proxy_stopped_reason": "clean_finish"
},
"usage": {
"input_tokens": 150,
"cached_tokens": 0,
"output_tokens": 1550,
"reasoning_tokens": 1550
}
}
}
Continuation Flow
User Request
↓
CodexCont (round 1)
↓
Upstream API → 516 reasoning tokens (truncated)
↓
CodexCont detects 518*1-2, buffers output, continues
↓
CodexCont (round 2, reasoning replayed + "Continue thinking...")
↓
Upstream API → 250 reasoning tokens (complete)
↓
CodexCont flushes final output, reconstructs terminal event
↓
User receives single coherent stream
Running Tests
uv run python tests/test_middleware.py
.venv/Scripts/python.exe tests/test_middleware.py
Tests cover:
- Truncation detection math
- SSE parsing/rewriting
- Commentary and tool-pair continuation
- Auth safety guards
- Header transparency
- Upstream URL resolution
Troubleshooting
Proxy not detecting truncation
Check request format:
payload = {
"stream": True,
"reasoning": True,
}
Verify configuration:
[continue]
enabled = true
tier_gate_low = 1
tier_gate_high = 100
Authentication errors
With Responses-API-Base override:
[auth]
mode = "passthrough"
Inject mode rejecting requests:
- The proxy blocks requests with
Responses-API-Base when using inject mode to prevent credential leaks
- Solution: Use
passthrough mode and send auth in request headers
High first-token latency for final output
This is expected behavior. Final answer text is buffered until the terminal round proves it's not truncated. Reasoning tokens stream live, but final message content waits for confirmation.
Upstream connection errors
Check upstream URL:
[upstream]
url = "https://chatgpt.com/backend-api/codex/responses"
mode = "fixed"
Enable debug logging:
import logging
logging.basicConfig(level=logging.DEBUG)
Non-streaming requests not folded
Currently expected: non-streaming requests pass through unchanged. Use "stream": true to enable continuation folding.
Tool name conflicts
When using method = "tool_pair":
[continue]
continue_tool_name = "continue_thinking"
If your request declares a real tool with this name, folding is disabled for safety.
Advanced Configuration
Multiple proxy instances
For load balancing, run multiple instances on different ports:
PORT=8787 uv run python run.py
PORT=8788 uv run python run.py
Update config for port override:
import os
from middleware.config import load_config
config = load_config()
config.server.port = int(os.getenv("PORT", 8787))
Stateful repair mode
[repair_followup]
mode = "stateful"
Warning: State is process-local and not shared across instances. Not recommended for production load-balanced deployments.
Custom continuation messages
Edit middleware/codex.py:
CONTINUE_MARKER = "Continue your reasoning from where you left off..."
def _build_tool_pair_continuation(...):
pass
Integration Examples
With LangChain
from langchain.chat_models import ChatOpenAI
llm = ChatOpenAI(
openai_api_base="http://127.0.0.1:8787/v1",
model="gpt-4",
streaming=True
)
response = llm.invoke("Complex reasoning task...")
With OpenAI Python SDK
from openai import OpenAI
client = OpenAI(
base_url="http://127.0.0.1:8787/v1",
api_key=os.getenv("OPENAI_API_KEY")
)
stream = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Think deeply about..."}],
stream=True
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="")
With Cursor/Claude Code
Configure in editor settings:
{
"openai.api.baseUrl": "http://127.0.0.1:8787/v1",
"openai.api.key": "${OPENAI_API_KEY}"
}
Best Practices
- Use environment variables for secrets: Never hardcode API keys in
config.toml
- Start with
passthrough auth mode: Simplest and most secure for development
- Monitor
proxy_rounds metadata: Understand how many continuation rounds are triggered
- Set reasonable safety limits: Prevent runaway token costs with
max_rounds and max_reasoning_tokens
- Use
commentary method: More reliable than legacy tool_pair approach
- Test without proxy first: Ensure upstream connectivity before adding middleware layer
- Enable streaming: Non-streaming requests bypass continuation logic