jinzd-ai-cli 0.4.320 → 0.4.322
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 +2 -2
- package/README.zh-CN.md +2 -2
- package/dist/{batch-LRYDPB6F.js → batch-IMC6Q63Y.js} +2 -2
- package/dist/{chunk-NOAWUEJJ.js → chunk-3TWEKDHH.js} +1 -1
- package/dist/{chunk-TKBWA3XJ.js → chunk-FHBV5EUM.js} +4 -4
- package/dist/{chunk-WY4IWCQ5.js → chunk-G46THFJN.js} +1 -1
- package/dist/{chunk-4S2XD3M2.js → chunk-HVVDGSUN.js} +4 -4
- package/dist/{chunk-46OEMKQX.js → chunk-NFPJ6KUU.js} +8 -4
- package/dist/{chunk-WW2LFOWE.js → chunk-NX72SBGU.js} +1 -1
- package/dist/{chunk-DB4HVUPI.js → chunk-OR46O57D.js} +1 -1
- package/dist/{chunk-5VZHSSLW.js → chunk-RO67VWKW.js} +1 -1
- package/dist/{chunk-N6YFBRQV.js → chunk-RSWCASRV.js} +1 -1
- package/dist/{chunk-QB3MECZJ.js → chunk-SYK2TDKV.js} +24 -17
- package/dist/{chunk-P4FJBD2H.js → chunk-W7D4M4KV.js} +1 -1
- package/dist/{chunk-SKQUWDRM.js → chunk-X5ZC4TI4.js} +1 -1
- package/dist/{chunk-YAMPLTYO.js → chunk-XVB4RARX.js} +74 -1
- package/dist/{chunk-46M65JDN.js → chunk-ZSR2UIRD.js} +56 -19
- package/dist/{chunk-J7IPNING.js → chunk-ZUONW7FS.js} +1 -1
- package/dist/{ci-7TSOMDHV.js → ci-74EPK5JN.js} +5 -5
- package/dist/{ci-format-6A2RFYZS.js → ci-format-QADWGCX7.js} +2 -2
- package/dist/{constants-EHYM2NS5.js → constants-P5JJ6FO4.js} +1 -1
- package/dist/{constants-P33UDQVS.js → constants-SSVJCBAT.js} +1 -1
- package/dist/{doctor-cli-2B72UMZO.js → doctor-cli-KJT5HMQB.js} +5 -5
- package/dist/electron-server.js +170 -49
- package/dist/{hub-JACLTKYY.js → hub-5CPMJQVG.js} +1 -1
- package/dist/index.js +29 -20
- package/dist/{persistent-memory-5ICLP275.js → persistent-memory-BOUJARIV.js} +2 -2
- package/dist/{persistent-memory-ZIM6ICIR.js → persistent-memory-H5MUAC4X.js} +2 -2
- package/dist/{pr-UBGLNROK.js → pr-BU2FN7CO.js} +5 -5
- package/dist/{run-tests-HCID73KE.js → run-tests-6JKF6JJZ.js} +2 -2
- package/dist/{run-tests-SYJG4S3N.js → run-tests-WJJW77HK.js} +2 -2
- package/dist/{server-BVTFIPB2.js → server-GFL7MYAP.js} +5 -5
- package/dist/{server-3UEEPEUD.js → server-XGY6OUUT.js} +15 -15
- package/dist/{task-orchestrator-6NRCGF5V.js → task-orchestrator-EETPUWBK.js} +5 -5
- package/dist/{usage-6V64TTRE.js → usage-BVHFDNRW.js} +3 -3
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
- **Web UI Memory Panel** *(v0.4.90+, B4)* — new 🧠 Memory sidebar tab with semantic search across past chats; each hit has **➕ Inject** (quotes the snippet into the chat input as a markdown blockquote so you can review/edit before sending — no silent context injection) and **↗ Load** (jumps to source session). Bulk "Inject top 3" for recall bundles
|
|
45
45
|
- **Streaming Tool Use** — Real-time streaming of AI reasoning and tool calls as they happen
|
|
46
46
|
- **Sub-Agents** — Delegate complex subtasks to isolated child agents with independent tool loops
|
|
47
|
-
- **
|
|
47
|
+
- **Thinking control** — `/think on|off|low|high|max` across Claude, DeepSeek, GLM-5, Ollama thinking models (off by default where the API allows it)
|
|
48
48
|
- **Plan Mode** — Read-only planning phase (`/plan`) where AI analyzes before executing, with loop detection
|
|
49
49
|
- **Auto-Pause** — Automatically pauses every 10 rounds for user review and redirection
|
|
50
50
|
- **MCP Protocol** — Connect external MCP servers for dynamic tool discovery
|
|
@@ -206,7 +206,7 @@ AI autonomously invokes these 30 tools during conversations:
|
|
|
206
206
|
| `/provider` | Switch AI provider |
|
|
207
207
|
| `/model` | Switch model; `/model refresh [provider]` refreshes live model cache |
|
|
208
208
|
| `/plan` | Enter read-only planning mode |
|
|
209
|
-
| `/think` |
|
|
209
|
+
| `/think` | Thinking on/off and effort (`on\|off\|low\|high\|max\|status`) |
|
|
210
210
|
| `/test` | Auto-detect and run project tests |
|
|
211
211
|
| `/review` | AI code review of current git diff |
|
|
212
212
|
| `/security-review` | Security vulnerability scan on git diff |
|
package/README.zh-CN.md
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
- **Web UI Memory 面板**(v0.4.90+,B4)— sidebar 新增 🧠 Memory 标签页,跨 session 语义搜索;每条 hit 带 **➕ Inject**(把片段作为 markdown 引用块塞进聊天输入框,用户可在上面继续打字编辑——不是静默注入上下文)和 **↗ Load**(跳转对应 session);顶部"➕ Inject top 3"一键批量
|
|
35
35
|
- **流式工具调用** — 实时流式展示 AI 推理过程和工具调用
|
|
36
36
|
- **子代理系统** — 将复杂子任务委派给独立子代理执行
|
|
37
|
-
-
|
|
37
|
+
- **思考控制** — `/think on|off|low|high|max`,覆盖 Claude、DeepSeek、GLM-5、Ollama 思考模型(API 允许关闭的默认关闭)
|
|
38
38
|
- **规划模式** — `/plan` 进入只读规划,AI 先分析后执行,内置死循环检测
|
|
39
39
|
- **自动暂停** — 每 10 轮自动暂停,用户可审查进度或重定向 AI
|
|
40
40
|
- **MCP 协议** — 接入外部 MCP 服务器,动态发现工具
|
|
@@ -203,7 +203,7 @@ AI 在对话中可自主调用 30 个工具:
|
|
|
203
203
|
| `/provider` | 切换 AI Provider |
|
|
204
204
|
| `/model` | 切换模型 |
|
|
205
205
|
| `/plan` | 进入只读规划模式 |
|
|
206
|
-
| `/think` |
|
|
206
|
+
| `/think` | 思考开关与档位(`on\|off\|low\|high\|max\|status`) |
|
|
207
207
|
| `/test` | 自动检测并运行测试 |
|
|
208
208
|
| `/review` | AI 代码审查 git diff |
|
|
209
209
|
| `/security-review` | 安全漏洞扫描 git diff |
|
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
} from "./chunk-RS7SKYTS.js";
|
|
5
5
|
import {
|
|
6
6
|
ConfigManager
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-OR46O57D.js";
|
|
8
8
|
import "./chunk-TU3L3PW7.js";
|
|
9
9
|
import {
|
|
10
10
|
atomicWriteFileSync
|
|
11
11
|
} from "./chunk-BMLQPSHP.js";
|
|
12
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-ZUONW7FS.js";
|
|
13
13
|
|
|
14
14
|
// src/cli/batch.ts
|
|
15
15
|
import Anthropic from "@anthropic-ai/sdk";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
evaluateCiGate,
|
|
4
4
|
normalizeCiThresholds
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-W7D4M4KV.js";
|
|
6
6
|
import {
|
|
7
7
|
buildReviewPrompt,
|
|
8
8
|
buildSecurityReviewPrompt,
|
|
@@ -13,13 +13,13 @@ import {
|
|
|
13
13
|
} from "./chunk-6YZEZFX5.js";
|
|
14
14
|
import {
|
|
15
15
|
ProviderRegistry
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-XVB4RARX.js";
|
|
17
17
|
import {
|
|
18
18
|
ConfigManager
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-OR46O57D.js";
|
|
20
20
|
import {
|
|
21
21
|
VERSION
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-ZUONW7FS.js";
|
|
23
23
|
|
|
24
24
|
// src/cli/ci.ts
|
|
25
25
|
import { execFileSync } from "child_process";
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
MEMORY_FILE_NAME,
|
|
14
14
|
MEMORY_MAX_CHARS,
|
|
15
15
|
MEMORY_STORE_FILE_NAME
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-ZUONW7FS.js";
|
|
17
17
|
|
|
18
18
|
// src/memory/persistent-memory.ts
|
|
19
19
|
import { copyFileSync, existsSync, mkdirSync, readFileSync, statSync } from "fs";
|
|
@@ -8,13 +8,13 @@ import {
|
|
|
8
8
|
listHooks,
|
|
9
9
|
listInstalledPlugins,
|
|
10
10
|
resetStats
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-RO67VWKW.js";
|
|
12
12
|
import {
|
|
13
13
|
ProviderRegistry
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-XVB4RARX.js";
|
|
15
15
|
import {
|
|
16
16
|
ConfigManager
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-OR46O57D.js";
|
|
18
18
|
import {
|
|
19
19
|
getGitRoot
|
|
20
20
|
} from "./chunk-HOSJZMQS.js";
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
MCP_PROJECT_CONFIG_NAME,
|
|
27
27
|
MEMORY_FILE_NAME,
|
|
28
28
|
VERSION
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-ZUONW7FS.js";
|
|
30
30
|
|
|
31
31
|
// src/diagnostics/doctor-report.ts
|
|
32
32
|
import { existsSync as existsSync3, statSync as statSync2 } from "fs";
|
|
@@ -108,17 +108,21 @@ var PRICING_TABLE = {
|
|
|
108
108
|
"glm-4.6": { input: 0.6, output: 2.2 },
|
|
109
109
|
"glm-4.6v": { input: 0.6, output: 2.2 },
|
|
110
110
|
"glm-5": { input: 0.85, output: 2.85 },
|
|
111
|
-
// GLM-5.3
|
|
111
|
+
// GLM-5.3:官方定价页(open.bigmodel.cn/pricing,2026-10-08 浏览器读取)——输入 8 元、
|
|
112
|
+
// 输出 28 元、缓存命中 2 元(每百万 token),按 ¥6.9/$1 换算。此前记的 $1.40/$4.40 是
|
|
113
|
+
// Z.ai 国际站的美元价,而本 provider 打的是国内站、按人民币计费,高报约 20%;更大的
|
|
114
|
+
// 偏差在**缓存**:没有 cacheRead 时缓存命中按输入全价算,2026-10-07 审计会话 1474 万
|
|
115
|
+
// 缓存 token 被记成 $21.34,按官方缓存价约 $4.90(2026-10-07 审计 X-03)。
|
|
112
116
|
// 注意它**始终思考**,思考 token 按输出价计费 —— 实际成本高度取决于 reasoning_effort。
|
|
113
|
-
"glm-5.3": { input:
|
|
117
|
+
"glm-5.3": { input: 8 / CNY_PER_USD, output: 28 / CNY_PER_USD, cacheRead: 2 / CNY_PER_USD },
|
|
114
118
|
// GLM-5.3-Flash:官方定价页(open.bigmodel.cn/pricing)一手数字——输入 0.8 元、
|
|
115
119
|
// 输出 2.8 元、缓存命中 0.23 元(每百万 token),按记账汇率 ¥6.9/$1 换算。
|
|
116
120
|
// **刻意记恢复价而非当前的 5 折限时价**(0.4/1.4/0.115 元):官方只说「限时两周」、
|
|
117
121
|
// 没公布截止日期,静态表表达不了这个时间维度;高估比低估安全——预算告警早触发
|
|
118
122
|
// 好过晚触发。折扣期内 `/cost` 会比实际偏高约一倍,这是刻意的取舍。
|
|
119
123
|
"glm-5.3-flash": { input: 0.116, output: 0.406, cacheRead: 0.033 },
|
|
120
|
-
// GLM-5.2
|
|
121
|
-
"glm-5.2": { input:
|
|
124
|
+
// GLM-5.2:与 GLM-5.3 同价(同一定价页:8 / 28 / 缓存命中 2 元),口径修正同上。
|
|
125
|
+
"glm-5.2": { input: 8 / CNY_PER_USD, output: 28 / CNY_PER_USD, cacheRead: 2 / CNY_PER_USD },
|
|
122
126
|
// GLM-5V-Turbo(2026-04 视觉编程旗舰)官方直连 API 定价 $1.20 / $4.00。
|
|
123
127
|
"glm-5v-turbo": { input: 1.2, output: 4 },
|
|
124
128
|
"glm-5.1": { input: 0.95, output: 3.15 },
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
MEMORY_FILE_NAME,
|
|
13
13
|
MEMORY_MAX_CHARS,
|
|
14
14
|
MEMORY_STORE_FILE_NAME
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-X5ZC4TI4.js";
|
|
16
16
|
|
|
17
17
|
// src/memory/persistent-memory.ts
|
|
18
18
|
import { copyFileSync, existsSync, mkdirSync, readFileSync, statSync } from "fs";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
computeCost,
|
|
4
4
|
formatCost
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-NFPJ6KUU.js";
|
|
6
6
|
import {
|
|
7
7
|
clearRecentlyDeniedAutoActions,
|
|
8
8
|
estimateTokens,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
setPreferredAgentName,
|
|
17
17
|
truncateForPersist,
|
|
18
18
|
undoStack
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-ZSR2UIRD.js";
|
|
20
20
|
import {
|
|
21
21
|
buildReviewPrompt,
|
|
22
22
|
buildSecurityReviewPrompt
|
|
@@ -51,7 +51,7 @@ import {
|
|
|
51
51
|
touchMemoryReferences,
|
|
52
52
|
updateMemoryApproval,
|
|
53
53
|
updateMemoryEntry
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-G46THFJN.js";
|
|
55
55
|
import {
|
|
56
56
|
theme
|
|
57
57
|
} from "./chunk-5C76XDDF.js";
|
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
import {
|
|
66
66
|
buildDoctorReport,
|
|
67
67
|
formatDoctorReport
|
|
68
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-HVVDGSUN.js";
|
|
69
69
|
import {
|
|
70
70
|
describePlugin,
|
|
71
71
|
getActivePluginAssets,
|
|
@@ -80,7 +80,7 @@ import {
|
|
|
80
80
|
trustHook,
|
|
81
81
|
trustPlugin,
|
|
82
82
|
untrustHook
|
|
83
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-RO67VWKW.js";
|
|
84
84
|
import {
|
|
85
85
|
isCleanDocumentBody,
|
|
86
86
|
stripOuterCodeFence
|
|
@@ -109,11 +109,11 @@ import {
|
|
|
109
109
|
MCP_TOOL_PREFIX,
|
|
110
110
|
REPO_URL,
|
|
111
111
|
VERSION
|
|
112
|
-
} from "./chunk-
|
|
112
|
+
} from "./chunk-ZUONW7FS.js";
|
|
113
113
|
|
|
114
114
|
// src/skills/manager.ts
|
|
115
115
|
import { existsSync, readdirSync, mkdirSync, statSync } from "fs";
|
|
116
|
-
import { join } from "path";
|
|
116
|
+
import { basename as basename2, dirname, join } from "path";
|
|
117
117
|
|
|
118
118
|
// src/skills/types.ts
|
|
119
119
|
import { readFileSync } from "fs";
|
|
@@ -253,7 +253,14 @@ var SkillManager = class {
|
|
|
253
253
|
}
|
|
254
254
|
/** 获取激活技能的 prompt 内容(null 表示无激活技能) */
|
|
255
255
|
getActivePromptContent() {
|
|
256
|
-
|
|
256
|
+
const skill = this.activeSkill;
|
|
257
|
+
if (!skill) return null;
|
|
258
|
+
if (basename2(skill.filePath) === "SKILL.md") {
|
|
259
|
+
return `Skill directory (SKILL_DIR, \u6280\u80FD\u76EE\u5F55): ${dirname(skill.filePath)}
|
|
260
|
+
|
|
261
|
+
${skill.content}`;
|
|
262
|
+
}
|
|
263
|
+
return skill.content;
|
|
257
264
|
}
|
|
258
265
|
/** 获取激活技能的工具白名单 Set(null 表示无限制) */
|
|
259
266
|
getActiveToolFilter() {
|
|
@@ -2426,7 +2433,7 @@ No tools match "${filter}".
|
|
|
2426
2433
|
const { join: join6 } = await import("path");
|
|
2427
2434
|
const { existsSync: existsSync6 } = await import("fs");
|
|
2428
2435
|
const { getGitRoot } = await import("./git-context-EXOEHQSF.js");
|
|
2429
|
-
const { MCP_PROJECT_CONFIG_NAME } = await import("./constants-
|
|
2436
|
+
const { MCP_PROJECT_CONFIG_NAME } = await import("./constants-SSVJCBAT.js");
|
|
2430
2437
|
const { approveProject, hashMcpFile } = await import("./project-trust-KGG2BWKC.js");
|
|
2431
2438
|
const cwd = process.cwd();
|
|
2432
2439
|
const projectRoot = getGitRoot(cwd) ?? cwd;
|
|
@@ -3534,7 +3541,7 @@ function createReviewCommands() {
|
|
|
3534
3541
|
usage: "/test [command|filter]",
|
|
3535
3542
|
async execute(args, ctx) {
|
|
3536
3543
|
try {
|
|
3537
|
-
const { executeTests } = await import("./run-tests-
|
|
3544
|
+
const { executeTests } = await import("./run-tests-WJJW77HK.js");
|
|
3538
3545
|
const argStr = args.join(" ").trim();
|
|
3539
3546
|
let testArgs = {};
|
|
3540
3547
|
if (argStr) {
|
|
@@ -4391,7 +4398,7 @@ ${view.chatHeading}
|
|
|
4391
4398
|
|
|
4392
4399
|
// src/repl/commands/session-commands.ts
|
|
4393
4400
|
import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
4394
|
-
import { resolve, dirname } from "path";
|
|
4401
|
+
import { resolve, dirname as dirname2 } from "path";
|
|
4395
4402
|
import chalk2 from "chalk";
|
|
4396
4403
|
|
|
4397
4404
|
// src/core/session-cost.ts
|
|
@@ -4718,7 +4725,7 @@ function createSessionCommands() {
|
|
|
4718
4725
|
const exported = buildSessionExport(session, format, outFile);
|
|
4719
4726
|
const absPath = resolve(process.cwd(), exported.filename);
|
|
4720
4727
|
try {
|
|
4721
|
-
mkdirSync2(
|
|
4728
|
+
mkdirSync2(dirname2(absPath), { recursive: true });
|
|
4722
4729
|
writeFileSync2(absPath, exported.content, "utf-8");
|
|
4723
4730
|
ctx.renderer.printSuccess(`Exported ${exported.messageCount} messages \u2192 ${absPath}`);
|
|
4724
4731
|
} catch (err) {
|
|
@@ -4885,7 +4892,7 @@ function createSessionCommands() {
|
|
|
4885
4892
|
}
|
|
4886
4893
|
|
|
4887
4894
|
// src/repl/commands/misc-commands.ts
|
|
4888
|
-
import { basename as
|
|
4895
|
+
import { basename as basename3 } from "path";
|
|
4889
4896
|
import { platform as platform3 } from "os";
|
|
4890
4897
|
function createMiscCommands() {
|
|
4891
4898
|
return [
|
|
@@ -5142,7 +5149,7 @@ ${hint}` : "")
|
|
|
5142
5149
|
return;
|
|
5143
5150
|
}
|
|
5144
5151
|
const description = args.join(" ").trim() || "Please describe this image";
|
|
5145
|
-
ctx.renderer.printSuccess(`\u{1F4CB} Image loaded: ${
|
|
5152
|
+
ctx.renderer.printSuccess(`\u{1F4CB} Image loaded: ${basename3(imgPath)}`);
|
|
5146
5153
|
await ctx.sendAsChat(`@${imgPath} ${description}`);
|
|
5147
5154
|
}
|
|
5148
5155
|
},
|
|
@@ -5587,7 +5594,7 @@ function clearDevState() {
|
|
|
5587
5594
|
|
|
5588
5595
|
// src/tools/deferred-save.ts
|
|
5589
5596
|
import { statSync as statSync4 } from "fs";
|
|
5590
|
-
import { basename as
|
|
5597
|
+
import { basename as basename4 } from "path";
|
|
5591
5598
|
function snapshotFile(path) {
|
|
5592
5599
|
try {
|
|
5593
5600
|
const st = statSync4(path);
|
|
@@ -5608,7 +5615,7 @@ var SAVE_CLAIM_PATTERNS = [
|
|
|
5608
5615
|
/\b(?:saved|written|created|generated)\s+(?:to|at|as|into)\b/i
|
|
5609
5616
|
];
|
|
5610
5617
|
function narratesSavedTarget(content, path) {
|
|
5611
|
-
const base =
|
|
5618
|
+
const base = basename4(path);
|
|
5612
5619
|
if (!base || !content.includes(base)) return null;
|
|
5613
5620
|
for (const re of SAVE_CLAIM_PATTERNS) {
|
|
5614
5621
|
if (re.test(content)) return re.source;
|
|
@@ -5630,7 +5637,7 @@ function decideDeferredSave(params) {
|
|
|
5630
5637
|
return {
|
|
5631
5638
|
kind: "skip",
|
|
5632
5639
|
reason: "narrates-target",
|
|
5633
|
-
message: `\u21AA \u8DF3\u8FC7 deferred \u843D\u76D8\uFF1A\u6700\u7EC8\u56DE\u590D\u662F\u5173\u4E8E ${
|
|
5640
|
+
message: `\u21AA \u8DF3\u8FC7 deferred \u843D\u76D8\uFF1A\u6700\u7EC8\u56DE\u590D\u662F\u5173\u4E8E ${basename4(path)} \u7684\u6C47\u62A5\u800C\u975E\u6587\u6863\u6B63\u6587\uFF08matched: ${narrated}\uFF09\u3002`
|
|
5634
5641
|
};
|
|
5635
5642
|
}
|
|
5636
5643
|
if (!isCleanDocumentBody(body)) {
|
|
@@ -2120,6 +2120,7 @@ function ollamaNativeBaseUrl(openAiBaseUrl) {
|
|
|
2120
2120
|
return openAiBaseUrl.replace(/\/+$/, "").replace(/\/v1$/, "");
|
|
2121
2121
|
}
|
|
2122
2122
|
var NATIVE_API_TIMEOUT_MS = 3e3;
|
|
2123
|
+
var SMALL_CONTEXT_WARN = 16384;
|
|
2123
2124
|
var OllamaProvider = class extends OpenAICompatibleProvider {
|
|
2124
2125
|
// 用 127.0.0.1 而非 localhost:Node.js 18+ 在 Windows 上优先解析 localhost 为 IPv6 (::1),
|
|
2125
2126
|
// 但 Ollama 默认只监听 IPv4,导致连接失败。
|
|
@@ -2198,12 +2199,13 @@ var OllamaProvider = class extends OpenAICompatibleProvider {
|
|
|
2198
2199
|
if (show?.capabilities?.includes("thinking")) thinkingModels.add(id);
|
|
2199
2200
|
if (running.size === 0 && !show) return;
|
|
2200
2201
|
const digest = digests.get(id);
|
|
2201
|
-
const { contextWindow } = resolveOllamaContextWindow({
|
|
2202
|
+
const { contextWindow, source } = resolveOllamaContextWindow({
|
|
2202
2203
|
runningContext: digest && running.get(digest) || running.get(id),
|
|
2203
2204
|
show,
|
|
2204
2205
|
fallback: this.estimateContextWindow(id)
|
|
2205
2206
|
});
|
|
2206
2207
|
result.set(id, contextWindow);
|
|
2208
|
+
this.contextSources.set(id, source);
|
|
2207
2209
|
}));
|
|
2208
2210
|
return { contextWindows: result, thinkingModels };
|
|
2209
2211
|
}
|
|
@@ -2299,6 +2301,77 @@ var OllamaProvider = class extends OpenAICompatibleProvider {
|
|
|
2299
2301
|
const target = norm(model);
|
|
2300
2302
|
return this.dynamicModels.some((m) => m.supportsThinking === true && norm(m.id) === target);
|
|
2301
2303
|
}
|
|
2304
|
+
// ── 加载后补读真实窗口(2026-10-07 审计 C-01)────────────────────────────
|
|
2305
|
+
//
|
|
2306
|
+
// 上下文窗口只在启动时读一次。模型当时若还没加载,`/api/ps` 里没有它,只能取训练上限
|
|
2307
|
+
// (Qwen3.8 是 262K);而服务端实际开的窗口可能只有它的几十分之一。第一次请求把模型
|
|
2308
|
+
// 加载进来之后若不再读,上下文压力监控、自动压缩与工具预算就整场按那个大数在算——
|
|
2309
|
+
// aicli 以为还有余量,Ollama 早已在悄悄截掉最早的消息(v0.4.311 那次说的正是这个后果)。
|
|
2310
|
+
// 所以每个模型在首次请求之后补读一次 `/api/ps`;读到的窗口若小得连工具定义都放不下,
|
|
2311
|
+
// 提示一次怎么调大。都是后台做,不拖慢这次请求。
|
|
2312
|
+
/** 每个模型的窗口是从哪一级读到的(只有 'running' 是服务端实际值) */
|
|
2313
|
+
contextSources = /* @__PURE__ */ new Map();
|
|
2314
|
+
refreshedAfterLoad = /* @__PURE__ */ new Set();
|
|
2315
|
+
warnedSmallContext = /* @__PURE__ */ new Set();
|
|
2316
|
+
async chat(request) {
|
|
2317
|
+
try {
|
|
2318
|
+
return await super.chat(request);
|
|
2319
|
+
} finally {
|
|
2320
|
+
this.scheduleContextRefresh(request.model);
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
async *chatStream(request) {
|
|
2324
|
+
try {
|
|
2325
|
+
yield* super.chatStream(request);
|
|
2326
|
+
} finally {
|
|
2327
|
+
this.scheduleContextRefresh(request.model);
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
async chatWithTools(request, tools) {
|
|
2331
|
+
try {
|
|
2332
|
+
return await super.chatWithTools(request, tools);
|
|
2333
|
+
} finally {
|
|
2334
|
+
this.scheduleContextRefresh(request.model);
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
async *chatWithToolsStream(request, tools) {
|
|
2338
|
+
try {
|
|
2339
|
+
yield* super.chatWithToolsStream(request, tools);
|
|
2340
|
+
} finally {
|
|
2341
|
+
this.scheduleContextRefresh(request.model);
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
scheduleContextRefresh(model) {
|
|
2345
|
+
const key = model.replace(/:latest$/, "");
|
|
2346
|
+
if (this.refreshedAfterLoad.has(key)) return;
|
|
2347
|
+
this.refreshedAfterLoad.add(key);
|
|
2348
|
+
void this.refreshLoadedContext(model).catch(() => {
|
|
2349
|
+
});
|
|
2350
|
+
}
|
|
2351
|
+
/** 补读已加载模型的实际窗口,更新同一份权重(digest 相同)的所有别名。测试可直接 await。 */
|
|
2352
|
+
async refreshLoadedContext(model) {
|
|
2353
|
+
const norm = (id2) => id2.replace(/:latest$/, "");
|
|
2354
|
+
const [running, digests] = await Promise.all([this.fetchRunningContexts(), this.fetchDigests()]);
|
|
2355
|
+
const self = this.dynamicModels.find((m) => norm(m.id) === norm(model));
|
|
2356
|
+
const id = self?.id ?? model;
|
|
2357
|
+
const digest = digests.get(id);
|
|
2358
|
+
const actual = digest && running.get(digest) || running.get(id);
|
|
2359
|
+
if (!actual) return;
|
|
2360
|
+
for (const m of this.dynamicModels) {
|
|
2361
|
+
if (m.id === id || digest && digests.get(m.id) === digest) {
|
|
2362
|
+
m.contextWindow = actual;
|
|
2363
|
+
this.contextSources.set(m.id, "running");
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
if (actual < SMALL_CONTEXT_WARN && !this.warnedSmallContext.has(norm(id))) {
|
|
2367
|
+
this.warnedSmallContext.add(norm(id));
|
|
2368
|
+
process.stderr.write(
|
|
2369
|
+
`
|
|
2370
|
+
[ollama] ${id} is loaded with a ${actual.toLocaleString()}-token context window. aicli's tool definitions alone take about 8K tokens, so earlier messages will be silently cut off. Raise it: set OLLAMA_CONTEXT_LENGTH=32768 (or more) for the Ollama server, or add "PARAMETER num_ctx 32768" to the model's Modelfile.
|
|
2371
|
+
`
|
|
2372
|
+
);
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2302
2375
|
/** 实时刷新模型列表 */
|
|
2303
2376
|
async listModels() {
|
|
2304
2377
|
await this.tryConnect();
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
searchPersistentMemories,
|
|
12
12
|
touchMemoryReferences,
|
|
13
13
|
updateMemoryEntry
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-G46THFJN.js";
|
|
15
15
|
import {
|
|
16
16
|
indexProject
|
|
17
17
|
} from "./chunk-RWRZVQCB.js";
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
runHook,
|
|
31
31
|
runLifecycleHooks,
|
|
32
32
|
runTool
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-RO67VWKW.js";
|
|
34
34
|
import {
|
|
35
35
|
buildTruncatedArgumentsError,
|
|
36
36
|
getDangerLevel,
|
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
recoverGbkMojibake,
|
|
65
65
|
runTestsTool,
|
|
66
66
|
shellInvocation
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-3TWEKDHH.js";
|
|
68
68
|
import {
|
|
69
69
|
CONFIG_DIR_NAME,
|
|
70
70
|
DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
SUBAGENT_ALLOWED_TOOLS,
|
|
74
74
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
75
75
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-ZUONW7FS.js";
|
|
77
77
|
import {
|
|
78
78
|
getCurrentSessionKey,
|
|
79
79
|
getExecutionConfigDir,
|
|
@@ -6872,21 +6872,37 @@ function estimateTokens(text) {
|
|
|
6872
6872
|
return Math.ceil(tokens) + 4;
|
|
6873
6873
|
}
|
|
6874
6874
|
function estimateToolDefinitionTokens(def) {
|
|
6875
|
-
|
|
6876
|
-
|
|
6877
|
-
|
|
6878
|
-
if (param.enum) {
|
|
6879
|
-
charCount += param.enum.join(" ").length;
|
|
6880
|
-
}
|
|
6881
|
-
}
|
|
6882
|
-
const structuralOverhead = 40 + Object.keys(def.parameters).length * 30;
|
|
6883
|
-
return Math.ceil((charCount + structuralOverhead) * 0.25) + 10;
|
|
6875
|
+
const json = JSON.stringify({ name: def.name, description: def.description, parameters: def.parameters });
|
|
6876
|
+
const cjk = json.match(CJK_REGEX)?.length ?? 0;
|
|
6877
|
+
return Math.ceil((json.length - cjk + 40) / 3.7 + cjk * 1.5);
|
|
6884
6878
|
}
|
|
6885
6879
|
|
|
6886
6880
|
// src/tools/registry.ts
|
|
6887
6881
|
import { pathToFileURL } from "url";
|
|
6888
6882
|
import { existsSync as existsSync13, mkdirSync as mkdirSync3, readdirSync as readdirSync7 } from "fs";
|
|
6889
6883
|
import { join as join6 } from "path";
|
|
6884
|
+
var TRIMMABLE_BUILTIN_ORDER = [
|
|
6885
|
+
"google_search",
|
|
6886
|
+
"recall_memory",
|
|
6887
|
+
"search_code",
|
|
6888
|
+
"notebook_edit",
|
|
6889
|
+
"spawn_agent",
|
|
6890
|
+
"run_interactive",
|
|
6891
|
+
"save_memory",
|
|
6892
|
+
"find_references",
|
|
6893
|
+
"get_outline",
|
|
6894
|
+
"find_symbol",
|
|
6895
|
+
"task_stop",
|
|
6896
|
+
"task_list",
|
|
6897
|
+
"task_create",
|
|
6898
|
+
"git_log",
|
|
6899
|
+
"git_diff",
|
|
6900
|
+
"git_commit",
|
|
6901
|
+
"git_status",
|
|
6902
|
+
"web_fetch",
|
|
6903
|
+
"web_search",
|
|
6904
|
+
"run_tests"
|
|
6905
|
+
];
|
|
6890
6906
|
var ToolRegistry = class {
|
|
6891
6907
|
tools = /* @__PURE__ */ new Map();
|
|
6892
6908
|
pluginToolNames = /* @__PURE__ */ new Set();
|
|
@@ -6954,7 +6970,7 @@ var ToolRegistry = class {
|
|
|
6954
6970
|
totalTokens += estimateToolDefinitionTokens(def);
|
|
6955
6971
|
}
|
|
6956
6972
|
if (totalTokens <= tokenBudget) {
|
|
6957
|
-
return { definitions: allDefs, trimmedCount: 0, systemNote: null };
|
|
6973
|
+
return { definitions: allDefs, trimmedCount: 0, trimmedBuiltins: [], systemNote: null };
|
|
6958
6974
|
}
|
|
6959
6975
|
const builtinDefs = [];
|
|
6960
6976
|
const mcpDefs = [];
|
|
@@ -6966,10 +6982,19 @@ var ToolRegistry = class {
|
|
|
6966
6982
|
}
|
|
6967
6983
|
}
|
|
6968
6984
|
let budget = tokenBudget;
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
const
|
|
6985
|
+
const trimmedBuiltins = [];
|
|
6986
|
+
let builtinCost = builtinDefs.reduce((n, d) => n + estimateToolDefinitionTokens(d), 0);
|
|
6987
|
+
const keptBuiltins = new Set(builtinDefs.map((d) => d.name));
|
|
6988
|
+
for (const name of TRIMMABLE_BUILTIN_ORDER) {
|
|
6989
|
+
if (builtinCost <= budget) break;
|
|
6990
|
+
const def = builtinDefs.find((d) => d.name === name);
|
|
6991
|
+
if (!def || this.pluginToolNames.has(name)) continue;
|
|
6992
|
+
keptBuiltins.delete(name);
|
|
6993
|
+
trimmedBuiltins.push(name);
|
|
6994
|
+
builtinCost -= estimateToolDefinitionTokens(def);
|
|
6995
|
+
}
|
|
6996
|
+
budget -= builtinCost;
|
|
6997
|
+
const kept = builtinDefs.filter((d) => keptBuiltins.has(d.name));
|
|
6973
6998
|
const used = usedToolNames ?? /* @__PURE__ */ new Set();
|
|
6974
6999
|
const remaining = [];
|
|
6975
7000
|
for (const def of mcpDefs) {
|
|
@@ -6991,6 +7016,12 @@ var ToolRegistry = class {
|
|
|
6991
7016
|
trimmed++;
|
|
6992
7017
|
}
|
|
6993
7018
|
}
|
|
7019
|
+
const notes = [];
|
|
7020
|
+
if (trimmedBuiltins.length > 0) {
|
|
7021
|
+
notes.push(
|
|
7022
|
+
`[Tool Budget] To fit this model's context window, these tools are not available in this session: ${trimmedBuiltins.join(", ")}. Use bash for the equivalent (git commands, grep for symbols, curl for web pages) instead of calling them.`
|
|
7023
|
+
);
|
|
7024
|
+
}
|
|
6994
7025
|
let systemNote = null;
|
|
6995
7026
|
if (trimmed > 0) {
|
|
6996
7027
|
const trimmedServers = /* @__PURE__ */ new Set();
|
|
@@ -7003,7 +7034,13 @@ var ToolRegistry = class {
|
|
|
7003
7034
|
}
|
|
7004
7035
|
systemNote = `[MCP Tool Budget] ${trimmed} MCP tool(s) from server(s) [${[...trimmedServers].join(", ")}] were excluded to fit the context window. If you need a specific MCP tool that isn't listed, tell the user to ask for it explicitly.`;
|
|
7005
7036
|
}
|
|
7006
|
-
|
|
7037
|
+
if (systemNote) notes.push(systemNote);
|
|
7038
|
+
return {
|
|
7039
|
+
definitions: kept,
|
|
7040
|
+
trimmedCount: trimmed,
|
|
7041
|
+
trimmedBuiltins,
|
|
7042
|
+
systemNote: notes.length > 0 ? notes.join("\n\n") : null
|
|
7043
|
+
};
|
|
7007
7044
|
}
|
|
7008
7045
|
listAll() {
|
|
7009
7046
|
return [...this.tools.values()];
|
|
@@ -3,16 +3,16 @@ import {
|
|
|
3
3
|
CI_COMMENT_MARKER,
|
|
4
4
|
countSeverity,
|
|
5
5
|
runCi
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-FHBV5EUM.js";
|
|
7
|
+
import "./chunk-W7D4M4KV.js";
|
|
8
8
|
import "./chunk-HLWUDRBO.js";
|
|
9
9
|
import "./chunk-6YZEZFX5.js";
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-XVB4RARX.js";
|
|
11
|
+
import "./chunk-OR46O57D.js";
|
|
12
12
|
import "./chunk-E2W2MI6H.js";
|
|
13
13
|
import "./chunk-TU3L3PW7.js";
|
|
14
14
|
import "./chunk-BMLQPSHP.js";
|
|
15
|
-
import "./chunk-
|
|
15
|
+
import "./chunk-ZUONW7FS.js";
|
|
16
16
|
export {
|
|
17
17
|
CI_COMMENT_MARKER,
|
|
18
18
|
countSeverity,
|