| 1 | #!/usr/bin/env python3 |
| 2 | """Local Concentrate contract stub for keyless dogfood (no network, no account). |
| 3 | |
| 4 | Speaks the documented surface of https://api.concentrate.ai/v1 well enough to |
| 5 | prove Codewhale's real request path end to end: |
| 6 | |
| 7 | GET /v1/responses/health -> 200, empty body (unauthenticated) |
| 8 | GET /v1/models -> {"object":"list","data":[{"id":...}]} (unauthenticated) |
| 9 | POST /v1/responses -> typed `response.*` SSE events, no `[DONE]` |
| 10 | |
| 11 | Contract sources (fetched 2026-08-29): |
| 12 | https://concentrate.ai/docs/api-reference/introduction |
| 13 | https://concentrate.ai/docs/api-reference/endpoint/request-parameters |
| 14 | https://concentrate.ai/docs/api-reference/endpoint/streaming |
| 15 | https://concentrate.ai/docs/api-reference/endpoint/errors |
| 16 | https://concentrate.ai/docs/api-reference/endpoint/list-models |
| 17 | https://concentrate.ai/docs/api-reference/endpoint/health |
| 18 | |
| 19 | The stub asserts what a real gateway would enforce and what Codewhale must |
| 20 | send: a `Bearer` Authorization header equal to CONCENTRATE_STUB_EXPECT_KEY, |
| 21 | `model` passed through verbatim, `stream: true`, and no undocumented top-level |
| 22 | fields. Every request is appended as JSON to CONCENTRATE_STUB_LOG so the |
| 23 | driver can assert the receipt after the run. A wrong key answers with the |
| 24 | documented 401 body so the error path is exercised too. |
| 25 | |
| 26 | Usage: CONCENTRATE_STUB_PORT=8790 CONCENTRATE_STUB_EXPECT_KEY=stub-key \ |
| 27 | CONCENTRATE_STUB_LOG=/tmp/concentrate-stub.jsonl python3 scripts/concentrate-stub.py |
| 28 | """ |
| 29 | from __future__ import annotations |
| 30 | |
| 31 | import json |
| 32 | import os |
| 33 | import sys |
| 34 | import time |
| 35 | from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer |
| 36 | |
| 37 | PORT = int(os.environ.get("CONCENTRATE_STUB_PORT", "8790")) |
| 38 | EXPECT_KEY = os.environ.get("CONCENTRATE_STUB_EXPECT_KEY", "stub-key") |
| 39 | LOG = os.environ.get("CONCENTRATE_STUB_LOG", "") |
| 40 | REPLY_TEXT = os.environ.get("CONCENTRATE_STUB_REPLY", "ok from the concentrate stub") |
| 41 | |
| 42 | # https://concentrate.ai/docs/api-reference/endpoint/request-parameters |
| 43 | DOCUMENTED_TOP_LEVEL = { |
| 44 | "model", "input", "max_output_tokens", "temperature", "top_p", "stream", |
| 45 | "text", "reasoning", "tools", "tool_choice", "parallel_tool_calls", |
| 46 | "routing", "cache_control", "prompt_cache_options", |
| 47 | } |
| 48 | |
| 49 | # A slice of the live catalog shape read on 2026-08-29 (ids are plain; the |
| 50 | # upstream provider lives in `owned_by`). |
| 51 | MODELS = [ |
| 52 | {"id": "deepseek-v4-pro", "object": "model", "owned_by": "deepseek", "type": "chat", "display_name": "DeepSeek V4 Pro"}, |
| 53 | {"id": "gpt-5.6-sol", "object": "model", "owned_by": "openai", "type": "chat", "display_name": "GPT-5.6 Sol"}, |
| 54 | {"id": "claude-fable-5", "object": "model", "owned_by": "anthropic", "type": "chat", "display_name": "Claude Fable 5"}, |
| 55 | ] |
| 56 | |
| 57 | |
| 58 | def log_event(record: dict) -> None: |
| 59 | if not LOG: |
| 60 | return |
| 61 | with open(LOG, "a", encoding="utf-8") as handle: |
| 62 | handle.write(json.dumps(record) + "\n") |
| 63 | |
| 64 | |
| 65 | class Handler(BaseHTTPRequestHandler): |
| 66 | server_version = "concentrate-stub/0.1" |
| 67 | |
| 68 | def log_message(self, fmt, *args): # quiet by default; the driver reads the JSONL log |
| 69 | if os.environ.get("CONCENTRATE_STUB_VERBOSE"): |
| 70 | sys.stderr.write("%s - %s\n" % (self.address_string(), fmt % args)) |
| 71 | |
| 72 | def _json(self, status: int, payload: dict | None, headers: dict | None = None) -> None: |
| 73 | body = b"" if payload is None else json.dumps(payload).encode() |
| 74 | self.send_response(status) |
| 75 | self.send_header("Content-Type", "application/json") |
| 76 | self.send_header("Content-Length", str(len(body))) |
| 77 | for key, value in (headers or {}).items(): |
| 78 | self.send_header(key, value) |
| 79 | self.end_headers() |
| 80 | if body: |
| 81 | self.wfile.write(body) |
| 82 | |
| 83 | def do_GET(self): # noqa: N802 (http.server API) |
| 84 | path = self.path.split("?", 1)[0].rstrip("/") |
| 85 | log_event({"method": "GET", "path": self.path, "authorization": self.headers.get("Authorization")}) |
| 86 | if path == "/v1/responses/health": |
| 87 | # https://concentrate.ai/docs/api-reference/endpoint/health — 200, empty body, no auth. |
| 88 | self.send_response(200) |
| 89 | self.send_header("Content-Type", "application/json") |
| 90 | self.send_header("Content-Length", "0") |
| 91 | self.end_headers() |
| 92 | return |
| 93 | if path == "/v1/models": |
| 94 | # https://concentrate.ai/docs/api-reference/endpoint/list-models — no auth required. |
| 95 | self._json(200, {"object": "list", "data": MODELS}) |
| 96 | return |
| 97 | self._json(404, {"error": "Not Found", "message": f"No route for {path}"}) |
| 98 | |
| 99 | def do_POST(self): # noqa: N802 |
| 100 | path = self.path.split("?", 1)[0].rstrip("/") |
| 101 | length = int(self.headers.get("Content-Length") or 0) |
| 102 | raw = self.rfile.read(length) if length else b"" |
| 103 | try: |
| 104 | body = json.loads(raw or b"{}") |
| 105 | except json.JSONDecodeError: |
| 106 | self._json(400, {"error": "Bad Request", "message": "Invalid JSON body"}) |
| 107 | return |
| 108 | auth = self.headers.get("Authorization") or "" |
| 109 | record = { |
| 110 | "method": "POST", |
| 111 | "path": self.path, |
| 112 | "authorization": auth, |
| 113 | "model": body.get("model"), |
| 114 | "stream": body.get("stream"), |
| 115 | "top_level_fields": sorted(body.keys()), |
| 116 | "undocumented_fields": sorted(set(body.keys()) - DOCUMENTED_TOP_LEVEL), |
| 117 | "input_roles": [item.get("role") for item in body.get("input", []) if isinstance(item, dict)], |
| 118 | "tool_names": [tool.get("name") for tool in body.get("tools", []) if isinstance(tool, dict)], |
| 119 | } |
| 120 | log_event(record) |
| 121 | if path != "/v1/responses": |
| 122 | self._json(404, {"error": "Not Found", "message": f"No route for {path}"}) |
| 123 | return |
| 124 | # https://concentrate.ai/docs/api-reference/endpoint/errors |
| 125 | if auth != f"Bearer {EXPECT_KEY}": |
| 126 | self._json(401, {"error": "Unauthorized", "message": "Invalid API key"}) |
| 127 | return |
| 128 | if not body.get("model"): |
| 129 | self._json(400, {"error": "Bad Request", "message": "Invalid model name: ''"}) |
| 130 | return |
| 131 | if record["undocumented_fields"]: |
| 132 | self._json(400, {"error": "Bad Request", "message": f"Invalid parameters: {record['undocumented_fields']}"}) |
| 133 | return |
| 134 | if body.get("model") == "stub/insufficient-credits": |
| 135 | self._json(402, {"error": "Insufficient funds", "message": "Your account has insufficient credits. Please add credits to continue."}) |
| 136 | return |
| 137 | if not body.get("stream"): |
| 138 | self._json(200, self._completed_response(body)) |
| 139 | return |
| 140 | self._stream(body) |
| 141 | |
| 142 | def _completed_response(self, body: dict) -> dict: |
| 143 | selected = body["model"] if "/" in body["model"] else f"stub/{body['model']}" |
| 144 | return { |
| 145 | "id": "resp_stub_1", |
| 146 | "object": "response", |
| 147 | "created_at": int(time.time()), |
| 148 | "status": "completed", |
| 149 | "model": selected, |
| 150 | "output": [{ |
| 151 | "type": "message", "id": "msg_stub_1", "status": "completed", "role": "assistant", |
| 152 | "content": [{"type": "output_text", "text": REPLY_TEXT, "annotations": []}], |
| 153 | }], |
| 154 | "usage": {"input_tokens": 12, "output_tokens": 5, "total_tokens": 17, |
| 155 | "input_tokens_details": {"cached_tokens": 0}}, |
| 156 | } |
| 157 | |
| 158 | def _stream(self, body: dict) -> None: |
| 159 | # https://concentrate.ai/docs/api-reference/endpoint/streaming — typed |
| 160 | # events, `event:` + `data:` frames, sequence numbers, no [DONE]. |
| 161 | response = self._completed_response(body) |
| 162 | self.send_response(200) |
| 163 | self.send_header("Content-Type", "text/event-stream") |
| 164 | self.send_header("Cache-Control", "no-cache") |
| 165 | self.end_headers() |
| 166 | seq = 0 |
| 167 | |
| 168 | def emit(event_type: str, payload: dict) -> None: |
| 169 | nonlocal seq |
| 170 | payload = {"type": event_type, "sequence_number": seq, **payload} |
| 171 | seq += 1 |
| 172 | self.wfile.write(f"event: {event_type}\ndata: {json.dumps(payload)}\n\n".encode()) |
| 173 | self.wfile.flush() |
| 174 | |
| 175 | in_progress = {**response, "status": "in_progress", "output": [], "usage": None} |
| 176 | emit("response.created", {"response": in_progress}) |
| 177 | emit("response.in_progress", {"response": in_progress}) |
| 178 | item = {"type": "message", "id": "msg_stub_1", "status": "in_progress", "role": "assistant", "content": []} |
| 179 | emit("response.output_item.added", {"output_index": 0, "item": item}) |
| 180 | emit("response.content_part.added", {"item_id": "msg_stub_1", "output_index": 0, "content_index": 0, |
| 181 | "part": {"type": "output_text", "text": "", "annotations": []}}) |
| 182 | words = REPLY_TEXT.split(" ") |
| 183 | for index, word in enumerate(words): |
| 184 | delta = word if index == len(words) - 1 else word + " " |
| 185 | emit("response.output_text.delta", {"item_id": "msg_stub_1", "output_index": 0, "content_index": 0, "delta": delta}) |
| 186 | emit("response.output_text.done", {"item_id": "msg_stub_1", "output_index": 0, "content_index": 0, "text": REPLY_TEXT}) |
| 187 | emit("response.content_part.done", {"item_id": "msg_stub_1", "output_index": 0, "content_index": 0, |
| 188 | "part": {"type": "output_text", "text": REPLY_TEXT, "annotations": []}}) |
| 189 | emit("response.output_item.done", {"output_index": 0, "item": response["output"][0]}) |
| 190 | emit("response.completed", {"response": response}) |
| 191 | |
| 192 | |
| 193 | def main() -> int: |
| 194 | server = ThreadingHTTPServer(("127.0.0.1", PORT), Handler) |
| 195 | print(f"concentrate-stub listening on http://127.0.0.1:{server.server_address[1]}/v1", flush=True) |
| 196 | try: |
| 197 | server.serve_forever() |
| 198 | except KeyboardInterrupt: |
| 199 | pass |
| 200 | return 0 |
| 201 | |
| 202 | |
| 203 | if __name__ == "__main__": |
| 204 | sys.exit(main()) |
| 205 |