Skip to main content

GPTMock banner

GPTMock

OpenAI & Ollama compatible API powered by your ChatGPT account.

Tests Coverage Python 3.13+ License: MIT

This is a fork of RayBytes/chatmock. The original Flask + synchronous requests stack has been replaced with FastAPI + async httpx, a layered architecture (router / service / infra), pydantic-settings configuration, and uv as the build system.

Integration and coverage badges are updated from local runs. Refresh both by running scripts/test.sh with GIST_TOKEN available in your environment or .env.

GPTMock runs a local protocol adapter in front of the ChatGPT Codex backend. OpenAI SDKs, OpenAI-compatible frontends and gateways, and Ollama-compatible clients can use the same authenticated backend without GPTMock pretending that remote models are local weights. Its model catalog is a configured snapshot, not a live availability check. Backend access can change before that catalog is updated; see Supported Models for dated results and known stale entries.

GPTMock adapts client requests to the backend's supported format while preserving model identity, instruction text, strict function schemas, tool choice, reasoning controls, and service-tier requests. For GPT-5.3 Codex Spark, GPT-5.5, GPT-5.6 Luna/Terra/Sol, and GPT-6 Astra, system-message text is carried in the Responses instructions field so existing chat clients can keep their system prompts. The actual response model, service tier, terminal status, and remaining upstream errors are returned to the client.

Migration note: --reasoning-compat now defaults to standard, which emits reasoning via delta.reasoning_content / message.reasoning_content instead of injecting <think> tags into content. Set --reasoning-compat think-tags (or GPTMOCK_REASONING_COMPAT=think-tags) to keep the old behavior.

Requirements

  • Docker Engine 24+ with Docker Compose v2 (recommended deployment)
  • Paid ChatGPT account (Plus / Pro / Team / Enterprise)
  • Python 3.13+ and uv only for direct, non-Docker usage

The standard docker-compose.yml uses rapidrabbit76/gptmock:latest, the ./volumes/gptmock bind mount, and requires a local .env file. Its published ports bind to all host interfaces.

The commands below explicitly select docker-compose.local.yml, a separate configuration that builds the checked-out source and applies the hardened runtime settings. It does not overwrite or merge into docker-compose.yml. When testing an unmerged pull request, check out its branch before building; the published image and PyPI package may not contain those changes yet.

1. Clone and build

git clone https://github.com/rapidrabbit76/GPTMock.git
cd GPTMock
docker compose -f docker-compose.local.yml build

2. Start (first run — login + serve in one step)

Run the container interactively. If no credentials are found, the login flow starts automatically:

docker compose -f docker-compose.local.yml run --rm --service-ports serve

A URL will be printed in the terminal:

No credentials found. Starting login flow...
Starting local login server on http://localhost:1455
If your browser did not open, navigate to:
  https://auth.openai.com/oauth/authorize?...

If the browser can't reach this machine, paste the full redirect URL here and press Enter:

