clauderipple 0.8.10 → 0.9.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 +60 -0
- package/README.es.md +21 -15
- package/README.ja.md +13 -9
- package/README.ko.md +23 -9
- package/README.md +26 -11
- package/README.pt-BR.md +21 -15
- package/README.zh-CN.md +13 -9
- package/dist/app/package.json +1 -1
- package/dist/cli/src/codex.js +3 -1
- package/dist/cli/src/settings.js +5 -2
- package/dist/mod/.claude-plugin/plugin.json +9 -1
- package/dist/mod/hooks/cache.ts +60 -0
- package/dist/mod/hooks/compact.ts +40 -0
- package/dist/mod/hooks/handoff.ts +43 -0
- package/dist/mod/hooks/i18n.ts +2716 -0
- package/dist/mod/hooks/judge.ts +242 -0
- package/dist/mod/hooks/ladder.js +179 -0
- package/dist/mod/hooks/ladder.ts +174 -0
- package/dist/mod/hooks/modes.ts +93 -0
- package/dist/mod/hooks/register.tsx +1458 -256
- package/dist/mod/hooks/session.ts +62 -0
- package/dist/mod/hooks/settings.js +342 -0
- package/dist/mod/hooks/settings.ts +321 -0
- package/dist/mod/hooks/stats.ts +59 -0
- package/dist/mod/hooks/ui/agents.tsx +138 -0
- package/dist/mod/hooks/ui/alerts.tsx +373 -0
- package/dist/mod/hooks/ui/art.ts +628 -0
- package/dist/mod/hooks/ui/band.tsx +836 -0
- package/dist/mod/hooks/ui/kit.tsx +258 -0
- package/dist/mod/hooks/ui/log.tsx +109 -0
- package/dist/mod/hooks/ui/parts.tsx +217 -0
- package/dist/mod/hooks/ui/ripple.ts +614 -0
- package/dist/mod/hooks/ui/settings.tsx +376 -0
- package/dist/mod/hooks/ui/setup.tsx +148 -0
- package/dist/mod/hooks/ui/theme.ts +217 -0
- package/dist/mod/hooks/ui/view.ts +371 -0
- package/dist/mod/hooks/worker.ts +1 -1
- package/dist/mod/hooks/workers.ts +217 -0
- package/dist/mod/tests/register.test.tsx +1730 -0
- package/dist/mod/tests/ui.test.tsx +853 -0
- package/dist/mod/tsconfig.json +2 -1
- package/dist/mod/types/index.d.ts +320 -1
- package/dist/router/src/admin.js +170 -52
- package/dist/router/src/agents.js +24 -5
- package/dist/router/src/bootstrap.js +4 -2
- package/dist/router/src/config.js +3 -0
- package/dist/router/src/health.js +33 -0
- package/dist/router/src/index.js +1 -0
- package/dist/router/src/ingress/models.js +4 -1
- package/dist/router/src/mod-settings.js +120 -0
- package/dist/router/src/model-policy.js +6 -0
- package/dist/router/src/model-scores.js +159 -0
- package/dist/router/src/picker.js +7 -0
- package/dist/router/src/providers/chatgpt/index.js +23 -5
- package/dist/router/src/providers/chatgpt/translate.js +4 -1
- package/dist/router/src/providers/google/index.js +8 -3
- package/dist/router/src/providers/openai/index.js +6 -1
- package/dist/router/src/providers/openai/translate.js +6 -1
- package/dist/router/src/proxy.js +62 -24
- package/dist/router/src/requestlog.js +78 -20
- package/dist/router/src/version.js +1 -1
- package/dist/ui/app.js +908 -209
- package/dist/ui/favicon-32.png +0 -0
- package/dist/ui/favicon.svg +12 -0
- package/dist/ui/i18n.js +919 -233
- package/dist/ui/index.html +159 -87
- package/dist/ui/style.css +789 -410
- package/docs/ARCHITECTURE.md +141 -0
- package/package.json +7 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,65 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.1 — 2026-10-14
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **The request log records more of each request** (`logs/requests.jsonl`, #55). Every new field is
|
|
8
|
+
optional, so older records and readers keep working.
|
|
9
|
+
- Anthropic's request id or the message id, to match a row to the transcript, subagents included.
|
|
10
|
+
- Why a request ended before reaching a model, with the right provider instead of `anthropic`.
|
|
11
|
+
- Whether a call was the auto-mode classifier or a web search.
|
|
12
|
+
- An explicit `cacheWrite: 0`.
|
|
13
|
+
- The service tier that was asked for and the one the provider served. This shows whether a Fast
|
|
14
|
+
request was honoured (#54).
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Saving the mod settings failed on Windows with `EPERM … fsync` since 0.9.0 (#53).
|
|
19
|
+
- "Haiku returned no verdict" appeared now and then. When Haiku breaks the end of its JSON, the
|
|
20
|
+
verdict's complete fields are now read instead of the whole answer being dropped (#53).
|
|
21
|
+
- A response over 64KiB that arrived in one piece (every compressed answer, for one) lost its usage
|
|
22
|
+
and stop reason in the request log.
|
|
23
|
+
- Alert cards centre their buttons when the title takes two lines.
|
|
24
|
+
- Ripple Remote no longer lists a resumed session's old halves, and a host restart no longer marks
|
|
25
|
+
idle sessions as just used.
|
|
26
|
+
|
|
27
|
+
## 0.9.0 — 2026-10-13
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **The ripple mod.** A band above the Code tab's prompt shows reasoning effort, context, the
|
|
32
|
+
cache timer, and which model answered each request with its cache hit. Log opens the request
|
|
33
|
+
log, ⚙ opens quick settings, and the dashboard has a mod page with every setting.
|
|
34
|
+
- **Effort picked per prompt.** A small judge model (Haiku 5.5 or Jev) reads the prompt and the
|
|
35
|
+
recent turns, then sets low through max. Pick an effort yourself whenever you want; Auto comes
|
|
36
|
+
back when you switch it on.
|
|
37
|
+
- **Workers picked per task.** The main chat hands work to `ripple:auto`, and the judge decides
|
|
38
|
+
how hard each task is and sends it to the matching rung: light work to DeepSeek or GLM, hard work
|
|
39
|
+
to GPT or Opus. Rungs, candidate models and named modes (prefer or avoid a model, eager
|
|
40
|
+
delegation, switch off at a quota reset) are set on the dashboard. Every pick is kept in
|
|
41
|
+
`logs/worker-picks.jsonl`.
|
|
42
|
+
- **Warnings that save tokens.** Cards appear when the prompt cache has gone cold on a big chat,
|
|
43
|
+
when the context gets heavy, and when a plan window passes 80%. Each card offers compact or a
|
|
44
|
+
handoff.
|
|
45
|
+
- **Handoff to a fresh session.** A handoff writes a summary and opens a new session in the same
|
|
46
|
+
folder with it in the prompt box. The current chat is left as it is.
|
|
47
|
+
- **리플이**, the mascot, on the band and every card, acting out what the band is doing. Mod text
|
|
48
|
+
in six languages, following the Mac's system language.
|
|
49
|
+
- **Artificial Analysis scores** for every routable model, refreshed daily, used to rank worker
|
|
50
|
+
candidates by measured cost.
|
|
51
|
+
- A provider that answers 402 or says its quota is exhausted is skipped for a while.
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
|
|
55
|
+
- Dashboard settings are rebuilt in the style of macOS System Settings.
|
|
56
|
+
- The mod's settings live in the router, so every session follows a change at once.
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- Judge-only models such as Jev no longer appear in pickers, worker lists or Codex.
|
|
61
|
+
- The install script works under macOS `/bin/sh` again.
|
|
62
|
+
|
|
3
63
|
## 0.8.10 — 2026-10-10
|
|
4
64
|
|
|
5
65
|
### Added
|
package/README.es.md
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<img src="docs/media/icon.png" width="128" alt="ClaudeRipple">
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
1
|
<h1 align="center">ClaudeRipple</h1>
|
|
6
2
|
|
|
7
3
|
<p align="center"><a href="README.md">English</a> · <a href="README.ko.md">한국어</a> · <a href="README.zh-CN.md">简体中文</a> · <a href="README.ja.md">日本語</a> · <b>Español</b> · <a href="README.pt-BR.md">Português (BR)</a></p>
|
|
@@ -26,16 +22,24 @@
|
|
|
26
22
|
</p>
|
|
27
23
|
|
|
28
24
|
<p align="center">
|
|
29
|
-
<img src="docs/media/
|
|
25
|
+
<a href="https://github.com/PBJ-2/clauderipple/releases/download/v0.9.0/clauderipple-demo.mp4"><img src="docs/media/demo.webp" width="880" alt="Recorrido de un minuto: otros modelos en el propio menú de modelos de Claude Desktop, el esfuerzo ajustado en cada prompt y cada subagente enviado al modelo adecuado. Haz clic para ver el vídeo completo."></a><br>
|
|
26
|
+
<sub>Recorrido de un minuto: otros modelos en el propio menú de modelos de Claude Desktop, el esfuerzo ajustado en cada prompt y cada subagente enviado al modelo adecuado. Haz clic para ver el vídeo completo.</sub>
|
|
30
27
|
</p>
|
|
31
28
|
|
|
32
29
|
<table align="center">
|
|
33
30
|
<tr>
|
|
34
|
-
<td align="center" width="34%"><img src="docs/media/picker
|
|
35
|
-
<td align="center" width="66%"><img src="docs/media/
|
|
31
|
+
<td align="center" width="34%"><img src="docs/media/picker.png" width="300" alt="GPT, DeepSeek, GLM y Gemini en el propio menú de modelos de Claude Desktop"><br><sub>GPT, DeepSeek, GLM y Gemini en el propio menú de modelos de Claude Desktop</sub></td>
|
|
32
|
+
<td align="center" width="66%"><img src="docs/media/answer.png" alt="GPT-6 Astra trabajando en la pestaña Code, con cada solicitud registrada a la derecha"><br><sub>GPT-6 Astra trabajando en la pestaña Code, con cada solicitud registrada a la derecha</sub></td>
|
|
33
|
+
</tr>
|
|
34
|
+
<tr>
|
|
35
|
+
<td colspan="2" align="center"><img src="docs/media/subagents.png" alt="Subagentes con DeepSeek y GLM, identificados en el panel de tareas"><br><sub>Subagentes con DeepSeek y GLM, identificados en el panel de tareas</sub></td>
|
|
36
|
+
</tr>
|
|
37
|
+
<tr>
|
|
38
|
+
<td colspan="2" align="center"><img src="docs/media/mod-band.png" alt="El mod ripple: esfuerzo, contexto, temporizador de caché y qué modelo respondió, con su acierto de caché"><br><sub>El mod ripple: esfuerzo, contexto, temporizador de caché y qué modelo respondió, con su acierto de caché</sub></td>
|
|
36
39
|
</tr>
|
|
37
40
|
<tr>
|
|
38
|
-
<td
|
|
41
|
+
<td align="center" width="50%"><img src="docs/media/mod-alerts.png" alt="Avisos cuando la caché se enfría o un límite está cerca, y traspaso a un chat nuevo"><br><sub>Avisos cuando la caché se enfría o un límite está cerca, y traspaso a un chat nuevo</sub></td>
|
|
42
|
+
<td align="center" width="50%"><img src="docs/media/mod-settings.png" alt="Ajustes rápidos: esfuerzo automático, el juez, modos de workers"><br><sub>Ajustes rápidos: esfuerzo automático, el juez, modos de workers</sub></td>
|
|
39
43
|
</tr>
|
|
40
44
|
</table>
|
|
41
45
|
|
|
@@ -304,13 +308,15 @@ los modelos que asignas van a tu proveedor, y todo lo demás va a Anthropic byte
|
|
|
304
308
|
la última hora.
|
|
305
309
|
- **Etiquetas de subagentes.** El panel de tareas en segundo plano muestra
|
|
306
310
|
`Terra·high · Review` en lugar de un genérico "Agent".
|
|
307
|
-
- **
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
un worker
|
|
312
|
-
|
|
313
|
-
|
|
311
|
+
- **El mod ripple, encima del prompt.** Una banda muestra el esfuerzo de razonamiento, el
|
|
312
|
+
contexto, el temporizador de caché y qué modelo respondió tu última solicitud, con su
|
|
313
|
+
acierto de caché. Un pequeño modelo juez (Haiku 5.5 o Jev) lee cada prompt junto con los
|
|
314
|
+
turnos recientes y fija el esfuerzo, de low a max. El trabajo delegado va a `ripple:auto`,
|
|
315
|
+
y el juez envía cada tarea a un worker según su dificultad: lo ligero a DeepSeek o GLM, lo
|
|
316
|
+
difícil a GPT u Opus. Unas tarjetas avisan cuando la caché se ha enfriado, el contexto pesa
|
|
317
|
+
demasiado o una ventana del plan pasa del 80 %, y ofrecen compactar o traspasar a una sesión
|
|
318
|
+
nueva en la misma carpeta. `Log` (o `/ripple-log`) abre el registro de solicitudes en un
|
|
319
|
+
panel lateral. Un solo interruptor en la pantalla Clientes, o `clauderipple mod on`.
|
|
314
320
|
- **Imágenes con tu suscripción de ChatGPT.** `clauderipple image "<prompt>"`, con
|
|
315
321
|
imágenes de referencia y fondos transparentes. A los subagentes se les explica cómo
|
|
316
322
|
hacerlo, así que un worker de GPT o DeepSeek puede crear una imagen y verla sin una
|
package/README.ja.md
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<img src="docs/media/icon.png" width="128" alt="ClaudeRipple">
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
1
|
<h1 align="center">ClaudeRipple</h1>
|
|
6
2
|
|
|
7
3
|
<p align="center"><a href="README.md">English</a> · <a href="README.ko.md">한국어</a> · <a href="README.zh-CN.md">简体中文</a> · <b>日本語</b> · <a href="README.es.md">Español</a> · <a href="README.pt-BR.md">Português (BR)</a></p>
|
|
@@ -25,16 +21,24 @@
|
|
|
25
21
|
</p>
|
|
26
22
|
|
|
27
23
|
<p align="center">
|
|
28
|
-
<img src="docs/media/
|
|
24
|
+
<a href="https://github.com/PBJ-2/clauderipple/releases/download/v0.9.0/clauderipple-demo.mp4"><img src="docs/media/demo.webp" width="880" alt="1分ツアー:Claude Desktop自身のモデルメニューに他のモデルが並び、プロンプトごとに推論強度を決め、サブエージェントは合うモデルに振り分けます。クリックで全編を再生。"></a><br>
|
|
25
|
+
<sub>1分ツアー:Claude Desktop自身のモデルメニューに他のモデルが並び、プロンプトごとに推論強度を決め、サブエージェントは合うモデルに振り分けます。クリックで全編を再生。</sub>
|
|
29
26
|
</p>
|
|
30
27
|
|
|
31
28
|
<table align="center">
|
|
32
29
|
<tr>
|
|
33
|
-
<td align="center" width="34%"><img src="docs/media/picker
|
|
34
|
-
<td align="center" width="66%"><img src="docs/media/
|
|
30
|
+
<td align="center" width="34%"><img src="docs/media/picker.png" width="300" alt="Claude Desktop本来のモデルメニューにGPT・DeepSeek・GLM・Gemini"><br><sub>Claude Desktop本来のモデルメニューにGPT・DeepSeek・GLM・Gemini</sub></td>
|
|
31
|
+
<td align="center" width="66%"><img src="docs/media/answer.png" alt="Codeタブで作業するGPT-6 Astra、右側にすべてのリクエストログ"><br><sub>Codeタブで作業するGPT-6 Astra、右側にすべてのリクエストログ</sub></td>
|
|
32
|
+
</tr>
|
|
33
|
+
<tr>
|
|
34
|
+
<td colspan="2" align="center"><img src="docs/media/subagents.png" alt="DeepSeekとGLMで動くサブエージェント。タスクパネルに実際の名前で表示"><br><sub>DeepSeekとGLMで動くサブエージェント。タスクパネルに実際の名前で表示</sub></td>
|
|
35
|
+
</tr>
|
|
36
|
+
<tr>
|
|
37
|
+
<td colspan="2" align="center"><img src="docs/media/mod-band.png" alt="rippleモッド:推論強度、コンテキスト、キャッシュタイマー、実際に応答したモデルとキャッシュヒット率"><br><sub>rippleモッド:推論強度、コンテキスト、キャッシュタイマー、実際に応答したモデルとキャッシュヒット率</sub></td>
|
|
35
38
|
</tr>
|
|
36
39
|
<tr>
|
|
37
|
-
<td
|
|
40
|
+
<td align="center" width="50%"><img src="docs/media/mod-alerts.png" alt="キャッシュが冷えたり上限が近づくと警告、新しいチャットへの引き継ぎ"><br><sub>キャッシュが冷えたり上限が近づくと警告、新しいチャットへの引き継ぎ</sub></td>
|
|
41
|
+
<td align="center" width="50%"><img src="docs/media/mod-settings.png" alt="クイック設定:自動推論強度、判定モデル、ワーカーモード"><br><sub>クイック設定:自動推論強度、判定モデル、ワーカーモード</sub></td>
|
|
38
42
|
</tr>
|
|
39
43
|
</table>
|
|
40
44
|
|
|
@@ -167,7 +171,7 @@ Claude Codeのシステムプロンプトとツールの説明はClaude向けに
|
|
|
167
171
|
- **設計段階で正しさを確保**。プロンプトキャッシュを保持(Anthropicのキャッシュブレークポイントと、安定したOpenAIのプレフィックス)、Claude Codeのサーバー側スレッドを処理、ツール呼び出しと画像を往復で変換、推論強度を各モデルが受け付ける範囲に調整、互換ベンダー向けにはAnthropic専用のリクエストフィールドを除去。
|
|
168
172
|
- **本物のリクエストログ**。誰が依頼し、どのモデルが応答したか、入力 / キャッシュ / 出力のトークン数、レイテンシ、ステータスをリクエストごとに記録し、直近1時間のサマリーも表示します。
|
|
169
173
|
- **サブエージェントの名前タグ**。バックグラウンドタスクパネルに、汎用の「Agent」ではなく`Terra·high · Review`のように表示されます。
|
|
170
|
-
-
|
|
174
|
+
- **プロンプトの上のrippleモッド**。帯1本に推論強度、コンテキスト、キャッシュタイマー、直前のリクエストに実際に応答したモデルとキャッシュヒット率を表示します。小さな判定モデル(Haiku 5.5またはJev)がプロンプトごとに直近の会話と合わせて読み、lowからmaxまで推論強度を決めます。任せた作業は`ripple:auto`に渡り、判定モデルが難しさに応じてワーカーを選びます。軽い作業はDeepSeekやGLM、難しい作業はGPTやOpusへ。キャッシュが冷えたとき、コンテキストが重くなったとき、プランの上限が80%を超えたときにカードで知らせ、圧縮か、同じフォルダの新しいセッションへの引き継ぎを提案します。`Log`(または`/ripple-log`)でリクエストログをサイドペインに開きます。「クライアント」画面のスイッチ1つ、または`clauderipple mod on`で有効にできます。
|
|
171
175
|
- **ChatGPTのサブスクリプションで画像を生成**。`clauderipple image "<prompt>"`で、参照画像や透明背景にも対応します。サブエージェントにもやり方が伝えられているので、GPTやDeepSeekのワーカーでも、画像ツールなしで画像を作って確認できます。
|
|
172
176
|
- **必要なら軽量なワーカーを**。スイッチ1つで、生成されるサブエージェントに、セッションのすべてのMCPサーバーとプラグインではなく、ワーカーが使うツールだけを渡します。あるワーカーの最初のリクエストは33kトークンから9kトークンに減りました。
|
|
173
177
|
- **ターミナルを使いたくない人のために**。ワンクリックの接続テストとモデル検出付きのプロバイダープリセット、ドロップダウンによるモデルマッピング、自動保存、韓国語と英語のUI。独自のランタイムを同梱し、初回起動時に自らセットアップするメニューバーアプリ。署名・公証済みです。
|
package/README.ko.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="brand/mark-dark.svg">
|
|
4
|
+
<source media="(prefers-color-scheme: light)" srcset="brand/mark.svg">
|
|
5
|
+
<img src="brand/mark.svg" width="120" height="120" alt="ClaudeRipple 마스코트 리플이: 속이 빈 파문 고리에 물마루가 말려 오른 모습">
|
|
6
|
+
</picture>
|
|
3
7
|
</p>
|
|
4
8
|
|
|
5
9
|
<h1 align="center">ClaudeRipple</h1>
|
|
@@ -25,16 +29,24 @@
|
|
|
25
29
|
</p>
|
|
26
30
|
|
|
27
31
|
<p align="center">
|
|
28
|
-
<img src="docs/media/
|
|
32
|
+
<a href="https://github.com/PBJ-2/clauderipple/releases/download/v0.9.0/clauderipple-demo.mp4"><img src="docs/media/demo.webp" width="880" alt="1분 둘러보기: Claude Desktop의 모델 메뉴에 다른 모델이 들어가고, 프롬프트마다 추론 강도를 정하고, 서브에이전트는 맞는 모델로 보냅니다. 누르면 전체 영상이 열립니다."></a><br>
|
|
33
|
+
<sub>1분 둘러보기: Claude Desktop의 모델 메뉴에 다른 모델이 들어가고, 프롬프트마다 추론 강도를 정하고, 서브에이전트는 맞는 모델로 보냅니다. 누르면 전체 영상이 열립니다.</sub>
|
|
29
34
|
</p>
|
|
30
35
|
|
|
31
36
|
<table align="center">
|
|
32
37
|
<tr>
|
|
33
|
-
<td align="center" width="34%"><img src="docs/media/picker
|
|
34
|
-
<td align="center" width="66%"><img src="docs/media/
|
|
38
|
+
<td align="center" width="34%"><img src="docs/media/picker.png" width="300" alt="Claude Desktop의 원래 모델 메뉴에 GPT·DeepSeek·GLM·Gemini"><br><sub>Claude Desktop의 원래 모델 메뉴에 GPT·DeepSeek·GLM·Gemini</sub></td>
|
|
39
|
+
<td align="center" width="66%"><img src="docs/media/answer.png" alt="Code 탭에서 일하는 GPT-6 Astra, 오른쪽에는 모든 요청 기록"><br><sub>Code 탭에서 일하는 GPT-6 Astra, 오른쪽에는 모든 요청 기록</sub></td>
|
|
35
40
|
</tr>
|
|
36
41
|
<tr>
|
|
37
|
-
<td colspan="2" align="center"><img src="docs/media/subagents.png" alt="
|
|
42
|
+
<td colspan="2" align="center"><img src="docs/media/subagents.png" alt="DeepSeek·GLM으로 도는 서브에이전트, 작업 패널에 실제 이름으로"><br><sub>DeepSeek·GLM으로 도는 서브에이전트, 작업 패널에 실제 이름으로</sub></td>
|
|
43
|
+
</tr>
|
|
44
|
+
<tr>
|
|
45
|
+
<td colspan="2" align="center"><img src="docs/media/mod-band.png" alt="리플 모드: 추론 강도, 컨텍스트, 캐시 타이머, 실제로 답한 모델과 캐시 적중률"><br><sub>리플 모드: 추론 강도, 컨텍스트, 캐시 타이머, 실제로 답한 모델과 캐시 적중률</sub></td>
|
|
46
|
+
</tr>
|
|
47
|
+
<tr>
|
|
48
|
+
<td align="center" width="50%"><img src="docs/media/mod-alerts.png" alt="캐시가 식거나 한도가 가까우면 경고, 새 대화로 인수인계"><br><sub>캐시가 식거나 한도가 가까우면 경고, 새 대화로 인수인계</sub></td>
|
|
49
|
+
<td align="center" width="50%"><img src="docs/media/mod-settings.png" alt="빠른 설정: 자동 추론 강도, 판정 모델, 워커 모드"><br><sub>빠른 설정: 자동 추론 강도, 판정 모델, 워커 모드</sub></td>
|
|
38
50
|
</tr>
|
|
39
51
|
</table>
|
|
40
52
|
|
|
@@ -237,10 +249,12 @@ ClaudeRipple은 Claude Code 프로세스만 신뢰하는 작은 HTTPS 프록시
|
|
|
237
249
|
서버 측 스레드 처리, 도구 호출과 이미지 왕복, 모델이 받는 범위로 추론 강도 클램프, 호환 벤더에는 Anthropic 전용 필드 제거.
|
|
238
250
|
- **제대로 된 요청 로그.** 누가 물었고 어떤 모델이 답했는지, 입력·캐시·출력 토큰, 지연, 상태를 요청마다. 한 시간 요약 포함.
|
|
239
251
|
- **서브에이전트 이름표.** 백그라운드 작업 패널에 "Agent" 대신 `Terra·high · Review`가 보입니다.
|
|
240
|
-
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
252
|
+
- **입력창 위의 리플 모드.** 띠 하나에 추론 강도, 컨텍스트, 캐시 타이머, 마지막 요청에 실제로 답한 모델과 캐시
|
|
253
|
+
적중률이 보입니다. 작은 판정 모델(Haiku 5.5 또는 Jev)이 프롬프트마다 최근 대화와 함께 읽고 low부터 max까지 추론
|
|
254
|
+
강도를 정합니다. 맡긴 일은 `ripple:auto`로 가고, 판정 모델이 난이도에 따라 워커를 고릅니다. 가벼운 일은 DeepSeek·GLM,
|
|
255
|
+
어려운 일은 GPT·Opus로. 캐시가 식었을 때, 컨텍스트가 무거워졌을 때, 요금제 한도가 80%를 넘었을 때 카드로 알려 주고,
|
|
256
|
+
압축이나 같은 폴더 새 세션으로의 인수인계를 제안합니다. `Log`(또는 `/ripple-log`)로 요청 로그를 옆 패널에 엽니다.
|
|
257
|
+
클라이언트 화면의 스위치 하나, 또는 `clauderipple mod on`.
|
|
244
258
|
- **ChatGPT 구독으로 이미지 생성.** `clauderipple image "<프롬프트>"`. 참고 이미지와 투명 배경도 됩니다. 서브에이전트에도
|
|
245
259
|
방법이 적혀 있어, GPT나 DeepSeek 워커가 이미지 도구 없이 이미지를 만들고 직접 확인합니다.
|
|
246
260
|
- **원하면 가벼운 워커.** 스위치 하나로, 생성된 서브에이전트에 세션의 MCP·플러그인 도구 전부 대신 워커가 쓰는 도구만
|
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="brand/mark-dark.svg">
|
|
4
|
+
<source media="(prefers-color-scheme: light)" srcset="brand/mark.svg">
|
|
5
|
+
<img src="brand/mark.svg" width="120" height="120" alt="The ClaudeRipple mascot: a hollow ripple ring with a curling wave crest">
|
|
6
|
+
</picture>
|
|
3
7
|
</p>
|
|
4
8
|
|
|
5
9
|
<h1 align="center">ClaudeRipple</h1>
|
|
@@ -26,16 +30,24 @@
|
|
|
26
30
|
</p>
|
|
27
31
|
|
|
28
32
|
<p align="center">
|
|
29
|
-
<img src="docs/media/
|
|
33
|
+
<a href="https://github.com/PBJ-2/clauderipple/releases/download/v0.9.0/clauderipple-demo.mp4"><img src="docs/media/demo.webp" width="880" alt="A one-minute tour: other models in Claude Desktop's own model menu, effort set for every prompt, and each subagent sent to the model that fits. Click for the full video."></a><br>
|
|
34
|
+
<sub>A one-minute tour: other models in Claude Desktop's own model menu, effort set for every prompt, and each subagent sent to the model that fits. Click for the full video.</sub>
|
|
30
35
|
</p>
|
|
31
36
|
|
|
32
37
|
<table align="center">
|
|
33
38
|
<tr>
|
|
34
|
-
<td align="center" width="34%"><img src="docs/media/picker
|
|
35
|
-
<td align="center" width="66%"><img src="docs/media/
|
|
39
|
+
<td align="center" width="34%"><img src="docs/media/picker.png" width="300" alt="GPT, DeepSeek, GLM and Gemini in Claude Desktop's own model menu"><br><sub>GPT, DeepSeek, GLM and Gemini in Claude Desktop's own model menu</sub></td>
|
|
40
|
+
<td align="center" width="66%"><img src="docs/media/answer.png" alt="GPT-6 Astra working in the Code tab, every request logged on the right"><br><sub>GPT-6 Astra working in the Code tab, every request logged on the right</sub></td>
|
|
36
41
|
</tr>
|
|
37
42
|
<tr>
|
|
38
|
-
<td colspan="2" align="center"><img src="docs/media/subagents.png" alt="Subagents on
|
|
43
|
+
<td colspan="2" align="center"><img src="docs/media/subagents.png" alt="Subagents on DeepSeek and GLM, named in the background-task panel"><br><sub>Subagents on DeepSeek and GLM, named in the background-task panel</sub></td>
|
|
44
|
+
</tr>
|
|
45
|
+
<tr>
|
|
46
|
+
<td colspan="2" align="center"><img src="docs/media/mod-band.png" alt="The ripple mod: effort, context, cache timer, and which model answered with its cache hit"><br><sub>The ripple mod: effort, context, cache timer, and which model answered with its cache hit</sub></td>
|
|
47
|
+
</tr>
|
|
48
|
+
<tr>
|
|
49
|
+
<td align="center" width="50%"><img src="docs/media/mod-alerts.png" alt="Warnings when the cache goes cold or a limit is near, and a handoff to a fresh chat"><br><sub>Warnings when the cache goes cold or a limit is near, and a handoff to a fresh chat</sub></td>
|
|
50
|
+
<td align="center" width="50%"><img src="docs/media/mod-settings.png" alt="Quick settings: automatic effort, the judge, worker modes"><br><sub>Quick settings: automatic effort, the judge, worker modes</sub></td>
|
|
39
51
|
</tr>
|
|
40
52
|
</table>
|
|
41
53
|
|
|
@@ -286,12 +298,15 @@ you map go to your provider, everything else goes to Anthropic byte for byte.
|
|
|
286
298
|
latency, status, per request, with a one-hour summary.
|
|
287
299
|
- **Subagent name tags.** The background-task panel shows `Terra·high · Review`
|
|
288
300
|
instead of a generic "Agent".
|
|
289
|
-
- **The
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
301
|
+
- **The ripple mod, above the prompt.** A band shows the reasoning effort, context, cache
|
|
302
|
+
timer, and which model answered your last request with its cache hit. A small judge
|
|
303
|
+
model (Haiku 5.5 or Jev) reads each prompt with the recent turns and sets the effort,
|
|
304
|
+
low through max. Delegated work goes to `ripple:auto`, and the judge sends each task to
|
|
305
|
+
a worker by difficulty: light work to DeepSeek or GLM, hard work to GPT or Opus. Cards
|
|
306
|
+
warn when the cache has gone cold, the context gets heavy or a plan window passes 80%,
|
|
307
|
+
and offer compact or a handoff to a fresh session in the same folder. `Log` (or
|
|
308
|
+
`/ripple-log`) opens the request log in a side pane. One switch on the Clients screen,
|
|
309
|
+
or `clauderipple mod on`.
|
|
295
310
|
- **Images from your ChatGPT subscription.** `clauderipple image "<prompt>"`, with
|
|
296
311
|
reference images and transparent backgrounds. Subagents are told how, so a GPT or
|
|
297
312
|
DeepSeek worker can make an image and look at it without an image tool.
|
package/README.pt-BR.md
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<img src="docs/media/icon.png" width="128" alt="ClaudeRipple">
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
1
|
<h1 align="center">ClaudeRipple</h1>
|
|
6
2
|
|
|
7
3
|
<p align="center"><a href="README.md">English</a> · <a href="README.ko.md">한국어</a> · <a href="README.zh-CN.md">简体中文</a> · <a href="README.ja.md">日本語</a> · <a href="README.es.md">Español</a> · <b>Português (BR)</b></p>
|
|
@@ -26,16 +22,24 @@
|
|
|
26
22
|
</p>
|
|
27
23
|
|
|
28
24
|
<p align="center">
|
|
29
|
-
<img src="docs/media/
|
|
25
|
+
<a href="https://github.com/PBJ-2/clauderipple/releases/download/v0.9.0/clauderipple-demo.mp4"><img src="docs/media/demo.webp" width="880" alt="Tour de um minuto: outros modelos no próprio menu de modelos do Claude Desktop, o esforço ajustado a cada prompt e cada subagente enviado ao modelo certo. Clique para ver o vídeo completo."></a><br>
|
|
26
|
+
<sub>Tour de um minuto: outros modelos no próprio menu de modelos do Claude Desktop, o esforço ajustado a cada prompt e cada subagente enviado ao modelo certo. Clique para ver o vídeo completo.</sub>
|
|
30
27
|
</p>
|
|
31
28
|
|
|
32
29
|
<table align="center">
|
|
33
30
|
<tr>
|
|
34
|
-
<td align="center" width="34%"><img src="docs/media/picker
|
|
35
|
-
<td align="center" width="66%"><img src="docs/media/
|
|
31
|
+
<td align="center" width="34%"><img src="docs/media/picker.png" width="300" alt="GPT, DeepSeek, GLM e Gemini no próprio menu de modelos do Claude Desktop"><br><sub>GPT, DeepSeek, GLM e Gemini no próprio menu de modelos do Claude Desktop</sub></td>
|
|
32
|
+
<td align="center" width="66%"><img src="docs/media/answer.png" alt="GPT-6 Astra trabalhando na aba Code, com cada requisição registrada à direita"><br><sub>GPT-6 Astra trabalhando na aba Code, com cada requisição registrada à direita</sub></td>
|
|
33
|
+
</tr>
|
|
34
|
+
<tr>
|
|
35
|
+
<td colspan="2" align="center"><img src="docs/media/subagents.png" alt="Subagentes no DeepSeek e no GLM, identificados no painel de tarefas"><br><sub>Subagentes no DeepSeek e no GLM, identificados no painel de tarefas</sub></td>
|
|
36
|
+
</tr>
|
|
37
|
+
<tr>
|
|
38
|
+
<td colspan="2" align="center"><img src="docs/media/mod-band.png" alt="O mod ripple: esforço, contexto, timer do cache e qual modelo respondeu, com o acerto de cache"><br><sub>O mod ripple: esforço, contexto, timer do cache e qual modelo respondeu, com o acerto de cache</sub></td>
|
|
36
39
|
</tr>
|
|
37
40
|
<tr>
|
|
38
|
-
<td
|
|
41
|
+
<td align="center" width="50%"><img src="docs/media/mod-alerts.png" alt="Avisos quando o cache esfria ou um limite está perto, e passagem para um chat novo"><br><sub>Avisos quando o cache esfria ou um limite está perto, e passagem para um chat novo</sub></td>
|
|
42
|
+
<td align="center" width="50%"><img src="docs/media/mod-settings.png" alt="Ajustes rápidos: esforço automático, o juiz, modos de workers"><br><sub>Ajustes rápidos: esforço automático, o juiz, modos de workers</sub></td>
|
|
39
43
|
</tr>
|
|
40
44
|
</table>
|
|
41
45
|
|
|
@@ -299,13 +303,15 @@ que você mapeia vão para o seu provedor, e todo o resto vai para a Anthropic b
|
|
|
299
303
|
última hora.
|
|
300
304
|
- **Identificação dos subagentes.** O painel de tarefas em segundo plano mostra
|
|
301
305
|
`Terra·high · Review` em vez de um "Agent" genérico.
|
|
302
|
-
- **
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
306
|
+
- **O mod ripple, acima do prompt.** Uma faixa mostra o esforço de raciocínio, o contexto, o
|
|
307
|
+
timer do cache e qual modelo respondeu sua última requisição, com o acerto de cache. Um
|
|
308
|
+
pequeno modelo juiz (Haiku 5.5 ou Jev) lê cada prompt junto com os turnos recentes e define
|
|
309
|
+
o esforço, de low a max. O trabalho delegado vai para `ripple:auto`, e o juiz manda cada
|
|
310
|
+
tarefa para um worker conforme a dificuldade: o leve para DeepSeek ou GLM, o difícil para
|
|
311
|
+
GPT ou Opus. Cartões avisam quando o cache esfriou, o contexto ficou pesado ou uma janela do
|
|
312
|
+
plano passou de 80%, e oferecem compactar ou passar para uma sessão nova na mesma pasta.
|
|
313
|
+
`Log` (ou `/ripple-log`) abre o log de requisições em um painel lateral. Basta um botão na
|
|
314
|
+
tela **Clientes**, ou `clauderipple mod on`.
|
|
309
315
|
- **Imagens pela sua assinatura do ChatGPT.** `clauderipple image "<prompt>"`, com imagens
|
|
310
316
|
de referência e fundos transparentes. Os subagentes recebem instruções de como fazer,
|
|
311
317
|
então um worker GPT ou DeepSeek consegue criar uma imagem e olhar para ela sem uma
|
package/README.zh-CN.md
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<img src="docs/media/icon.png" width="128" alt="ClaudeRipple">
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
1
|
<h1 align="center">ClaudeRipple</h1>
|
|
6
2
|
|
|
7
3
|
<p align="center"><a href="README.md">English</a> · <a href="README.ko.md">한국어</a> · <b>简体中文</b> · <a href="README.ja.md">日本語</a> · <a href="README.es.md">Español</a> · <a href="README.pt-BR.md">Português (BR)</a></p>
|
|
@@ -26,16 +22,24 @@
|
|
|
26
22
|
</p>
|
|
27
23
|
|
|
28
24
|
<p align="center">
|
|
29
|
-
<img src="docs/media/
|
|
25
|
+
<a href="https://github.com/PBJ-2/clauderipple/releases/download/v0.9.0/clauderipple-demo.mp4"><img src="docs/media/demo.webp" width="880" alt="一分钟概览:其他模型出现在 Claude Desktop 自带的模型菜单里,每条提示设定推理强度,子代理分派给合适的模型。点击观看完整视频。"></a><br>
|
|
26
|
+
<sub>一分钟概览:其他模型出现在 Claude Desktop 自带的模型菜单里,每条提示设定推理强度,子代理分派给合适的模型。点击观看完整视频。</sub>
|
|
30
27
|
</p>
|
|
31
28
|
|
|
32
29
|
<table align="center">
|
|
33
30
|
<tr>
|
|
34
|
-
<td align="center" width="34%"><img src="docs/media/picker
|
|
35
|
-
<td align="center" width="66%"><img src="docs/media/
|
|
31
|
+
<td align="center" width="34%"><img src="docs/media/picker.png" width="300" alt="Claude Desktop 自带的模型菜单里出现 GPT、DeepSeek、GLM、Gemini"><br><sub>Claude Desktop 自带的模型菜单里出现 GPT、DeepSeek、GLM、Gemini</sub></td>
|
|
32
|
+
<td align="center" width="66%"><img src="docs/media/answer.png" alt="GPT-6 Astra 在 Code 标签页中工作,右侧记录每一个请求"><br><sub>GPT-6 Astra 在 Code 标签页中工作,右侧记录每一个请求</sub></td>
|
|
33
|
+
</tr>
|
|
34
|
+
<tr>
|
|
35
|
+
<td colspan="2" align="center"><img src="docs/media/subagents.png" alt="运行在 DeepSeek 和 GLM 上的子代理,在任务面板中显示真实名称"><br><sub>运行在 DeepSeek 和 GLM 上的子代理,在任务面板中显示真实名称</sub></td>
|
|
36
|
+
</tr>
|
|
37
|
+
<tr>
|
|
38
|
+
<td colspan="2" align="center"><img src="docs/media/mod-band.png" alt="ripple 模组:推理强度、上下文、缓存计时,以及实际作答的模型和缓存命中率"><br><sub>ripple 模组:推理强度、上下文、缓存计时,以及实际作答的模型和缓存命中率</sub></td>
|
|
36
39
|
</tr>
|
|
37
40
|
<tr>
|
|
38
|
-
<td
|
|
41
|
+
<td align="center" width="50%"><img src="docs/media/mod-alerts.png" alt="缓存变冷或额度将满时提醒,并可交接到新的对话"><br><sub>缓存变冷或额度将满时提醒,并可交接到新的对话</sub></td>
|
|
42
|
+
<td align="center" width="50%"><img src="docs/media/mod-settings.png" alt="快速设置:自动推理强度、判定模型、工作者模式"><br><sub>快速设置:自动推理强度、判定模型、工作者模式</sub></td>
|
|
39
43
|
</tr>
|
|
40
44
|
</table>
|
|
41
45
|
|
|
@@ -168,7 +172,7 @@ Claude Code 的系统提示词和工具描述是为 Claude 编写的,所以其
|
|
|
168
172
|
- **从设计上保证正确。** 保留提示缓存(Anthropic 缓存断点和稳定的 OpenAI 前缀),处理 Claude Code 的服务端线程,完整保留双向传递的工具调用和图片,将推理强度限定在各模型接受的范围内,并为兼容厂商去除 Anthropic 专有的请求字段。
|
|
169
173
|
- **真正的请求日志。** 逐条记录谁发起了请求、哪个模型作答、输入 / 缓存 / 输出 token、延迟和状态,并附最近一小时的汇总。
|
|
170
174
|
- **子代理名称标签。** 后台任务面板显示 `Terra·high · Review`,而不是笼统的“Agent”。
|
|
171
|
-
-
|
|
175
|
+
- **输入框上方的 ripple 模组。** 一条横栏显示推理强度、上下文、缓存计时,以及上一个请求实际由哪个模型作答和缓存命中率。一个小型判定模型(Haiku 5.5 或 Jev)会结合最近的对话阅读每条提示词,在 low 到 max 之间设定推理强度。委派的工作交给 `ripple:auto`,由判定模型按难度挑选 worker:轻活交给 DeepSeek 或 GLM,难活交给 GPT 或 Opus。缓存变冷、上下文变重或套餐额度超过 80% 时会弹出卡片提醒,并提供压缩或交接到同一文件夹的新会话。`Log`(或 `/ripple-log`)会在侧边窗格中打开请求日志。在“客户端”页面上打开一个开关即可启用,或运行 `clauderipple mod on`。
|
|
172
176
|
- **用 ChatGPT 订阅生成图片。** `clauderipple image "<prompt>"`,支持参考图和透明背景。子代理会被告知用法,因此 GPT 或 DeepSeek worker 无需图像工具也能生成图片并查看结果。
|
|
173
177
|
- **按需精简 worker。** 打开一个开关,生成的子代理就只获得 worker 会用到的工具,而不是会话中的所有 MCP 服务器和插件:某个 worker 的首个请求因此从 33k token 降到了 9k token。
|
|
174
178
|
- **为不想碰终端的人而设计。** 供应商预设支持一键连接测试和模型发现,下拉式模型映射,自动保存,韩语和英语界面。菜单栏应用自带运行时,首次启动时自动完成设置。经过签名和公证。
|
package/dist/app/package.json
CHANGED
package/dist/cli/src/codex.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import os from "node:os";
|
|
6
6
|
import path from "node:path";
|
|
7
|
+
import { isJudgeOnlyModel } from "../../router/src/model-policy.js";
|
|
7
8
|
const START = "# >>> ClaudeRipple Codex provider >>>";
|
|
8
9
|
const END = "# <<< ClaudeRipple Codex provider <<<";
|
|
9
10
|
const PROFILE_START = "# >>> ClaudeRipple Codex profile >>>";
|
|
@@ -76,7 +77,8 @@ export function writeCodexCatalog(models, home = codexHome()) {
|
|
|
76
77
|
catch {
|
|
77
78
|
return undefined;
|
|
78
79
|
}
|
|
79
|
-
|
|
80
|
+
models = models.filter(m => !isJudgeOnlyModel(m.id));
|
|
81
|
+
const entries = (cached.models ?? []).filter((m) => typeof m.slug === "string" && !isJudgeOnlyModel(m.slug));
|
|
80
82
|
const template = entries.find((m) => m.slug === "gpt-5.5" && m.model_messages) ?? entries.find((m) => m.model_messages);
|
|
81
83
|
if (!template)
|
|
82
84
|
return undefined;
|
package/dist/cli/src/settings.js
CHANGED
|
@@ -216,11 +216,14 @@ export function agentTitleHookEnabled() {
|
|
|
216
216
|
}
|
|
217
217
|
// ---- Status mod (packages/mod) ------------------------------------------------------------
|
|
218
218
|
/** The `name` in packages/mod/.claude-plugin/plugin.json: how our entry is told from anyone else's. */
|
|
219
|
-
export const STATUS_MOD_NAME = "
|
|
219
|
+
export const STATUS_MOD_NAME = "ripple";
|
|
220
|
+
/** Its name until 0.8.10: an entry an older install added is still ours to replace or remove. */
|
|
221
|
+
const OLD_STATUS_MOD_NAMES = ["clauderipple-status"];
|
|
220
222
|
const PLUGIN_DIRS = "CLAUDE_CODE_PLUGIN_DIRS";
|
|
221
223
|
function isStatusMod(dir) {
|
|
222
224
|
try {
|
|
223
|
-
|
|
225
|
+
const name = JSON.parse(fs.readFileSync(path.join(dir, ".claude-plugin", "plugin.json"), "utf8")).name;
|
|
226
|
+
return name === STATUS_MOD_NAME || OLD_STATUS_MOD_NAMES.includes(name);
|
|
224
227
|
}
|
|
225
228
|
catch {
|
|
226
229
|
return false;
|
|
@@ -1 +1,9 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"name": "ripple",
|
|
3
|
+
"displayName": "ClaudeRipple",
|
|
4
|
+
"version": "0.7.0",
|
|
5
|
+
"description": "Picks the reasoning effort for every prompt and the worker for every delegated task, can keep the prompt cache warm, and shows where ClaudeRipple sent each request.",
|
|
6
|
+
"author": { "name": "ClaudeRipple" },
|
|
7
|
+
"license": "GPL-3.0-only",
|
|
8
|
+
"types": "./types/index.d.ts"
|
|
9
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ModelForkResult } from 'claude-code'
|
|
2
|
+
import type { CacheMemo, Settings, Usage, WarmState } from '../types'
|
|
3
|
+
import { weighted } from './stats'
|
|
4
|
+
import { t } from './i18n.ts'
|
|
5
|
+
import type { Lang } from './i18n.ts'
|
|
6
|
+
|
|
7
|
+
const HOUR = 3600000
|
|
8
|
+
const FIVE_MINUTES = 300000
|
|
9
|
+
|
|
10
|
+
export function ttlFromUsage(usage: Usage): number {
|
|
11
|
+
if ((usage.cache_creation?.ephemeral_1h_input_tokens ?? 0) > 0) return HOUR
|
|
12
|
+
if ((usage.cache_creation?.ephemeral_5m_input_tokens ?? 0) > 0) return FIVE_MINUTES
|
|
13
|
+
return HOUR
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** A five-minute tail must not shorten a mostly-read hour-long prefix. */
|
|
17
|
+
export function nextMemo(prev: CacheMemo | null, usage: Usage, now: number): CacheMemo {
|
|
18
|
+
const total = (usage.input_tokens ?? 0) + (usage.cache_creation_input_tokens ?? 0) + (usage.cache_read_input_tokens ?? 0)
|
|
19
|
+
const mostlyRead = (usage.cache_read_input_tokens ?? 0) > total / 2
|
|
20
|
+
const explicit = (usage.cache_creation?.ephemeral_1h_input_tokens ?? 0) > 0 || (usage.cache_creation?.ephemeral_5m_input_tokens ?? 0) > 0
|
|
21
|
+
let ttlMs = explicit ? ttlFromUsage(usage) : prev?.ttlMs ?? HOUR
|
|
22
|
+
if (prev?.ttlMs === HOUR && mostlyRead) ttlMs = HOUR
|
|
23
|
+
if (!explicit && prev && now - prev.lastReplyAt > FIVE_MINUTES && mostlyRead) ttlMs = HOUR
|
|
24
|
+
return { ttlMs, lastReplyAt: now, expiresAt: now + ttlMs }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function secondsLeft(memo: CacheMemo | null, now: number): number | null {
|
|
28
|
+
return memo ? Math.max(0, Math.ceil((memo.expiresAt - now) / 1000)) : null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Never pay to revive an expired cache or extend the last-real-reply bound with our own pings. */
|
|
32
|
+
export function shouldPing(input: {
|
|
33
|
+
settings: Settings; memo: CacheMemo | null; warm: WarmState; now: number; idle: boolean
|
|
34
|
+
contextTokens: number; lastRealReplyAt: number | null
|
|
35
|
+
}): { ping: true } | { ping: false; reason?: string } {
|
|
36
|
+
const { settings, memo, warm, now } = input
|
|
37
|
+
if (!settings.keepWarm) return { ping: false, reason: 'keep warm is off' }
|
|
38
|
+
if (warm.stopped) return { ping: false, reason: warm.stopped }
|
|
39
|
+
if (!input.idle) return { ping: false, reason: 'chat is busy' }
|
|
40
|
+
if (!memo || memo.expiresAt <= now) return { ping: false, reason: 'cache is not warm' }
|
|
41
|
+
if (input.lastRealReplyAt === null || now >= input.lastRealReplyAt + settings.keepWarmHours * HOUR) return { ping: false, reason: 'keep warm time bound reached' }
|
|
42
|
+
if (input.contextTokens < settings.keepWarmMinTokens) return { ping: false, reason: 'chat is too small' }
|
|
43
|
+
const lead = memo.ttlMs === FIVE_MINUTES ? 60000 : 240000
|
|
44
|
+
return memo.expiresAt - now <= lead ? { ping: true } : { ping: false }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Failed forks stop once; answered cache misses still count the real tokens they spent. */
|
|
48
|
+
export function afterPing(warm: WarmState, forkResult: ModelForkResult | null, now: number, lang: Lang = 'en'): WarmState {
|
|
49
|
+
if (!forkResult?.isAnswered) return { ...warm, stopped: t(lang, 'toasts.warmNoReply') }
|
|
50
|
+
const next: WarmState = { pings: warm.pings + 1, cost: warm.cost + weighted(forkResult.usage), lastPingAt: now }
|
|
51
|
+
if (forkResult.usage.cache_read_input_tokens <= 0) next.stopped = t(lang, 'toasts.warmNoCache')
|
|
52
|
+
return next
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function restoreFromResume(secondsSinceLastResponse: number | undefined, likelyExpired: boolean | undefined, ttlMs: number, now: number): CacheMemo | null {
|
|
56
|
+
if (secondsSinceLastResponse === undefined || !Number.isFinite(secondsSinceLastResponse) || secondsSinceLastResponse < 0) return null
|
|
57
|
+
const lastReplyAt = now - secondsSinceLastResponse * 1000
|
|
58
|
+
const expiresAt = lastReplyAt + ttlMs
|
|
59
|
+
return { ttlMs, lastReplyAt, expiresAt: likelyExpired || expiresAt <= now ? now - 1 : expiresAt }
|
|
60
|
+
}
|