jinzd-ai-cli 0.4.325 → 0.4.327

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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/{batch-BGKTM75D.js → batch-NBI46MI4.js} +6 -4
  4. package/dist/{chunk-PIX4ZPFB.js → chunk-AVVT7ZZT.js} +129 -72
  5. package/dist/{chunk-NFPJ6KUU.js → chunk-BRZZ3QAI.js} +23 -5
  6. package/dist/{chunk-TJFHBYQ3.js → chunk-C2625RDR.js} +1 -1
  7. package/dist/{chunk-N6QFHXSF.js → chunk-C3EFGIJY.js} +34 -2
  8. package/dist/{chunk-PXJ3XVR5.js → chunk-CLGEU35T.js} +1 -1
  9. package/dist/{chunk-NBNRQ44O.js → chunk-HN5A5ZXX.js} +1 -1
  10. package/dist/{chunk-GCYH5WOZ.js → chunk-I7J7E7OB.js} +1 -1
  11. package/dist/{chunk-3ALMUKHF.js → chunk-KIE2KL2R.js} +4 -4
  12. package/dist/{chunk-5BS2NVSB.js → chunk-L3KXGINR.js} +4 -4
  13. package/dist/{chunk-CVWR3VYH.js → chunk-NFA6OCYA.js} +1 -1
  14. package/dist/{chunk-KS6RNA4E.js → chunk-NW3X6KQR.js} +1 -1
  15. package/dist/{chunk-C52FQ3ZE.js → chunk-RE72FGOG.js} +14 -11
  16. package/dist/{chunk-NI7YIDLF.js → chunk-URTVV3CB.js} +1 -1
  17. package/dist/{chunk-GVVYQJYF.js → chunk-YHTEI5KL.js} +4 -4
  18. package/dist/{chunk-WDD76ALZ.js → chunk-ZAZUWQBG.js} +1 -1
  19. package/dist/{ci-OE7Q3UOI.js → ci-XDUIRFJL.js} +5 -5
  20. package/dist/{ci-format-OWSFR34D.js → ci-format-DRD4BRGP.js} +2 -2
  21. package/dist/{constants-74TAAY4L.js → constants-NZVTDFL4.js} +1 -1
  22. package/dist/{constants-W2CH36YR.js → constants-QFXJCLTM.js} +1 -1
  23. package/dist/{doctor-cli-6C3WJTL5.js → doctor-cli-Z2Y4MWLK.js} +5 -5
  24. package/dist/electron-server.js +200 -92
  25. package/dist/{hub-RHMDL74E.js → hub-OE7M7DRD.js} +1 -1
  26. package/dist/index.js +21 -20
  27. package/dist/{persistent-memory-S2QLVL43.js → persistent-memory-EWDVXYTZ.js} +2 -2
  28. package/dist/{persistent-memory-OAFPFGKB.js → persistent-memory-Q34UVU4P.js} +2 -2
  29. package/dist/{pr-5PMXXHH6.js → pr-XWYKWZ2C.js} +5 -5
  30. package/dist/{run-tests-7AOMBU2D.js → run-tests-6EB6ABYH.js} +2 -2
  31. package/dist/{run-tests-W773M3KK.js → run-tests-WUN5OEU5.js} +2 -2
  32. package/dist/{server-SK4JQWT5.js → server-KQBLT4EX.js} +17 -16
  33. package/dist/{server-O75UHHR7.js → server-N7GH5D3I.js} +5 -5
  34. package/dist/{task-orchestrator-7H7UYCU7.js → task-orchestrator-MWWHWMBT.js} +5 -5
  35. package/dist/{usage-F6BD7DHL.js → usage-VFQINJ7I.js} +3 -3
  36. package/dist/wasm/web-tree-sitter.wasm +0 -0
  37. package/package.json +15 -15
@@ -55,7 +55,7 @@ import {
55
55
  touchMemoryReferences,
56
56
  updateMemoryApproval,
57
57
  updateMemoryEntry
58
- } from "./chunk-PXJ3XVR5.js";
58
+ } from "./chunk-CLGEU35T.js";
59
59
  import {
60
60
  DEFAULT_PATTERNS,
61
61
  redactJson,
@@ -81,7 +81,7 @@ import {
81
81
  recoverGbkMojibake,
82
82
  runTestsTool,
83
83
  shellInvocation
84
- } from "./chunk-TJFHBYQ3.js";
84
+ } from "./chunk-C2625RDR.js";
85
85
  import {
86
86
  getCurrentSessionKey,
87
87
  getExecutionConfigDir,
@@ -123,7 +123,7 @@ import {
123
123
  SUBAGENT_MAX_ROUNDS_LIMIT,
124
124
  VERSION,
125
125
  buildUserIdentityPrompt
126
- } from "./chunk-GCYH5WOZ.js";
126
+ } from "./chunk-I7J7E7OB.js";
127
127
 
128
128
  // src/web/access.ts
129
129
  import { randomBytes, timingSafeEqual } from "crypto";
