@oneciel-ai/claude-any 0.1.39 → 0.1.42
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/README.md +16 -1
- package/claude_any.py +57 -10
- package/docs/README.ja.md +16 -1
- package/docs/README.ko.md +16 -1
- package/docs/README.zh.md +16 -1
- package/docs/manual.md +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ arguments through unchanged.
|
|
|
48
48
|
|
|
49
49
|
Credits: One Ciel LLC
|
|
50
50
|
|
|
51
|
-
Current version: `0.1.
|
|
51
|
+
Current version: `0.1.42`
|
|
52
52
|
|
|
53
53
|
## Why This Exists
|
|
54
54
|
|
|
@@ -381,6 +381,21 @@ steps under that larger model's supervision.
|
|
|
381
381
|
|
|
382
382
|
## Changelog
|
|
383
383
|
|
|
384
|
+
### 0.1.42
|
|
385
|
+
|
|
386
|
+
- **Live stream progress**: the statusline now updates streamed upstream output
|
|
387
|
+
progress with formatted input/output token estimates and chunk counts.
|
|
388
|
+
|
|
389
|
+
### 0.1.41
|
|
390
|
+
|
|
391
|
+
- **Statusline formatting**: upstream token counts now use thousands separators
|
|
392
|
+
and a space before `tok`, for example `27,501 tok`.
|
|
393
|
+
|
|
394
|
+
### 0.1.40
|
|
395
|
+
|
|
396
|
+
- **RPM 0 is preserved**: setting `rate_limit_rpm=0` now stores an explicit
|
|
397
|
+
unlimited mode instead of falling back to the provider default.
|
|
398
|
+
|
|
384
399
|
### 0.1.39
|
|
385
400
|
|
|
386
401
|
- **Menu input fixes**: restores terminal line/echo mode before text or number
|
package/claude_any.py
CHANGED
|
@@ -85,7 +85,7 @@ PROVIDER_LABELS = {
|
|
|
85
85
|
"self-hosted-nim": "Self Hosted NIM",
|
|
86
86
|
}
|
|
87
87
|
APP_NAME = "Claude Any"
|
|
88
|
-
VERSION = "0.1.
|
|
88
|
+
VERSION = "0.1.42"
|
|
89
89
|
CREDITS = "Credits: One Ciel LLC"
|
|
90
90
|
|
|
91
91
|
LOG_LEVELS = {"SILENT": 0, "ERROR": 1, "WARN": 2, "INFO": 3, "DEBUG": 4, "TRACE": 5}
|
|
@@ -1339,7 +1339,22 @@ def main():
|
|
|
1339
1339
|
tokens = activity.get("tokens")
|
|
1340
1340
|
rpm_text += f" | upstream {age:.0f}s"
|
|
1341
1341
|
if tokens:
|
|
1342
|
-
|
|
1342
|
+
try:
|
|
1343
|
+
rpm_text += f" {int(tokens):,} tok"
|
|
1344
|
+
except Exception:
|
|
1345
|
+
rpm_text += f" {tokens} tok"
|
|
1346
|
+
output_tokens = activity.get("output_tokens")
|
|
1347
|
+
if output_tokens:
|
|
1348
|
+
try:
|
|
1349
|
+
rpm_text += f" -> {int(output_tokens):,} tok"
|
|
1350
|
+
except Exception:
|
|
1351
|
+
rpm_text += f" -> {output_tokens} tok"
|
|
1352
|
+
chunks = activity.get("chunks")
|
|
1353
|
+
if chunks:
|
|
1354
|
+
try:
|
|
1355
|
+
rpm_text += f" ({int(chunks):,} chunks)"
|
|
1356
|
+
except Exception:
|
|
1357
|
+
rpm_text += f" ({chunks} chunks)"
|
|
1343
1358
|
elif event in ("success", "error"):
|
|
1344
1359
|
rpm_text += f" | {event} {age:.0f}s"
|
|
1345
1360
|
print(f"{left} | {color(rpm_text)}")
|
|
@@ -2207,8 +2222,10 @@ def router_rate_limit_recent(timestamps: Any, now: float, window: float, *, incl
|
|
|
2207
2222
|
|
|
2208
2223
|
def router_rate_limit_usage(provider: str, pcfg: dict[str, Any], model: str | None = None) -> tuple[int, int | None]:
|
|
2209
2224
|
rpm = router_rate_limit_effective_rpm(provider, pcfg, model)
|
|
2210
|
-
if rpm is None:
|
|
2211
|
-
return 0, None
|
|
2225
|
+
if rpm is None:
|
|
2226
|
+
return 0, None
|
|
2227
|
+
if rpm == 0:
|
|
2228
|
+
return 0, 0
|
|
2212
2229
|
key = router_rate_limit_key(provider, pcfg, model)
|
|
2213
2230
|
now = time.time()
|
|
2214
2231
|
try:
|
|
@@ -4697,6 +4714,8 @@ def stream_openai_chat_to_anthropic_sse(
|
|
|
4697
4714
|
source_body: dict[str, Any] | None = None,
|
|
4698
4715
|
start_index: int = 0,
|
|
4699
4716
|
word_chunking: bool = False,
|
|
4717
|
+
input_tokens: int | None = None,
|
|
4718
|
+
input_bytes: int | None = None,
|
|
4700
4719
|
) -> None:
|
|
4701
4720
|
next_content_index = start_index
|
|
4702
4721
|
text_started = False
|
|
@@ -4709,6 +4728,8 @@ def stream_openai_chat_to_anthropic_sse(
|
|
|
4709
4728
|
tool_fragments: dict[int, dict[str, Any]] = {}
|
|
4710
4729
|
output_tokens = 0
|
|
4711
4730
|
finish_reason = "stop"
|
|
4731
|
+
chunks_seen = 0
|
|
4732
|
+
last_activity_update = 0.0
|
|
4712
4733
|
|
|
4713
4734
|
def emit(event_name: str, payload: dict[str, Any]) -> None:
|
|
4714
4735
|
handler.wfile.write(f"event: {event_name}\ndata: {json.dumps(payload, ensure_ascii=False)}\n\n".encode())
|
|
@@ -4736,8 +4757,27 @@ def stream_openai_chat_to_anthropic_sse(
|
|
|
4736
4757
|
{"type": "content_block_delta", "index": idx, "delta": {"type": "text_delta", "text": text}},
|
|
4737
4758
|
)
|
|
4738
4759
|
|
|
4760
|
+
def update_stream_activity(force: bool = False) -> None:
|
|
4761
|
+
nonlocal last_activity_update
|
|
4762
|
+
now = time.time()
|
|
4763
|
+
if not force and now - last_activity_update < 0.5:
|
|
4764
|
+
return
|
|
4765
|
+
last_activity_update = now
|
|
4766
|
+
estimated_output = output_tokens or max(0, len(text_so_far) // 4)
|
|
4767
|
+
write_router_activity(
|
|
4768
|
+
"request",
|
|
4769
|
+
provider,
|
|
4770
|
+
model,
|
|
4771
|
+
tokens=input_tokens,
|
|
4772
|
+
bytes=input_bytes,
|
|
4773
|
+
output_tokens=estimated_output,
|
|
4774
|
+
chunks=chunks_seen,
|
|
4775
|
+
stream=True,
|
|
4776
|
+
)
|
|
4777
|
+
|
|
4739
4778
|
try:
|
|
4740
4779
|
for raw_line in resp:
|
|
4780
|
+
chunks_seen += 1
|
|
4741
4781
|
line = raw_line.decode("utf-8", errors="ignore").strip()
|
|
4742
4782
|
if not line or line.startswith(":"):
|
|
4743
4783
|
continue
|
|
@@ -4789,6 +4829,7 @@ def stream_openai_chat_to_anthropic_sse(
|
|
|
4789
4829
|
emit_text_delta(to_flush)
|
|
4790
4830
|
else:
|
|
4791
4831
|
emit_text_delta(text_chunk)
|
|
4832
|
+
update_stream_activity()
|
|
4792
4833
|
for call in delta.get("tool_calls") or []:
|
|
4793
4834
|
if not isinstance(call, dict):
|
|
4794
4835
|
continue
|
|
@@ -4804,6 +4845,8 @@ def stream_openai_chat_to_anthropic_sse(
|
|
|
4804
4845
|
slot["name"] += str(fn.get("name"))
|
|
4805
4846
|
if fn.get("arguments"):
|
|
4806
4847
|
slot["arguments"] += str(fn.get("arguments"))
|
|
4848
|
+
update_stream_activity()
|
|
4849
|
+
update_stream_activity(force=True)
|
|
4807
4850
|
if word_chunking and text_buffer:
|
|
4808
4851
|
to_flush, text_buffer = _split_word_buffer(text_buffer, force=True)
|
|
4809
4852
|
emit_text_delta(to_flush)
|
|
@@ -5108,6 +5151,8 @@ def forward_openai_compatible_chat(handler: BaseHTTPRequestHandler, provider: st
|
|
|
5108
5151
|
model,
|
|
5109
5152
|
emit_retry_notice,
|
|
5110
5153
|
)
|
|
5154
|
+
req_tokens = estimate_tokens(req_body)
|
|
5155
|
+
req_bytes = len(json.dumps(req_body, ensure_ascii=False).encode("utf-8"))
|
|
5111
5156
|
stream_openai_chat_to_anthropic_sse(
|
|
5112
5157
|
handler,
|
|
5113
5158
|
resp,
|
|
@@ -5116,8 +5161,10 @@ def forward_openai_compatible_chat(handler: BaseHTTPRequestHandler, provider: st
|
|
|
5116
5161
|
source_body=body,
|
|
5117
5162
|
start_index=index,
|
|
5118
5163
|
word_chunking=bool(pcfg.get("stream_word_chunking", False)),
|
|
5164
|
+
input_tokens=req_tokens,
|
|
5165
|
+
input_bytes=req_bytes,
|
|
5119
5166
|
)
|
|
5120
|
-
write_router_activity("success", provider, model, tokens=
|
|
5167
|
+
write_router_activity("success", provider, model, tokens=req_tokens, bytes=req_bytes, stream=True)
|
|
5121
5168
|
except RuntimeError as exc:
|
|
5122
5169
|
msg = str(exc)
|
|
5123
5170
|
write_anthropic_stream_blocks(handler, [{"type": "text", "text": f"Upstream error: {msg}"}], index)
|
|
@@ -6663,11 +6710,11 @@ def apply_provider_option(provider: str, pcfg: dict[str, Any], token: str) -> No
|
|
|
6663
6710
|
raise SystemExit("timeout must be a positive integer; values above 10000 are treated as milliseconds")
|
|
6664
6711
|
pcfg["request_timeout_ms"] = fixed if key.endswith("_ms") or fixed > 10000 else fixed * 1000
|
|
6665
6712
|
return
|
|
6666
|
-
if key in ("rate_limit", "rate_limit_rpm", "rpm"):
|
|
6667
|
-
fixed = positive_int(value)
|
|
6668
|
-
if value in (0, "0", False, None):
|
|
6669
|
-
pcfg
|
|
6670
|
-
return
|
|
6713
|
+
if key in ("rate_limit", "rate_limit_rpm", "rpm"):
|
|
6714
|
+
fixed = positive_int(value)
|
|
6715
|
+
if value in (0, "0", False, None):
|
|
6716
|
+
pcfg["rate_limit_rpm"] = 0
|
|
6717
|
+
return
|
|
6671
6718
|
if not fixed:
|
|
6672
6719
|
raise SystemExit("rate_limit_rpm must be a positive integer, or 0/unset to disable")
|
|
6673
6720
|
pcfg["rate_limit_rpm"] = fixed
|
package/docs/README.ja.md
CHANGED
|
@@ -47,7 +47,7 @@ vLLM、NVIDIA hosted、self-hosted NIM を選択し、通常の Claude Code 引
|
|
|
47
47
|
|
|
48
48
|
Credits: One Ciel LLC
|
|
49
49
|
|
|
50
|
-
現在のバージョン: `0.1.
|
|
50
|
+
現在のバージョン: `0.1.42`
|
|
51
51
|
|
|
52
52
|
## 作られた理由
|
|
53
53
|
|
|
@@ -351,6 +351,21 @@ Windows/Linux 管理、クリーンアップスクリプト、定期的なセキ
|
|
|
351
351
|
|
|
352
352
|
## 変更履歴
|
|
353
353
|
|
|
354
|
+
### 0.1.42
|
|
355
|
+
|
|
356
|
+
- **ライブストリーム進捗**: statusline が upstream streaming の出力進捗を
|
|
357
|
+
入力/出力 token 推定値と chunk 数で継続更新します。
|
|
358
|
+
|
|
359
|
+
### 0.1.41
|
|
360
|
+
|
|
361
|
+
- **Statusline 表示改善**: upstream token 数に桁区切りと `tok` 前の空白を入れ、
|
|
362
|
+
`27,501 tok` のように表示します。
|
|
363
|
+
|
|
364
|
+
### 0.1.40
|
|
365
|
+
|
|
366
|
+
- **RPM 0 を保持**: `rate_limit_rpm=0` の設定が provider 既定値に戻らず、
|
|
367
|
+
明示的な無制限モードとして保存されます。
|
|
368
|
+
|
|
354
369
|
### 0.1.39
|
|
355
370
|
|
|
356
371
|
- **メニュー入力修正**: テキスト/数字プロンプトの前に terminal line/echo mode を
|
package/docs/README.ko.md
CHANGED
|
@@ -47,7 +47,7 @@ NVIDIA hosted, self-hosted NIM을 선택하고, Claude Code의 일반 인자는
|
|
|
47
47
|
|
|
48
48
|
Credits: One Ciel LLC
|
|
49
49
|
|
|
50
|
-
현재 버전: `0.1.
|
|
50
|
+
현재 버전: `0.1.42`
|
|
51
51
|
|
|
52
52
|
## 왜 만들었나
|
|
53
53
|
|
|
@@ -351,6 +351,21 @@ Windows 이벤트 로그 리뷰, 바이러스/랜섬웨어 침입 시도 정리,
|
|
|
351
351
|
|
|
352
352
|
## 변경 이력
|
|
353
353
|
|
|
354
|
+
### 0.1.42
|
|
355
|
+
|
|
356
|
+
- **실시간 스트림 진행 표시**: statusline이 upstream streaming 출력 진행을
|
|
357
|
+
입력/출력 token 추정치와 chunk 수로 계속 갱신합니다.
|
|
358
|
+
|
|
359
|
+
### 0.1.41
|
|
360
|
+
|
|
361
|
+
- **Statusline 표시 개선**: upstream token 수에 천 단위 구분자와 `tok` 앞 공백을
|
|
362
|
+
넣어 `27,501 tok`처럼 표시합니다.
|
|
363
|
+
|
|
364
|
+
### 0.1.40
|
|
365
|
+
|
|
366
|
+
- **RPM 0 유지**: `rate_limit_rpm=0` 설정이 provider 기본값으로 되돌아가지 않고
|
|
367
|
+
명시적인 무제한 모드로 저장됩니다.
|
|
368
|
+
|
|
354
369
|
### 0.1.39
|
|
355
370
|
|
|
356
371
|
- **메뉴 입력 수정**: 텍스트/숫자 프롬프트 전에 터미널 line/echo 모드를 복구하여
|
package/docs/README.zh.md
CHANGED
|
@@ -47,7 +47,7 @@ NIM,并把普通 Claude Code 参数原样传递。
|
|
|
47
47
|
|
|
48
48
|
Credits: One Ciel LLC
|
|
49
49
|
|
|
50
|
-
当前版本: `0.1.
|
|
50
|
+
当前版本: `0.1.42`
|
|
51
51
|
|
|
52
52
|
## 为什么存在
|
|
53
53
|
|
|
@@ -337,6 +337,21 @@ Hermes 格式模型或部分较旧的 Qwen tool template。
|
|
|
337
337
|
|
|
338
338
|
## 更新日志
|
|
339
339
|
|
|
340
|
+
### 0.1.42
|
|
341
|
+
|
|
342
|
+
- **实时流式进度**:statusline 会持续更新 upstream streaming 输出进度,
|
|
343
|
+
显示输入/输出 token 估算值和 chunk 数。
|
|
344
|
+
|
|
345
|
+
### 0.1.41
|
|
346
|
+
|
|
347
|
+
- **Statusline 格式优化**:upstream token 数现在带千位分隔符,并在 `tok` 前加入空格,
|
|
348
|
+
例如 `27,501 tok`。
|
|
349
|
+
|
|
350
|
+
### 0.1.40
|
|
351
|
+
|
|
352
|
+
- **保留 RPM 0**:`rate_limit_rpm=0` 现在会保存为明确的无限制模式,
|
|
353
|
+
不会回退到 provider 默认值。
|
|
354
|
+
|
|
340
355
|
### 0.1.39
|
|
341
356
|
|
|
342
357
|
- **菜单输入修复**:在文本/数字提示前恢复 terminal line/echo mode,
|
package/docs/manual.md
CHANGED
package/package.json
CHANGED