Two ways to complete login:

  1. Browser on the same machine — the URL opens automatically and the OAuth callback is caught on port 1455.
  2. Browser on a different machine — open the URL, complete login, then copy the full redirect URL from the browser address bar (starts with http://localhost:1455/auth/callback?code=...) and paste it into the terminal.

Once login succeeds, the server starts automatically.

3. Subsequent starts

Once credentials are saved in the volume, just run in the background:

docker compose -f docker-compose.local.yml up -d serve

docker-compose.local.yml uses the named volume gptmock-data; the original docker-compose.yml continues to use ./volumes/gptmock. The two configurations have separate credential storage. Log in once for the selected configuration, or explicitly migrate existing credentials before switching.

4. Verify

curl -s http://localhost:8000/health | jq .

Docker Environment Variables

All server options below are also available as environment variables. Use the GPTMOCK_* canonical names (see Server Options).

Additional Docker-specific variables:

Variable Default Description
GPTMOCK_HOME /data Auth file directory — mount a volume here
GPTMOCK_LOGIN_BIND 0.0.0.0 OAuth callback server bind address
GPTMOCK_API_KEY unset Optional Bearer token required by /v1/* and /api/* routes
GPTMOCK_OUTPUT_TOKEN_POLICY omit Handle unenforceable client output limits: omit with warning/header or reject with HTTP 400
GPTMOCK_OLLAMA_VERSION 0.12.10 Ollama API compatibility header version

In docker-compose.local.yml, the published ports bind to host loopback. If you expose them on a LAN, configure GPTMOCK_API_KEY and an explicit GPTMOCK_CORS_ORIGINS allowlist first.

Docker Security Defaults

The separate docker-compose.local.yml deployment runs as UID/GID 10001, mounts the root filesystem read-only, drops every Linux capability, enables no-new-privileges, applies a PID limit, and persists credentials only in the gptmock-data volume. Ports 8000 and 1455 are published to host loopback only.

API authentication is optional for local loopback use. To require a Bearer token, copy .env.example to .env and set:

GPTMOCK_API_KEY=replace-with-a-long-random-value
GPTMOCK_CORS_ORIGINS=

Clients must then send Authorization: Bearer <GPTMOCK_API_KEY> to /v1/* and /api/*. The health endpoint remains unauthenticated for container health checks. Browser CORS access stays disabled until an explicit origin allowlist is configured.


Direct Install (uvx)

This is the non-Docker development path. No clone or persistent installation is needed.

1. Login

uvx gptmock login

A browser window will open for ChatGPT OAuth. After login, tokens are saved to ~/.config/gptmock/auth.json.

2. Start the server

uvx gptmock serve

The server starts at http://127.0.0.1:8000. Use http://127.0.0.1:8000/v1 as your OpenAI base URL.

3. Verify

uvx gptmock info

Tip: Shell Alias

alias gptmock='uvx gptmock'

gptmock login
gptmock serve --port 9000
gptmock info

Note: To install directly from the GitHub repository instead of PyPI:

uvx --from "git+https://github.com/rapidrabbit76/GPTMock" gptmock login
uvx --from "git+https://github.com/rapidrabbit76/GPTMock" gptmock serve

Usage Examples

Use an explicit model that is currently available to your ChatGPT account. The basic text examples below use gpt-5.6-luna, which completed direct Chat and Responses requests in the 2026-09-13 check. This does not establish every SDK or tool workflow. For authenticated deployments, add Authorization: Bearer <GPTMOCK_API_KEY> to the curl examples and use the configured key in SDK clients.

Existing Docker volume migration

The image runs as UID/GID 10001:10001. The original Compose bind mount can contain files written by an older root-running image; image-layer ownership does not change host bind-mount permissions. Back up the credential directory and stop GPTMock before migrating it. On a Linux host, from the verified GPTMock checkout directory:

realpath ./volumes/gptmock
sudo chown -R 10001:10001 ./volumes/gptmock
sudo chmod 700 ./volumes/gptmock
sudo chmod 600 ./volumes/gptmock/auth.json  # if credentials already exist

Apply ownership changes only to that credential directory, not the repository or a broader parent directory. Do not use world-writable permissions. Docker Desktop bind-mount permission behavior can differ; the separate local Compose named volume is the recommended fresh-install path. Login and serve check storage access before starting and report migration guidance if it is inaccessible. Concurrent credential refreshes sharing one auth home are serialized using a local filesystem lock; avoid simultaneous manual re-login and refresh or network filesystems without reliable locking.

OpenCode

Use OpenCode's Responses provider as the recommended configuration. OpenCode 1.x configuration:

{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "gptmock": {
      "npm": "@ai-sdk/openai",
      "name": "GPTMock",
      "options": {
        "baseURL": "http://127.0.0.1:8000/v1",
        "apiKey": "replace-with-your-GPTMOCK_API_KEY"
      },
      "models": {
        "gpt-5.6-luna": {
          "name": "GPT-5.6 Luna",
          "reasoning": true,
          "tool_call": true,
          "variants": {
            "none": { "reasoningEffort": "none" },
            "low": { "reasoningEffort": "low" },
            "medium": { "reasoningEffort": "medium" },
            "high": { "reasoningEffort": "high" },
            "xhigh": { "reasoningEffort": "xhigh" },
            "max": { "reasoningEffort": "max" }
          }
        }
      }
    }
  }
}

Select gptmock/gpt-5.6-luna and the desired variant. OpenCode automatically sends max_output_tokens; GPTMock's default omit policy keeps the request compatible while explicitly reporting that the limit was not enforced.

For gpt-5.3-codex-spark, gpt-5.5, the GPT-6 Astra/Sol/Luna models, and the GPT-5.6 Luna/Terra/Sol models, GPTMock's Chat endpoint moves text system messages into upstream instructions. OpenCode 1.17.18 completed a real Astra file-read tool call and its follow-up through both adapters. The other listed models use the same system-message adaptation; that does not establish full client/tool compatibility for every model. SDK versions may encode Responses prompts as developer input or as instructions.

To request maximum Astra reasoning, select gpt-6-astra with --variant max (provider option reasoningEffort: "max"). gpt-6-astra-max is not a model: that removed alias returns HTTP 400 with migration guidance instead of silently selecting another effort. max remains supported through the reasoning parameter.

Troubleshooting: System messages are not allowed

Older GPTMock builds adapted text system messages only for Astra, and the first extension covered GPT-5.6 Luna/Terra/Sol. Chat clients sending system prompts to GPT-5.5 or GPT-5.3 Codex Spark could still receive HTTP 400 from the backend. The adapter now covers all six concrete models, the gpt-5.6 alias, and their existing *-fast requests. No Spark fast alias is added. Existing instructions and system text are retained in order; developer messages and tool history remain unchanged.

If this error persists, verify that the running GPTMock container includes the fix, not just that the source checkout was updated. Rebuild and recreate the GPTMock service using its existing deployment configuration and credential storage. When a gateway sits between the client and GPTMock, compare a small system-plus-user request directly against GPTMock and through the gateway before changing the client's API mode or model. A successful direct request does not by itself verify the complete Hermes or other agent workflow.

The regression tests in tests/test_astra.py cover Chat Completions, Responses, Ollama chat/generate, fast aliases, and streaming/non-streaming requests using a simulated upstream. Live client verification is separate from these tests.

GPT-5.5 and Spark verification (2026-09-13): both models rejected literal system messages through an unpatched Chat route, but completed non-streaming developer-message Chat requests and streaming/non-streaming Responses requests using instructions. After rebuilding and recreating the Docker service with the extended adapter, direct Chat requests for GPT-5.5, its existing fast alias, and Spark passed all six streaming/non-streaming checks with system, developer, and user input. Each returned HTTP 200, the expected concrete model, and the expected test marker. One earlier Spark streaming sample through the local adapter did not exactly match the requested text; follow-up and deployed checks matched. These results verify the deployed GPTMock Chat path, not an end-to-end Hermes/OpenCode workflow or LiteLLM configuration changes. Do not discard system prompts or silently substitute another model to hide this error.

Python (OpenAI SDK)

from openai import OpenAI

client = OpenAI(
    base_url="http://127.0.0.1:8000/v1",
    api_key="gptmock-local"  # use GPTMOCK_API_KEY when it is configured
)

resp = client.chat.completions.create(
    model="gpt-5.6-luna",
    messages=[{"role": "user", "content": "hello world"}]
)
print(resp.choices[0].message.content)

Python (LangChain)

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    base_url="http://127.0.0.1:8000/v1",
    api_key="gptmock-local",  # use GPTMOCK_API_KEY when it is configured
    model="gpt-5.6-luna",
)
response = llm.invoke("hello world")
print(response.content)

curl

curl http://127.0.0.1:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.6-luna",
    "messages": [{"role": "user", "content": "hello world"}]
  }'

Image Generation (Responses API)

GPTMock can expose the ChatGPT Codex backend's built-in image generation tool through POST /v1/responses. This uses your existing GPTMock / Codex OAuth credentials; no separate OpenAI API key is required.

The original examples used gpt-5.4 and gpt-5.4-mini; both were rejected by the tested ChatGPT Codex backend on 2026-09-13. Image generation was not revalidated with a replacement model. The following illustrates the request format only: replace <verified-image-generation-model> with a model whose image-generation tool access you have verified for your account. A successful text response alone does not verify image generation.

Pass an image_generation tool in the Responses API request:

curl http://127.0.0.1:8000/v1/responses \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<verified-image-generation-model>",
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": [
          {
            "type": "input_text",
            "text": "Use the image_generation tool to create a cute illustration of a fluffy orange tabby cat sitting on a white background. Return only the generated image."
          }
        ]
      }
    ],
    "tools": [{"type": "image_generation", "output_format": "png"}],
    "tool_choice": "auto",
    "stream": false
  }'

For non-streaming requests, generated images are returned as image_generation_call items in output. The result field is a base64-encoded PNG payload:

{
  "output": [
    {
      "type": "message",
      "status": "completed",
      "role": "assistant",
      "content": [{"type": "output_text", "text": ""}]
    },
    {
      "type": "image_generation_call",
      "id": "ig_...",
      "status": "generating",
      "output_format": "png",
      "revised_prompt": "A cute illustration of a fluffy orange tabby cat...",
      "result": "<base64 png>"
    }
  ]
}

Given the parsed response JSON, find an image result by type rather than assuming a fixed output position:

import base64

image_b64 = next(
    (item["result"] for item in response.get("output", [])
     if item.get("type") == "image_generation_call" and item.get("result")),
    None,
)
if image_b64 is None:
    raise RuntimeError("The response did not contain a generated image")
with open("cat.png", "wb") as fp:
    fp.write(base64.b64decode(image_b64))

Notes: Image-generation support is account- and backend-dependent. Earlier documentation reported successful GPT-5.4/mini image generation, but that is historical evidence, not current availability.

Local Image Inspection (view_image)

GPTMock also supports a Codex-compatible view_image client-side tool for POST /v1/responses. Unlike image_generation, this is not executed by the upstream backend: GPTMock reads the local file, returns it to the model as an input_image function-call output, and then continues the Responses turn.

Enable it per request by passing the shorthand tool. This is a request-format example, not a fresh live validation: replace <verified-image-input-model> with a currently available model verified for image input and function calling, and use an image path readable by the GPTMock server:

curl http://127.0.0.1:8000/v1/responses \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<verified-image-input-model>",
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": [
          {
            "type": "input_text",
            "text": "Use view_image to inspect this local image path: /images/example.png. Describe it briefly."
          }
        ]
      }
    ],
    "tools": [{"type": "view_image"}],
    "tool_choice": "auto",
    "stream": false
  }'

The shorthand is normalized to a Responses function tool named view_image. You can also provide an explicit function tool with the same name.

Docker: paths are resolved inside the container, not on the client or host. The image does not include the repository's assets/banner.png. Mount your image directory read-only at /images alongside the existing credential volume, set GPTMOCK_VIEW_IMAGE_ROOTS=/images, and ensure the container's non-root user can read the selected file. Merely setting the allowed roots does not mount or copy any files.

By default, view_image can read files under the server's current working directory only. Configure the readable roots when needed:

GPTMOCK_VIEW_IMAGE_ROOTS="/path/to/images:/another/root" gptmock serve

Additional knobs:

Variable Default Description
GPTMOCK_VIEW_IMAGE_ROOTS server cwd os.pathsep-separated list of readable image roots
GPTMOCK_VIEW_IMAGE_ALLOW_ANY_PATH off Set to 1 to allow any local path readable by the server process
GPTMOCK_VIEW_IMAGE_MAX_BYTES 20971520 Maximum image file size in bytes

Supported image content types are PNG, JPEG, GIF, and WebP. detail: "original" is accepted when the model requests original-resolution handling.


Supported Models

The following snapshot combines the current registry with direct backend checks on 2026-09-13 (KST). The availability check used low effort, non-streaming, user-only Chat Completions and Responses requests. Successful responses contained the requested test text and the expected concrete model name. It did not rerun every reasoning level, tools, images, or client integration. The effort column describes GPTMock's configured validation range, not fresh verification of every level.

Model Configured Reasoning Efforts Observed Backend Status (2026-09-13)
gpt-5.3-codex-spark low / medium / high / xhigh ✅ Text and instructions requests completed; system text is adapted by GPTMock
gpt-5.5 low / medium / high / xhigh ✅ Text and instructions requests completed; system text is adapted by GPTMock
gpt-5.6 none / low / medium / high / xhigh / max ✅ Completed as gpt-5.6-sol
gpt-5.6-sol none / low / medium / high / xhigh / max ✅ Basic text requests completed
gpt-5.6-terra none / low / medium / high / xhigh / max ✅ Basic text requests completed
gpt-5.6-luna none / low / medium / high / xhigh / max ✅ Basic text requests completed
gpt-6-astra low / medium / high / xhigh / max ✅ Basic text requests completed

GPT-6 Sol and Luna (added 2026-09-29): gpt-6-sol and gpt-6-luna are also advertised by /v1/models and /api/tags and route to their exact upstream IDs. Both accept none, low, medium (default), high, xhigh, and max, matching the official Sol and Luna model documentation. Their *-fast aliases request service_tier="priority" without appearing in discovery. With reasoning models exposed, effort aliases such as gpt-6-sol-max and gpt-6-luna-none are available; Astra's removed -max alias remains a separate restriction.

Sol and Luna use the existing Responses-backed adapters for OpenAI Chat/Completions/Responses and Ollama chat/generate. Tests cover discovery, reasoning validation, exact upstream model selection, fast aliases, and streaming/system-message adaptation with a simulated upstream. They were not part of the September 13 backend snapshot above, and account availability, live tool calls, and system-role acceptance have not been verified against the ChatGPT backend.

Removed GPT-5.4 models: gpt-5.4 and gpt-5.4-mini returned The '…' model is not supported when using Codex with a ChatGPT account. in the 2026-09-13 check. They and their effort variants are no longer advertised by /v1/models or /api/tags; their fast aliases are no longer registered. /api/show returns HTTP 404 for these removed entries. This is a dated backend/account observation, not a claim about public OpenAI API availability.

Direct Docker probes on 2026-09-03 confirmed every listed GPT-5.6 reasoning effort (none through max) for Sol, Terra, and Luna through /v1/responses. All 18 requests completed successfully and returned the requested concrete model name.

Fast compatibility aliases: *-fast names are accepted when requested directly and add service_tier="priority" to the same verified base-model request. They are not separate models, are not advertised by /v1/models or /api/tags, and do not guarantee priority service. New integrations should prefer the verified base model plus an explicit service_tier="priority" request. GPTMock returns the actual upstream service_tier unchanged. The seven pre-Astra aliases were accepted on 2026-08-26 with service_tier="default". Astra's priority request was separately accepted on 2026-09-05 and also returned default; gpt-6-astra-fast uses that same request-only convention.

Fast aliases inherit their base model's availability. On 2026-09-13, gpt-5.4-fast and gpt-5.4-mini-fast were rejected and have since been removed from alias registration; gpt-5.5-fast completed as gpt-5.5 with actual tier default. Recognizing an alias does not make an unavailable base model usable.

GPT-5.6 compatibility note: GPTMock exposes only verified GPT-5.6 model names. gpt-5.6 follows OpenAI's documented alias to gpt-5.6-sol. OpenAI documents Pro as reasoning.mode="pro" on the same model rather than as a *-pro model ID, but the ChatGPT Codex backend rejected that mode in direct probes. GPTMock therefore advertises no Pro model slug and rejects reasoning.mode locally instead of sending a request known to be unsupported by this upstream.

GPT-6 Astra: gpt-6-astra connects directly to that exact upstream model. The official model documentation lists low, medium, high, xhigh, and max; direct ChatGPT Codex probes on 2026-09-05 completed at all five efforts and echoed the requested model and effort. That backend rejected none, minimal, ultra, gpt-6-astra-pro, and reasoning.mode="pro". Those options are not advertised as supported. OpenAI Chat Completions and Ollama clients use GPTMock's existing Responses-backed adapter, including tool calls. See Astra validation for the tested interfaces and limitations.

System-message compatibility: for GPT-5.3 Codex Spark, GPT-5.5, GPT-5.6 Luna/Terra/Sol, and GPT-6 Astra/Sol/Luna, GPTMock carries text system messages into instructions, after any existing instructions and in message order. Developer/user messages and tool results remain in input. This applies to OpenAI Chat, Responses, Ollama chat, and Ollama generate's system field, including existing fast aliases and streaming. Sol/Luna use this as a compatibility policy; their backend requirement for it has not been verified. Existing clients can keep their system prompts. Other models and unsupported non-text system content are passed through unchanged.

Upstream availability note: model availability can change independently of GPTMock releases. The older model list reflects direct probes made on 2026-08-26, GPT-5.6 was rechecked on 2026-09-03, and Astra was verified on 2026-09-05. gpt-5, gpt-5.1, gpt-5.2, gpt-5-codex, gpt-5.1-codex, gpt-5.1-codex-mini, gpt-5.1-codex-max, gpt-5.2-codex, and gpt-5.3-codex were rejected and are therefore not advertised.

Deprecated / Unsupported Models

The rejected names listed above, including GPT-5.4/mini, are omitted from /v1/models and /api/tags. Explicit retired or unknown non-alias identifiers are still forwarded to upstream and its rejection is preserved, rather than being silently replaced with a different model. GPT-5.4 fast identifiers no longer receive synthetic priority translation. Certain removed aliases, such as gpt-6-astra-max, and unsupported reasoning options are rejected locally.

Always supply a non-empty model name. Generation requests without model return HTTP 422. Empty or whitespace-only model names return HTTP 400 before upstream authentication, rather than implicitly selecting GPT-5.4 or another model. An explicitly configured debug-model override remains available for diagnostics.

Request and Response Semantics

Input or event GPTMock behavior
system and developer messages For Spark, GPT-5.5, GPT-5.6 Luna/Terra/Sol, and Astra, system text is moved into instructions and developer messages remain in input; other models retain the supplied roles
Function tools with strict: true Strict schema flag and parameters are preserved
tool_choice: "required" Forwarded as required; never weakened to auto
Rejected tools or model options Upstream error is returned; GPTMock does not remove tools and retry
reasoning.effort or Chat reasoning_effort Validated against the selected model family and forwarded; conflicting values are rejected
Explicit reasoning.mode Rejected locally; the connected ChatGPT Codex backend rejected Pro mode
max_output_tokens, max_completion_tokens, or max_tokens Not forwarded because the ChatGPT Codex upstream cannot enforce them. Default omit mode logs a warning and returns X-GPTMock-Omitted-Parameters; reject mode returns HTTP 400
service_tier or *-fast request Requested tier is sent, while the tier actually returned by upstream is exposed unchanged
response.incomplete Preserved by /v1/responses; mapped to length or content_filter for text. Incomplete tool responses produce an error in Chat/Ollama, not an executable tool_calls finish
response.failed or interrupted SSE Returned as an explicit error; an interrupted stream is never converted into a successful completion
Upstream response model Returned unchanged instead of being replaced with the requested alias
Ollama model metadata Marked as remote with zero/empty unknown size and digest values; no GGUF, Llama family, parameter size, quantization, or local evaluation timings are fabricated
Ollama function calls Arguments are native JSON objects. Streaming fragments are buffered until a valid tool-call finish; tool results are matched by name when supplied

The GPT-5.6 alias and reasoning-effort range follow OpenAI's GPT-5.6 model guidance. GPTMock's accepted options are narrower because they reflect what the ChatGPT Codex backend accepted during the dated probes above, not what may be available through a separate OpenAI API account.

The default output-token policy is intentionally compatibility-oriented. OpenAI SDKs and agent frontends commonly add an output-token field even when the user did not set one. GPTMock accepts such requests but does not claim that the limit was honored: the field is omitted only from the upstream request, a warning names the omitted field, and the HTTP response exposes the same fact. Use --output-token-policy reject when failing closed is preferable to frontend compatibility.

Docker-backed OpenCode 1.17.18 probes on 2026-09-03 verified direct Luna/Sol/Terra model selection, none/high/max reasoning variants, service_tier="priority" request preservation, streaming, tool definitions, tool_choice="auto", and a complete function-call/result/final-answer loop. The upstream response still reported the actual tier as default. OpenCode did not emit configured top_p, tool_choice="required", or strict tool schemas in these runs, so those semantics remain covered by GPTMock's direct request tests rather than claimed as OpenCode-verified.

The 2026-09-05 pre-PR verification reran OpenCode against a temporary local server, including Astra, reasoning variants, tool round trips, and injected stream failures. Native Ollama SDK tool loops and direct strict/named-tool tests also passed. These live checks are separate from the Docker image/runtime checks; see pre-PR validation for results, versions, and coverage boundaries.

Ollama Request Semantics

GPTMock supports both /api/chat and /api/generate. The native Ollama think field maps string levels to reasoning effort; GPTMock additionally accepts the full model-specific effort range (none through max) and the explicit reasoning_effort field. think: false suppresses the returned thinking summary. The non-standard service_tier: "priority" field requests priority service, while the actual upstream tier remains authoritative. Ollama format: "json" and JSON-schema objects map to structured output.

options.num_predict cannot be enforced by the ChatGPT Codex backend, so it follows GPTMOCK_OUTPUT_TOKEN_POLICY: default omit mode returns X-GPTMock-Omitted-Parameters: options.num_predict, while reject mode returns HTTP 400. Other non-empty Ollama runtime options are rejected instead of being silently ignored. Generate-only suffix, non-empty template, context, and raw: true are also rejected because this upstream cannot preserve their meaning.

Docker probes on 2026-09-03 verified authenticated raw HTTP requests for tags, show, structured output, reasoning, priority tier requests, streaming, strict required tools, tool-result continuation, output-limit policy, and upstream errors. Ollama CLI 0.33.1 also completed ollama show and a streaming ollama run through the loopback-only unauthenticated container. Two CLI limitations remain explicit: the CLI did not send OLLAMA_API_KEY to a custom local host, and ollama list panicked when it encountered the intentionally empty remote-model digest. GPTMock will not fabricate a weight digest to satisfy that client assumption; use /api/tags, ollama show <model>, or an Ollama-compatible client that accepts remote metadata.


API Endpoints

Method Path Description
POST /v1/chat/completions OpenAI Chat Completions (stream / non-stream)
POST /v1/completions OpenAI Text Completions
POST /v1/responses OpenAI Responses API semantics
GET /v1/models List configured model metadata; not a live availability check
GET /api/version Ollama-compatible version info
POST /api/chat Ollama-compatible chat
POST /api/generate Ollama-compatible text generation
POST /api/show Ollama-compatible model details
GET /api/tags Ollama model list
GET /health Health check

Features

  • Streaming & Non-streaming — real-time SSE and buffered JSON responses, including explicit incomplete terminal states
  • Structured Output — response_format with json_schema / json_object support
  • Tool / Function Calling — including web search with URL citation annotations via responses_tools
  • Image Generation — Responses API image_generation tool support with base64 PNG output
  • Local Image Inspection — Codex-compatible view_image function tool for allowed local image paths
  • Thinking Summaries — standard mode returns reasoning_content by default; optional think-tags, o3, and legacy modes support other clients
  • Responses API — POST /v1/responses for LangChain and other clients that auto-route codex models
  • Ollama Compatibility — chat and generate APIs with remote-model metadata, without fabricated GGUF sizes, digests, or local evaluation timings
  • Auto Token Refresh — JWT tokens are refreshed automatically before expiry

Server Options

gptmock serve [OPTIONS]

Each option can also be set via environment variable. Precedence: CLI flag > GPTMOCK_* env > CHATGPT_LOCAL_* legacy env > default.

Option Env var Default Description
--host GPTMOCK_HOST 127.0.0.1 Bind address
--port GPTMOCK_PORT 8000 Bind port
--verbose GPTMOCK_VERBOSE off Log request/response payloads
--verbose-obfuscation GPTMOCK_VERBOSE_OBFUSCATION off Also dump raw SSE/obfuscation events
--debug-model GPTMOCK_DEBUG_MODEL — Force all requests to use this model name
--reasoning-effort GPTMOCK_REASONING_EFFORT medium none / minimal / low / medium / high / xhigh / max; availability is model-specific
--reasoning-summary GPTMOCK_REASONING_SUMMARY auto auto / concise / detailed / none
--reasoning-compat GPTMOCK_REASONING_COMPAT standard How reasoning is exposed: standard / think-tags / o3 / legacy (openai is accepted as an alias for standard, current as an alias for legacy)
--expose-reasoning-models GPTMOCK_EXPOSE_REASONING_MODELS off Show effort variants as separate models in /v1/models
--enable-web-search GPTMOCK_DEFAULT_WEB_SEARCH off Enable web search by default when responses_tools is omitted
--output-token-policy GPTMOCK_OUTPUT_TOKEN_POLICY omit omit unenforceable output limits with warning/header, or reject them with HTTP 400
--cors-origins GPTMOCK_CORS_ORIGINS disabled Comma-separated allowed CORS origins
— GPTMOCK_API_KEY unset Optional Bearer token for /v1/* and /api/*; strongly recommended before non-loopback exposure

Legacy aliases: CHATGPT_LOCAL_REASONING_EFFORT, CHATGPT_LOCAL_REASONING_SUMMARY, CHATGPT_LOCAL_REASONING_COMPAT, CHATGPT_LOCAL_EXPOSE_REASONING_MODELS, CHATGPT_LOCAL_ENABLE_WEB_SEARCH, CHATGPT_LOCAL_DEBUG_MODEL are still accepted as fallbacks.


Use --enable-web-search to enable the web search tool by default for all requests. When enabled, the model decides autonomously whether a query needs a web search. You can also enable web search per-request without the server flag by passing the parameters below.

Request Parameters

Parameter Values Description
responses_tools [{"type":"web_search"}] Enable web search for this request
responses_tool_choice "auto" / "none" Let the model decide, or disable

Annotations (URL Citations)

When web search is active, the model may return annotations containing source URLs. These are included automatically in responses:

Non-streaming (stream: false) — annotations are attached to the message:

{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "SpaceX launched 29 Starlink satellites...",
        "annotations": [
          {
            "type": "url_citation",
            "start_index": 0,
            "end_index": 150,
            "url": "https://spaceflightnow.com/...",
            "title": "SpaceX Falcon 9 launch"
          }
        ]
      }
    }
  ]
}

Streaming (stream: true) — annotations arrive as a dedicated chunk before the final stop chunk:

data: {"choices": [{"delta": {"annotations": [{"type": "url_citation", "start_index": 0, "end_index": 150, "url": "https://...", "title": "..."}]}, "finish_reason": null}]}
data: {"choices": [{"delta": {}, "finish_reason": "stop"}]}

Responses API (POST /v1/responses, non-streaming) — annotations are nested inside the output content:

{
  "output": [
    {
      "type": "message",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "SpaceX launched 29 Starlink satellites...",
          "annotations": [
            {
              "type": "url_citation",
              "start_index": 0,
              "end_index": 150,
              "url": "https://spaceflightnow.com/...",
              "title": "SpaceX Falcon 9 launch"
            }
          ]
        }
      ]
    }
  ]
}

Example Request

This shows the web-search request format. The basic text availability check above did not revalidate web-search entitlement or tool execution for the example model.

curl http://127.0.0.1:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.6-luna",
    "messages": [{"role":"user","content":"Find current METAR rules"}],
    "stream": true,
    "responses_tools": [{"type": "web_search"}],
    "responses_tool_choice": "auto"
  }'

Notes & Limits

  • Requires an active, paid ChatGPT account.
  • Context length may be partially used by internal system instructions.
  • For the lowest-reasoning latency baseline, use the lowest effort supported by the selected model (none for GPT-5.6, otherwise usually low) and set --reasoning-summary to none.
  • Context limits and account entitlements are controlled by the ChatGPT Codex backend and may differ from the ChatGPT app or OpenAI API.
  • When the model returns a thinking summary, the default standard mode emits reasoning_content fields without polluting content. Set --reasoning-compat think-tags to keep <think> tags for older chat apps, or --reasoning-compat legacy for the older reasoning fields.
  • This project is not affiliated with OpenAI. Use responsibly and at your own risk.

Credits

Metadata

Release files for gptmock 2026.9.29

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gptmock 2026.9.29
File Size Uploaded
gptmock-2026.9.29.tar.gz 5.9 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for gptmock 2026.9.29
File Interpreter ABI Platform
gptmock-2026.9.29-py3-none-any.whl Python 3 none any Details

Total release size: 6.0 MB

Release files / gptmock-2026.9.29.tar.gz

Download URL gptmock-2026.9.29.tar.gz
Size 5.9 MB
Tags Source
SHA-256 checksum
How to use checksums
6274b95b6b7229a835e4ea62447528962be76be6f96b6765240531cb360a5fec
BLAKE2b-256 checksum
How to use checksums
eef66c298e1451a14616f7195e098fd115c1aaea16898ae7394127c6670cf579
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.

Transparency log

Release files / gptmock-2026.9.29-py3-none-any.whl

Download URL gptmock-2026.9.29-py3-none-any.whl
Size 93.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0395467d48492f4af6bb4664580a6e329786a8fd2c3e1bb83376df28d22adeec
BLAKE2b-256 checksum
How to use checksums
06638213d04d75dec16c493d3fa4c6273d92ff9da5dbe014fce16d86b988e128
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

2026.9.29 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page