@yanzc/claude-pro 0.4.4 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/api.js +19 -5
- package/src/print.js +1 -0
- package/src/ui/repl.js +2 -0
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ claude-pro config set CLAUDE_PRO_PROVIDER claude-code
|
|
|
75
75
|
什么都没配置时(没有 `CLAUDE_PRO_PROVIDER`,也没有 `ANTHROPIC_BASE_URL`/`ANTHROPIC_AUTH_TOKEN`/`ANTHROPIC_API_KEY`/`ANTHROPIC_MODEL`)默认用**网关**,第一次启动直接弹出登录选择(网关排第一);配置了 API 端点、密钥或模型的老用户仍然默认 `api`。交互界面里 `/login` 选择模型请求发往哪里(记在 `~/.claude-pro/settings.json` 的 `CLAUDE_PRO_PROVIDER`,每个后端各自记住 `/model`、`/effort`):
|
|
76
76
|
|
|
77
77
|
- **Claude 订阅**(`claude-code`):本机 Claude Code 的登录,见上一节。
|
|
78
|
-
- **网关**(`gateway`):[codex-gateway](../codex-gateway) 的账户,默认 `https://gw.predix.icu`(`CLAUDE_PRO_GATEWAY_URL` 可改)。第一次选它会在浏览器打开网关的登录页,登录(或注册)后点“授权”,浏览器被带回本机,claude-pro 用一次性 code 换到这台电脑专用的 API Key,存在 `~/.claude-pro/gateway.json`(仅本人可读)。费用从网关账户余额扣,`/cost` 显示余额,充值和用量在网关的 `/user` 页面。模型默认 `opus`,`/model` 可选 `sonnet`、`haiku`、`gpt-6.1-sol`(网关用它自己的 Codex 登录转发,按 OpenAI 官方价扣费);子 agent 在 Claude 主模型下用 `sonnet`。网关每次请求按 `max_tokens` 预扣余额,所以这里默认 `max_tokens` 是 32K
|
|
78
|
+
- **网关**(`gateway`):[codex-gateway](../codex-gateway) 的账户,默认 `https://gw.predix.icu`(`CLAUDE_PRO_GATEWAY_URL` 可改)。第一次选它会在浏览器打开网关的登录页,登录(或注册)后点“授权”,浏览器被带回本机,claude-pro 用一次性 code 换到这台电脑专用的 API Key,存在 `~/.claude-pro/gateway.json`(仅本人可读)。费用从网关账户余额扣,`/cost` 显示余额,充值和用量在网关的 `/user` 页面。模型默认 `opus`,`/model` 可选 `sonnet`、`haiku`、`gpt-6.1-sol`(网关用它自己的 Codex 登录转发,按 OpenAI 官方价扣费);子 agent 在 Claude 主模型下用 `sonnet`。网关每次请求按 `max_tokens` 预扣余额,所以这里默认 `max_tokens` 是 32K。每个请求带上会话 ID(`X-Claude-Code-Session-Id`,和 Claude Code 一样;子 agent 用主对话的,`/clear` 换新的,`--resume` 和自动重启沿用原来的),网关据此让同一个对话 1 小时内继续用同一个上游账号,提示词缓存才不会因为换账号而失效。`/logout` 删除本机的网关 Key。
|
|
79
79
|
- **Codex 订阅**(`codex`):本机 `codex login`(ChatGPT 套餐)写下的 `~/.codex/auth.json`(`CODEX_HOME` 可改)。请求直接发往 Codex 后端,Anthropic 格式在本机和 OpenAI Responses 格式互相转换(工具调用、推理、缓存用量都对应上);访问令牌快到期时用同一文件里的刷新令牌续期并写回,Codex CLI 也能接着用。模型默认取 `~/.codex/config.toml` 的 `model`,否则 `gpt-6.1-sol`;不设 effort 时用模型自己的默认值(`models_cache.json` 里写的)。
|
|
80
80
|
|
|
81
81
|
## 配置
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yanzc/claude-pro",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "claude-pro: a self-implemented coding agent for Anthropic-compatible APIs or local Claude Code subscription login. Full access with no permission prompts; file edits are checkpointed and can be rewound.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
package/src/api.js
CHANGED
|
@@ -193,6 +193,9 @@ const outputCaps = new Map();
|
|
|
193
193
|
// Models that refused the effort parameter (Haiku does): it is left out for them from then on.
|
|
194
194
|
const noEffort = new Set();
|
|
195
195
|
export const effortSupported = (modelId) => !noEffort.has(modelId);
|
|
196
|
+
// Models that refused thinking "disabled" (MAX_THINKING_TOKENS=0): Opus 5.5, Fable, Sonnet 5.5, and Opus 5 at a
|
|
197
|
+
// high effort. Their requests leave `thinking` out from then on, which is adaptive thinking.
|
|
198
|
+
const thinkingStaysOn = new Set();
|
|
196
199
|
|
|
197
200
|
// The effort a model uses when none is sent (docs.claude.com, "Effort"): medium on Opus 5.5 and Haiku 5.5, high on
|
|
198
201
|
// the other models that take one; for a GPT model, the gateway's metadata or the local Codex models cache. null for
|
|
@@ -243,8 +246,10 @@ export function parseMaxTokensLimit(message) {
|
|
|
243
246
|
// Codex backend only: Anthropic refuses their signatures ("Invalid `signature` in `thinking` block"), so a
|
|
244
247
|
// conversation that moves from a GPT model to Claude, or to another provider, sends them without those blocks.
|
|
245
248
|
// The session keeps them, for a later switch back. `inTurn`: blocks were taken out of the turn in progress (the
|
|
246
|
-
// tool loop since the last prompt), whose assistant messages Anthropic wants to start with thinking when thinking
|
|
247
|
-
// is
|
|
249
|
+
// tool loop since the last prompt), whose assistant messages Anthropic wants to start with thinking when a thinking
|
|
250
|
+
// budget is set; such a turn's requests leave `thinking` out until the next prompt. That is no thinking on older
|
|
251
|
+
// models and adaptive thinking on those that cannot turn it off (Opus 5.5, Fable, Sonnet 5.5 refuse "disabled"),
|
|
252
|
+
// which takes assistant messages without thinking.
|
|
248
253
|
const isCodexThinking = (b) => b?.type === 'thinking' && typeof b.signature === 'string' && b.signature.startsWith(SIGNATURE_PREFIX);
|
|
249
254
|
const isPrompt = (m) => m.role === 'user' && !(Array.isArray(m.content) && m.content.some((b) => b.type === 'tool_result'));
|
|
250
255
|
function withoutCodexThinking(messages) {
|
|
@@ -294,9 +299,9 @@ export function buildParams(config, { model, system, messages, tools, maxTokens,
|
|
|
294
299
|
const eff = effortToSend(config, model.id, (effort === undefined ? config.effort : effort) || (/^gpt-/i.test(model.id) ? defaultEffort(model.id, config) : null));
|
|
295
300
|
if (eff && !noEffort.has(model.id)) params.output_config = { effort: eff };
|
|
296
301
|
const budget = config.thinkingBudget;
|
|
297
|
-
if (budget === 0) params.thinking = { type: 'disabled' };
|
|
302
|
+
if (budget === 0 && !thinkingStaysOn.has(model.id)) params.thinking = { type: 'disabled' };
|
|
298
303
|
else if (budget > 0) params.thinking = { type: 'enabled', budget_tokens: Math.min(budget, params.max_tokens - 1) };
|
|
299
|
-
if (turnLostThinking) params.thinking
|
|
304
|
+
if (turnLostThinking) delete params.thinking;
|
|
300
305
|
return params;
|
|
301
306
|
}
|
|
302
307
|
|
|
@@ -365,6 +370,9 @@ export async function streamMessage(config, request, { signal, onEvent = () => {
|
|
|
365
370
|
}
|
|
366
371
|
let client = getClient(config, login);
|
|
367
372
|
const params = buildParams(config, request, login);
|
|
373
|
+
// The gateway keeps a conversation on the upstream account that served it, where its prompt cache is; the
|
|
374
|
+
// session id names the conversation, in the header Claude Code sends it in.
|
|
375
|
+
const options = { signal, ...(config.usesGateway && config.sessionId ? { headers: { 'X-Claude-Code-Session-Id': config.sessionId } } : {}) };
|
|
368
376
|
let authReloaded = false;
|
|
369
377
|
const refused = new Set(); // what the endpoint refused for this request: remembered once a request got through
|
|
370
378
|
const retryState = { attempt: 0, rateLimitHits: 0, waitedMs: 0, overloaded: 0, overloadedWaitMs: 0 };
|
|
@@ -373,7 +381,7 @@ export async function streamMessage(config, request, { signal, onEvent = () => {
|
|
|
373
381
|
let emitted = false;
|
|
374
382
|
const startedAt = Date.now(); // the cache TTL counts from the start of the request, not from the end of the reply
|
|
375
383
|
try {
|
|
376
|
-
const stream = await client.messages.create(params,
|
|
384
|
+
const stream = await client.messages.create(params, options);
|
|
377
385
|
if (paused) {
|
|
378
386
|
const overloaded = paused.overloaded;
|
|
379
387
|
paused = null;
|
|
@@ -477,6 +485,12 @@ export async function streamMessage(config, request, { signal, onEvent = () => {
|
|
|
477
485
|
delete params.output_config;
|
|
478
486
|
continue;
|
|
479
487
|
}
|
|
488
|
+
// A model whose thinking cannot be turned off: carry on with its adaptive thinking.
|
|
489
|
+
if (err.status === 400 && params.thinking?.type === 'disabled' && /thinking\.type\.disabled|"disabled"/i.test(err.message) && /not supported/i.test(err.message)) {
|
|
490
|
+
thinkingStaysOn.add(params.model);
|
|
491
|
+
delete params.thinking;
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
480
494
|
// The endpoint does not take cache_control (or the 1-hour ttl) where it was sent: carry on without it
|
|
481
495
|
// instead of failing the request, and do not send it there again (see refuseCache).
|
|
482
496
|
if (err.status === 400 && /cache_control|\bttl\b/i.test(err.message)) {
|
package/src/print.js
CHANGED
|
@@ -62,6 +62,7 @@ export async function runPrint({ prompt, flags, cwd, stdout = process.stdout, st
|
|
|
62
62
|
store.systemPrompt = loaded.systemPrompt;
|
|
63
63
|
runtime.resumeSystemPrompt(loaded.systemPrompt); // continue behind the prompt (and the cache) the conversation had
|
|
64
64
|
}
|
|
65
|
+
runtime.config.sessionId = store.id; // sent to the gateway with each request (see streamMessage)
|
|
65
66
|
const ctrl = new AbortController();
|
|
66
67
|
const onSigint = () => ctrl.abort();
|
|
67
68
|
process.on('SIGINT', onSigint);
|
package/src/ui/repl.js
CHANGED
|
@@ -210,6 +210,8 @@ export class App {
|
|
|
210
210
|
|
|
211
211
|
await this.startPeer();
|
|
212
212
|
this.runtime = await createRuntime({ cwd: this.cwd, flags: this.flags, io: this });
|
|
213
|
+
// The conversation's id, sent to the gateway with each request (see streamMessage); it follows /clear and /resume.
|
|
214
|
+
Object.defineProperty(this.runtime.config, 'sessionId', { get: () => this.store.id, configurable: true });
|
|
213
215
|
this.commands = buildCommands(this);
|
|
214
216
|
// Keys typed while starting up stay buffered in stdin until we listen.
|
|
215
217
|
stdin.on('keypress', (str, key) => {
|