clauderipple 0.7.0 → 0.8.1
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 +77 -0
- package/README.ko.md +18 -2
- package/README.md +27 -5
- package/dist/app/package.json +1 -1
- package/dist/cli/src/claude-auth.js +35 -1
- package/dist/cli/src/codex.js +23 -0
- package/dist/cli/src/hooks/agent-title.js +58 -29
- package/dist/cli/src/index.js +46 -1
- package/dist/cli/src/picker.js +19 -11
- package/dist/cli/src/runtime.js +3 -0
- package/dist/cli/src/settings.js +49 -0
- package/dist/mod/.claude-plugin/plugin.json +1 -0
- package/dist/mod/hooks/hooks.json +1 -0
- package/dist/mod/hooks/register.tsx +309 -0
- package/dist/mod/hooks/worker.ts +49 -0
- package/dist/mod/tsconfig.json +3 -0
- package/dist/mod/types/index.d.ts +30 -0
- package/dist/router/src/admin.js +411 -32
- package/dist/router/src/agents.js +24 -8
- package/dist/router/src/catalog.js +80 -0
- package/dist/router/src/compat.js +27 -1
- package/dist/router/src/config.js +31 -0
- package/dist/router/src/index.js +12 -1
- package/dist/router/src/ingress/server.js +3 -2
- package/dist/router/src/picker.js +33 -2
- package/dist/router/src/presets.js +2 -1
- package/dist/router/src/providers/chatgpt/index.js +77 -18
- package/dist/router/src/providers/chatgpt/translate.js +34 -6
- package/dist/router/src/providers/google/accounts.js +345 -0
- package/dist/router/src/providers/google/antigravity.js +392 -0
- package/dist/router/src/providers/google/index.js +617 -0
- package/dist/router/src/providers/google/login.js +249 -0
- package/dist/router/src/providers/google/thoughtSignatures.js +47 -0
- package/dist/router/src/providers/google/translate.js +539 -0
- package/dist/router/src/providers/google/transport.js +118 -0
- package/dist/router/src/providers/openai/translate.js +3 -3
- package/dist/router/src/proxy.js +116 -9
- package/dist/router/src/requestlog.js +2 -0
- package/dist/router/src/routing.js +22 -0
- package/dist/router/src/version.js +1 -1
- package/dist/ui/app.js +420 -45
- package/dist/ui/i18n.js +76 -4
- package/dist/ui/index.html +5 -0
- package/dist/ui/style.css +4 -0
- package/docs/ARCHITECTURE.md +307 -4
- package/package.json +1 -1
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -48,6 +48,35 @@ Why this path is stable:
|
|
|
48
48
|
|
|
49
49
|
## 2. What the app does with the official third-party setting (why competitors lose)
|
|
50
50
|
|
|
51
|
+
### Optional Auto mode classifier target
|
|
52
|
+
|
|
53
|
+
`autoModeClassifier: { provider, model, effort }` selects the inference target for
|
|
54
|
+
Claude Code's tool-free security-monitor system requests. It is opt-in: without
|
|
55
|
+
this setting, native routing remains unchanged. For example:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
"autoModeClassifier": {"provider": "codex", "model": "gpt-6-luna", "effort": "low"}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The named provider must exist and support outbound inference. Detection uses the
|
|
62
|
+
security-monitor system prompt, never user messages or routing markers. The
|
|
63
|
+
original security prompt, context, output format and native decision logic remain
|
|
64
|
+
intact. Configure this field in the JSON config; the settings GUI has no control
|
|
65
|
+
for it yet. Removing the field restores ordinary routing.
|
|
66
|
+
|
|
67
|
+
This request is Auto mode's safety check: it decides whether an action the agent
|
|
68
|
+
wants to take runs without asking. A target that judges worse than the model
|
|
69
|
+
Claude Code chose lets more through, and nothing reports it, since an allowed
|
|
70
|
+
action looks like any other. Choose the target for its judgement, not for its
|
|
71
|
+
quota. Matching keys on the classifier prompt's opening sentence; if a Claude Code
|
|
72
|
+
release rewords it, the requests stop matching and go back to the native
|
|
73
|
+
classifier, which is the safe direction to fail in.
|
|
74
|
+
|
|
75
|
+
Verified with Desktop's Claude Code 2.1.284: both classification stages used the
|
|
76
|
+
configured target; an authorized temporary-file write proceeded and an explicitly
|
|
77
|
+
forbidden deletion was denied. The registered `CLAUDE_CODE_AUTO_MODE_MODEL`
|
|
78
|
+
environment variable did not change the actual native classifier requests.
|
|
79
|
+
|
|
51
80
|
Verified in `app.asar` (`.vite/build/index.chunk-C0sgyfNn.js`, `-2CuMdv3h.js`):
|
|
52
81
|
|
|
53
82
|
- The gateway setting (`inferenceGatewayBaseUrl`) is a **whole-app deployment
|
|
@@ -114,6 +143,14 @@ chat is out of reach for every approach, ours included.
|
|
|
114
143
|
router logs `PICKER injected … surfaces: …` on each bootstrap.
|
|
115
144
|
- Injecting `additional_model_options` into the Claude Code bootstrap response
|
|
116
145
|
does **not** reach the app picker (measured; the app never reads that field).
|
|
146
|
+
- **The effort menu is per entry.** The Code tab reads each model's own
|
|
147
|
+
`thinking.effort_options` (ids from `low/medium/high/xhigh/max`; an option may
|
|
148
|
+
carry `recommended`, which the app falls back to when the selected level is not
|
|
149
|
+
listed) — read from the app's cached web bundle, 2026-10-02. A cloned Claude
|
|
150
|
+
entry therefore offered Claude's ladder for every routed model; the injected
|
|
151
|
+
entry now keeps only the template options whose id the model's ladder holds,
|
|
152
|
+
recommends high (or the nearest), and drops `thinking` when none remain. The
|
|
153
|
+
real bootstrap's option fields beyond `id`/`recommended` were not captured.
|
|
117
154
|
- **Windows uses the same mechanism** (measured end to end in a Windows 11 VM,
|
|
118
155
|
2026-09-14: picker listed the GPT models, a call routed, the model answered).
|
|
119
156
|
Two things differ and nothing else does:
|
|
@@ -128,6 +165,47 @@ chat is out of reach for every approach, ours included.
|
|
|
128
165
|
The app's own log line confirms the proxy took effect:
|
|
129
166
|
`[egress-proxy] pinned to fixed proxy at 127.0.0.1:<port>; OS proxy settings ignored`.
|
|
130
167
|
|
|
168
|
+
### 3a. The status mod (packages/mod)
|
|
169
|
+
|
|
170
|
+
Claude Code mods (function hooks in a plugin, announced 2026-10-01; on by default
|
|
171
|
+
from CLI 2.1.287, and already loading in the desktop app's 2.1.286 on 2026-10-05)
|
|
172
|
+
draw inside the session itself, on the terminal and on the desktop alike.
|
|
173
|
+
`packages/mod` is one: the `AbovePrompt` band shows where this session's last
|
|
174
|
+
request went, and a `Pane` holds the request log.
|
|
175
|
+
|
|
176
|
+
- **How a session's requests are found.** Claude Code sends its session id as
|
|
177
|
+
`X-Claude-Code-Session-Id` on every `/v1/messages` (captured from CLI 2.1.286
|
|
178
|
+
with a local listener, 2026-10-05: the header equalled `--session-id`). The
|
|
179
|
+
router keeps it on the request record and `/api/requests?session=` filters by
|
|
180
|
+
it. A record without the field means a router older than this; the mod says
|
|
181
|
+
so rather than show another session's route.
|
|
182
|
+
- **The display only reads** the admin API (port from `config.json` as
|
|
183
|
+
`adminPort` works it out).
|
|
184
|
+
- **It also sets worker spawns right** (`hooks/worker.ts`, `agent.spawn`), for
|
|
185
|
+
the agents named in `generated-agents.json` only. A `model` argument on the
|
|
186
|
+
Agent call is replaced by the agent file's own id (a Claude alias there ran
|
|
187
|
+
the worker on Claude with its output cut to 64 tokens), with a toast. A
|
|
188
|
+
`[[ripple: name@level]]` marker anywhere in the prompt that names this worker
|
|
189
|
+
becomes the id's `@level` and leaves the prompt; one naming another alias is
|
|
190
|
+
moved to the first line, the only place `routing.ts` reads it. Measured on
|
|
191
|
+
CLI 2.1.286 (2026-10-05): the hook's `model` is what the subagent runs on —
|
|
192
|
+
`model: "sonnet"` plus the marker on the second line reached the router as
|
|
193
|
+
`deepseek-v4.1-flash@low`, effort low. Without the mod, the first-line rule
|
|
194
|
+
and the no-`model` rule stand as before.
|
|
195
|
+
- **Where it can draw.** The desktop app's header icons (terminal, diff,
|
|
196
|
+
browser) are the app's own; the mod API (CLI 2.1.286 types) has no place for
|
|
197
|
+
a plugin's button there. Its sites are the band, the status line, panes,
|
|
198
|
+
transcript rows and slash commands.
|
|
199
|
+
- **A pane's open state is the engine's.** A module reload drops its pane
|
|
200
|
+
without a `ui.close` the module hears, while `$.state` survives the reload: a
|
|
201
|
+
flag kept there stuck the Log button on "Close log" (2026-10-05). The mod asks
|
|
202
|
+
`$.ui.panes()` instead.
|
|
203
|
+
- **Enabling it** is `env.CLAUDE_CODE_PLUGIN_DIRS` in `~/.claude/settings.json`,
|
|
204
|
+
the one place a desktop-started session reads plugin folders from. It is a
|
|
205
|
+
path list other plugins may share, so only the entry whose manifest is named
|
|
206
|
+
`clauderipple-status` is added or removed (`clauderipple mod on|off`, the
|
|
207
|
+
Clients screen switch).
|
|
208
|
+
|
|
131
209
|
## 4. Provider adapters
|
|
132
210
|
|
|
133
211
|
- **Declared models route themselves (2026-09-19).** A provider's `models` list —
|
|
@@ -162,7 +240,8 @@ chat is out of reach for every approach, ours included.
|
|
|
162
240
|
also a subagent the operator can name: for every id exactly one non-ingress
|
|
163
241
|
provider declares, the router writes `~/.claude/agents/<name>.md` (`agents.ts`;
|
|
164
242
|
`name` = the id with anything outside `[a-z0-9-]` folded to `-`, frontmatter
|
|
165
|
-
`model:` = the exact id, `@
|
|
243
|
+
`model:` = the exact id, `@high` when the provider offers any effort level —
|
|
244
|
+
`@medium` until 2026-10-02). It
|
|
166
245
|
records what it wrote in `<home>/generated-agents.json` and touches **only**
|
|
167
246
|
those files: a hand-written agent of the same name wins and is left alone, an
|
|
168
247
|
unticked model removes its generated file and nothing else, identical content is
|
|
@@ -223,8 +302,22 @@ chat is out of reach for every approach, ours included.
|
|
|
223
302
|
`/zen/v1/responses`, not the Codex backend): gpt-6-sol, gpt-6-luna,
|
|
224
303
|
gpt-5.6-sol and gpt-5.6-luna all accept `none, low, medium, high, xhigh,
|
|
225
304
|
max` and answer `400 param: reasoning.effort` to both `minimal` and
|
|
226
|
-
`ultra`. So `ultra` is not a level that API takes on any of them
|
|
227
|
-
the Codex backend
|
|
305
|
+
`ultra`. So `ultra` is not a level that API takes on any of them. **Settled
|
|
306
|
+
2026-10-06 on the Codex backend too:** gpt-6.1-sol with `reasoning.effort:
|
|
307
|
+
"ultra"` answered `400 Invalid value: 'ultra'. Supported values are: 'none',
|
|
308
|
+
'minimal', 'low', 'medium', 'high', 'xhigh', and 'max'`, while `max` answered
|
|
309
|
+
200. The catalogue's own description of `ultra` is "Maximum reasoning with
|
|
310
|
+
automatic task delegation": it is `max` on the wire plus the Codex CLI
|
|
311
|
+
spawning its own sub-agents, which in Claude Code are Claude Code's
|
|
312
|
+
subagents. Keep the clamp. (`reasoning.mode` takes `standard`/`pro`, and
|
|
313
|
+
gpt-6.1-sol refuses `pro`: "not supported with this model".)
|
|
314
|
+
- **Credits (2026-10-06).** Every Codex response carries
|
|
315
|
+
`x-codex-credits-has-credits` / `-unlimited` (`True`/`False`) and
|
|
316
|
+
`-balance`; `/wham/usage` has `credits: {has_credits, unlimited,
|
|
317
|
+
overage_limit_reached, balance}`. OpenAI's help centre: included usage is
|
|
318
|
+
spent first, then purchased credits. So a window at 100% with credits left
|
|
319
|
+
is not an exhausted account — `exhaustedForMs` no longer rests it, and a
|
|
320
|
+
real 429 still does.
|
|
228
321
|
- **Model catalogue (2026-09-23).** `GET {base}/codex/models?client_version=<v>`
|
|
229
322
|
with the same credentials answers `{ models: [{ slug, display_name,
|
|
230
323
|
visibility: "list"|"hide", context_window, supported_reasoning_levels:
|
|
@@ -348,6 +441,20 @@ chat is out of reach for every approach, ours included.
|
|
|
348
441
|
from the start; the ChatGPT and openai-compatible translators do the same, and a `tool_choice`
|
|
349
442
|
that named a dropped tool is dropped with it. The adapter logs each drop by name, because the
|
|
350
443
|
failure it replaces is silent.
|
|
444
|
+
- **A dropped server tool's instructions are withdrawn too (issue #47).** The advisor does reach
|
|
445
|
+
adapters: Claude Code 2.1.286 declares `{ type: "advisor_20260301", name: "advisor", model }`
|
|
446
|
+
on every subagent whatever its `tools:` list says, and explains it in an `isMeta` user message
|
|
447
|
+
(`# Advisor Tool`, "call advisor BEFORE substantive work"). Measured 2026-10-04: `dropped server
|
|
448
|
+
tools for gpt-6-astra: advisor` on every worker request, and 26 of 28 routed worker transcripts
|
|
449
|
+
reporting the tool missing. Dropping only the declaration leaves an instruction the model cannot
|
|
450
|
+
follow. Each translated path that drops server tools therefore appends one line after the
|
|
451
|
+
caller's system text naming them and telling the model to disregard instructions to call them
|
|
452
|
+
(`droppedServerToolNote`), the same move the CLI makes when it removes the advisor itself ("The
|
|
453
|
+
advisor tool is no longer available; disregard the earlier advisor instructions."). The CLI's
|
|
454
|
+
wording is not matched or stripped, since it changes between releases. Names are sorted, so one
|
|
455
|
+
set yields one byte sequence and the cached prefix holds. An anthropic-compatible provider with
|
|
456
|
+
`serverTools: true` keeps every server tool and gets no line; whether DeepSeek runs `advisor` is
|
|
457
|
+
unmeasured.
|
|
351
458
|
- **Where web search actually runs (measured 2026-09-17).** Claude Code does not put `web_search`
|
|
352
459
|
in the main request. `WebSearch` opens a *separate side request* — system prompt "You are an
|
|
353
460
|
assistant for performing a web search tool use", one message "Perform a web search for the
|
|
@@ -624,6 +731,12 @@ chat is out of reach for every approach, ours included.
|
|
|
624
731
|
this turn), the caller's own `Authorization`/`chatgpt-account-id` is used
|
|
625
732
|
once as sent — pointing Codex here never leaves it worse off. A WebSocket
|
|
626
733
|
upgrade is answered 426 so Codex falls back to SSE.
|
|
734
|
+
- **Codex app model list.** `codex on` also points `model_catalog_json` at
|
|
735
|
+
`~/.codex/clauderipple-models.json`: Codex's own `models_cache.json` entries
|
|
736
|
+
plus ours. That file *replaces* Codex's list, so it must follow both sides —
|
|
737
|
+
the router rewrites it when its config loads and when Codex's cache changes
|
|
738
|
+
(checked once a minute; the app reads the catalog only at startup). With the
|
|
739
|
+
first alone, gpt-6.1-sol (2026-09-30) reached Codex's cache but not the app.
|
|
627
740
|
- Configure a native API-key target as
|
|
628
741
|
`{ "type":"anthropic", "auth":"api-key", "apiKey":"…" }` (or set
|
|
629
742
|
`ANTHROPIC_API_KEY`). Configure a compatible target as today, for example an
|
|
@@ -791,7 +904,16 @@ what we do not have yet — so that adding a provider does not start with readin
|
|
|
791
904
|
`effortLevels` overrides provider defaults, including `[]` for “no effort”. When
|
|
792
905
|
an OpenRouter `/models` entry has `supported_parameters`,
|
|
793
906
|
`reasoning_effort` maps to `[low, medium, high]`; its absence maps to `[]`.
|
|
794
|
-
Vendors that do not report that field keep their configured fallback.
|
|
907
|
+
Vendors that do not report that field keep their configured fallback. For the
|
|
908
|
+
OpenCode presets (`opencode-go`, `opencode-zen`) a model's ladder comes from
|
|
909
|
+
models.dev — the catalogue OpenCode's own client reads, whose `reasoning_options`
|
|
910
|
+
states it — and its `provider.npm` puts that wire first; one request then settles
|
|
911
|
+
the wire and catches a plan refusal. Asking every level instead took ~10 sequential
|
|
912
|
+
requests per model (glm-5.3-flash 1m54s, upstream latency 0.5–25s per one-token
|
|
913
|
+
request, 2026-10-02) and was less right: a 200 means "not refused", and
|
|
914
|
+
glm-5.3-flash accepted seven levels where the catalogue lists `low`/`high`/`max`.
|
|
915
|
+
A model the catalogue lacks, or a catalogue that cannot be fetched, is measured as
|
|
916
|
+
before (`catalog.ts`, `capabilities.ts`). Chat wire
|
|
795
917
|
forwards Anthropic `stop_sequences` as `stop`; Responses wire deliberately omits
|
|
796
918
|
them because its common stateless schema has no corresponding universal field.
|
|
797
919
|
- We do not assert a provider-wide cache hit rate: the adapter records
|
|
@@ -804,6 +926,167 @@ what we do not have yet — so that adding a provider does not start with readin
|
|
|
804
926
|
credit. Preset endpoint and capability claims cite the vendor's official docs in
|
|
805
927
|
`packages/router/src/presets.ts`.
|
|
806
928
|
|
|
929
|
+
### 4d. `google` providers (implemented 2026-10-01)
|
|
930
|
+
|
|
931
|
+
Gemini is a translated provider, not an ingress-only one: it holds no server-side thread,
|
|
932
|
+
so a `thread:continue` is refused exactly as in §4c and the CLI resends a stateless
|
|
933
|
+
history. It routes by its declared models, its agent files are generated like any other
|
|
934
|
+
provider's, and a `web_search` side request aimed at it is refused, not sent. The
|
|
935
|
+
adapter lives in `packages/router/src/providers/google/` and separates translation
|
|
936
|
+
(`translate.ts`), the wire (`transport.ts`) and the signature store
|
|
937
|
+
(`thoughtSignatures.ts`) so Stage 2 (Antigravity Code Assist) is a new transport only.
|
|
938
|
+
|
|
939
|
+
Both modes are implemented: `api-key` (AI Studio) below, and `auth: "antigravity"` (Cloud
|
|
940
|
+
Code Assist) in its own subsection. No live key or Antigravity subscription exists in this
|
|
941
|
+
environment, so everything below is doc- and source-derived and **not measured** unless it
|
|
942
|
+
says otherwise:
|
|
943
|
+
|
|
944
|
+
- Stream endpoint `POST {base}/v1beta/models/{model}:streamGenerateContent?alt=sse`,
|
|
945
|
+
the key on header `x-goog-api-key`, base default `https://generativelanguage.googleapis.com`
|
|
946
|
+
(https://ai.google.dev/api/generate-content#method:-models.streamgeneratecontent).
|
|
947
|
+
- `systemInstruction` takes `{role:"user"|"model", parts:[…]}`; `contents` is the
|
|
948
|
+
`user`/`model` turn list; a part is `{text}`, `{inlineData:{mimeType,data}}`,
|
|
949
|
+
`{functionCall:{name,args}}` or `{functionResponse:{name,response}}`. The `role` of a
|
|
950
|
+
`functionResponse` part must be `user` (https://ai.google.dev/api/caching#Content).
|
|
951
|
+
- Tools map to `tools[].functionDeclarations[].parametersJsonSchema` — a protobuf
|
|
952
|
+
`Value` carrying a full JSON Schema, mutually exclusive with the legacy `parameters`
|
|
953
|
+
(https://ai.google.dev/api/caching#FunctionDeclaration). We send `parametersJsonSchema`.
|
|
954
|
+
- A function name is at most 64 characters, must start with a letter or underscore and
|
|
955
|
+
may contain letters, digits, underscores, dots, dashes and colons (same
|
|
956
|
+
`FunctionDeclaration.name`); longer ids are mangled and restored as in §4c.
|
|
957
|
+
- `toolConfig.functionCallingConfig.mode` is `AUTO` / `ANY` / `NONE`; `ANY` may also
|
|
958
|
+
carry `allowedFunctionNames` (https://ai.google.dev/api/caching#FunctionCallingConfig).
|
|
959
|
+
Anthropic `tool` maps to `ANY` + `allowedFunctionNames`, `none` to `NONE`.
|
|
960
|
+
- Gemini 3 reasons with `generationConfig.thinkingConfig.thinkingLevel`
|
|
961
|
+
(`minimal|low|medium|high`); Gemini 2.5 with `thinkingConfig.thinkingBudget`
|
|
962
|
+
(0..24576 flash, 128..32768 pro; 0 disables) (https://ai.google.dev/gemini-api/docs/thinking).
|
|
963
|
+
`output_config.effort` is clamped to the model family and to the provider's
|
|
964
|
+
`effortLevels` when set. **(assumption)** Some samples spell the REST field
|
|
965
|
+
`thinking_level` flatly; we emit the documented nested `generationConfig.thinkingConfig`
|
|
966
|
+
shape.
|
|
967
|
+
- `usageMetadata` fields are `promptTokenCount`, `cachedContentTokenCount`,
|
|
968
|
+
`candidatesTokenCount`, `thoughtsTokenCount`
|
|
969
|
+
(https://ai.google.dev/api/generate-content#UsageMetadata). Input =
|
|
970
|
+
`promptTokenCount − cachedContentTokenCount`, cache read = `cachedContentTokenCount`,
|
|
971
|
+
output = `candidatesTokenCount + thoughtsTokenCount`.
|
|
972
|
+
- A `finishReason` of `STOP` closes as `end_turn` (or `tool_use` when function calls
|
|
973
|
+
were seen); `MAX_TOKENS` as `max_tokens`; anything else as `end_turn` with a log. A
|
|
974
|
+
stream that ends with no `finishReason` is the §5 stalled-upstream shape: it becomes a
|
|
975
|
+
retryable `overloaded_error`, never a silent `end_turn`
|
|
976
|
+
(https://ai.google.dev/api/generate-content#FinishReason).
|
|
977
|
+
- A wrong key answers `400` with `status: "API_KEY_INVALID"` (or a `401`/`403` whose
|
|
978
|
+
body names the key); that maps to Anthropic `authentication_error` (401). `429
|
|
979
|
+
RESOURCE_EXHAUSTED` maps to `rate_limit_error`, `5xx` to `overloaded_error`, other
|
|
980
|
+
`4xx` to `invalid_request_error`. A bare `403` is read as a permission/region problem,
|
|
981
|
+
not a bad key.
|
|
982
|
+
- `GET {base}/v1beta/models?pageSize=1000` (key on `x-goog-api-key`) lists
|
|
983
|
+
`{name, displayName, inputTokenLimit, supportedGenerationMethods, thinking}` with a
|
|
984
|
+
`nextPageToken`; only entries whose `supportedGenerationMethods` include
|
|
985
|
+
`generateContent` are kept, `id` is `name` minus `models/`, and
|
|
986
|
+
`contextWindow = inputTokenLimit`
|
|
987
|
+
(https://ai.google.dev/api/models#method:-models.list).
|
|
988
|
+
- **thoughtSignature (Gemini 3).** A `functionCall` part on a reasoning model may carry a
|
|
989
|
+
`thoughtSignature`, and a client replaying that call must return the same signature or
|
|
990
|
+
the API rejects the turn ("Function call is missing a thought_signature in
|
|
991
|
+
functionCall parts"). The store keeps signatures keyed by our minted `tool_use` id in a
|
|
992
|
+
bounded LRU (10,000) and re-attaches them on replay; per-part for parallel calls, where
|
|
993
|
+
Gemini signs only the first call of a step. On a turn with no cached signature at all (a
|
|
994
|
+
router restart, a history another model wrote) the documented sentinel
|
|
995
|
+
`skip_thought_signature_validator` goes on that turn's **first** call, Gemini 3 only. The
|
|
996
|
+
guide calls it a last resort that costs model performance, so it is never added to a turn
|
|
997
|
+
that has a real signature — the unsigned parallel calls of a healthy turn are normal
|
|
998
|
+
(https://cloud.google.com/vertex-ai/generative-ai/docs/thought-signatures, sentinel
|
|
999
|
+
paragraph read 2026-10-01).
|
|
1000
|
+
|
|
1001
|
+
### 4d-ii. Google `auth: "antigravity"` (Cloud Code Assist) — implemented 2026-10-01
|
|
1002
|
+
|
|
1003
|
+
A Google subscription signed in through `clauderipple google-login`, streaming through the
|
|
1004
|
+
Cloud Code Assist (CCA) backend, with several accounts rotating. Same translation as AI
|
|
1005
|
+
Studio; only `transport.ts` differs. Accounts live in `<home>/google-accounts.json` (0600,
|
|
1006
|
+
cross-process lock, atomic write, one account per email+project, a re-login replaces its own
|
|
1007
|
+
entry), the sign-in in `login.ts`, the account pool and refresh in `accounts.ts`, and the wire
|
|
1008
|
+
facts and model-id resolution in `antigravity.ts`. **Every wire fact below is taken from the
|
|
1009
|
+
reference implementation opencodex (GitHub `lidge-jun/opencodex`, read 2026-10-01 as a
|
|
1010
|
+
behavioral spec — no code copied; project rule) and is not measured live** — no Antigravity
|
|
1011
|
+
subscription exists in this environment. Files are under `src/`:
|
|
1012
|
+
|
|
1013
|
+
- OAuth is Google's standard installed-app flow with PKCE S256. Client id
|
|
1014
|
+
`1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com`, secret
|
|
1015
|
+
`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` (public client values, overridable by env;
|
|
1016
|
+
`oauth/google-antigravity.ts:17-20`). Authorize
|
|
1017
|
+
`https://accounts.google.com/o/oauth2/v2/auth`, tokens
|
|
1018
|
+
`https://oauth2.googleapis.com/token`, userinfo
|
|
1019
|
+
`https://www.googleapis.com/oauth2/v2/userinfo`; scopes `cloud-platform`, `userinfo.email`,
|
|
1020
|
+
`userinfo.profile`, `cclog`, `experimentsandconfigs`; `access_type=offline`,
|
|
1021
|
+
`prompt=consent select_account`; loopback callback port 51121 preferred, path `/callback`,
|
|
1022
|
+
any free port otherwise (`google-antigravity.ts:21-35,177-196`). The token body carries the
|
|
1023
|
+
client id **and** secret and `code_verifier` (form-encoded).
|
|
1024
|
+
- Project discovery: `POST https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist` with
|
|
1025
|
+
`{metadata:{ideType:"ANTIGRAVITY"}}`; without a project,
|
|
1026
|
+
`POST https://daily-cloudcode-pa.googleapis.com/v1internal:onboardUser` with
|
|
1027
|
+
`{tier_id:"free-tier", metadata:{ide_type, ide_name:"antigravity", ide_version}}`, polled up
|
|
1028
|
+
to 5 times, 2 s apart, until `done:true` (`google-antigravity.ts:97-137`). The project id is
|
|
1029
|
+
read from `cloudaicompanionProject | projectId | project[.id]`. A sign-in that finds no
|
|
1030
|
+
project fails rather than storing a credential that would fail every call.
|
|
1031
|
+
- Request: `POST {base}/v1internal:streamGenerateContent?alt=sse` (non-streaming
|
|
1032
|
+
`:generateContent`), base default `https://daily-cloudcode-pa.googleapis.com`
|
|
1033
|
+
(`adapters/google.ts:1056-1160`; devlog `140.21`). Envelope
|
|
1034
|
+
`{ model, userAgent:"antigravity", requestType:"agent", project, requestId:"agent-<uuid>",
|
|
1035
|
+
request }`, where `request` is the standard Gemini body plus a nested camelCase
|
|
1036
|
+
`sessionId` (`adapters/google.ts:1145-1158`; `google-antigravity-wire.ts:53-77`). Headers:
|
|
1037
|
+
`Authorization: Bearer <token>` and `User-Agent: antigravity/ide/<ver> (os_type=…; arch=…;
|
|
1038
|
+
aidev_client; auth_method=oauth)` — the IDE client family is required, the backend 404s
|
|
1039
|
+
CLI-shaped UAs (`adapters/client-fingerprint.ts:44-65`). Response frames nest the standard
|
|
1040
|
+
Gemini payload under `response` (`adapters/google.ts:1281,1591-1596`).
|
|
1041
|
+
- Model ids. CCA's wire ids carry the tier as a suffix (`gemini-3.8-flash-low`) or a
|
|
1042
|
+
`-tiered` rename (`gemini-3.7-flash-tiered`), while the picker shows a collapsed base id.
|
|
1043
|
+
Resolution, from `providers/antigravity-models.ts`: `gemini-3.8-flash` → its suffix per
|
|
1044
|
+
effort (`…-low/medium/high`, no `thinkingLevel` beside it — the suffix IS the effort);
|
|
1045
|
+
`gemini-3.1-pro` → `gemini-3.1-pro-low` / `gemini-pro-agent` with `thinkingLevel`;
|
|
1046
|
+
`gemini-3.7-flash` → `gemini-3.7-flash-tiered` with `thinkingLevel`; a `claude-*` id takes a
|
|
1047
|
+
`thinkingLevel` only (`resolveAntigravityThinkingLevel` clamps `xhigh/max/ultra`→`high`).
|
|
1048
|
+
CCA's own catalogue is `POST {dailyApi}/v1internal:fetchAvailableModels` with `{project}`,
|
|
1049
|
+
body `{models:{<wireId>:{maxTokens,…}}, agentModelSorts:[{groups:[{modelIds:[…]}]}],
|
|
1050
|
+
tieredModelIds:{flash:[…]}}` (`providers/quota/antigravity.ts:166-168`,
|
|
1051
|
+
`providers/antigravity-models.ts:489-560`); when it cannot be read we fall back to the
|
|
1052
|
+
static collapsed list (`gemini-3.8-flash`, `gemini-3.7-flash`, `gemini-3.1-pro`,
|
|
1053
|
+
`gemini-3.1-flash-image`, `claude-sonnet-4-6`, `claude-opus-4-6-thinking`,
|
|
1054
|
+
`gpt-oss-120b-medium`, context windows from CCA `maxTokens`).
|
|
1055
|
+
- Claude models on CCA force `toolConfig.functionCallingConfig.mode = "VALIDATED"`; a client
|
|
1056
|
+
asking for no tools gets the declarations dropped instead (`adapters/google.ts:1109-1120`).
|
|
1057
|
+
- **thoughtSignature.** The CCA path sends a real signature back on the exact `functionCall`
|
|
1058
|
+
the model signed and never adds the `skip_thought_signature_validator` sentinel (a fabricated
|
|
1059
|
+
signature is not "real"). opencodex filters a stored signature with
|
|
1060
|
+
`isLikelyRealThoughtSignature` (`google-antigravity-wire.ts:30-42`) to keep a foreign id
|
|
1061
|
+
(`toolu_…`, `call_…`) out of the signature field, which Antigravity 400s
|
|
1062
|
+
(`TYPE_BYTES`/Base64 decode failure). We do not need that filter: our store is keyed by the
|
|
1063
|
+
`tool_use` id we minted and holds only a `thoughtSignature` the vendor itself sent, so a
|
|
1064
|
+
foreign id is never placed in the field.
|
|
1065
|
+
- **Accounts and credentials (§4 Credential pools).** A conversation stays on the account that
|
|
1066
|
+
answered while it is healthy (moving it costs the prompt cache); a refusal before any byte
|
|
1067
|
+
reaches the client moves the turn to the next account: 401 (or a 403 that reads as a
|
|
1068
|
+
credential refusal) gets one refresh and a replay, a fresh token refused with a 401 again
|
|
1069
|
+
marks the account for sign-in; 429/402 rest the account to its `retry-after` (or a default);
|
|
1070
|
+
another 403, 5xx or a connect failure rests it briefly; any other 4xx is the request's fault
|
|
1071
|
+
and is not retried. Refresh is per account, single-flight per token generation, five minutes
|
|
1072
|
+
ahead; only a structured `invalid_grant` marks an account for sign-in. Only the access token
|
|
1073
|
+
and the account email/project id are ever in memory; no token reaches a log or an API response.
|
|
1074
|
+
- Session id and prompt cache. The real client puts a stable per-conversation id at
|
|
1075
|
+
`request.sessionId` so provider-side replay can associate a signature with the call that made
|
|
1076
|
+
it; instability loses it (`google-antigravity-wire.ts:62-88`). We derive it from the router's
|
|
1077
|
+
own `conversationKey` (sha256 → BigEndian uint64 masked to 63 bits, left-padded with `-`,
|
|
1078
|
+
CLIProxyAPI's `generateStableSessionID` shape). `requestId` is a fresh `agent-<uuid>` per
|
|
1079
|
+
request, so it does not enter the cacheable body prefix.
|
|
1080
|
+
- **Terms.** Using Antigravity credentials from a non-Google client is against Google's terms
|
|
1081
|
+
(Antigravity terms §6; the Gemini CLI FAQ) and Google blocked a large number of such accounts
|
|
1082
|
+
in February 2026. The CLI prints this once before a sign-in and the sign-in API returns it in
|
|
1083
|
+
a `warning` field for the GUI; the wording states only the fact. ClaudeRipple is not
|
|
1084
|
+
affiliated with Google.
|
|
1085
|
+
- Admin: `POST/GET /api/google-login`, `POST /api/google-login/code`, `POST
|
|
1086
|
+
/api/google-login/cancel`, `POST /api/google-logout`, `GET /api/google-accounts`,
|
|
1087
|
+
`PATCH/DELETE /api/google-accounts/:id`, and `POST /api/providers/probe` with
|
|
1088
|
+
`{type:"google", auth:"antigravity"}`. CLI: `clauderipple google-login` / `google-logout`.
|
|
1089
|
+
|
|
807
1090
|
## 5. Failure modes that must not exist in the product (all observed)
|
|
808
1091
|
|
|
809
1092
|
| Observed | Product requirement |
|
|
@@ -819,6 +1102,7 @@ what we do not have yet — so that adding a provider does not start with readin
|
|
|
819
1102
|
| Tool names over 64 characters were forwarded to the Responses API unchanged, so a single connected MCP server — the product's own use case (§2) — failed every request of that turn (found by reading the source, issue #1, 2026-09-17) | Any name a translated provider sends is mangled into the provider's constraint deterministically and restored on the way back (§4). A translator must validate what it forwards against the wire it forwards to, not only what it builds itself. |
|
|
820
1103
|
| Unknown-model context window defaulted to 200K, compaction fired at 151K; fixed via `CLAUDE_CODE_MAX_CONTEXT_TOKENS=272000` (applies only to models not in the CLI's built-in table; Claude models unaffected) | Installer sets this env for mapped models; document that it does not affect Claude models. |
|
|
821
1104
|
| Server tools (`web_search`) were declared to translated providers as ordinary functions: a tool the model can call and nothing can run. Not observed live, because Claude Code currently routes its web search elsewhere (§4) — the failure was one server-side flag away, and its shape is an empty answer with nothing logged (issue #4, 2026-09-17) | A translator declares only what the provider can actually execute, and says in the log what it removed. A capability that silently disappears is worse than one that visibly fails. |
|
|
1105
|
+
| Routed workers were told to call the `advisor` after its declaration was dropped: Claude Code explains the tool in a user message the router left in place, so 26 of 28 worker transcripts reported it missing, every turn (issue #47, 2026-10-04) | Removing a capability includes withdrawing what was said about it. A translator that drops a tool adds one stable line saying so, rather than editing the caller's text. |
|
|
822
1106
|
| One context window was written to every routed model and every slot, because `cli.autoCompactWindow` is a single number while `auto_compact_windows` and `context_window_by_model` are per-model maps. Routed models do not share a window: set it high and the smaller model overflows before it compacts, set it low and the larger throws away most of its own (issue #2, 2026-09-17) | A window belongs to a model, not to the router. `CliModel.contextWindow` and `Route.contextWindow` win, then whatever the vendor's `/models` reported as `context_length`, then the global value as the fallback it always was. A value the config can only express once must not be injected into a map that is keyed per model. |
|
|
823
1107
|
| proxenos sends only the 7-day quota window, so the app shows a "weekly limit" banner | Quota reporting must mirror the shape Anthropic returns. |
|
|
824
1108
|
| After a reboot the router listened 4 minutes after login (26s of it between exec and `listen()`), and for that whole window Claude Desktop was a blank page with `ERR_PROXY_CONNECTION_FAILED` — in picker mode every byte the app sends goes through us, so a router that is merely slow reads as an app that is broken (2026-09-14 09:59 boot → 10:15:59 listening) | The launchd agent is `ProcessType=Interactive`, never `Background` (that key throttles CPU and I/O — launchd.plist(5)). `listen()` comes before certificate minting and any other startup work, so a client waits rather than being refused. Every startup logs its budget (`startup Nms: node …, config …, listen …`). |
|
|
@@ -827,6 +1111,7 @@ what we do not have yet — so that adding a provider does not start with readin
|
|
|
827
1111
|
| Windows: the scheduled task inherited the console that started it, so closing the installer window killed the router with `0xC000013A` (Ctrl+C), 2026-09-14 | The task runs a PowerShell launcher that uses `Start-Process -PassThru -Wait`: detached from any console, still tracked so `RestartCount` keeps acting as KeepAlive and the exit code (including the health self-exit 75) propagates. |
|
|
828
1112
|
| Windows: `install` registered a logon-triggered task and stopped there, so the router did not exist until the next sign-in — launchd starts at bootstrap (`RunAtLoad`) and the difference was invisible | `install` starts the supervisor itself on both platforms and prints the result. |
|
|
829
1113
|
| Windows: trusting the CA failed with "this operation cannot use the UI" — every PowerShell call carried `-NonInteractive`, and the confirmation dialog never appeared, so picker mode stopped with no certificate and no explanation | Certificate trust and removal run WITHOUT `-NonInteractive` (and without `windowsHide`). They are UI operations by design: the OS must be able to show the user what it is being asked to trust. |
|
|
1114
|
+
| macOS, new Mac (2026-10-06): picker mode on, router up, and Claude Desktop would not open — every claude.ai load failed `ERR_CERT_AUTHORITY_INVALID`, router logged `tls alert certificate unknown`; `dump-trust-settings` had no entry for the CA. "Trusted" was decided by `find-certificate` (the item is in the login keychain), which says nothing about trust, so `picker on` could skip the trust step and `status` could read an untrusted CA as trusted | On macOS the CA counts as trusted only when the user trust domain (`security dump-trust-settings`) lists it. `picker off` deletes the keychain item even when it carries no trust. |
|
|
830
1115
|
| Windows: sign-in failed with `missing_required_parameter` because the OAuth URL was opened via `cmd /c start`, and cmd reads `&` as a command separator — everything after the first parameter was cut off and run as commands (2026-09-14) | Browsers are opened with `Start-Process <url>` as a single quoted argument. Any URL we hand to a shell must survive its metacharacters. |
|
|
831
1116
|
| The provider form's "also show in the Claude app picker" box only records `cli.extraModels`; picker mode itself stayed off, nothing was injected, and the user believed the picker was on (Windows x64, 2026-09-14: `config.json` had no `picker` key, no CA, no Config Library) | When that box is ticked while picker mode is off, the form says so under the box and offers to turn picker mode on right after saving. Any control that *looks* like it enables picker mode must either enable it or say what is still missing. |
|
|
832
1117
|
| A DeepSeek mapping answered `401` on every real request while the provider form's own "Test connection" stayed green — the test sends the provider's headers alone, live traffic also carried the caller's `authorization` (2026-09-15, Windows) | A routed request carries provider authentication only (§4). The connection test and live traffic must present the same auth set, or the test certifies a path nobody uses. |
|
|
@@ -843,6 +1128,7 @@ what we do not have yet — so that adding a provider does not start with readin
|
|
|
843
1128
|
| The worker registry was four places that did not know each other — `providers.*.models`, `aliases`, `~/.claude/agents/*.md`, and prose in CLAUDE.md — and every new provider needed all four edited by hand; the one left out was the one that failed (2026-09-19, DeepSeek) | One source: a ticked model *is* a worker. Agent files and marker aliases are generated from `config.json` (§4 "worker definitions"); nothing about a worker is written twice. |
|
|
844
1129
|
| ChatGPT prompt-cache hit fell from 93% (2026-09-13) to 9% (2026-09-20) with nothing in our request changing — the backend had started keying the cache on the conversation's identity (`session-id`/`thread-id`/`x-client-request-id`/`client_metadata`), which we never sent; `prompt_cache_key` alone no longer earned a write | The adapter states the conversation's identity the way the Codex CLI does (§4) and echoes `x-codex-turn-state`. The acceptance metric (≥90% on translated providers) is watched per day in `requests.jsonl`; a fall with an unchanged request means the wire changed under us, and the reference to diff against is the real CLI captured through a local proxy, not our own memory of the protocol. |
|
|
845
1130
|
| Remote Control registration failed locally with 405 before Anthropic saw it: Claude Code 2.1.275 uses HTTPS absolute-form (`POST https://api.anthropic.com/v1/environments/bridge HTTP/1.1`) rather than CONNECT for registration, polling and heartbeats, while the forward-proxy socket accepted CONNECT only (issue #10, Windows 11) | Accept valid HTTPS absolute-form, strip proxy-only headers, replace Host, rewrite only the target to origin-form, and relay one request over direct TLS outside model routing. Force `Connection: close`: reusing that TLS socket could send a later proxy-form request to the first origin. Parser tests plus a live local TLS origin verify body and credential preservation. |
|
|
1131
|
+
| The status mod's band said "router not answering" on every tick while the admin API answered curl (2026-10-06, CLI 2.1.288): the host's `$.http.fetch("http://127.0.0.1:8792/…")` went through `HTTPS_PROXY` as plain-HTTP absolute-form (`GET http://127.0.0.1:8792/… HTTP/1.1`), loopback included, and the proxy socket answered 405 to anything but CONNECT or `https:` absolute-form. Measured with a probe mod under `claude -p --plugin-dir`: 405 with an empty body | `http:` absolute-form is relayed like `https:` (same header rewrite, `Connection: close`) over plain TCP. A live loopback origin test covers it. |
|
|
846
1132
|
| Re-running `clauderipple install` as a normal Windows user rewrote the launcher, then `Register-ScheduledTask -Force` could answer `0x80070005 Access is denied` even though the existing per-user task was already correct (issue #9) | Reuse an existing task only when its entire intended definition matches: one PowerShell action and exact arguments, current user, limited interactive logon, one matching logon trigger, restart count/interval, no execution limit, IgnoreNew, and battery policy. A missing, stale or foreign same-named task still takes the normal registration/error path. |
|
|
847
1133
|
| OpenCode Go's relay answered `403 {"message":"Error from provider (Console Go): Upstream request failed: …"}` during a few seconds of its own trouble. The 403 was classified as an auth failure, which both cooled the credential for 60s **and** removed it from the retry candidate list, so the router could not retry inside the turn and answered the user with what read as an authentication error. Five times in a day, each cleared by asking again (2026-09-21) | A 403 whose body reports an upstream failure is charged a **zero** cooldown. It is not a statement about the credential, and any wait at all moves the conversation off a key that did nothing and takes its prompt cache with it (§4). With no cooldown the credential stays retryable, so the turn is answered on the next attempt instead of becoming a user-visible failure. The body is the only way to tell this apart from a real 403 (policy, region, blocked model), so it is read for 403 and only 403. |
|
|
848
1134
|
| The same relay 403 kept reaching the user after that fix, because it was the wrong layer: DeepSeek runs on `openai-compatible`, whose adapter was **never** retried at all — the in-turn retry lives only in the anthropic-compatible wire path (`nextCredential`), and `credentialsOf` gives a translated provider exactly one credential and no fallback. So a relay hiccup had nowhere to go but the user (2026-09-21, root cause of the day's repeated "authentication failed") | Every translated adapter retries the `fetch` **before** any status or byte is written, so the turn is still replaceable (§4 "the first byte commits the turn"). `fetchWithRetry` retries only `transient` verdicts — connect failures, 5xx, and a 403 reporting a broken upstream — to the ceiling of 10 attempts the CLI itself uses, with a 250ms→2s backoff. A 401/429 is **not** retried: the adapter holds one credential, so asking the key that just refused the identical request again only delays the error. `classify` is reused for the judgement, with `kind === "transient"` narrowing a pool's answer to an adapter's. |
|
|
@@ -850,6 +1136,9 @@ what we do not have yet — so that adding a provider does not start with readin
|
|
|
850
1136
|
| A session switched from gpt-6-astra to claude-opus-5-5 failed every turn with `400 messages.2.content.0.thinking: each thinking block must contain thinking`: the translated adapters hand the CLI reasoning as `thinking` blocks with no signature (and no text when the reasoning item had no summary), the CLI keeps them, and passthrough replayed them to Anthropic (2026-09-28) | Before a request reaches Anthropic (`PASS` and the account-pool provider), assistant `thinking` blocks without a signature are dropped (`thinking.ts`) — Anthropic's own always carry one — and a turn left empty goes with them. Passthrough stays byte-exact when there is nothing to drop. |
|
|
851
1137
|
| Re-running the installer — the documented update — replaced the files and left the router running the old code: `install` treats a running router as done, and on Windows and Linux an unchanged supervisor definition is not re-registered, so nothing restarted it until the next login (found 2026-09-28 while building `update`; the tray's own restart covered only the packaged app) | `install` asks a router that is already running for its version and restarts one that differs. Measured in the Windows 11 VM: 0.5.1 running, installer run with 0.6.0 → "restarting it on 0.6.0", status 0.6.0. |
|
|
852
1138
|
| The tray's Electron (~270MB) was fetched into the installed package's own `node_modules`, and `npm install -g` of any other version deleted it with the old files (measured 2026-09-28): every update silently took the tray away, and on Windows a running tray held `electron.exe` inside the folder npm had to replace | Electron lives in `<home>/tray-runtime`, outside anything an update replaces. Both install scripts move one found in the old place there before installing (Windows first stops a tray running from it, and starts it again after setup) — checked on macOS and in the VM with a locked `electron.exe`. |
|
|
1139
|
+
| 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. |
|
|
1140
|
+
| 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). |
|
|
1141
|
+
| 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. |
|
|
853
1142
|
|
|
854
1143
|
## 6. Blocked paths (measured, do not retry)
|
|
855
1144
|
|
|
@@ -868,3 +1157,17 @@ CC BY-NC-ND (no forks, no sponsors). CLI-targeting `claude-code-router` has
|
|
|
868
1157
|
37,180★, `opencodex` 14,300★ with two README sponsors. Open positions: English
|
|
869
1158
|
distribution, GPL-3.0 license (chosen 2026-09-13 over MIT: sole author, reversible later, blocks closed commercial repackaging), sponsor slots. Positioning: an **add-on for Claude
|
|
870
1159
|
subscribers**, not a replacement for people without one.
|
|
1160
|
+
|
|
1161
|
+
|
|
1162
|
+
### Codex context-overflow recovery
|
|
1163
|
+
|
|
1164
|
+
The subscription backend can reject an oversized request with HTTP 200 followed by
|
|
1165
|
+
`response.failed` / `context_length_exceeded`. The Messages adapter maps this to
|
|
1166
|
+
`invalid_request_error` and prefixes `prompt is too long`, which Desktop CLI
|
|
1167
|
+
2.1.284 recognizes. Keep the initial message-start event pending until another
|
|
1168
|
+
translated event arrives so an early rejection can retain HTTP 400. Transient
|
|
1169
|
+
overloads and interrupted streams remain retryable.
|
|
1170
|
+
|
|
1171
|
+
Both streaming and non-streaming early-rejection paths are covered by adapter
|
|
1172
|
+
tests. The client still needs to compact its history or otherwise reduce input;
|
|
1173
|
+
this mapping does not increase the backend's context limit.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clauderipple",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Use GPT (ChatGPT Plus/Pro), 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": [
|