codex-convert-proxy 0.1.0

A high-performance proxy server that converts between different AI API formats
Documentation

Codex Convert Proxy

A high-performance proxy service that converts between OpenAI Responses API (used by Codex) and Chat Completions API (used by Chinese LLM providers).

Background

Codex 0.118+ uses the Responses API, but most Chinese LLM providers (GLM, Kimi, DeepSeek, MiniMax) only support the Chat Completions API. This proxy bridges the gap by performing bidirectional format conversion.

Architecture

┌─────────────┐    Responses API    ┌──────────────────┐   Chat API   ┌─────────────────┐
│    Codex    │ ──────────────────▶ │ codex-convert-   │ ──────────▶ │  LLM Provider   │
│   Client    │ ◀────────────────── │     proxy        │ ◀────────── │  (GLM/Kimi/...) │
└─────────────┘    Responses API     └──────────────────┘   SSE/JSON    └─────────────────┘

Features

  • Multi-backend routing: Route requests to different LLM providers based on path prefix
  • Protocol conversion: Responses API ↔ Chat API bidirectional conversion
  • Streaming SSE support: Real-time conversion of Server-Sent Events
  • Provider-specific handling: Per-provider request/response transformation
  • OpenTelemetry tracing: Built-in observability support
  • TLS support: Secure upstream connections via rustls

Supported Providers

Provider Model API Path Notes
GLM (Zhipu AI) glm-4, glm-5 /chat/completions Removes tools, flattens content
Kimi (Moonshot) moonshot-v1-* /v1/chat/completions OpenAI compatible
DeepSeek deepseek-chat /v1/chat/completions OpenAI compatible
MiniMax ab-01, ab-02 /v1/chat/completions Flattens content, converts developer role

Quick Start

1. Configure

Edit config.json:

{
  "listen": "0.0.0.0:8280",
  "log_dir": "./logs",
  "log_body": false,
  "backends": [
    {
      "name": "glm",
      "url": "https://open.bigmodel.cn/api/coding/paas/v4",
      "api_key": "YOUR_API_KEY",
      "model": "glm-5",
      "protocol": "openai",
      "match_rules": {
        "default": true
      }
    },
    {
      "name": "kimi",
      "url": "https://api.moonshot.cn/v1",
      "api_key": "YOUR_API_KEY",
      "model": "moonshot-v1-8k",
      "protocol": "openai",
      "match_rules": {
        "path_prefix": "/kimi"
      }
    },
    {
      "name": "deepseek",
      "url": "https://api.deepseek.com/v1",
      "api_key": "YOUR_API_KEY",
      "model": "deepseek-chat",
      "protocol": "openai",
      "match_rules": {
        "path_prefix": "/deepseek"
      }
    }
  ]
}

2. Build & Run

# Development
cargo run --bin server -- --config config.json

# Production
cargo build --release
./target/release/codex-convert-proxy --config config.json

Or use Make:

make run

3. Test with Codex

# Set Codex endpoint
export CODEX_API_URL=http://localhost:8280

# Or use codex exec with proxy
codex exec --provider openai-compatible --api-key dummy --base-url http://localhost:8280/v1 --model glm-5 "Hello, write a hello world in Python"

Configuration Reference

Backend Configuration

Field Type Required Description
name string Yes Backend identifier
url string Yes Upstream API base URL
api_key string Yes API authentication key
model string Yes Model name to use with this backend
protocol string Yes Currently only "openai" is supported
match_rules.path_prefix string No Route requests by path prefix
match_rules.default boolean No Set as default backend

Match Rules

Requests are routed based on match_rules:

  1. path_prefix: Matches if request path starts with the prefix (e.g., /kimikimi backend)
  2. default: The fallback backend when no prefix matches

API Endpoints

The proxy handles the Responses API format at the root path:

Method Path Description
POST / Convert and forward Responses API request
GET /health Health check

Provider-Specific Handling

GLM

  • API path: /chat/completions (not /v1/chat/completions)
  • Removes tools and tool_choice from requests (not supported)
  • Converts developer role to user
  • Flattens content array to string

MiniMax

  • Converts developer role to user
  • Flattens content array to string
  • Ensures response content is string format

Kimi / DeepSeek

  • Fully OpenAI Chat API compatible
  • No special transformation needed

Monitoring

Logs

Logs are written to the configured log_dir:

./logs/
├── codex-convert-proxy.log
└── error.log

OpenTelemetry

Configure OTLP endpoint for tracing:

{
  "telemetry": {
    "enabled": true,
    "service_name": "codex-convert-proxy",
    "otlp_endpoint": "http://localhost:4317"
  }
}

Development

# Run tests
cargo test

# Run with debug logging
RUST_LOG=debug cargo run --bin server -- --config config.json

# Build release
cargo build --release

Project Structure

src/
├── main.rs              # CLI entry point
├── lib.rs               # Library exports
├── config.rs            # Configuration loading
├── proxy/
│   └── proxy_impl.rs    # Pingora ProxyHttp implementation
├── providers/
│   ├── trait_.rs        # Provider trait definition
│   ├── glm.rs           # GLM provider
│   ├── kimi.rs          # Kimi/Moonshot provider
│   ├── deepseek.rs      # DeepSeek provider
│   └── minimax.rs       # MiniMax provider
├── convert/
│   ├── request.rs       # Responses → Chat API conversion
│   ├── response.rs      # Chat → Responses API conversion
│   └── streaming.rs    # SSE streaming conversion
├── types/
│   ├── chat_api.rs      # Chat API types
│   └── response_api.rs  # Responses API types
├── streaming.rs         # SSE parsing utilities
├── server.rs            # Pingora server setup
├── stats.rs             # Request statistics
├── telemetry.rs         # OpenTelemetry setup
├── logger.rs            # Logging configuration
└── error.rs             # Error types

License

MIT