@@ -693,7 +693,18 @@ ${err}`
693
693
  const DEEPSEEK_TARGET = "deepseek-flash";
694
694
  const LEGACY_KIMI = /* @__PURE__ */ new Set(["kimi-k2-0711-preview", "kimi-k2-turbo-preview"]);
695
695
  const KIMI_TARGET = "kimi-k2.6";
696
+ const LEGACY_CLAUDE = {
697
+ "claude-sonnet-4-5-20250929": "claude-sonnet-5-5",
698
+ "claude-sonnet-4-5": "claude-sonnet-5-5",
699
+ "claude-sonnet-4-20250514": "claude-sonnet-5-5",
700
+ "claude-3-7-sonnet-20250219": "claude-sonnet-5-5",
701
+ "claude-opus-4-20250514": "claude-opus-5-5",
702
+ "claude-opus-4-1-20250805": "claude-opus-5-5",
703
+ "claude-3-5-haiku-20241022": "claude-haiku-5-5",
704
+ "claude-3-haiku-20240307": "claude-haiku-5-5"
705
+ };
696
706
  let changed = false;
707
+ let claudeTarget;
697
708
  const dm = this.config.defaultModels;
698
709
  if (dm) {
699
710
  if (LEGACY_DEEPSEEK.has(dm.deepseek)) {
@@ -704,6 +715,17 @@ ${err}`
704
715
  dm.kimi = KIMI_TARGET;
705
716
  changed = true;
706
717
  }
718
+ const orTo = dm.openrouter ? { "anthropic/claude-opus-4": "anthropic/claude-opus-5.5", "anthropic/claude-haiku-4": "anthropic/claude-haiku-5.5" }[dm.openrouter] : void 0;
719
+ if (orTo) {
720
+ dm.openrouter = orTo;
721
+ changed = true;
722
+ }
723
+ const claudeTo = dm.claude ? LEGACY_CLAUDE[dm.claude] : void 0;
724
+ if (claudeTo) {
725
+ dm.claude = claudeTo;
726
+ claudeTarget = claudeTo;
727
+ changed = true;
728
+ }
707
729
  }
708
730
  const mp = this.config.modelParams;
709
731
  if (mp) {
@@ -725,10 +747,20 @@ ${err}`
725
747
  changed = true;
726
748
  }
727
749
  }
750
+ for (const [legacy, target] of Object.entries(LEGACY_CLAUDE)) {
751
+ if (legacy in mp) {
752
+ if (!(target in mp)) {
753
+ mp[target] = mp[legacy];
754
+ }
755
+ delete mp[legacy];
756
+ claudeTarget ??= target;
757
+ changed = true;
758
+ }
759
+ }
728
760
  }
729
761
  if (changed) {
730
762
  process.stderr.write(
731
- `[ai-cli] Migrated retired model ids in config.json (deepseek \u2192 ${DEEPSEEK_TARGET}, kimi \u2192 ${KIMI_TARGET})
763
+ `[ai-cli] Migrated retired model ids in config.json (deepseek \u2192 ${DEEPSEEK_TARGET}, kimi \u2192 ${KIMI_TARGET}` + (claudeTarget ? `, claude \u2192 ${claudeTarget}` : "") + `)
732
764
  `
733
765
  );
734
766
  }
@@ -918,12 +950,23 @@ function getDeepSeekV4Pricing(model, at) {
918
950
  }
919
951
  var PRICING_TABLE = {
920
952
  // ── Anthropic Claude ──────────────────────────────────────────
921
- "claude-opus-4-8": { input: 15, output: 75, cacheWrite: 18.75, cacheRead: 1.5 },
922
- "claude-opus-4-7": { input: 15, output: 75, cacheWrite: 18.75, cacheRead: 1.5 },
923
- "claude-opus-4-6": { input: 15, output: 75, cacheWrite: 18.75, cacheRead: 1.5 },
924
- "claude-opus-4-5": { input: 15, output: 75, cacheWrite: 18.75, cacheRead: 1.5 },
953
+ // 2026-10-09 按官方 Pricing 页核实(USD/MTok)。cacheWrite 取 5 分钟缓存写入价(aicli 只用
954
+ // ephemeral 默认 5m)。缓存读取倍率不统一:Fable 5.1 0.025x、Opus 5.5 / Sonnet 5.5 0.05x、其余 0.1x。
955
+ // 此前 Opus 4.5–4.8 记成 $15/$75(Opus 4.1 的价),费用显示高了 3 倍。
956
+ "claude-fable-5-1": { input: 10, output: 50, cacheWrite: 12.5, cacheRead: 0.25 },
957
+ "claude-fable-5": { input: 10, output: 50, cacheWrite: 12.5, cacheRead: 1 },
958
+ "claude-opus-5-5": { input: 4, output: 20, cacheWrite: 5, cacheRead: 0.2 },
959
+ "claude-opus-5": { input: 5, output: 25, cacheWrite: 6.25, cacheRead: 0.5 },
960
+ "claude-opus-4-8": { input: 5, output: 25, cacheWrite: 6.25, cacheRead: 0.5 },
961
+ "claude-opus-4-7": { input: 5, output: 25, cacheWrite: 6.25, cacheRead: 0.5 },
962
+ "claude-opus-4-6": { input: 5, output: 25, cacheWrite: 6.25, cacheRead: 0.5 },
963
+ "claude-opus-4-5": { input: 5, output: 25, cacheWrite: 6.25, cacheRead: 0.5 },
964
+ "claude-sonnet-5-5": { input: 2, output: 10, cacheWrite: 2.5, cacheRead: 0.1 },
965
+ "claude-sonnet-5": { input: 2, output: 10, cacheWrite: 2.5, cacheRead: 0.2 },
925
966
  "claude-sonnet-4-6": { input: 3, output: 15, cacheWrite: 3.75, cacheRead: 0.3 },
926
967
  "claude-sonnet-4-5-20250929": { input: 3, output: 15, cacheWrite: 3.75, cacheRead: 0.3 },
968
+ // Haiku 5.5 按提示长度分档:此处为 ≤100K 档,超过的那档见 computeCost 的 CLAUDE_HAIKU_55_LONG
969
+ "claude-haiku-5-5": { input: 0.1, output: 0.5, cacheWrite: 0.125, cacheRead: 0.01 },
927
970
  "claude-haiku-4-5-20251001": { input: 1, output: 5, cacheWrite: 1.25, cacheRead: 0.1 },
928
971
  "claude-haiku-4-5": { input: 1, output: 5, cacheWrite: 1.25, cacheRead: 0.1 },
929
972
  // Legacy Claude 3.x families (prefix fallback handles minor date suffixes)
@@ -1058,8 +1101,15 @@ function getPricing(provider, model, at = /* @__PURE__ */ new Date()) {
1058
1101
  }
1059
1102
  return null;
1060
1103
  }
