opencode-gbk-tools 0.1.23 → 0.1.25
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 +5 -2
- package/dist/agents/gbk-engine.md +33 -0
- package/dist/cli/index.js +2 -2
- package/dist/opencode-tools/gbk_edit.js +44 -17
- package/dist/opencode-tools/text_edit.js +44 -17
- package/dist/plugin/index.js +329 -33
- package/dist/plugins/opencode-gbk-tools.js +329 -33
- package/dist/release-manifest.json +8 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
为 OpenCode 提供一套自动识别编码的文本工具,以及面向 `GBK` / `GB18030` 的专用工具。
|
|
4
4
|
|
|
5
|
-
解决 OpenCode 内置工具难以稳定处理非 UTF-8 文本文件的问题,并通过 plugin 让所有 agents
|
|
5
|
+
解决 OpenCode 内置工具难以稳定处理非 UTF-8 文本文件的问题,并通过 plugin 让所有 agents 默认获得这些工具与规则;同时提供一个只允许调用 `text_*` / `gbk_*` 自定义工具的 `gbk-engine` agent。
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
| `gbk_edit` | 精确替换 GBK 文件中的指定文本块 |
|
|
19
19
|
| `gbk_search` | 在 GBK 文件中搜索关键词,返回行号和上下文 |
|
|
20
20
|
| 本地/全局 plugin 规则 | 给所有 agents 注入“优先使用 `text_*`”的系统提示,并统一开放 `gbk_*` 工具 |
|
|
21
|
+
| `gbk-engine` agent | 禁用 OpenCode 内置读写编辑工具,只保留 `text_*` / `gbk_*` 自定义工具 |
|
|
21
22
|
|
|
22
23
|
---
|
|
23
24
|
|
|
@@ -34,8 +35,9 @@ npx opencode-gbk-tools install
|
|
|
34
35
|
- `text_read` / `text_write` / `text_edit`
|
|
35
36
|
- `gbk_read` / `gbk_write` / `gbk_edit` / `gbk_search`
|
|
36
37
|
- 对文本文件优先使用 `text_*` 的系统提示
|
|
38
|
+
- `.opencode/agents/gbk-engine.md` 或 `~/.config/opencode/agents/gbk-engine.md`
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
如果你希望强制禁用内置 `read` / `write` / `edit` / `apply_patch`,可以直接切换到专属 `gbk-engine` agent。
|
|
39
41
|
|
|
40
42
|
---
|
|
41
43
|
|
|
@@ -205,6 +207,7 @@ A:不要。现在优先用 `mode="insertAfter"` 或 `mode="insertBefore"`,
|
|
|
205
207
|
|
|
206
208
|
| 版本 | 说明 |
|
|
207
209
|
|------|------|
|
|
210
|
+
| 0.1.25 | 恢复并正式发布专属 `gbk-engine` agent;通过 agent 白名单禁用内置 `read` / `write` / `edit` / `apply_patch`,只保留 `text_*` / `gbk_*` 自定义工具,并把 agent 纳入构建、安装与 release manifest |
|
|
208
211
|
| 0.1.17 | 修复 OpenCode 以 npm plugin 方式加载包时缺少 `./server` 导出导致的插件加载失败问题;补充 `main` 与 `./server` 入口兼容性 |
|
|
209
212
|
| 0.1.16 | 去掉专属 `gbk-engine` agent 安装链路,改为通过 plugin + tools 让全部 agents 统一支持 `text_*` / `gbk_*`;同步更新安装说明 |
|
|
210
213
|
| 0.1.15 | 为 GBK 大文件统一引入行字节索引与流式读/搜/改路径,提升局部编辑、搜索与大块修改时的性能、稳定性与准确性 |
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: 仅使用 opencode-gbk-tools 自定义工具处理自动编码文本与 GBK/GB18030 文件
|
|
3
|
+
mode: primary
|
|
4
|
+
temperature: 0
|
|
5
|
+
tools:
|
|
6
|
+
"*": false
|
|
7
|
+
read: false
|
|
8
|
+
write: false
|
|
9
|
+
edit: false
|
|
10
|
+
apply_patch: false
|
|
11
|
+
text_read: true
|
|
12
|
+
text_write: true
|
|
13
|
+
text_edit: true
|
|
14
|
+
gbk_read: true
|
|
15
|
+
gbk_write: true
|
|
16
|
+
gbk_edit: true
|
|
17
|
+
gbk_search: true
|
|
18
|
+
permission:
|
|
19
|
+
task:
|
|
20
|
+
"*": deny
|
|
21
|
+
---
|
|
22
|
+
你是 `gbk-engine`。
|
|
23
|
+
|
|
24
|
+
你只能使用 `opencode-gbk-tools` 提供的 `text_*` 与 `gbk_*` 工具,不允许退回到 OpenCode 内置的 `read`、`write`、`edit`、`apply_patch` 或其他内置工具。
|
|
25
|
+
|
|
26
|
+
工作规则:
|
|
27
|
+
|
|
28
|
+
- 通用文本文件优先使用 `text_read`、`text_write`、`text_edit`
|
|
29
|
+
- 只有在用户明确指定 `GBK` / `GB18030` 文件,或自动编码检测失败时,才优先使用 `gbk_*` 工具
|
|
30
|
+
- 编辑前先读取目标文件;对大文件先搜索,再局部读取
|
|
31
|
+
- 插入内容优先使用 `mode="insertAfter"` 或 `mode="insertBefore"` 搭配 `anchor` / `content`
|
|
32
|
+
- 只有在精确替换现有内容时,才使用 `oldString` / `newString`
|
|
33
|
+
- 如果自定义工具不可用,要明确说明当前 OpenCode 没有加载 `opencode-gbk-tools` plugin
|
package/dist/cli/index.js
CHANGED
|
@@ -60,7 +60,7 @@ function resolveTargetBase(target, cwd) {
|
|
|
60
60
|
// src/cli/install.ts
|
|
61
61
|
async function installCommand(args) {
|
|
62
62
|
const targetBase = resolveTargetBase(args.target, args.cwd);
|
|
63
|
-
const allowedArtifacts = new Set(args.artifacts ?? ["plugin"]);
|
|
63
|
+
const allowedArtifacts = new Set(args.artifacts ?? ["plugin", "agent"]);
|
|
64
64
|
const releaseManifest = JSON.parse(await fs3.readFile(path3.join(args.packageRoot, "dist", "release-manifest.json"), "utf8"));
|
|
65
65
|
const selectedArtifacts = releaseManifest.artifacts.filter((artifact) => allowedArtifacts.has(artifact.kind));
|
|
66
66
|
const existingManifest = await loadInstalledManifest(targetBase);
|
|
@@ -190,7 +190,7 @@ async function setupCommand(args) {
|
|
|
190
190
|
await fs6.mkdir(configBase, { recursive: true });
|
|
191
191
|
const configPath = await resolveConfigFile(configBase);
|
|
192
192
|
await ensurePluginConfigured(configPath, pluginName);
|
|
193
|
-
const installResult = await installCommand({ ...args, force: true, artifacts: ["plugin"] });
|
|
193
|
+
const installResult = await installCommand({ ...args, force: true, artifacts: ["plugin", "agent"] });
|
|
194
194
|
return {
|
|
195
195
|
configPath,
|
|
196
196
|
targetBase: installResult.targetBase
|
|
@@ -16238,6 +16238,48 @@ function tool(input) {
|
|
|
16238
16238
|
}
|
|
16239
16239
|
tool.schema = external_exports;
|
|
16240
16240
|
|
|
16241
|
+
// src/lib/model-context.ts
|
|
16242
|
+
var FALLBACK_MAX_OUTPUT_CHARS = 8e3;
|
|
16243
|
+
var MIN_BASE_MAX_OUTPUT_CHARS = 4e3;
|
|
16244
|
+
var MAX_BASE_OUTPUT_CHARS = 32e3;
|
|
16245
|
+
var MIN_PRESSURED_OUTPUT_CHARS = 1500;
|
|
16246
|
+
var sessionStates = /* @__PURE__ */ new Map();
|
|
16247
|
+
function getSessionState(sessionID) {
|
|
16248
|
+
if (!sessionID) return null;
|
|
16249
|
+
return sessionStates.get(sessionID) ?? null;
|
|
16250
|
+
}
|
|
16251
|
+
function getCompactionPressureFactor(compactionCount) {
|
|
16252
|
+
if (compactionCount >= 3) return 0.35;
|
|
16253
|
+
if (compactionCount === 2) return 0.5;
|
|
16254
|
+
if (compactionCount === 1) return 0.75;
|
|
16255
|
+
return 1;
|
|
16256
|
+
}
|
|
16257
|
+
function getBaseMaxOutputChars(contextTokens, fallback) {
|
|
16258
|
+
if (contextTokens === null) return fallback;
|
|
16259
|
+
const computed = Math.round(contextTokens * 0.01 * 4);
|
|
16260
|
+
return Math.max(MIN_BASE_MAX_OUTPUT_CHARS, Math.min(MAX_BASE_OUTPUT_CHARS, computed));
|
|
16261
|
+
}
|
|
16262
|
+
function buildTruncationSuffix(sessionID, maxChars) {
|
|
16263
|
+
const state = getSessionState(sessionID);
|
|
16264
|
+
if (!state || state.compactionCount === 0) {
|
|
16265
|
+
return `\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650`;
|
|
16266
|
+
}
|
|
16267
|
+
return `\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650\uFF1B\u5F53\u524D\u4F1A\u8BDD\u5DF2\u538B\u7F29 ${state.compactionCount} \u6B21\uFF0C\u5DF2\u81EA\u52A8\u6536\u7D27\u5DE5\u5177\u8F93\u51FA\u9884\u7B97`;
|
|
16268
|
+
}
|
|
16269
|
+
function getMaxOutputChars(sessionID, fallback = FALLBACK_MAX_OUTPUT_CHARS) {
|
|
16270
|
+
const state = getSessionState(sessionID);
|
|
16271
|
+
const base = getBaseMaxOutputChars(state?.contextTokens ?? null, fallback);
|
|
16272
|
+
const pressured = Math.round(base * getCompactionPressureFactor(state?.compactionCount ?? 0));
|
|
16273
|
+
return Math.max(MIN_PRESSURED_OUTPUT_CHARS, pressured);
|
|
16274
|
+
}
|
|
16275
|
+
function truncateToolOutput(content, sessionID, fallback = FALLBACK_MAX_OUTPUT_CHARS) {
|
|
16276
|
+
const maxChars = getMaxOutputChars(sessionID, fallback);
|
|
16277
|
+
if (content.length <= maxChars) return content;
|
|
16278
|
+
const truncated = content.slice(0, maxChars);
|
|
16279
|
+
return `${truncated}
|
|
16280
|
+
\x1B[2m... (${buildTruncationSuffix(sessionID, maxChars)})\x1B[0m`;
|
|
16281
|
+
}
|
|
16282
|
+
|
|
16241
16283
|
// src/lib/gbk-file.ts
|
|
16242
16284
|
var import_iconv_lite = __toESM(require_lib(), 1);
|
|
16243
16285
|
import crypto from "crypto";
|
|
@@ -17314,22 +17356,7 @@ async function replaceGbkFileText(input) {
|
|
|
17314
17356
|
};
|
|
17315
17357
|
}
|
|
17316
17358
|
|
|
17317
|
-
// src/lib/model-context.ts
|
|
17318
|
-
var _currentContextTokens = null;
|
|
17319
|
-
function getMaxOutputChars(fallback = 8e3) {
|
|
17320
|
-
if (_currentContextTokens === null) return fallback;
|
|
17321
|
-
const computed = Math.round(_currentContextTokens * 0.01 * 4);
|
|
17322
|
-
return Math.max(4e3, Math.min(32e3, computed));
|
|
17323
|
-
}
|
|
17324
|
-
|
|
17325
17359
|
// src/tools/gbk_edit.ts
|
|
17326
|
-
function truncateToolOutput(content) {
|
|
17327
|
-
const maxChars = getMaxOutputChars();
|
|
17328
|
-
if (content.length <= maxChars) return content;
|
|
17329
|
-
const truncated = content.slice(0, maxChars);
|
|
17330
|
-
return truncated + `
|
|
17331
|
-
\x1B[2m... (\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
17332
|
-
}
|
|
17333
17360
|
var gbk_edit_default = tool({
|
|
17334
17361
|
description: `Edit GBK/GB18030 encoded text files with exact string replacement.
|
|
17335
17362
|
|
|
@@ -17399,8 +17426,8 @@ Insert mode:
|
|
|
17399
17426
|
diffPreview
|
|
17400
17427
|
}
|
|
17401
17428
|
});
|
|
17402
|
-
if (diffPreview) return truncateToolOutput(diffPreview);
|
|
17403
|
-
return truncateToolOutput(JSON.stringify(result, null, 2));
|
|
17429
|
+
if (diffPreview) return truncateToolOutput(diffPreview, context.sessionID);
|
|
17430
|
+
return truncateToolOutput(JSON.stringify(result, null, 2), context.sessionID);
|
|
17404
17431
|
}
|
|
17405
17432
|
});
|
|
17406
17433
|
export {
|
|
@@ -16238,6 +16238,48 @@ function tool(input) {
|
|
|
16238
16238
|
}
|
|
16239
16239
|
tool.schema = external_exports;
|
|
16240
16240
|
|
|
16241
|
+
// src/lib/model-context.ts
|
|
16242
|
+
var FALLBACK_MAX_OUTPUT_CHARS = 8e3;
|
|
16243
|
+
var MIN_BASE_MAX_OUTPUT_CHARS = 4e3;
|
|
16244
|
+
var MAX_BASE_OUTPUT_CHARS = 32e3;
|
|
16245
|
+
var MIN_PRESSURED_OUTPUT_CHARS = 1500;
|
|
16246
|
+
var sessionStates = /* @__PURE__ */ new Map();
|
|
16247
|
+
function getSessionState(sessionID) {
|
|
16248
|
+
if (!sessionID) return null;
|
|
16249
|
+
return sessionStates.get(sessionID) ?? null;
|
|
16250
|
+
}
|
|
16251
|
+
function getCompactionPressureFactor(compactionCount) {
|
|
16252
|
+
if (compactionCount >= 3) return 0.35;
|
|
16253
|
+
if (compactionCount === 2) return 0.5;
|
|
16254
|
+
if (compactionCount === 1) return 0.75;
|
|
16255
|
+
return 1;
|
|
16256
|
+
}
|
|
16257
|
+
function getBaseMaxOutputChars(contextTokens, fallback) {
|
|
16258
|
+
if (contextTokens === null) return fallback;
|
|
16259
|
+
const computed = Math.round(contextTokens * 0.01 * 4);
|
|
16260
|
+
return Math.max(MIN_BASE_MAX_OUTPUT_CHARS, Math.min(MAX_BASE_OUTPUT_CHARS, computed));
|
|
16261
|
+
}
|
|
16262
|
+
function buildTruncationSuffix(sessionID, maxChars) {
|
|
16263
|
+
const state = getSessionState(sessionID);
|
|
16264
|
+
if (!state || state.compactionCount === 0) {
|
|
16265
|
+
return `\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650`;
|
|
16266
|
+
}
|
|
16267
|
+
return `\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650\uFF1B\u5F53\u524D\u4F1A\u8BDD\u5DF2\u538B\u7F29 ${state.compactionCount} \u6B21\uFF0C\u5DF2\u81EA\u52A8\u6536\u7D27\u5DE5\u5177\u8F93\u51FA\u9884\u7B97`;
|
|
16268
|
+
}
|
|
16269
|
+
function getMaxOutputChars(sessionID, fallback = FALLBACK_MAX_OUTPUT_CHARS) {
|
|
16270
|
+
const state = getSessionState(sessionID);
|
|
16271
|
+
const base = getBaseMaxOutputChars(state?.contextTokens ?? null, fallback);
|
|
16272
|
+
const pressured = Math.round(base * getCompactionPressureFactor(state?.compactionCount ?? 0));
|
|
16273
|
+
return Math.max(MIN_PRESSURED_OUTPUT_CHARS, pressured);
|
|
16274
|
+
}
|
|
16275
|
+
function truncateToolOutput(content, sessionID, fallback = FALLBACK_MAX_OUTPUT_CHARS) {
|
|
16276
|
+
const maxChars = getMaxOutputChars(sessionID, fallback);
|
|
16277
|
+
if (content.length <= maxChars) return content;
|
|
16278
|
+
const truncated = content.slice(0, maxChars);
|
|
16279
|
+
return `${truncated}
|
|
16280
|
+
\x1B[2m... (${buildTruncationSuffix(sessionID, maxChars)})\x1B[0m`;
|
|
16281
|
+
}
|
|
16282
|
+
|
|
16241
16283
|
// src/lib/text-file.ts
|
|
16242
16284
|
var import_iconv_lite2 = __toESM(require_lib(), 1);
|
|
16243
16285
|
import crypto2 from "crypto";
|
|
@@ -16990,22 +17032,7 @@ async function replaceTextFileText(input) {
|
|
|
16990
17032
|
};
|
|
16991
17033
|
}
|
|
16992
17034
|
|
|
16993
|
-
// src/lib/model-context.ts
|
|
16994
|
-
var _currentContextTokens = null;
|
|
16995
|
-
function getMaxOutputChars(fallback = 8e3) {
|
|
16996
|
-
if (_currentContextTokens === null) return fallback;
|
|
16997
|
-
const computed = Math.round(_currentContextTokens * 0.01 * 4);
|
|
16998
|
-
return Math.max(4e3, Math.min(32e3, computed));
|
|
16999
|
-
}
|
|
17000
|
-
|
|
17001
17035
|
// src/tools/text_edit.ts
|
|
17002
|
-
function truncateToolOutput(content) {
|
|
17003
|
-
const maxChars = getMaxOutputChars();
|
|
17004
|
-
if (content.length <= maxChars) return content;
|
|
17005
|
-
const truncated = content.slice(0, maxChars);
|
|
17006
|
-
return truncated + `
|
|
17007
|
-
\x1B[2m... (\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
17008
|
-
}
|
|
17009
17036
|
var text_edit_default = tool({
|
|
17010
17037
|
description: `Edit text files with automatic encoding detection and preservation.
|
|
17011
17038
|
|
|
@@ -17056,8 +17083,8 @@ var text_edit_default = tool({
|
|
|
17056
17083
|
diffPreview
|
|
17057
17084
|
}
|
|
17058
17085
|
});
|
|
17059
|
-
if (diffPreview) return truncateToolOutput(diffPreview);
|
|
17060
|
-
return truncateToolOutput(JSON.stringify(result, null, 2));
|
|
17086
|
+
if (diffPreview) return truncateToolOutput(diffPreview, context.sessionID);
|
|
17087
|
+
return truncateToolOutput(JSON.stringify(result, null, 2), context.sessionID);
|
|
17061
17088
|
}
|
|
17062
17089
|
});
|
|
17063
17090
|
export {
|
package/dist/plugin/index.js
CHANGED
|
@@ -3816,6 +3816,100 @@ var require_lib = __commonJS({
|
|
|
3816
3816
|
}
|
|
3817
3817
|
});
|
|
3818
3818
|
|
|
3819
|
+
// src/lib/session-pressure.ts
|
|
3820
|
+
var AUTO_SUMMARIZE_PRESSURE_RATIO = 0.85;
|
|
3821
|
+
var AUTO_SUMMARIZE_COOLDOWN_MS = 6e4;
|
|
3822
|
+
var PRESSURE_CHECK_INTERVAL_MS = 15e3;
|
|
3823
|
+
var SESSION_PRESSURE_MESSAGE_LIMIT = 200;
|
|
3824
|
+
function estimateUnknownChars(value) {
|
|
3825
|
+
if (typeof value === "string") return value.length;
|
|
3826
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value).length;
|
|
3827
|
+
if (Array.isArray(value)) {
|
|
3828
|
+
return value.reduce((total, item) => total + estimateUnknownChars(item), 0);
|
|
3829
|
+
}
|
|
3830
|
+
if (!value || typeof value !== "object") return 0;
|
|
3831
|
+
try {
|
|
3832
|
+
return JSON.stringify(value).length;
|
|
3833
|
+
} catch {
|
|
3834
|
+
return 0;
|
|
3835
|
+
}
|
|
3836
|
+
}
|
|
3837
|
+
function estimateDiffChars(summary) {
|
|
3838
|
+
let chars = (summary.title?.length ?? 0) + (summary.body?.length ?? 0);
|
|
3839
|
+
for (const diff of summary.diffs ?? []) {
|
|
3840
|
+
chars += diff.file.length + diff.before.length + diff.after.length;
|
|
3841
|
+
}
|
|
3842
|
+
return chars;
|
|
3843
|
+
}
|
|
3844
|
+
function estimateToolPartChars(part) {
|
|
3845
|
+
let chars = part.tool.length + estimateUnknownChars(part.metadata);
|
|
3846
|
+
switch (part.state.status) {
|
|
3847
|
+
case "pending":
|
|
3848
|
+
chars += estimateUnknownChars(part.state.input) + part.state.raw.length;
|
|
3849
|
+
break;
|
|
3850
|
+
case "running":
|
|
3851
|
+
chars += estimateUnknownChars(part.state.input);
|
|
3852
|
+
chars += part.state.title?.length ?? 0;
|
|
3853
|
+
chars += estimateUnknownChars(part.state.metadata);
|
|
3854
|
+
break;
|
|
3855
|
+
case "completed":
|
|
3856
|
+
chars += estimateUnknownChars(part.state.input);
|
|
3857
|
+
chars += part.state.output.length + part.state.title.length;
|
|
3858
|
+
chars += estimateUnknownChars(part.state.metadata);
|
|
3859
|
+
break;
|
|
3860
|
+
case "error":
|
|
3861
|
+
chars += estimateUnknownChars(part.state.input);
|
|
3862
|
+
chars += part.state.error.length + estimateUnknownChars(part.state.metadata);
|
|
3863
|
+
break;
|
|
3864
|
+
}
|
|
3865
|
+
return chars;
|
|
3866
|
+
}
|
|
3867
|
+
function estimatePartChars(part) {
|
|
3868
|
+
switch (part.type) {
|
|
3869
|
+
case "text":
|
|
3870
|
+
return part.text.length;
|
|
3871
|
+
case "reasoning":
|
|
3872
|
+
return Math.round(part.text.length * 0.25);
|
|
3873
|
+
case "file":
|
|
3874
|
+
return (part.filename?.length ?? 0) + (part.source?.text.value.length ?? 0);
|
|
3875
|
+
case "tool":
|
|
3876
|
+
return estimateToolPartChars(part);
|
|
3877
|
+
case "step-start":
|
|
3878
|
+
return part.snapshot?.length ?? 0;
|
|
3879
|
+
case "step-finish":
|
|
3880
|
+
return part.reason.length + (part.snapshot?.length ?? 0);
|
|
3881
|
+
case "snapshot":
|
|
3882
|
+
return part.snapshot.length;
|
|
3883
|
+
case "patch":
|
|
3884
|
+
return part.hash.length + part.files.join("\n").length;
|
|
3885
|
+
case "agent":
|
|
3886
|
+
return part.name.length + (part.source?.value.length ?? 0);
|
|
3887
|
+
case "retry":
|
|
3888
|
+
return estimateUnknownChars(part.error);
|
|
3889
|
+
case "compaction":
|
|
3890
|
+
return 32;
|
|
3891
|
+
case "subtask":
|
|
3892
|
+
return part.prompt.length + part.description.length + part.agent.length;
|
|
3893
|
+
}
|
|
3894
|
+
}
|
|
3895
|
+
function estimateMessageChars(message, parts) {
|
|
3896
|
+
let chars = 0;
|
|
3897
|
+
if (message.role === "user") {
|
|
3898
|
+
chars += message.system?.length ?? 0;
|
|
3899
|
+
if (message.summary) {
|
|
3900
|
+
chars += estimateDiffChars(message.summary);
|
|
3901
|
+
}
|
|
3902
|
+
}
|
|
3903
|
+
for (const part of parts) {
|
|
3904
|
+
chars += estimatePartChars(part);
|
|
3905
|
+
}
|
|
3906
|
+
return chars;
|
|
3907
|
+
}
|
|
3908
|
+
function estimateSessionTokens(messages) {
|
|
3909
|
+
const totalChars = messages.reduce((total, message) => total + estimateMessageChars(message.info, message.parts), 0);
|
|
3910
|
+
return Math.ceil(totalChars / 4);
|
|
3911
|
+
}
|
|
3912
|
+
|
|
3819
3913
|
// node_modules/zod/v4/classic/external.js
|
|
3820
3914
|
var external_exports = {};
|
|
3821
3915
|
__export(external_exports, {
|
|
@@ -16238,6 +16332,132 @@ function tool(input) {
|
|
|
16238
16332
|
}
|
|
16239
16333
|
tool.schema = external_exports;
|
|
16240
16334
|
|
|
16335
|
+
// src/lib/model-context.ts
|
|
16336
|
+
var FALLBACK_MAX_OUTPUT_CHARS = 8e3;
|
|
16337
|
+
var MIN_BASE_MAX_OUTPUT_CHARS = 4e3;
|
|
16338
|
+
var MAX_BASE_OUTPUT_CHARS = 32e3;
|
|
16339
|
+
var MIN_PRESSURED_OUTPUT_CHARS = 1500;
|
|
16340
|
+
var sessionStates = /* @__PURE__ */ new Map();
|
|
16341
|
+
function getOrCreateSessionState(sessionID) {
|
|
16342
|
+
let state = sessionStates.get(sessionID);
|
|
16343
|
+
if (!state) {
|
|
16344
|
+
state = {
|
|
16345
|
+
contextTokens: null,
|
|
16346
|
+
compactionCount: 0,
|
|
16347
|
+
estimatedTokens: null,
|
|
16348
|
+
pressureRatio: null,
|
|
16349
|
+
lastPressureCheckedAt: null,
|
|
16350
|
+
autoSummarizeInFlight: false,
|
|
16351
|
+
lastAutoSummarizeAt: null,
|
|
16352
|
+
autoSummarizeCount: 0
|
|
16353
|
+
};
|
|
16354
|
+
sessionStates.set(sessionID, state);
|
|
16355
|
+
}
|
|
16356
|
+
return state;
|
|
16357
|
+
}
|
|
16358
|
+
function getSessionState(sessionID) {
|
|
16359
|
+
if (!sessionID) return null;
|
|
16360
|
+
return sessionStates.get(sessionID) ?? null;
|
|
16361
|
+
}
|
|
16362
|
+
function getCompactionPressureFactor(compactionCount) {
|
|
16363
|
+
if (compactionCount >= 3) return 0.35;
|
|
16364
|
+
if (compactionCount === 2) return 0.5;
|
|
16365
|
+
if (compactionCount === 1) return 0.75;
|
|
16366
|
+
return 1;
|
|
16367
|
+
}
|
|
16368
|
+
function getBaseMaxOutputChars(contextTokens, fallback) {
|
|
16369
|
+
if (contextTokens === null) return fallback;
|
|
16370
|
+
const computed = Math.round(contextTokens * 0.01 * 4);
|
|
16371
|
+
return Math.max(MIN_BASE_MAX_OUTPUT_CHARS, Math.min(MAX_BASE_OUTPUT_CHARS, computed));
|
|
16372
|
+
}
|
|
16373
|
+
function buildTruncationSuffix(sessionID, maxChars) {
|
|
16374
|
+
const state = getSessionState(sessionID);
|
|
16375
|
+
if (!state || state.compactionCount === 0) {
|
|
16376
|
+
return `\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650`;
|
|
16377
|
+
}
|
|
16378
|
+
return `\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650\uFF1B\u5F53\u524D\u4F1A\u8BDD\u5DF2\u538B\u7F29 ${state.compactionCount} \u6B21\uFF0C\u5DF2\u81EA\u52A8\u6536\u7D27\u5DE5\u5177\u8F93\u51FA\u9884\u7B97`;
|
|
16379
|
+
}
|
|
16380
|
+
function setCurrentContextTokens(sessionID, tokens) {
|
|
16381
|
+
if (!sessionID || tokens <= 0) return;
|
|
16382
|
+
const state = getOrCreateSessionState(sessionID);
|
|
16383
|
+
state.contextTokens = tokens;
|
|
16384
|
+
}
|
|
16385
|
+
function markSessionCompacted(sessionID) {
|
|
16386
|
+
if (!sessionID) return;
|
|
16387
|
+
const state = getOrCreateSessionState(sessionID);
|
|
16388
|
+
state.compactionCount += 1;
|
|
16389
|
+
state.estimatedTokens = null;
|
|
16390
|
+
state.pressureRatio = null;
|
|
16391
|
+
state.lastPressureCheckedAt = null;
|
|
16392
|
+
}
|
|
16393
|
+
function getSessionCompactionCount(sessionID) {
|
|
16394
|
+
return getSessionState(sessionID)?.compactionCount ?? 0;
|
|
16395
|
+
}
|
|
16396
|
+
function updateSessionPressure(sessionID, estimatedTokens, pressureRatio, checkedAt = Date.now()) {
|
|
16397
|
+
if (!sessionID) return;
|
|
16398
|
+
const state = getOrCreateSessionState(sessionID);
|
|
16399
|
+
state.estimatedTokens = estimatedTokens;
|
|
16400
|
+
state.pressureRatio = pressureRatio;
|
|
16401
|
+
state.lastPressureCheckedAt = checkedAt;
|
|
16402
|
+
}
|
|
16403
|
+
function clearSessionPressure(sessionID) {
|
|
16404
|
+
if (!sessionID) return;
|
|
16405
|
+
const state = getOrCreateSessionState(sessionID);
|
|
16406
|
+
state.estimatedTokens = null;
|
|
16407
|
+
state.pressureRatio = null;
|
|
16408
|
+
state.lastPressureCheckedAt = null;
|
|
16409
|
+
}
|
|
16410
|
+
function getSessionPressure(sessionID) {
|
|
16411
|
+
const state = getSessionState(sessionID);
|
|
16412
|
+
if (!state || state.estimatedTokens === null || state.pressureRatio === null || state.lastPressureCheckedAt === null) {
|
|
16413
|
+
return null;
|
|
16414
|
+
}
|
|
16415
|
+
return {
|
|
16416
|
+
estimatedTokens: state.estimatedTokens,
|
|
16417
|
+
pressureRatio: state.pressureRatio,
|
|
16418
|
+
checkedAt: state.lastPressureCheckedAt
|
|
16419
|
+
};
|
|
16420
|
+
}
|
|
16421
|
+
function isAutoSummarizeInFlight(sessionID) {
|
|
16422
|
+
return getSessionState(sessionID)?.autoSummarizeInFlight ?? false;
|
|
16423
|
+
}
|
|
16424
|
+
function markAutoSummarizeStarted(sessionID) {
|
|
16425
|
+
if (!sessionID) return;
|
|
16426
|
+
const state = getOrCreateSessionState(sessionID);
|
|
16427
|
+
state.autoSummarizeInFlight = true;
|
|
16428
|
+
}
|
|
16429
|
+
function markAutoSummarizeFinished(sessionID, summarized, finishedAt = Date.now()) {
|
|
16430
|
+
if (!sessionID) return;
|
|
16431
|
+
const state = getOrCreateSessionState(sessionID);
|
|
16432
|
+
state.autoSummarizeInFlight = false;
|
|
16433
|
+
if (summarized) {
|
|
16434
|
+
state.lastAutoSummarizeAt = finishedAt;
|
|
16435
|
+
state.autoSummarizeCount += 1;
|
|
16436
|
+
state.estimatedTokens = null;
|
|
16437
|
+
state.pressureRatio = null;
|
|
16438
|
+
state.lastPressureCheckedAt = null;
|
|
16439
|
+
}
|
|
16440
|
+
}
|
|
16441
|
+
function getLastAutoSummarizeAt(sessionID) {
|
|
16442
|
+
return getSessionState(sessionID)?.lastAutoSummarizeAt ?? null;
|
|
16443
|
+
}
|
|
16444
|
+
function getAutoSummarizeCount(sessionID) {
|
|
16445
|
+
return getSessionState(sessionID)?.autoSummarizeCount ?? 0;
|
|
16446
|
+
}
|
|
16447
|
+
function getMaxOutputChars(sessionID, fallback = FALLBACK_MAX_OUTPUT_CHARS) {
|
|
16448
|
+
const state = getSessionState(sessionID);
|
|
16449
|
+
const base = getBaseMaxOutputChars(state?.contextTokens ?? null, fallback);
|
|
16450
|
+
const pressured = Math.round(base * getCompactionPressureFactor(state?.compactionCount ?? 0));
|
|
16451
|
+
return Math.max(MIN_PRESSURED_OUTPUT_CHARS, pressured);
|
|
16452
|
+
}
|
|
16453
|
+
function truncateToolOutput(content, sessionID, fallback = FALLBACK_MAX_OUTPUT_CHARS) {
|
|
16454
|
+
const maxChars = getMaxOutputChars(sessionID, fallback);
|
|
16455
|
+
if (content.length <= maxChars) return content;
|
|
16456
|
+
const truncated = content.slice(0, maxChars);
|
|
16457
|
+
return `${truncated}
|
|
16458
|
+
\x1B[2m... (${buildTruncationSuffix(sessionID, maxChars)})\x1B[0m`;
|
|
16459
|
+
}
|
|
16460
|
+
|
|
16241
16461
|
// src/lib/gbk-file.ts
|
|
16242
16462
|
var import_iconv_lite = __toESM(require_lib(), 1);
|
|
16243
16463
|
import crypto from "crypto";
|
|
@@ -17610,25 +17830,7 @@ async function writeGbkFile(input) {
|
|
|
17610
17830
|
}
|
|
17611
17831
|
}
|
|
17612
17832
|
|
|
17613
|
-
// src/lib/model-context.ts
|
|
17614
|
-
var _currentContextTokens = null;
|
|
17615
|
-
function setCurrentContextTokens(tokens) {
|
|
17616
|
-
_currentContextTokens = tokens;
|
|
17617
|
-
}
|
|
17618
|
-
function getMaxOutputChars(fallback = 8e3) {
|
|
17619
|
-
if (_currentContextTokens === null) return fallback;
|
|
17620
|
-
const computed = Math.round(_currentContextTokens * 0.01 * 4);
|
|
17621
|
-
return Math.max(4e3, Math.min(32e3, computed));
|
|
17622
|
-
}
|
|
17623
|
-
|
|
17624
17833
|
// src/tools/gbk_edit.ts
|
|
17625
|
-
function truncateToolOutput(content) {
|
|
17626
|
-
const maxChars = getMaxOutputChars();
|
|
17627
|
-
if (content.length <= maxChars) return content;
|
|
17628
|
-
const truncated = content.slice(0, maxChars);
|
|
17629
|
-
return truncated + `
|
|
17630
|
-
\x1B[2m... (\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
17631
|
-
}
|
|
17632
17834
|
var gbk_edit_default = tool({
|
|
17633
17835
|
description: `Edit GBK/GB18030 encoded text files with exact string replacement.
|
|
17634
17836
|
|
|
@@ -17698,8 +17900,8 @@ Insert mode:
|
|
|
17698
17900
|
diffPreview
|
|
17699
17901
|
}
|
|
17700
17902
|
});
|
|
17701
|
-
if (diffPreview) return truncateToolOutput(diffPreview);
|
|
17702
|
-
return truncateToolOutput(JSON.stringify(result, null, 2));
|
|
17903
|
+
if (diffPreview) return truncateToolOutput(diffPreview, context.sessionID);
|
|
17904
|
+
return truncateToolOutput(JSON.stringify(result, null, 2), context.sessionID);
|
|
17703
17905
|
}
|
|
17704
17906
|
});
|
|
17705
17907
|
|
|
@@ -18765,13 +18967,6 @@ async function replaceTextFileText(input) {
|
|
|
18765
18967
|
}
|
|
18766
18968
|
|
|
18767
18969
|
// src/tools/text_edit.ts
|
|
18768
|
-
function truncateToolOutput2(content) {
|
|
18769
|
-
const maxChars = getMaxOutputChars();
|
|
18770
|
-
if (content.length <= maxChars) return content;
|
|
18771
|
-
const truncated = content.slice(0, maxChars);
|
|
18772
|
-
return truncated + `
|
|
18773
|
-
\x1B[2m... (\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
18774
|
-
}
|
|
18775
18970
|
var text_edit_default = tool({
|
|
18776
18971
|
description: `Edit text files with automatic encoding detection and preservation.
|
|
18777
18972
|
|
|
@@ -18822,8 +19017,8 @@ var text_edit_default = tool({
|
|
|
18822
19017
|
diffPreview
|
|
18823
19018
|
}
|
|
18824
19019
|
});
|
|
18825
|
-
if (diffPreview) return
|
|
18826
|
-
return
|
|
19020
|
+
if (diffPreview) return truncateToolOutput(diffPreview, context.sessionID);
|
|
19021
|
+
return truncateToolOutput(JSON.stringify(result, null, 2), context.sessionID);
|
|
18827
19022
|
}
|
|
18828
19023
|
});
|
|
18829
19024
|
|
|
@@ -18904,7 +19099,66 @@ var text_write_default = tool({
|
|
|
18904
19099
|
});
|
|
18905
19100
|
|
|
18906
19101
|
// src/plugin/index.ts
|
|
18907
|
-
|
|
19102
|
+
var MANAGED_TOOL_IDS = /* @__PURE__ */ new Set([
|
|
19103
|
+
"gbk_read",
|
|
19104
|
+
"gbk_write",
|
|
19105
|
+
"gbk_edit",
|
|
19106
|
+
"gbk_search",
|
|
19107
|
+
"text_read",
|
|
19108
|
+
"text_write",
|
|
19109
|
+
"text_edit"
|
|
19110
|
+
]);
|
|
19111
|
+
function truncateMetadataPreview(value, sessionID) {
|
|
19112
|
+
const previewMaxChars = Math.max(800, Math.min(2e3, Math.floor(getMaxOutputChars(sessionID) / 2)));
|
|
19113
|
+
if (value.length <= previewMaxChars) return value;
|
|
19114
|
+
const truncated = value.slice(0, previewMaxChars);
|
|
19115
|
+
return `${truncated}
|
|
19116
|
+
\x1B[2m... (metadata diffPreview \u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${previewMaxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
19117
|
+
}
|
|
19118
|
+
async function maybeAutoSummarizeSession(client, directory, input) {
|
|
19119
|
+
if (!client?.session?.messages || !client.session.summarize) return;
|
|
19120
|
+
if (isAutoSummarizeInFlight(input.sessionID)) return;
|
|
19121
|
+
const contextTokens = input.model.limit?.context;
|
|
19122
|
+
if (typeof contextTokens !== "number" || contextTokens <= 0) return;
|
|
19123
|
+
const now = Date.now();
|
|
19124
|
+
const lastAutoSummarizeAt = getLastAutoSummarizeAt(input.sessionID);
|
|
19125
|
+
if (lastAutoSummarizeAt !== null && now - lastAutoSummarizeAt < AUTO_SUMMARIZE_COOLDOWN_MS) {
|
|
19126
|
+
return;
|
|
19127
|
+
}
|
|
19128
|
+
let pressure = getSessionPressure(input.sessionID);
|
|
19129
|
+
if (!pressure || now - pressure.checkedAt >= PRESSURE_CHECK_INTERVAL_MS) {
|
|
19130
|
+
const response = await client.session.messages({
|
|
19131
|
+
path: { id: input.sessionID },
|
|
19132
|
+
query: {
|
|
19133
|
+
directory,
|
|
19134
|
+
limit: SESSION_PRESSURE_MESSAGE_LIMIT
|
|
19135
|
+
},
|
|
19136
|
+
throwOnError: true
|
|
19137
|
+
});
|
|
19138
|
+
const estimatedTokens = estimateSessionTokens(Array.isArray(response.data) ? response.data : []);
|
|
19139
|
+
const pressureRatio = estimatedTokens / contextTokens;
|
|
19140
|
+
updateSessionPressure(input.sessionID, estimatedTokens, pressureRatio, now);
|
|
19141
|
+
pressure = getSessionPressure(input.sessionID);
|
|
19142
|
+
}
|
|
19143
|
+
if (!pressure || pressure.pressureRatio < AUTO_SUMMARIZE_PRESSURE_RATIO) return;
|
|
19144
|
+
markAutoSummarizeStarted(input.sessionID);
|
|
19145
|
+
try {
|
|
19146
|
+
await client.session.summarize({
|
|
19147
|
+
path: { id: input.sessionID },
|
|
19148
|
+
body: {
|
|
19149
|
+
providerID: input.model.providerID,
|
|
19150
|
+
modelID: input.model.id
|
|
19151
|
+
},
|
|
19152
|
+
query: { directory },
|
|
19153
|
+
throwOnError: true
|
|
19154
|
+
});
|
|
19155
|
+
clearSessionPressure(input.sessionID);
|
|
19156
|
+
markAutoSummarizeFinished(input.sessionID, true);
|
|
19157
|
+
} catch {
|
|
19158
|
+
markAutoSummarizeFinished(input.sessionID, false);
|
|
19159
|
+
}
|
|
19160
|
+
}
|
|
19161
|
+
function createOpencodeGbkHooks(client, directory) {
|
|
18908
19162
|
return {
|
|
18909
19163
|
tool: {
|
|
18910
19164
|
gbk_read: gbk_read_default,
|
|
@@ -18915,21 +19169,63 @@ function createOpencodeGbkHooks() {
|
|
|
18915
19169
|
text_write: text_write_default,
|
|
18916
19170
|
text_edit: text_edit_default
|
|
18917
19171
|
},
|
|
19172
|
+
async event(input) {
|
|
19173
|
+
if (input.event.type === "session.compacted") {
|
|
19174
|
+
const sessionID = input.event.properties.sessionID;
|
|
19175
|
+
if (sessionID) {
|
|
19176
|
+
markSessionCompacted(sessionID);
|
|
19177
|
+
}
|
|
19178
|
+
}
|
|
19179
|
+
},
|
|
18918
19180
|
async "chat.params"(input) {
|
|
18919
19181
|
const contextTokens = input.model?.limit?.context;
|
|
18920
19182
|
if (typeof contextTokens === "number" && contextTokens > 0) {
|
|
18921
|
-
setCurrentContextTokens(contextTokens);
|
|
19183
|
+
setCurrentContextTokens(input.sessionID, contextTokens);
|
|
19184
|
+
await maybeAutoSummarizeSession(client, directory, input);
|
|
18922
19185
|
}
|
|
18923
19186
|
},
|
|
19187
|
+
async "tool.execute.after"(input, output) {
|
|
19188
|
+
if (!MANAGED_TOOL_IDS.has(input.tool)) return;
|
|
19189
|
+
const maxOutputChars = getMaxOutputChars(input.sessionID);
|
|
19190
|
+
const compactionCount = getSessionCompactionCount(input.sessionID);
|
|
19191
|
+
const sessionPressure = getSessionPressure(input.sessionID);
|
|
19192
|
+
const autoSummarizeCount = getAutoSummarizeCount(input.sessionID);
|
|
19193
|
+
const metadata = output.metadata && typeof output.metadata === "object" ? { ...output.metadata } : {};
|
|
19194
|
+
const nextOutput = truncateToolOutput(output.output, input.sessionID);
|
|
19195
|
+
if (nextOutput !== output.output) {
|
|
19196
|
+
metadata.outputTruncated = true;
|
|
19197
|
+
output.output = nextOutput;
|
|
19198
|
+
}
|
|
19199
|
+
if (typeof metadata.diffPreview === "string") {
|
|
19200
|
+
metadata.diffPreview = truncateMetadataPreview(metadata.diffPreview, input.sessionID);
|
|
19201
|
+
}
|
|
19202
|
+
metadata.maxOutputChars = maxOutputChars;
|
|
19203
|
+
if (compactionCount > 0) {
|
|
19204
|
+
metadata.sessionCompactions = compactionCount;
|
|
19205
|
+
}
|
|
19206
|
+
if (sessionPressure) {
|
|
19207
|
+
metadata.estimatedSessionTokens = sessionPressure.estimatedTokens;
|
|
19208
|
+
metadata.sessionPressureRatio = Number(sessionPressure.pressureRatio.toFixed(3));
|
|
19209
|
+
}
|
|
19210
|
+
if (autoSummarizeCount > 0) {
|
|
19211
|
+
metadata.autoSummarizeCount = autoSummarizeCount;
|
|
19212
|
+
}
|
|
19213
|
+
output.metadata = metadata;
|
|
19214
|
+
},
|
|
18924
19215
|
async "experimental.chat.system.transform"(_input, output) {
|
|
18925
19216
|
appendTextToolSystemPrompt(output.system);
|
|
19217
|
+
},
|
|
19218
|
+
async "experimental.session.compacting"(_input, output) {
|
|
19219
|
+
output.context.push(
|
|
19220
|
+
"Aggressively compress prior tool outputs. Keep only unresolved tasks, final decisions, exact file paths or line ranges, and the smallest snippets needed to continue. Drop repeated raw file content, full JSON payloads, verbose logs, and duplicated diff previews."
|
|
19221
|
+
);
|
|
18926
19222
|
}
|
|
18927
19223
|
};
|
|
18928
19224
|
}
|
|
18929
19225
|
var pluginModule = {
|
|
18930
19226
|
id: "opencode-gbk-tools",
|
|
18931
|
-
async server() {
|
|
18932
|
-
return createOpencodeGbkHooks();
|
|
19227
|
+
async server(ctx) {
|
|
19228
|
+
return createOpencodeGbkHooks(ctx.client, ctx.directory);
|
|
18933
19229
|
}
|
|
18934
19230
|
};
|
|
18935
19231
|
var plugin_default = pluginModule;
|
|
@@ -3816,6 +3816,100 @@ var require_lib = __commonJS({
|
|
|
3816
3816
|
}
|
|
3817
3817
|
});
|
|
3818
3818
|
|
|
3819
|
+
// src/lib/session-pressure.ts
|
|
3820
|
+
var AUTO_SUMMARIZE_PRESSURE_RATIO = 0.85;
|
|
3821
|
+
var AUTO_SUMMARIZE_COOLDOWN_MS = 6e4;
|
|
3822
|
+
var PRESSURE_CHECK_INTERVAL_MS = 15e3;
|
|
3823
|
+
var SESSION_PRESSURE_MESSAGE_LIMIT = 200;
|
|
3824
|
+
function estimateUnknownChars(value) {
|
|
3825
|
+
if (typeof value === "string") return value.length;
|
|
3826
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value).length;
|
|
3827
|
+
if (Array.isArray(value)) {
|
|
3828
|
+
return value.reduce((total, item) => total + estimateUnknownChars(item), 0);
|
|
3829
|
+
}
|
|
3830
|
+
if (!value || typeof value !== "object") return 0;
|
|
3831
|
+
try {
|
|
3832
|
+
return JSON.stringify(value).length;
|
|
3833
|
+
} catch {
|
|
3834
|
+
return 0;
|
|
3835
|
+
}
|
|
3836
|
+
}
|
|
3837
|
+
function estimateDiffChars(summary) {
|
|
3838
|
+
let chars = (summary.title?.length ?? 0) + (summary.body?.length ?? 0);
|
|
3839
|
+
for (const diff of summary.diffs ?? []) {
|
|
3840
|
+
chars += diff.file.length + diff.before.length + diff.after.length;
|
|
3841
|
+
}
|
|
3842
|
+
return chars;
|
|
3843
|
+
}
|
|
3844
|
+
function estimateToolPartChars(part) {
|
|
3845
|
+
let chars = part.tool.length + estimateUnknownChars(part.metadata);
|
|
3846
|
+
switch (part.state.status) {
|
|
3847
|
+
case "pending":
|
|
3848
|
+
chars += estimateUnknownChars(part.state.input) + part.state.raw.length;
|
|
3849
|
+
break;
|
|
3850
|
+
case "running":
|
|
3851
|
+
chars += estimateUnknownChars(part.state.input);
|
|
3852
|
+
chars += part.state.title?.length ?? 0;
|
|
3853
|
+
chars += estimateUnknownChars(part.state.metadata);
|
|
3854
|
+
break;
|
|
3855
|
+
case "completed":
|
|
3856
|
+
chars += estimateUnknownChars(part.state.input);
|
|
3857
|
+
chars += part.state.output.length + part.state.title.length;
|
|
3858
|
+
chars += estimateUnknownChars(part.state.metadata);
|
|
3859
|
+
break;
|
|
3860
|
+
case "error":
|
|
3861
|
+
chars += estimateUnknownChars(part.state.input);
|
|
3862
|
+
chars += part.state.error.length + estimateUnknownChars(part.state.metadata);
|
|
3863
|
+
break;
|
|
3864
|
+
}
|
|
3865
|
+
return chars;
|
|
3866
|
+
}
|
|
3867
|
+
function estimatePartChars(part) {
|
|
3868
|
+
switch (part.type) {
|
|
3869
|
+
case "text":
|
|
3870
|
+
return part.text.length;
|
|
3871
|
+
case "reasoning":
|
|
3872
|
+
return Math.round(part.text.length * 0.25);
|
|
3873
|
+
case "file":
|
|
3874
|
+
return (part.filename?.length ?? 0) + (part.source?.text.value.length ?? 0);
|
|
3875
|
+
case "tool":
|
|
3876
|
+
return estimateToolPartChars(part);
|
|
3877
|
+
case "step-start":
|
|
3878
|
+
return part.snapshot?.length ?? 0;
|
|
3879
|
+
case "step-finish":
|
|
3880
|
+
return part.reason.length + (part.snapshot?.length ?? 0);
|
|
3881
|
+
case "snapshot":
|
|
3882
|
+
return part.snapshot.length;
|
|
3883
|
+
case "patch":
|
|
3884
|
+
return part.hash.length + part.files.join("\n").length;
|
|
3885
|
+
case "agent":
|
|
3886
|
+
return part.name.length + (part.source?.value.length ?? 0);
|
|
3887
|
+
case "retry":
|
|
3888
|
+
return estimateUnknownChars(part.error);
|
|
3889
|
+
case "compaction":
|
|
3890
|
+
return 32;
|
|
3891
|
+
case "subtask":
|
|
3892
|
+
return part.prompt.length + part.description.length + part.agent.length;
|
|
3893
|
+
}
|
|
3894
|
+
}
|
|
3895
|
+
function estimateMessageChars(message, parts) {
|
|
3896
|
+
let chars = 0;
|
|
3897
|
+
if (message.role === "user") {
|
|
3898
|
+
chars += message.system?.length ?? 0;
|
|
3899
|
+
if (message.summary) {
|
|
3900
|
+
chars += estimateDiffChars(message.summary);
|
|
3901
|
+
}
|
|
3902
|
+
}
|
|
3903
|
+
for (const part of parts) {
|
|
3904
|
+
chars += estimatePartChars(part);
|
|
3905
|
+
}
|
|
3906
|
+
return chars;
|
|
3907
|
+
}
|
|
3908
|
+
function estimateSessionTokens(messages) {
|
|
3909
|
+
const totalChars = messages.reduce((total, message) => total + estimateMessageChars(message.info, message.parts), 0);
|
|
3910
|
+
return Math.ceil(totalChars / 4);
|
|
3911
|
+
}
|
|
3912
|
+
|
|
3819
3913
|
// node_modules/zod/v4/classic/external.js
|
|
3820
3914
|
var external_exports = {};
|
|
3821
3915
|
__export(external_exports, {
|
|
@@ -16238,6 +16332,132 @@ function tool(input) {
|
|
|
16238
16332
|
}
|
|
16239
16333
|
tool.schema = external_exports;
|
|
16240
16334
|
|
|
16335
|
+
// src/lib/model-context.ts
|
|
16336
|
+
var FALLBACK_MAX_OUTPUT_CHARS = 8e3;
|
|
16337
|
+
var MIN_BASE_MAX_OUTPUT_CHARS = 4e3;
|
|
16338
|
+
var MAX_BASE_OUTPUT_CHARS = 32e3;
|
|
16339
|
+
var MIN_PRESSURED_OUTPUT_CHARS = 1500;
|
|
16340
|
+
var sessionStates = /* @__PURE__ */ new Map();
|
|
16341
|
+
function getOrCreateSessionState(sessionID) {
|
|
16342
|
+
let state = sessionStates.get(sessionID);
|
|
16343
|
+
if (!state) {
|
|
16344
|
+
state = {
|
|
16345
|
+
contextTokens: null,
|
|
16346
|
+
compactionCount: 0,
|
|
16347
|
+
estimatedTokens: null,
|
|
16348
|
+
pressureRatio: null,
|
|
16349
|
+
lastPressureCheckedAt: null,
|
|
16350
|
+
autoSummarizeInFlight: false,
|
|
16351
|
+
lastAutoSummarizeAt: null,
|
|
16352
|
+
autoSummarizeCount: 0
|
|
16353
|
+
};
|
|
16354
|
+
sessionStates.set(sessionID, state);
|
|
16355
|
+
}
|
|
16356
|
+
return state;
|
|
16357
|
+
}
|
|
16358
|
+
function getSessionState(sessionID) {
|
|
16359
|
+
if (!sessionID) return null;
|
|
16360
|
+
return sessionStates.get(sessionID) ?? null;
|
|
16361
|
+
}
|
|
16362
|
+
function getCompactionPressureFactor(compactionCount) {
|
|
16363
|
+
if (compactionCount >= 3) return 0.35;
|
|
16364
|
+
if (compactionCount === 2) return 0.5;
|
|
16365
|
+
if (compactionCount === 1) return 0.75;
|
|
16366
|
+
return 1;
|
|
16367
|
+
}
|
|
16368
|
+
function getBaseMaxOutputChars(contextTokens, fallback) {
|
|
16369
|
+
if (contextTokens === null) return fallback;
|
|
16370
|
+
const computed = Math.round(contextTokens * 0.01 * 4);
|
|
16371
|
+
return Math.max(MIN_BASE_MAX_OUTPUT_CHARS, Math.min(MAX_BASE_OUTPUT_CHARS, computed));
|
|
16372
|
+
}
|
|
16373
|
+
function buildTruncationSuffix(sessionID, maxChars) {
|
|
16374
|
+
const state = getSessionState(sessionID);
|
|
16375
|
+
if (!state || state.compactionCount === 0) {
|
|
16376
|
+
return `\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650`;
|
|
16377
|
+
}
|
|
16378
|
+
return `\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650\uFF1B\u5F53\u524D\u4F1A\u8BDD\u5DF2\u538B\u7F29 ${state.compactionCount} \u6B21\uFF0C\u5DF2\u81EA\u52A8\u6536\u7D27\u5DE5\u5177\u8F93\u51FA\u9884\u7B97`;
|
|
16379
|
+
}
|
|
16380
|
+
function setCurrentContextTokens(sessionID, tokens) {
|
|
16381
|
+
if (!sessionID || tokens <= 0) return;
|
|
16382
|
+
const state = getOrCreateSessionState(sessionID);
|
|
16383
|
+
state.contextTokens = tokens;
|
|
16384
|
+
}
|
|
16385
|
+
function markSessionCompacted(sessionID) {
|
|
16386
|
+
if (!sessionID) return;
|
|
16387
|
+
const state = getOrCreateSessionState(sessionID);
|
|
16388
|
+
state.compactionCount += 1;
|
|
16389
|
+
state.estimatedTokens = null;
|
|
16390
|
+
state.pressureRatio = null;
|
|
16391
|
+
state.lastPressureCheckedAt = null;
|
|
16392
|
+
}
|
|
16393
|
+
function getSessionCompactionCount(sessionID) {
|
|
16394
|
+
return getSessionState(sessionID)?.compactionCount ?? 0;
|
|
16395
|
+
}
|
|
16396
|
+
function updateSessionPressure(sessionID, estimatedTokens, pressureRatio, checkedAt = Date.now()) {
|
|
16397
|
+
if (!sessionID) return;
|
|
16398
|
+
const state = getOrCreateSessionState(sessionID);
|
|
16399
|
+
state.estimatedTokens = estimatedTokens;
|
|
16400
|
+
state.pressureRatio = pressureRatio;
|
|
16401
|
+
state.lastPressureCheckedAt = checkedAt;
|
|
16402
|
+
}
|
|
16403
|
+
function clearSessionPressure(sessionID) {
|
|
16404
|
+
if (!sessionID) return;
|
|
16405
|
+
const state = getOrCreateSessionState(sessionID);
|
|
16406
|
+
state.estimatedTokens = null;
|
|
16407
|
+
state.pressureRatio = null;
|
|
16408
|
+
state.lastPressureCheckedAt = null;
|
|
16409
|
+
}
|
|
16410
|
+
function getSessionPressure(sessionID) {
|
|
16411
|
+
const state = getSessionState(sessionID);
|
|
16412
|
+
if (!state || state.estimatedTokens === null || state.pressureRatio === null || state.lastPressureCheckedAt === null) {
|
|
16413
|
+
return null;
|
|
16414
|
+
}
|
|
16415
|
+
return {
|
|
16416
|
+
estimatedTokens: state.estimatedTokens,
|
|
16417
|
+
pressureRatio: state.pressureRatio,
|
|
16418
|
+
checkedAt: state.lastPressureCheckedAt
|
|
16419
|
+
};
|
|
16420
|
+
}
|
|
16421
|
+
function isAutoSummarizeInFlight(sessionID) {
|
|
16422
|
+
return getSessionState(sessionID)?.autoSummarizeInFlight ?? false;
|
|
16423
|
+
}
|
|
16424
|
+
function markAutoSummarizeStarted(sessionID) {
|
|
16425
|
+
if (!sessionID) return;
|
|
16426
|
+
const state = getOrCreateSessionState(sessionID);
|
|
16427
|
+
state.autoSummarizeInFlight = true;
|
|
16428
|
+
}
|
|
16429
|
+
function markAutoSummarizeFinished(sessionID, summarized, finishedAt = Date.now()) {
|
|
16430
|
+
if (!sessionID) return;
|
|
16431
|
+
const state = getOrCreateSessionState(sessionID);
|
|
16432
|
+
state.autoSummarizeInFlight = false;
|
|
16433
|
+
if (summarized) {
|
|
16434
|
+
state.lastAutoSummarizeAt = finishedAt;
|
|
16435
|
+
state.autoSummarizeCount += 1;
|
|
16436
|
+
state.estimatedTokens = null;
|
|
16437
|
+
state.pressureRatio = null;
|
|
16438
|
+
state.lastPressureCheckedAt = null;
|
|
16439
|
+
}
|
|
16440
|
+
}
|
|
16441
|
+
function getLastAutoSummarizeAt(sessionID) {
|
|
16442
|
+
return getSessionState(sessionID)?.lastAutoSummarizeAt ?? null;
|
|
16443
|
+
}
|
|
16444
|
+
function getAutoSummarizeCount(sessionID) {
|
|
16445
|
+
return getSessionState(sessionID)?.autoSummarizeCount ?? 0;
|
|
16446
|
+
}
|
|
16447
|
+
function getMaxOutputChars(sessionID, fallback = FALLBACK_MAX_OUTPUT_CHARS) {
|
|
16448
|
+
const state = getSessionState(sessionID);
|
|
16449
|
+
const base = getBaseMaxOutputChars(state?.contextTokens ?? null, fallback);
|
|
16450
|
+
const pressured = Math.round(base * getCompactionPressureFactor(state?.compactionCount ?? 0));
|
|
16451
|
+
return Math.max(MIN_PRESSURED_OUTPUT_CHARS, pressured);
|
|
16452
|
+
}
|
|
16453
|
+
function truncateToolOutput(content, sessionID, fallback = FALLBACK_MAX_OUTPUT_CHARS) {
|
|
16454
|
+
const maxChars = getMaxOutputChars(sessionID, fallback);
|
|
16455
|
+
if (content.length <= maxChars) return content;
|
|
16456
|
+
const truncated = content.slice(0, maxChars);
|
|
16457
|
+
return `${truncated}
|
|
16458
|
+
\x1B[2m... (${buildTruncationSuffix(sessionID, maxChars)})\x1B[0m`;
|
|
16459
|
+
}
|
|
16460
|
+
|
|
16241
16461
|
// src/lib/gbk-file.ts
|
|
16242
16462
|
var import_iconv_lite = __toESM(require_lib(), 1);
|
|
16243
16463
|
import crypto from "crypto";
|
|
@@ -17610,25 +17830,7 @@ async function writeGbkFile(input) {
|
|
|
17610
17830
|
}
|
|
17611
17831
|
}
|
|
17612
17832
|
|
|
17613
|
-
// src/lib/model-context.ts
|
|
17614
|
-
var _currentContextTokens = null;
|
|
17615
|
-
function setCurrentContextTokens(tokens) {
|
|
17616
|
-
_currentContextTokens = tokens;
|
|
17617
|
-
}
|
|
17618
|
-
function getMaxOutputChars(fallback = 8e3) {
|
|
17619
|
-
if (_currentContextTokens === null) return fallback;
|
|
17620
|
-
const computed = Math.round(_currentContextTokens * 0.01 * 4);
|
|
17621
|
-
return Math.max(4e3, Math.min(32e3, computed));
|
|
17622
|
-
}
|
|
17623
|
-
|
|
17624
17833
|
// src/tools/gbk_edit.ts
|
|
17625
|
-
function truncateToolOutput(content) {
|
|
17626
|
-
const maxChars = getMaxOutputChars();
|
|
17627
|
-
if (content.length <= maxChars) return content;
|
|
17628
|
-
const truncated = content.slice(0, maxChars);
|
|
17629
|
-
return truncated + `
|
|
17630
|
-
\x1B[2m... (\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
17631
|
-
}
|
|
17632
17834
|
var gbk_edit_default = tool({
|
|
17633
17835
|
description: `Edit GBK/GB18030 encoded text files with exact string replacement.
|
|
17634
17836
|
|
|
@@ -17698,8 +17900,8 @@ Insert mode:
|
|
|
17698
17900
|
diffPreview
|
|
17699
17901
|
}
|
|
17700
17902
|
});
|
|
17701
|
-
if (diffPreview) return truncateToolOutput(diffPreview);
|
|
17702
|
-
return truncateToolOutput(JSON.stringify(result, null, 2));
|
|
17903
|
+
if (diffPreview) return truncateToolOutput(diffPreview, context.sessionID);
|
|
17904
|
+
return truncateToolOutput(JSON.stringify(result, null, 2), context.sessionID);
|
|
17703
17905
|
}
|
|
17704
17906
|
});
|
|
17705
17907
|
|
|
@@ -18765,13 +18967,6 @@ async function replaceTextFileText(input) {
|
|
|
18765
18967
|
}
|
|
18766
18968
|
|
|
18767
18969
|
// src/tools/text_edit.ts
|
|
18768
|
-
function truncateToolOutput2(content) {
|
|
18769
|
-
const maxChars = getMaxOutputChars();
|
|
18770
|
-
if (content.length <= maxChars) return content;
|
|
18771
|
-
const truncated = content.slice(0, maxChars);
|
|
18772
|
-
return truncated + `
|
|
18773
|
-
\x1B[2m... (\u8F93\u51FA\u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${maxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
18774
|
-
}
|
|
18775
18970
|
var text_edit_default = tool({
|
|
18776
18971
|
description: `Edit text files with automatic encoding detection and preservation.
|
|
18777
18972
|
|
|
@@ -18822,8 +19017,8 @@ var text_edit_default = tool({
|
|
|
18822
19017
|
diffPreview
|
|
18823
19018
|
}
|
|
18824
19019
|
});
|
|
18825
|
-
if (diffPreview) return
|
|
18826
|
-
return
|
|
19020
|
+
if (diffPreview) return truncateToolOutput(diffPreview, context.sessionID);
|
|
19021
|
+
return truncateToolOutput(JSON.stringify(result, null, 2), context.sessionID);
|
|
18827
19022
|
}
|
|
18828
19023
|
});
|
|
18829
19024
|
|
|
@@ -18904,7 +19099,66 @@ var text_write_default = tool({
|
|
|
18904
19099
|
});
|
|
18905
19100
|
|
|
18906
19101
|
// src/plugin/index.ts
|
|
18907
|
-
|
|
19102
|
+
var MANAGED_TOOL_IDS = /* @__PURE__ */ new Set([
|
|
19103
|
+
"gbk_read",
|
|
19104
|
+
"gbk_write",
|
|
19105
|
+
"gbk_edit",
|
|
19106
|
+
"gbk_search",
|
|
19107
|
+
"text_read",
|
|
19108
|
+
"text_write",
|
|
19109
|
+
"text_edit"
|
|
19110
|
+
]);
|
|
19111
|
+
function truncateMetadataPreview(value, sessionID) {
|
|
19112
|
+
const previewMaxChars = Math.max(800, Math.min(2e3, Math.floor(getMaxOutputChars(sessionID) / 2)));
|
|
19113
|
+
if (value.length <= previewMaxChars) return value;
|
|
19114
|
+
const truncated = value.slice(0, previewMaxChars);
|
|
19115
|
+
return `${truncated}
|
|
19116
|
+
\x1B[2m... (metadata diffPreview \u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${previewMaxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
19117
|
+
}
|
|
19118
|
+
async function maybeAutoSummarizeSession(client, directory, input) {
|
|
19119
|
+
if (!client?.session?.messages || !client.session.summarize) return;
|
|
19120
|
+
if (isAutoSummarizeInFlight(input.sessionID)) return;
|
|
19121
|
+
const contextTokens = input.model.limit?.context;
|
|
19122
|
+
if (typeof contextTokens !== "number" || contextTokens <= 0) return;
|
|
19123
|
+
const now = Date.now();
|
|
19124
|
+
const lastAutoSummarizeAt = getLastAutoSummarizeAt(input.sessionID);
|
|
19125
|
+
if (lastAutoSummarizeAt !== null && now - lastAutoSummarizeAt < AUTO_SUMMARIZE_COOLDOWN_MS) {
|
|
19126
|
+
return;
|
|
19127
|
+
}
|
|
19128
|
+
let pressure = getSessionPressure(input.sessionID);
|
|
19129
|
+
if (!pressure || now - pressure.checkedAt >= PRESSURE_CHECK_INTERVAL_MS) {
|
|
19130
|
+
const response = await client.session.messages({
|
|
19131
|
+
path: { id: input.sessionID },
|
|
19132
|
+
query: {
|
|
19133
|
+
directory,
|
|
19134
|
+
limit: SESSION_PRESSURE_MESSAGE_LIMIT
|
|
19135
|
+
},
|
|
19136
|
+
throwOnError: true
|
|
19137
|
+
});
|
|
19138
|
+
const estimatedTokens = estimateSessionTokens(Array.isArray(response.data) ? response.data : []);
|
|
19139
|
+
const pressureRatio = estimatedTokens / contextTokens;
|
|
19140
|
+
updateSessionPressure(input.sessionID, estimatedTokens, pressureRatio, now);
|
|
19141
|
+
pressure = getSessionPressure(input.sessionID);
|
|
19142
|
+
}
|
|
19143
|
+
if (!pressure || pressure.pressureRatio < AUTO_SUMMARIZE_PRESSURE_RATIO) return;
|
|
19144
|
+
markAutoSummarizeStarted(input.sessionID);
|
|
19145
|
+
try {
|
|
19146
|
+
await client.session.summarize({
|
|
19147
|
+
path: { id: input.sessionID },
|
|
19148
|
+
body: {
|
|
19149
|
+
providerID: input.model.providerID,
|
|
19150
|
+
modelID: input.model.id
|
|
19151
|
+
},
|
|
19152
|
+
query: { directory },
|
|
19153
|
+
throwOnError: true
|
|
19154
|
+
});
|
|
19155
|
+
clearSessionPressure(input.sessionID);
|
|
19156
|
+
markAutoSummarizeFinished(input.sessionID, true);
|
|
19157
|
+
} catch {
|
|
19158
|
+
markAutoSummarizeFinished(input.sessionID, false);
|
|
19159
|
+
}
|
|
19160
|
+
}
|
|
19161
|
+
function createOpencodeGbkHooks(client, directory) {
|
|
18908
19162
|
return {
|
|
18909
19163
|
tool: {
|
|
18910
19164
|
gbk_read: gbk_read_default,
|
|
@@ -18915,21 +19169,63 @@ function createOpencodeGbkHooks() {
|
|
|
18915
19169
|
text_write: text_write_default,
|
|
18916
19170
|
text_edit: text_edit_default
|
|
18917
19171
|
},
|
|
19172
|
+
async event(input) {
|
|
19173
|
+
if (input.event.type === "session.compacted") {
|
|
19174
|
+
const sessionID = input.event.properties.sessionID;
|
|
19175
|
+
if (sessionID) {
|
|
19176
|
+
markSessionCompacted(sessionID);
|
|
19177
|
+
}
|
|
19178
|
+
}
|
|
19179
|
+
},
|
|
18918
19180
|
async "chat.params"(input) {
|
|
18919
19181
|
const contextTokens = input.model?.limit?.context;
|
|
18920
19182
|
if (typeof contextTokens === "number" && contextTokens > 0) {
|
|
18921
|
-
setCurrentContextTokens(contextTokens);
|
|
19183
|
+
setCurrentContextTokens(input.sessionID, contextTokens);
|
|
19184
|
+
await maybeAutoSummarizeSession(client, directory, input);
|
|
18922
19185
|
}
|
|
18923
19186
|
},
|
|
19187
|
+
async "tool.execute.after"(input, output) {
|
|
19188
|
+
if (!MANAGED_TOOL_IDS.has(input.tool)) return;
|
|
19189
|
+
const maxOutputChars = getMaxOutputChars(input.sessionID);
|
|
19190
|
+
const compactionCount = getSessionCompactionCount(input.sessionID);
|
|
19191
|
+
const sessionPressure = getSessionPressure(input.sessionID);
|
|
19192
|
+
const autoSummarizeCount = getAutoSummarizeCount(input.sessionID);
|
|
19193
|
+
const metadata = output.metadata && typeof output.metadata === "object" ? { ...output.metadata } : {};
|
|
19194
|
+
const nextOutput = truncateToolOutput(output.output, input.sessionID);
|
|
19195
|
+
if (nextOutput !== output.output) {
|
|
19196
|
+
metadata.outputTruncated = true;
|
|
19197
|
+
output.output = nextOutput;
|
|
19198
|
+
}
|
|
19199
|
+
if (typeof metadata.diffPreview === "string") {
|
|
19200
|
+
metadata.diffPreview = truncateMetadataPreview(metadata.diffPreview, input.sessionID);
|
|
19201
|
+
}
|
|
19202
|
+
metadata.maxOutputChars = maxOutputChars;
|
|
19203
|
+
if (compactionCount > 0) {
|
|
19204
|
+
metadata.sessionCompactions = compactionCount;
|
|
19205
|
+
}
|
|
19206
|
+
if (sessionPressure) {
|
|
19207
|
+
metadata.estimatedSessionTokens = sessionPressure.estimatedTokens;
|
|
19208
|
+
metadata.sessionPressureRatio = Number(sessionPressure.pressureRatio.toFixed(3));
|
|
19209
|
+
}
|
|
19210
|
+
if (autoSummarizeCount > 0) {
|
|
19211
|
+
metadata.autoSummarizeCount = autoSummarizeCount;
|
|
19212
|
+
}
|
|
19213
|
+
output.metadata = metadata;
|
|
19214
|
+
},
|
|
18924
19215
|
async "experimental.chat.system.transform"(_input, output) {
|
|
18925
19216
|
appendTextToolSystemPrompt(output.system);
|
|
19217
|
+
},
|
|
19218
|
+
async "experimental.session.compacting"(_input, output) {
|
|
19219
|
+
output.context.push(
|
|
19220
|
+
"Aggressively compress prior tool outputs. Keep only unresolved tasks, final decisions, exact file paths or line ranges, and the smallest snippets needed to continue. Drop repeated raw file content, full JSON payloads, verbose logs, and duplicated diff previews."
|
|
19221
|
+
);
|
|
18926
19222
|
}
|
|
18927
19223
|
};
|
|
18928
19224
|
}
|
|
18929
19225
|
|
|
18930
19226
|
// src/local-plugin/opencode-gbk-tools.ts
|
|
18931
|
-
var OpencodeGbkToolsLocalPlugin = async () => {
|
|
18932
|
-
return createOpencodeGbkHooks();
|
|
19227
|
+
var OpencodeGbkToolsLocalPlugin = async (ctx) => {
|
|
19228
|
+
return createOpencodeGbkHooks(ctx.client, ctx.directory);
|
|
18933
19229
|
};
|
|
18934
19230
|
export {
|
|
18935
19231
|
OpencodeGbkToolsLocalPlugin
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifestVersion": 1,
|
|
3
3
|
"packageName": "opencode-gbk-tools",
|
|
4
|
-
"packageVersion": "0.1.
|
|
4
|
+
"packageVersion": "0.1.25",
|
|
5
5
|
"artifacts": [
|
|
6
6
|
{
|
|
7
7
|
"relativePath": "plugins/opencode-gbk-tools.js",
|
|
8
8
|
"kind": "plugin",
|
|
9
|
-
"expectedHash": "
|
|
9
|
+
"expectedHash": "55f2eae379bf3bd5a9129fbc413f255a4ffd9186d90a4fe26ecb3cc75b5a4c68",
|
|
10
|
+
"hashAlgorithm": "sha256"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"relativePath": "agents/gbk-engine.md",
|
|
14
|
+
"kind": "agent",
|
|
15
|
+
"expectedHash": "05a97cfe24d72339e45616638d0706d46c0d3782a3bfedefa1e59978adc5c3be",
|
|
10
16
|
"hashAlgorithm": "sha256"
|
|
11
17
|
}
|
|
12
18
|
]
|