@askalf/dario 6.2.0 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,94 @@
1
+ # Codex CLI on your Claude plan
2
+
3
+ OpenAI's Codex CLI runs on a Claude subscription through dario, with its
4
+ tools, since 6.3. The other way round — Claude Code on a ChatGPT plan — has
5
+ worked since 5.5.89. Both on one machine, one `dario proxy`, is the whole
6
+ point of the project in two panes.
7
+
8
+ ## Why this needed a new endpoint
9
+
10
+ Codex CLI 0.154 removed `wire_api = "chat"` for custom providers
11
+ ([openai/codex discussion 7782](https://github.com/openai/codex/discussions/7782)):
12
+ a provider has to speak the **Responses API** or it cannot be used at all. So
13
+ dario now has `POST /v1/responses`. The request is translated once at the front
14
+ door into the Messages shape every other dario path already serves — pool,
15
+ template, failover, mid-stream continuation — and everything written back is
16
+ translated at the write boundary. For a ChatGPT-subscription model the body
17
+ goes through to the codex backend untouched instead (it speaks Responses
18
+ natively), which is what keeps Codex's newest request features working there:
19
+ `additional_tools` input items, `custom` tools, `reasoning.context`,
20
+ `include`.
21
+
22
+ The OpenAI Agents SDK and anything else that speaks Responses gets the same
23
+ endpoint.
24
+
25
+ ## Setup
26
+
27
+ ```bash
28
+ dario proxy # your Claude plan, port 3456
29
+ ```
30
+
31
+ `~/.codex/config.toml`:
32
+
33
+ ```toml
34
+ model = "claude-opus-5"
35
+ model_provider = "dario"
36
+
37
+ [model_providers.dario]
38
+ name = "dario"
39
+ base_url = "http://127.0.0.1:3456/v1"
40
+ env_key = "DARIO_API_KEY"
41
+ wire_api = "responses"
42
+ ```
43
+
44
+ `export DARIO_API_KEY=dario` (any value until you set one on the proxy; then it
45
+ has to match), and `codex` runs on the Claude pool. `-m claude-sonnet-5` /
46
+ `-m claude-opus-5` / any `claude-*` id; `codex exec` works the same way.
47
+
48
+ With a ChatGPT account attached as well (`dario add altman`),
49
+ `-m gpt-5.6-sol` on the same provider block goes to that plan through dario —
50
+ pooling, failover and `x-dario-*` headers included.
51
+
52
+ Codex prints `Model metadata for claude-opus-5 not found. Defaulting to fallback
53
+ metadata` for any model it does not ship metadata for. Harmless: it falls back
54
+ to its classic request profile (top-level `tools` and `instructions`), which is
55
+ exactly the one the translation reads.
56
+
57
+ ## What runs, and what does not
58
+
59
+ Verified on 2026-09-12 with Codex CLI 0.154.0 on a Claude Max plan:
60
+
61
+ - a plain turn;
62
+ - the full agent loop — `exec_command` called by Claude, executed by Codex,
63
+ the `function_call_output` returned, Claude answering from it — with the
64
+ 17 KB Codex system prompt cached on the Claude side (98–99% cache reads
65
+ from the second turn);
66
+ - the same loop on a ChatGPT plan through the passthrough.
67
+
68
+ Translated on the Claude pool: `instructions` and `developer` messages
69
+ (hoisted to the system prompt, in order), `message` items with `input_text`,
70
+ `output_text` and `input_image` parts (data-URL and https images),
71
+ `function_call` / `function_call_output` (tool_use / tool_result, call ids
72
+ preserved), `function` tools (and `namespace` groups, flattened),
73
+ `tool_choice` including `required` and a named function,
74
+ `parallel_tool_calls: false`, `max_output_tokens`, `temperature`, `top_p`,
75
+ `reasoning.effort` (as dario's own `model:high` effort spelling). Back out:
76
+ `message`, `function_call` and `reasoning` items, the full Responses event
77
+ sequence with sequence numbers, usage in OpenAI terms (cached prefix inside
78
+ `input_tokens`, reported again under `cached_tokens`), `incomplete` on
79
+ `max_tokens`, `response.failed` on an upstream error.
80
+
81
+ Dropped, with a line at `--verbose`: hosted tool types the pool cannot run
82
+ (`web_search`, `file_search`, `mcp`, …), `custom` freeform tools,
83
+ `reasoning` items on the way in (OpenAI's encrypted content — the pool does
84
+ not need it back), `text.format`. `previous_response_id` on the Claude pool is a 400 naming the
85
+ field (dario is stateless there; send the full input each turn, which Codex
86
+ does); on a ChatGPT-subscription model it is forwarded untouched to a backend
87
+ that keeps state, `store` as you sent it or omitted for the backend's default.
88
+
89
+ Not built: a buffered (non-streaming) response from a ChatGPT-subscription
90
+ model on this route — the backend streams, and folding a Responses stream into
91
+ a response object is not written yet; the answer is a 400 naming `stream`.
92
+ Mid-stream continuation runs under this route on the Claude pool (the
93
+ translated request is an ordinary Anthropic-shape request) and not on the
94
+ passthrough.
@@ -134,6 +134,32 @@ is never closed with a synthetic `end_turn`; only the resume's own
134
134
  | `--pool-fallback=…` | where the second hop goes; without an entry for the other provider a stream gets the same-model resume only |
135
135
 
136
136
  On by default: it only ever acts where the alternative is a broken stream.
137
+ `dario doctor` reports which hops this host can take:
138
+
139
+ ```
140
+ [ OK ] Continuation on: a dying stream resumes on the same model, then on gpt-5.6-sol → claude-sonnet-5 (two hops)
141
+ [ OK ] Continuation on: a dying stream resumes on the same model only — add --pool-fallback for a second hop on the other subscription
142
+ [INFO] Continuation off — a stream that dies mid-answer ends truncated (unset DARIO_MIDSTREAM_CONTINUE / drop --no-midstream-continue)
143
+ ```
144
+
145
+ ## Seeing it happen
146
+
147
+ Nothing about a healthy stream shows the feature, so there is a tap that
148
+ kills one on purpose:
149
+
150
+ ```bash
151
+ DARIO_CHAOS_CUT_AFTER=300 dario proxy
152
+ ```
153
+
154
+ The first streamed answer dies after 300 characters — the upstream socket is
155
+ cut from dario's side, exactly the failure a real reset produces — and the
156
+ continuation finishes it. Point any client at the proxy, ask for something
157
+ long, and watch the answer keep going past the cut; a raw `curl -N` shows the
158
+ seam comment. `DARIO_CHAOS_CUT_STREAMS=3` cuts the first three instead of one.
159
+ The tap spares resumes, so it shows the first hop — the same model finishing
160
+ its own answer; the other subscription takes over only when that model cannot
161
+ serve the resume. dario warns loudly at startup while the tap is set; it is a
162
+ demo and test affordance, never a default.
137
163
 
138
164
  ## How it was proven
139
165
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askalf/dario",
3
- "version": "6.2.0",
3
+ "version": "6.3.0",
4
4
  "description": "Use your Claude and ChatGPT subscriptions in Cursor, Cline, Aider, Claude Code and the Agent SDK — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint: either plan answers either wire shape, with automatic failover when one hits its limit.",
5
5
  "type": "module",
6
6
  "bin": {