clauderipple 0.9.3 → 0.9.5
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.
- package/CHANGELOG.md +41 -0
- package/dist/app/package.json +1 -1
- package/dist/mod/hooks/i18n.ts +36 -0
- package/dist/mod/hooks/register.tsx +8 -4
- package/dist/mod/hooks/session.ts +2 -2
- package/dist/mod/hooks/ui/alerts.tsx +10 -0
- package/dist/mod/hooks/ui/art.ts +64 -1
- package/dist/mod/hooks/ui/band.tsx +70 -42
- package/dist/mod/hooks/ui/kit.tsx +34 -2
- package/dist/mod/hooks/ui/view.ts +5 -0
- package/dist/mod/tests/register.test.tsx +31 -3
- package/dist/mod/tests/ui.test.tsx +108 -18
- package/dist/mod/types/index.d.ts +1 -1
- package/dist/router/src/admin.js +65 -6
- package/dist/router/src/agents.js +5 -0
- package/dist/router/src/catalog.js +18 -8
- package/dist/router/src/index.js +13 -4
- package/dist/router/src/presets.js +3 -0
- package/dist/router/src/providers/chatgpt/index.js +49 -11
- package/dist/router/src/providers/chatgpt/translate.js +147 -7
- package/dist/router/src/providers/openai/index.js +29 -5
- package/dist/router/src/providers/openai/translate.js +247 -25
- package/dist/router/src/providers/retry.js +15 -0
- package/dist/router/src/reasoning.js +157 -0
- package/dist/router/src/thinking.js +20 -9
- package/dist/router/src/version.js +1 -1
- package/docs/ARCHITECTURE.md +56 -4
- package/package.json +3 -2
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
// from the manifests. Until 0.1.1 the router and the CLI each carried their own literal, and both
|
|
6
6
|
// still said "0.1.0" in the 0.1.1 release: after an update nobody could tell which router was
|
|
7
7
|
// running, and the tray app had nothing to compare (2026-09-15, reported from a Windows install).
|
|
8
|
-
export const VERSION = "0.9.
|
|
8
|
+
export const VERSION = "0.9.5";
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -731,8 +731,13 @@ must preserve **Data: Artificial Analysis (artificialanalysis.ai)** attribution.
|
|
|
731
731
|
- `WebFetch` needs none of this: the CLI fetches the URL itself (its own transport, cache and
|
|
732
732
|
preflight; there is no `web_fetch` server tool in the binary) and has the session's model read
|
|
733
733
|
the text. It works on any provider.
|
|
734
|
-
- Cache-safety decisions:
|
|
735
|
-
|
|
734
|
+
- Cache-safety decisions: a translated provider's own reasoning that comes back with the
|
|
735
|
+
request is sent back **byte-identically, in its original position** — that is what the
|
|
736
|
+
vendor's native clients do, and it is not a `cache_control` breakpoint; the forbidden
|
|
737
|
+
thing is *altering or re-signing* reasoning, which is what cost 12–20% cache (2026-09-20).
|
|
738
|
+
A thinking block of ours that names no vendor model, or another model than this request's,
|
|
739
|
+
is dropped (§5, "Muse workers"); foreign thinking of any other kind is dropped from
|
|
740
|
+
replayed history; identity line and `instructionsAppend` are constant
|
|
736
741
|
text; `prompt_cache_key` = sha256(metadata.user_id + first user message),
|
|
737
742
|
and sha256(system prompt) for a request that carries no `metadata.user_id`
|
|
738
743
|
and one lone user turn — see the conversation-key note in §4.
|
|
@@ -1061,9 +1066,11 @@ what we do not have yet — so that adding a provider does not start with readin
|
|
|
1061
1066
|
config still written as three providers is folded on the way in and its `direct` and
|
|
1062
1067
|
`routes` references follow; nothing is rewritten on disk, so it stays readable by an
|
|
1063
1068
|
older router until the GUI saves it.
|
|
1064
|
-
- Translation deliberately strips `
|
|
1069
|
+
- Translation deliberately strips `context_management`, `thread`,
|
|
1065
1070
|
`diagnostics`, and `container`; `thread:continue` is refused exactly as in §4a so
|
|
1066
|
-
the CLI resends a full stateless history.
|
|
1071
|
+
the CLI resends a full stateless history. Thinking is stripped by default too —
|
|
1072
|
+
except the reasoning this adapter itself handed out, which returns as the vendor's
|
|
1073
|
+
own item (see the reasoning-replay note below). The per-turn
|
|
1067
1074
|
`x-anthropic-billing-header` system block is also stripped because its changing
|
|
1068
1075
|
value breaks every vendor's stable-prefix cache opportunity. Orphan tool results
|
|
1069
1076
|
are sent as user text, not a tool result with no antecedent call.
|
|
@@ -1085,6 +1092,50 @@ what we do not have yet — so that adding a provider does not start with readin
|
|
|
1085
1092
|
before (`catalog.ts`, `capabilities.ts`). Chat wire
|
|
1086
1093
|
forwards Anthropic `stop_sequences` as `stop`; Responses wire deliberately omits
|
|
1087
1094
|
them because its common stateless schema has no corresponding universal field.
|
|
1095
|
+
- **Reasoning replay (both wires, 2026-10-14).** A reasoning model on either wire
|
|
1096
|
+
expects its own previous reasoning back on the next turn of a tool loop, and does
|
|
1097
|
+
badly without it. Measured on OpenCode Go's Muse at `xhigh`, same task, 3 runs
|
|
1098
|
+
each: with no replay 9.5k–24.5k reasoning tokens per run (2,197 per step past 80k
|
|
1099
|
+
context) and one run exhausted the context with no answer; with replay 3.2k–4.3k
|
|
1100
|
+
per run (725 per step past 80k) and all three answered, 94% cached.
|
|
1101
|
+
Native clients (OpenCode, the Codex CLI) do this by carrying the vendor's item in
|
|
1102
|
+
their own transcript and putting it back byte-for-byte where it was.
|
|
1103
|
+
Claude Code's transcript is the same medium, so the carrier is the **signature of a
|
|
1104
|
+
thinking block**: `reasoning.ts` encodes `clauderipple.v1:` + base64url JSON
|
|
1105
|
+
naming the wire, provider and model and the thing to restore — the vendor's whole
|
|
1106
|
+
Responses item for the Responses wire, or just the field name
|
|
1107
|
+
(`reasoning_content` / `reasoning`) for Chat. On the Responses wire the item is
|
|
1108
|
+
`{type:"reasoning", id, summary, encrypted_content}` and the request asks for it
|
|
1109
|
+
with `include:["reasoning.encrypted_content"]` (with `store:false` and
|
|
1110
|
+
`reasoning.summary:"auto"`, both of which the chatgpt adapter already sent); the
|
|
1111
|
+
block's text is the summary, or empty when the item had none. `include` is sent on
|
|
1112
|
+
every turn to the ChatGPT backend (as Codex sends it) and to a preset marked
|
|
1113
|
+
`sealedReasoning` (OpenCode Go, as OpenCode's own client sends it): a `store:false`
|
|
1114
|
+
backend that is not asked hands back nothing, so asking only once a conversation
|
|
1115
|
+
already carried reasoning would never start one. Any other Responses vendor is asked
|
|
1116
|
+
only once its own reasoning is already being carried, so an unmeasured vendor keeps
|
|
1117
|
+
its old request. Measured 2026-10-14 against OpenCode Go: the sealed item came back
|
|
1118
|
+
with `include` and without it (1426 bytes either way), replaying it in place
|
|
1119
|
+
answered 200, and the vendor tolerated both a tampered blob and a dropped item. On Chat the
|
|
1120
|
+
block's own text *is* the reasoning and it is reassembled into the field it arrived
|
|
1121
|
+
under on that assistant message — DeepSeek's docs make that mandatory whenever
|
|
1122
|
+
`tools` is present (`https://api-docs.deepseek.com/guides/thinking_mode/`), and it
|
|
1123
|
+
is harmless where a vendor ignores it, so this is not gated by an allowlist.
|
|
1124
|
+
Restore happens only when the envelope names this request's provider and model
|
|
1125
|
+
(model scope validation): another model's or account's `encrypted_content` is a
|
|
1126
|
+
400, and the envelope says whose it is. This is not exposed as a setting, and it
|
|
1127
|
+
does not weaken the cache lesson above — the vendor's bytes are re-sent unchanged,
|
|
1128
|
+
never re-signed or edited. `opencodex` (github.com/lidge-jun/opencodex,
|
|
1129
|
+
`devlog/_fin/260711_claude_inbound/003_evidence.md:93-118`) uses the same
|
|
1130
|
+
envelope-in-the-transcript approach and measured that Claude Code replays thinking
|
|
1131
|
+
blocks with their signature and does not validate it client-side; no code was
|
|
1132
|
+
copied from it. A 4xx that names reasoning/encrypted/item is answered by asking
|
|
1133
|
+
**once more without any replayed reasoning**, so an account switch that invalidates
|
|
1134
|
+
`encrypted_content` costs a little cache and not the turn. `router.log` and
|
|
1135
|
+
`requests.jsonl` carry `replayed=<n>` (items put back) and `reasoning=<n>` (items
|
|
1136
|
+
handed to the client). Gemini and the other translators strip these blocks; a
|
|
1137
|
+
conversation switched to a Claude model does too (`thinking.ts`), since Anthropic
|
|
1138
|
+
would reject a foreign signature.
|
|
1088
1139
|
- We do not assert a provider-wide cache hit rate: the adapter records
|
|
1089
1140
|
`prompt_tokens_details.cached_tokens` / `input_tokens_details.cached_tokens` when
|
|
1090
1141
|
a vendor returns it, and otherwise logs zero cache read. The byte-stable
|
|
@@ -1386,6 +1437,7 @@ plan unless marked otherwise.
|
|
|
1386
1437
|
| Adding a provider in the settings window restored three OpenCode effort ladders realigned by hand five hours earlier, so the app's effort menus for DeepSeek and GLM never narrowed (2026-10-02 23:13, found 10-05). `PUT /api/config` takes the whole config, and the screen built it from the copy it loaded at open and never re-read; the router itself also writes `config.json` (a measurement's results), so any of those was undone by the next unrelated save | Every GUI save fetches the router's config first and applies its own change to that. A provider form, which holds per-model fields (wire, ladder, window) from when it opened and has no control for them, takes a saved model's values from the router's copy. The provider and client screens re-read the config whenever they load. |
|
|
1387
1438
|
| In picker mode, claude.ai requests failed as `502 … ECONNRESET` in under a second — 259 times in four days (2026-10-03..06), mostly `current_user_access`, `desktop/features` and `event_logging`. The kept-alive upstream socket had been closed by claude.ai as the next request was written on it, and Node does not resend | A GET/HEAD/OPTIONS whose reused socket resets before any response is sent again (twice at most), logged `STALE`. A POST is never resent: a reset does not prove the upstream did not act on it. Not yet shown to be the cause of the Windows "chat history loads forever" report (DC, 2026-10-06). |
|
|
1388
1439
|
| An API-key provider with no declared effort ladder — DeepSeek, Kimi, GLM, MiniMax, Qwen, Groq, Mistral, a key and a URL — stripped every effort the user picked (`effort high→removed`) and the Claude app showed no effort menu for its models (DC reports, 2026-10-06). Declaring nothing was meant as "do not guess", but DeepSeek's API, for one, validates `output_config.effort` and maps it onto low/high/max | When nothing declares a ladder (no config ladder, no preset ladder, OpenAI-compatible `reasoning` not `effort` — the form writes `none` by default), a measurement sends a level no vendor defines first: accepted means the field is ignored (no effort, `[]`); refused means it is validated, and the levels the refusal names (else every known one) are sent one by one and the accepted ones become the model's ladder. A 429/5xx concludes nothing. The router runs this a minute after start for unsettled models, so existing providers need no re-save. The DeepSeek preset now declares low/high/max from its docs. |
|
|
1440
|
+
| Muse workers spent minutes per tool call, repeated the same reasoning every step, and one ended with no answer at all (2026-10-14). A reasoning model on a translated wire was getting its own previous reasoning dropped, so each step reasoned the whole problem again from scratch: measured at `xhigh` on OpenCode Go, 9.5k–24.5k reasoning tokens per run without replay against 3.2k–4.3k with it (3 runs each; 2,197 against 725 per step past 80k context; one no-replay run exhausted the context) | The vendor's reasoning is carried in the client's transcript and put back byte-identically at its original position: the Responses item whole, under `include:["reasoning.encrypted_content"]`, and on Chat its text as `reasoning_content`. `reasoning.ts` states the envelope; a block whose envelope names another provider or model is dropped, and a 4xx naming the reasoning is retried once without it. |
|
|
1389
1441
|
| ChatGPT accounts that had bought Codex credits were rested by the router the moment a window read 100%, though OpenAI serves them from credits past the window | `exhaustedForMs` ignores a full window while `credits.has_credits` or `unlimited` holds (and `overage_limit_reached` does not); an actual 429 still rests the account until the window resets. |
|
|
1390
1442
|
|
|
1391
1443
|
## 6. Blocked paths (measured, do not retry)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clauderipple",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.5",
|
|
4
4
|
"description": "Use GPT (any ChatGPT plan with Codex), DeepSeek and 400+ other models in the Claude Desktop Code tab and Claude Code while staying signed in to your Claude subscription — no third-party gateway mode. Several ChatGPT accounts that take over when one runs out, in Codex too.",
|
|
5
5
|
"license": "GPL-3.0-only",
|
|
6
6
|
"workspaces": [
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
"url": "https://github.com/PBJ-2/clauderipple/issues"
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
|
-
"proper-lockfile": "^4.1.2"
|
|
80
|
+
"proper-lockfile": "^4.1.2",
|
|
81
|
+
"undici": "7.24.4"
|
|
81
82
|
}
|
|
82
83
|
}
|