1104
+ var CLAUDE_HAIKU_55_LONG = { input: 0.5, output: 2.5, cacheWrite: 0.625, cacheRead: 0.05 };
1105
+ var CLAUDE_HAIKU_55_TIER_TOKENS = 1e5;
1106
+ function longPromptTier(model, usage) {
1107
+ if (!model.toLowerCase().startsWith("claude-haiku-5-5")) return null;
1108
+ const prompt = usage.inputTokens + (usage.cacheCreationTokens ?? 0) + (usage.cacheReadTokens ?? 0);
1109
+ return prompt > CLAUDE_HAIKU_55_TIER_TOKENS ? CLAUDE_HAIKU_55_LONG : null;
1110
+ }
1061
1111
  function computeCost(provider, model, usage, at = /* @__PURE__ */ new Date()) {
1062
- const p = getPricing(provider, model, at);
1112
+ const p = longPromptTier(model, usage) ?? getPricing(provider, model, at);
1063
1113
  if (!p) return null;
1064
1114
  const input = usage.inputTokens * p.input;
1065
1115
  const output = usage.outputTokens * p.output;
@@ -1366,6 +1416,10 @@ var BaseProvider = class {
1366
1416
  get supportsReasoningEffort() {
1367
1417
  return false;
1368
1418
  }
1419
+ /** 该模型能否关掉思考。默认能;Claude Opus 5.5 / Fable 5.x 关不掉(见 claude-models.ts) */
1420
+ canDisableThinking(_model) {
1421
+ return true;
1422
+ }
1369
1423
  /**
1370
1424
  * 将 Message[] 转换为 OpenAI API 格式的消息数组。
1371
1425
  * content 为 string 时直接传递;为 MessageContentPart[] 时保留数组格式(vision 请求)。
@@ -1511,6 +1565,75 @@ function describeNetworkFailure(err, ctx = {}) {
1511
1565
  return { code, address, transient, message: parts.join(" ") };
1512
1566
  }
1513
1567
 
1568
+ // src/providers/claude-models.ts
1569
+ var DISABLE_BY_MODEL = [
1570
+ [/^claude-sonnet-5-5/, { type: "between_tools" }],
1571
+ [/^claude-sonnet-5(?!-\d)/, { type: "disabled" }],
1572
+ [/^claude-opus-5(?!-\d)/, { type: "disabled" }],
1573
+ [/^claude-haiku-5-5/, { type: "disabled" }]
1574
+ ];
1575
+ function claudeThinkingStyle(model) {
1576
+ if (/^claude-(?:opus|sonnet|haiku)-4-5|^claude-3/.test(model)) return "manual";
1577
+ if (/^claude-(?:opus-4-[678]|sonnet-4-6)/.test(model)) return "adaptive-optin";
1578
+ return "adaptive-default";
1579
+ }
1580
+ function claudeAcceptsTemperature(model) {
1581
+ return /^claude-(?:opus|sonnet|haiku)-4-[56]|^claude-3/.test(model);
1582
+ }
1583
+ function claudeDisableThinking(model) {
1584
+ if (claudeThinkingStyle(model) !== "adaptive-default") return null;
1585
+ for (const [re, param] of DISABLE_BY_MODEL) if (re.test(model)) return param;
1586
+ return null;
1587
+ }
1588
+ function claudeCanDisableThinking(model) {
1589
+ return claudeThinkingStyle(model) !== "adaptive-default" || claudeDisableThinking(model) !== null;
1590
+ }
1591
+ var MANUAL_BUDGET = {
1592
+ low: 4096,
1593
+ high: 16e3,
1594
+ max: 32e3
1595
+ };
1596
+ var THINKING_MAX_TOKENS_STREAM = 32e3;
1597
+ var THINKING_MAX_TOKENS_NONSTREAM = 16e3;
1598
+ var NONSTREAM_SDK_LIMIT = 21333;
1599
+ function buildClaudeRequestParams(request, streaming) {
1600
+ const model = request.model;
1601
+ const style = claudeThinkingStyle(model);
1602
+ const wantThinking = request.thinking === true;
1603
+ let thinking;
1604
+ let outputConfig;
1605
+ let maxTokens = request.maxTokens ?? DEFAULT_MAX_TOKENS;
1606
+ const thinkingActive = wantThinking || style === "adaptive-default" && claudeDisableThinking(model) === null;
1607
+ if (thinkingActive && maxTokens === DEFAULT_MAX_TOKENS) {
1608
+ maxTokens = streaming ? THINKING_MAX_TOKENS_STREAM : THINKING_MAX_TOKENS_NONSTREAM;
1609
+ }
1610
+ if (wantThinking) {
1611
+ if (style === "manual") {
1612
+ let budget = Math.max(
1613
+ request.thinkingBudget ?? (request.thinkingEffort ? MANUAL_BUDGET[request.thinkingEffort] : 1e4),
1614
+ 1024
1615
+ );
1616
+ if (budget >= maxTokens) maxTokens = budget + 4096;
1617
+ if (!streaming && maxTokens > NONSTREAM_SDK_LIMIT) {
1618
+ maxTokens = NONSTREAM_SDK_LIMIT;
1619
+ budget = Math.max(1024, Math.min(budget, maxTokens - 4096));
1620
+ }
1621
+ thinking = { type: "enabled", budget_tokens: budget };
1622
+ } else {
1623
+ thinking = { type: "adaptive", display: "summarized" };
1624
+ outputConfig = { effort: request.thinkingEffort ?? "high" };
1625
+ }
1626
+ } else if (style === "adaptive-default") {
1627
+ thinking = claudeDisableThinking(model) ?? void 0;
1628
+ }
1629
+ const temperature = !wantThinking && claudeAcceptsTemperature(model) ? request.temperature : void 0;
1630
+ const out = { max_tokens: maxTokens };
1631
+ if (thinking) out.thinking = thinking;
1632
+ if (outputConfig) out.output_config = outputConfig;
1633
+ if (temperature !== void 0) out.temperature = temperature;
1634
+ return out;
1635
+ }
1636
+
1514
1637
  // src/providers/claude.ts
1515
1638
  var CACHE_MIN_SYSTEM_CHARS = 2e3;
1516
1639
  var ClaudeProvider = class extends BaseProvider {
@@ -1520,30 +1643,28 @@ var ClaudeProvider = class extends BaseProvider {
1520
1643
  info = {
1521
1644
  id: "claude",
1522
1645
  displayName: "Claude (Anthropic)",
1523
- defaultModel: "claude-sonnet-4-5-20250929",
1646
+ // 2026-10-09 按官方 Models overview / Model deprecations 核实:当前一代 4 个,
1647
+ // 上下文 1M、最大输出 128K;Sonnet 4.5 已弃用(2026-11-30 下线,官方推荐换 Sonnet 5.5),
1648
+ // 从清单移除,旧 config 由 config-manager 自愈迁移。Opus 4.6 / Haiku 4.5 仍为 Active,留作旧版。
1649
+ defaultModel: "claude-sonnet-5-5",
1524
1650
  apiKeyEnvVar: "AICLI_API_KEY_CLAUDE",
1525
1651
  requiresApiKey: true,
1526
1652
  models: [
1527
- {
1528
- id: "claude-opus-4-6",
1529
- displayName: "Claude Opus 4.6",
1530
- contextWindow: 2e5,
1531
- supportsStreaming: true
1532
- },
1533
- {
1534
- id: "claude-sonnet-4-5-20250929",
1535
- displayName: "Claude Sonnet 4.5",
1536
- contextWindow: 2e5,
1537
- supportsStreaming: true
1538
- },
1539
- {
1540
- id: "claude-haiku-4-5-20251001",
1541
- displayName: "Claude Haiku 4.5",
1542
- contextWindow: 2e5,
1543
- supportsStreaming: true
1544
- }
1653
+ { id: "claude-fable-5-1", displayName: "Claude Fable 5.1", contextWindow: 1e6, supportsStreaming: true, supportsThinking: true },
1654
+ { id: "claude-opus-5-5", displayName: "Claude Opus 5.5", contextWindow: 1e6, supportsStreaming: true, supportsThinking: true },
1655
+ { id: "claude-sonnet-5-5", displayName: "Claude Sonnet 5.5", contextWindow: 1e6, supportsStreaming: true, supportsThinking: true },
1656
+ { id: "claude-haiku-5-5", displayName: "Claude Haiku 5.5", contextWindow: 1e6, supportsStreaming: true, supportsThinking: true },
1657
+ { id: "claude-opus-4-6", displayName: "Claude Opus 4.6 (legacy)", contextWindow: 1e6, supportsStreaming: true, supportsThinking: true },
1658
+ { id: "claude-haiku-4-5-20251001", displayName: "Claude Haiku 4.5 (legacy)", contextWindow: 2e5, supportsStreaming: true, supportsThinking: true }
1545
1659
  ]
1546
1660
  };
1661
+ /** 4.6 起用 `output_config.effort` 控制思考深浅;4.5 系列按档位换算成思考预算 */
1662
+ get supportsReasoningEffort() {
1663
+ return true;
1664
+ }
1665
+ canDisableThinking(model) {
1666
+ return claudeCanDisableThinking(model);
1667
+ }
1547
1668
  async initialize(apiKey, options) {
1548
1669
  const clientOptions = {
1549
1670
  apiKey,
@@ -1651,24 +1772,6 @@ var ClaudeProvider = class extends BaseProvider {
1651
1772
  }
1652
1773
  return usage;
1653
1774
  }
1654
- /**
1655
- * 构建 Extended Thinking 参数。
1656
- * - thinking 启用时 temperature 必须为 1 或不设置(Anthropic API 要求)
1657
- * - budget_tokens 最小 1024,默认 10000
1658
- */
1659
- buildThinkingParams(request) {
1660
- if (!request.thinking) {
1661
- return { temperature: request.temperature };
1662
- }
1663
- return {
1664
- thinking: {
1665
- type: "enabled",
1666
- budget_tokens: Math.max(request.thinkingBudget ?? 1e4, 1024)
1667
- },
1668
- // thinking 启用时 temperature 必须不设置(API 强制 temperature=1)
1669
- temperature: void 0
1670
- };
1671
- }
1672
1775
  /**
1673
1776
  * 从 response.content 中提取文本内容。
1674
1777
  * 当 thinking 启用时,将 ThinkingBlock 内容用 <think>...</think> 标签包裹,
@@ -1679,7 +1782,8 @@ var ClaudeProvider = class extends BaseProvider {
1679
1782
  const textParts = [];
1680
1783
  for (const block of blocks) {
1681
1784
  if (block.type === "thinking") {
1682
- thinkingParts.push(block.thinking);
1785
+ const text = block.thinking;
1786
+ if (text) thinkingParts.push(text);
1683
1787
  } else if (block.type === "text") {
1684
1788
  textParts.push(block.text);
1685
1789
  }
@@ -1694,14 +1798,11 @@ var ClaudeProvider = class extends BaseProvider {
1694
1798
  async chat(request) {
1695
1799
  try {
1696
1800
  const messages = this.toClaudeMessagesWithToolHistory(request.messages);
1697
- const { thinking, temperature } = this.buildThinkingParams(request);
1698
1801
  const response = await this.client.messages.create({
1699
1802
  model: request.model,
1700
1803
  messages,
1701
1804
  system: this.buildSystemParam(request.systemPrompt, request.systemPromptVolatile),
1702
- max_tokens: request.maxTokens ?? 8192,
1703
- temperature,
1704
- thinking
1805
+ ...buildClaudeRequestParams(request, false)
1705
1806
  // 非流式路径必须收 signal,否则 Ctrl+C 期间请求不可中断(同 openai-compatible 的同类遗漏)
1706
1807
  }, { signal: request.signal });
1707
1808
  const content = this.extractContent(response.content);
@@ -1717,33 +1818,31 @@ var ClaudeProvider = class extends BaseProvider {
1717
1818
  async *chatStream(request) {
1718
1819
  try {
1719
1820
  const messages = this.toClaudeMessagesWithToolHistory(request.messages);
1720
- const { thinking, temperature } = this.buildThinkingParams(request);
1721
1821
  const stream = this.client.messages.stream({
1722
1822
  model: request.model,
1723
1823
  messages,
1724
1824
  system: this.buildSystemParam(request.systemPrompt, request.systemPromptVolatile),
1725
- max_tokens: request.maxTokens ?? 8192,
1726
- temperature,
1727
- thinking
1825
+ ...buildClaudeRequestParams(request, true)
1728
1826
  }, { signal: request.signal });
1729
- let currentBlockType = null;
1827
+ let thinkOpen = false;
1730
1828
  for await (const event of stream) {
1731
- if (event.type === "content_block_start") {
1732
- currentBlockType = event.content_block.type;
1733
- if (currentBlockType === "thinking") {
1734
- yield { delta: "<think>", done: false };
1735
- }
1736
- } else if (event.type === "content_block_delta") {
1829
+ if (event.type === "content_block_delta") {
1737
1830
  if (event.delta.type === "text_delta") {
1738
1831
  yield { delta: event.delta.text, done: false };
1739
1832
  } else if (event.delta.type === "thinking_delta") {
1740
- yield { delta: event.delta.thinking, done: false };
1833
+ const text = event.delta.thinking;
1834
+ if (!text) continue;
1835
+ if (!thinkOpen) {
1836
+ yield { delta: "<think>", done: false };
1837
+ thinkOpen = true;
1838
+ }
1839
+ yield { delta: text, done: false };
1741
1840
  }
1742
1841
  } else if (event.type === "content_block_stop") {
1743
- if (currentBlockType === "thinking") {
1842
+ if (thinkOpen) {
1744
1843
  yield { delta: "</think>", done: false };
1844
+ thinkOpen = false;
1745
1845
  }
1746
- currentBlockType = null;
1747
1846
  } else if (event.type === "message_stop") {
1748
1847
  yield { delta: "", done: true };
1749
1848
  }
@@ -1773,15 +1872,12 @@ var ClaudeProvider = class extends BaseProvider {
1773
1872
  const baseMessages = this.toClaudeMessagesWithToolHistory(request.messages);
1774
1873
  const extraMessages = request._extraMessages ?? [];
1775
1874
  const allMessages = [...baseMessages, ...extraMessages];
1776
- const { thinking, temperature } = this.buildThinkingParams(request);
1777
1875
  const response = await this.client.messages.create({
1778
1876
  model: request.model,
1779
1877
  messages: allMessages,
1780
1878
  tools: anthropicTools,
1781
1879
  system: this.buildSystemParam(request.systemPrompt, request.systemPromptVolatile),
1782
- max_tokens: request.maxTokens ?? 8192,
1783
- temperature,
1784
- thinking
1880
+ ...buildClaudeRequestParams(request, false)
1785
1881
  // 轮次耗尽的总结轮对所有 provider 都走这条非流式路径——漏 signal 则 Ctrl+C 无效
1786
1882
  }, { signal: request.signal });
1787
1883
  const usage = this.extractUsage(response.usage);
@@ -1827,7 +1923,6 @@ var ClaudeProvider = class extends BaseProvider {
1827
1923
  const baseMessages = this.toClaudeMessagesWithToolHistory(request.messages);
1828
1924
  const extraMessages = request._extraMessages ?? [];
1829
1925
  const allMessages = [...baseMessages, ...extraMessages];
1830
- const { thinking, temperature } = this.buildThinkingParams(request);
1831
1926
  let doneEmitted = false;
1832
1927
  const rawContentBlocks = [];
1833
1928
  try {
@@ -1836,12 +1931,11 @@ var ClaudeProvider = class extends BaseProvider {
1836
1931
  messages: allMessages,
1837
1932
  tools: anthropicTools,
1838
1933
  system: this.buildSystemParam(request.systemPrompt, request.systemPromptVolatile),
1839
- max_tokens: request.maxTokens ?? 8192,
1840
- temperature,
1841
- thinking
1934
+ ...buildClaudeRequestParams(request, true)
1842
1935
  }, { signal: request.signal });
1843
1936
  let currentBlockType = null;
1844
1937
  let currentToolIndex = 0;
1938
+ let thinkingShown = false;
1845
1939
  let currentBlockData = {};
1846
1940
  let startUsage = null;
1847
1941
  for await (const event of stream) {
@@ -1855,7 +1949,7 @@ var ClaudeProvider = class extends BaseProvider {
1855
1949
  currentBlockType = block.type;
1856
1950
  currentBlockData = { type: block.type };
1857
1951
  if (block.type === "thinking") {
1858
- yield { type: "thinking_start" };
1952
+ thinkingShown = false;
1859
1953
  currentBlockData = { type: "thinking", thinking: "", signature: "" };
1860
1954
  } else if (block.type === "text") {
1861
1955
  currentBlockData = { type: "text", text: "" };
@@ -1877,7 +1971,13 @@ var ClaudeProvider = class extends BaseProvider {
1877
1971
  currentBlockData.text += event.delta.text;
1878
1972
  } else if (event.delta.type === "thinking_delta") {
1879
1973
  const thinkingDelta = event.delta.thinking;
1880
- yield { type: "thinking_delta", delta: thinkingDelta };
1974
+ if (thinkingDelta) {
1975
+ if (!thinkingShown) {
1976
+ yield { type: "thinking_start" };
1977
+ thinkingShown = true;
1978
+ }
1979
+ yield { type: "thinking_delta", delta: thinkingDelta };
1980
+ }
1881
1981
  currentBlockData.thinking += thinkingDelta;
1882
1982
  } else if (event.delta.type === "input_json_delta") {
1883
1983
  const jsonDelta = event.delta.partial_json;
@@ -1892,7 +1992,7 @@ var ClaudeProvider = class extends BaseProvider {
1892
1992
  }
1893
1993
  } else if (event.type === "content_block_stop") {
1894
1994
  if (currentBlockType === "thinking") {
1895
- yield { type: "thinking_end" };
1995
+ if (thinkingShown) yield { type: "thinking_end" };
1896
1996
  } else if (currentBlockType === "tool_use") {
1897
1997
  yield { type: "tool_call_end", index: currentToolIndex };
1898
1998
  currentToolIndex++;
@@ -2055,10 +2155,12 @@ var ClaudeProvider = class extends BaseProvider {
2055
2155
  try {
2056
2156
  const response = await this.client.models.list();
2057
2157
  const data = response.data ?? [];
2158
+ const known = new Map(this.info.models.map((m) => [m.id, m.contextWindow]));
2058
2159
  return data.map((model) => ({
2059
2160
  id: model.id,
2060
2161
  displayName: model.id,
2061
- contextWindow: 2e5,
2162
+ // Models API 返回 max_input_tokens;SDK 类型未必带,取不到时用清单值或保守的 200K
2163
+ contextWindow: model.max_input_tokens ?? known.get(model.id) ?? 2e5,
2062
2164
  supportsStreaming: true,
2063
2165
  source: "live",
2064
2166
  available: true,
@@ -4709,13 +4811,15 @@ var OpenAIProvider = createStaticProviderClass(OPENAI_CONFIG);
4709
4811
  var OPENROUTER_CONFIG = {
4710
4812
  id: "openrouter",
4711
4813
  displayName: "OpenRouter",
4712
- defaultModel: "anthropic/claude-sonnet-4",
4814
+ defaultModel: "anthropic/claude-sonnet-5.5",
4713
4815
  apiKeyEnvVar: "AICLI_API_KEY_OPENROUTER",
4714
4816
  baseUrl: "https://openrouter.ai/api/v1",
4715
4817
  models: [
4716
- { id: "anthropic/claude-opus-4", displayName: "Claude Opus 4", contextWindow: 2e5, supportsStreaming: true },
4717
- { id: "anthropic/claude-sonnet-4", displayName: "Claude Sonnet 4", contextWindow: 2e5, supportsStreaming: true },
4718
- { id: "anthropic/claude-haiku-4", displayName: "Claude Haiku 4", contextWindow: 2e5, supportsStreaming: true },
4818
+ // 2026-10-09 对 /api/v1/models 实测:OpenRouter 的 Claude id 用点号(claude-sonnet-5.5),
4819
+ // 此前清单里的 `anthropic/claude-opus-4` / `anthropic/claude-haiku-4` 在列表里不存在
4820
+ { id: "anthropic/claude-opus-5.5", displayName: "Claude Opus 5.5", contextWindow: 1e6, supportsStreaming: true },
4821
+ { id: "anthropic/claude-sonnet-5.5", displayName: "Claude Sonnet 5.5", contextWindow: 1e6, supportsStreaming: true },
4822
+ { id: "anthropic/claude-haiku-5.5", displayName: "Claude Haiku 5.5", contextWindow: 1e6, supportsStreaming: true },
4719
4823
  { id: "openai/gpt-5.4", displayName: "GPT-5.4", contextWindow: 105e4, supportsStreaming: true },
4720
4824
  { id: "google/gemini-2.5-pro", displayName: "Gemini 2.5 Pro", contextWindow: 1048576, supportsStreaming: true },
4721
4825
  { id: "google/gemini-2.5-flash", displayName: "Gemini 2.5 Flash", contextWindow: 1048576, supportsStreaming: true },
@@ -16517,6 +16621,7 @@ function applyThinkCommand(sub, state2) {
16517
16621
  details: effort && !state2.supportsEffort ? [`Note: ${state2.provider} has no reasoning-effort levels \u2014 the level is ignored.`] : [],
16518
16622
  changed: true
16519
16623
  });
16624
+ const alwaysThinksNote = state2.alwaysThinks ? ["Note: this model always thinks and cannot turn it off \u2014 OFF only hides the thinking text; thinking tokens are still billed."] : [];
16520
16625
  const disable = () => ({
16521
16626
  runtimeThinking: false,
16522
16627
  // 刻意保留档位:重新开启时不该丢掉用户选过的档
@@ -16524,11 +16629,12 @@ function applyThinkCommand(sub, state2) {
16524
16629
  effective: false,
16525
16630
  origin: "runtime override",
16526
16631
  summary: "Extended Thinking: OFF",
16527
- details: [],
16632
+ details: alwaysThinksNote,
16528
16633
  changed: true
16529
16634
  });
16530
16635
  if (key === "status") {
16531
16636
  const details = current.effective ? [effortLine(state2, null)] : [
16637
+ ...alwaysThinksNote,
16532
16638
  "Enable with /think on | low | high | max, or set",
16533
16639
  "modelParams.<model>.thinking in ~/.aicli/config.json"
16534
16640
  ];
@@ -16675,7 +16781,7 @@ function parseRouteCommand(args) {
16675
16781
  }
16676
16782
  function routingEmptyRulesNote(routing) {
16677
16783
  if (routing && routing.rules.length > 0) return null;
16678
- return 'No rules configured yet. Add rules under `routing.rules` in ~/.aicli/config.json.\nExample: { match: { tag: "fast" }, model: "claude-haiku-4-5" }';
16784
+ return 'No rules configured yet. Add rules under `routing.rules` in ~/.aicli/config.json.\nExample: { match: { tag: "fast" }, model: "claude-haiku-5-5" }';
16679
16785
  }
16680
16786
  function describeRoutingRule(rule, index) {
16681
16787
  const parts = [];
@@ -16835,7 +16941,8 @@ async function handleThink(args, ctx) {
16835
16941
  configuredThinking: modelParams?.thinking,
16836
16942
  configuredEffort: modelParams?.thinkingEffort,
16837
16943
  supportsEffort: ctx.providers.has(ctx.currentProvider) ? ctx.providers.get(ctx.currentProvider).supportsReasoningEffort : false,
16838
- provider: ctx.currentProvider
16944
+ provider: ctx.currentProvider,
16945
+ alwaysThinks: ctx.providers.has(ctx.currentProvider) && ctx.providers.get(ctx.currentProvider).canDisableThinking?.(ctx.currentModel) === false
16839
16946
  });
16840
16947
  if (outcome.changed) {
16841
16948
  ctx.runtimeThinking = outcome.runtimeThinking;
@@ -17727,7 +17834,7 @@ Cache: write=${cacheCreate} read=${cacheRead}` : "";
17727
17834
  Cost: ${formatCost(cost)}` : "";
17728
17835
  let memoryLine = "";
17729
17836
  try {
17730
- const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-OAFPFGKB.js");
17837
+ const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-Q34UVU4P.js");
17731
17838
  const pending = countPendingMemories2(ctx.config.getConfigDir());
17732
17839
  if (pending > 0) memoryLine = `
17733
17840
  Memory: \u26A0 ${pending} pending approval \u2014 see the Memory panel or /memory`;
@@ -18715,7 +18822,7 @@ async function handleTest(args, ctx) {
18715
18822
  const isCommand = argStr.includes(" ") || /^(mvn|gradle|npm|pytest|cargo|go)\b/.test(argStr);
18716
18823
  testArgs = isCommand ? { command: argStr } : { filter: argStr };
18717
18824
  }
18718
- const runTests = ctx.runTests ?? (await import("./run-tests-7AOMBU2D.js")).executeTests;
18825
+ const runTests = ctx.runTests ?? (await import("./run-tests-6EB6ABYH.js")).executeTests;
18719
18826
  const report = await runTests(testArgs);
18720
18827
  ctx.send({ type: "info", message: report });
18721
18828
  } catch (err) {
@@ -19106,7 +19213,7 @@ async function handleMemory(args, ctx) {
19106
19213
  }
19107
19214
  if (intent.kind === "status") {
19108
19215
  const { getChatIndexStatus: getChatIndexStatus2 } = await import("./chat-index-RLVLQRRC.js");
19109
- const { listMemoryEntries: listMemoryEntries2, isMemoryExpired: isMemoryExpired2, formatMemoryForPrompt: formatMemoryForPrompt2 } = await import("./persistent-memory-OAFPFGKB.js");
19216
+ const { listMemoryEntries: listMemoryEntries2, isMemoryExpired: isMemoryExpired2, formatMemoryForPrompt: formatMemoryForPrompt2 } = await import("./persistent-memory-Q34UVU4P.js");
19110
19217
  const memories = listMemoryEntries2(configDir, { includeExpired: true, includeRejected: true });
19111
19218
  const injected = formatMemoryForPrompt2(configDir, process.cwd(), ctx.config.get("memory")?.maxChars);
19112
19219
  const view = buildMemoryStatusView({
@@ -19129,7 +19236,7 @@ async function handleMemory(args, ctx) {
19129
19236
  return;
19130
19237
  }
19131
19238
  if (intent.kind === "recall") {
19132
- const { searchPersistentMemories: searchPersistentMemories2, touchMemoryReferences: touchMemoryReferences2 } = await import("./persistent-memory-OAFPFGKB.js");
19239
+ const { searchPersistentMemories: searchPersistentMemories2, touchMemoryReferences: touchMemoryReferences2 } = await import("./persistent-memory-Q34UVU4P.js");
19133
19240
  const { searchChatMemory: searchChatMemory2 } = await import("./chat-index-RLVLQRRC.js");
19134
19241
  const persistentHits = searchPersistentMemories2(configDir, intent.query, process.cwd(), 3);
19135
19242
  if (persistentHits.length > 0) {
@@ -19250,7 +19357,7 @@ async function handleMemory(args, ctx) {
19250
19357
  ctx.handleMemoryManage(intent.action, args[1], intent.action === "expire" ? args[2] : void 0);
19251
19358
  } else if (intent.kind === "export") {
19252
19359
  if (args[1] === "md") {
19253
- const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-OAFPFGKB.js");
19360
+ const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-Q34UVU4P.js");
19254
19361
  ctx.send({
19255
19362
  type: "export_data",
19256
19363
  format: "md",
@@ -20040,7 +20147,8 @@ function createProviderCommands() {
20040
20147
  configuredThinking: ctx.getConfiguredThinking(),
20041
20148
  configuredEffort: ctx.getConfiguredThinkingEffort(),
20042
20149
  supportsEffort: ctx.getProviderSupportsReasoningEffort(),
20043
- provider: ctx.getCurrentProvider()
20150
+ provider: ctx.getCurrentProvider(),
20151
+ alwaysThinks: ctx.getModelCanDisableThinking ? !ctx.getModelCanDisableThinking() : false
20044
20152
  });
20045
20153
  if (outcome.changed) {
20046
20154
  ctx.setThinkingMode(outcome.runtimeThinking);
@@ -20255,7 +20363,7 @@ No tools match "${filter}".
20255
20363
  const { join: join26 } = await import("path");
20256
20364
  const { existsSync: existsSync32 } = await import("fs");
20257
20365
  const { getGitRoot: getGitRoot2 } = await import("./git-context-VNCA2GU7.js");
20258
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-W2CH36YR.js");
20366
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-QFXJCLTM.js");
20259
20367
  const { approveProject, hashMcpFile } = await import("./project-trust-6CJB5ZMX.js");
20260
20368
  const cwd = process.cwd();
20261
20369
  const projectRoot = getGitRoot2(cwd) ?? cwd;
@@ -21174,7 +21282,7 @@ function createReviewCommands() {
21174
21282
  usage: "/test [command|filter]",
21175
21283
  async execute(args, ctx) {
21176
21284
  try {
21177
- const { executeTests } = await import("./run-tests-7AOMBU2D.js");
21285
+ const { executeTests } = await import("./run-tests-6EB6ABYH.js");
21178
21286
  const argStr = args.join(" ").trim();
21179
21287
  let testArgs = {};
21180
21288
  if (argStr) {
@@ -158,7 +158,7 @@ ${content}`);
158
158
  }
159
159
  }
160
160
  async function runTaskMode(config, providers, configManager, topic) {
161
- const { TaskOrchestrator } = await import("./task-orchestrator-7H7UYCU7.js");
161
+ const { TaskOrchestrator } = await import("./task-orchestrator-MWWHWMBT.js");
162
162
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
163
163
  let interrupted = false;
164
164
  const onSigint = () => {