GPTMock
OpenAI & Ollama compatible API powered by your ChatGPT account.
This is a fork of RayBytes/chatmock. The original Flask + synchronous
requestsstack has been replaced with FastAPI + asynchttpx, a layered architecture (router / service / infra),pydantic-settingsconfiguration, anduvas 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-compatnow defaults tostandard, which emits reasoning viadelta.reasoning_content/message.reasoning_contentinstead of injecting<think>tags intocontent. Set--reasoning-compat think-tags(orGPTMOCK_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
uvonly for direct, non-Docker usage
Quick Start (Docker, recommended)
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:
- Browser on the same machine — the URL opens automatically and the OAuth callback is caught on port 1455.
- 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:
*-fastnames are accepted when requested directly and addservice_tier="priority"to the same verified base-model request. They are not separate models, are not advertised by/v1/modelsor/api/tags, and do not guarantee priority service. New integrations should prefer the verified base model plus an explicitservice_tier="priority"request. GPTMock returns the actual upstreamservice_tierunchanged. The seven pre-Astra aliases were accepted on 2026-08-26 withservice_tier="default". Astra's priority request was separately accepted on 2026-09-05 and also returneddefault;gpt-6-astra-fastuses 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.6follows OpenAI's documented alias togpt-5.6-sol. OpenAI documents Pro asreasoning.mode="pro"on the same model rather than as a*-promodel ID, but the ChatGPT Codex backend rejected that mode in direct probes. GPTMock therefore advertises no Pro model slug and rejectsreasoning.modelocally instead of sending a request known to be unsupported by this upstream.
GPT-6 Astra:
gpt-6-astraconnects directly to that exact upstream model. The official model documentation listslow,medium,high,xhigh, andmax; direct ChatGPT Codex probes on 2026-09-05 completed at all five efforts and echoed the requested model and effort. That backend rejectednone,minimal,ultra,gpt-6-astra-pro, andreasoning.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 ininput. This applies to OpenAI Chat, Responses, Ollama chat, and Ollama generate'ssystemfield, 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, andgpt-5.3-codexwere 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_formatwithjson_schema/json_objectsupport - Tool / Function Calling — including web search with URL citation annotations via
responses_tools - Image Generation — Responses API
image_generationtool support with base64 PNG output - Local Image Inspection — Codex-compatible
view_imagefunction tool for allowed local image paths - Thinking Summaries —
standardmode returnsreasoning_contentby default; optionalthink-tags,o3, andlegacymodes support other clients - Responses API —
POST /v1/responsesfor 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_MODELare still accepted as fallbacks.
Web Search
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 (
nonefor GPT-5.6, otherwise usuallylow) and set--reasoning-summarytonone. - 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
standardmode emitsreasoning_contentfields without pollutingcontent. Set--reasoning-compat think-tagsto keep<think>tags for older chat apps, or--reasoning-compat legacyfor the older reasoning fields. - This project is not affiliated with OpenAI. Use responsibly and at your own risk.
Credits
- Original project: RayBytes/chatmock
- This fork: rapidrabbit76/GPTMock
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)
| File | Size | Uploaded | |
|---|---|---|---|
| gptmock-2026.9.29.tar.gz | 5.9 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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 logRelease 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