mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-10-26 18:55:22 +00:00
此前截断分散在多层且互相冲突:Pi bash 保留尾部 50KB,RTK 兜底截断又只留 开头 12000 字符(砍掉报错与完整输出路径),pi-chrome 截开头 30K,web_fetch 各 provider 不一致。新扩展统一负责"新结果给模型看多少": - capture.ts 最先加载暂存原文,index.ts 最后加载(system-prompt 之前) - 超过 24K 字符时原文落盘 <agentDir>/my-pi/pi-overflow/(700/600、原子写), 优先取 bash fullOutputPath 完整文件;模型看到 头 + 中段信号行 + 尾 的有界 视图,行号基于落盘原文、结尾永远可见 - overflow_query:按 id 正则搜索、行区间、jsonPath 只读查询,id 校验防穿越 - 收编:RTK truncate 默认关闭、删除 pi-chrome truncateText、web_fetch 默认 每页 20000(上限 100000)、web_search max_results 限定 1–20 - pi-compaction 遮蔽带 details.overflow.id 的结果时在占位符提示 overflow_query - 登记 tools.jsonc / routing / 权限 allow / tool-search 常驻与分组 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
87 lines
3.5 KiB
TypeScript
87 lines
3.5 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { buildView, collectViewFromText } from "../src/view.ts";
|
|
import { readOverflowSettings, type OverflowSettings } from "../settings.ts";
|
|
|
|
function settings(overrides: Partial<OverflowSettings> = {}): OverflowSettings {
|
|
return {
|
|
...readOverflowSettings("/nonexistent/pi-overflow.json"),
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
const meta = { id: "abc123def456", tool: "bash" };
|
|
|
|
function view(text: string, s = settings()) {
|
|
return buildView(collectViewFromText(text, s), s, meta);
|
|
}
|
|
|
|
test("below threshold remains unchanged", () => {
|
|
const out = view("line one\nline two\nline three");
|
|
assert.ok(out.includes("line one"));
|
|
assert.ok(out.includes("line three"));
|
|
});
|
|
|
|
test("above threshold includes header, line ranges, signal lines and tail", () => {
|
|
const lines: string[] = [];
|
|
for (let i = 1; i <= 1000; i++) lines.push(`row ${i} ${i === 500 ? "ERROR boom" : "ok"}`);
|
|
const out = view(lines.join("\n"));
|
|
assert.match(out, /\[pi-overflow id=abc123def456 tool=bash 1000 lines/);
|
|
assert.match(out, /--- lines 1-40 ---/);
|
|
assert.match(out, /L500: row 500 ERROR boom/);
|
|
assert.match(out, /--- lines 881-1000 ---/);
|
|
assert.ok(out.includes("row 1000"));
|
|
});
|
|
|
|
test("output never exceeds thresholdChars", () => {
|
|
const lines = Array.from({ length: 5000 }, (_, i) => `line ${i} ${"x".repeat(60)}`);
|
|
const s = settings({ thresholdChars: 2000 });
|
|
const out = view(lines.join("\n"), s);
|
|
assert.ok(out.length <= 2000, `view ${out.length} exceeds budget`);
|
|
assert.ok(out.includes("line 4999"), "tail must survive");
|
|
});
|
|
|
|
test("few long lines still expose the ending", () => {
|
|
const lines = ["start", ...Array.from({ length: 5 }, (_, i) => `middle${i} ${"y".repeat(4000)}`), "THE_END_MARKER"];
|
|
const s = settings({ thresholdChars: 3000, headLines: 40, tailLines: 120 });
|
|
const out = view(lines.join("\n"), s);
|
|
assert.ok(out.includes("THE_END_MARKER"));
|
|
assert.ok(out.length <= 3000 + 100, `view ${out.length} far exceeds budget`);
|
|
});
|
|
|
|
test("same input produces identical output", () => {
|
|
const lines = Array.from({ length: 800 }, (_, i) => `entry ${i} ${i % 77 === 0 ? "warning" : "fine"}`);
|
|
const text = lines.join("\n");
|
|
assert.equal(view(text), view(text));
|
|
});
|
|
|
|
test("a single line over maxLineChars is truncated", () => {
|
|
const long = "z".repeat(2000);
|
|
const out = view(`a\n${long}\nb`, settings({ maxLineChars: 50 }));
|
|
assert.ok(out.includes("z".repeat(50) + "…"));
|
|
assert.ok(!out.includes("z".repeat(51)));
|
|
});
|
|
|
|
test("signals outrank head and survive when head+tail exceed the budget", () => {
|
|
// ~150-char lines: head 40 + tail 120 = 160 lines * 150 = ~24K plus
|
|
// overhead, over budget. Shrink order must keep some signals while head
|
|
// collapses to 10 lines before the 35/65 phase kicks in.
|
|
const lines = Array.from({ length: 400 }, (_, i) => {
|
|
const marker = i === 200 ? "ERROR detected here" : "ok";
|
|
return `line ${i + 1} ${marker} ${"x".repeat(140)}`;
|
|
});
|
|
const out = view(lines.join("\n"));
|
|
assert.match(out, /--- signals/);
|
|
assert.match(out, /L201: line 201 ERROR detected here/);
|
|
// head collapsed below the configured 40 lines
|
|
assert.match(out, /--- lines 1-(?:[0-9]|10) ---/);
|
|
assert.ok(out.includes("line 400"));
|
|
});
|
|
|
|
test("signal hits inside the tail region are not duplicated", () => {
|
|
const lines = Array.from({ length: 100 }, (_, i) => `line ${i + 1} ${"y".repeat(40)}`);
|
|
lines[99] = "line 100 tail-side ERROR";
|
|
const out = view(lines.join("\n"));
|
|
assert.ok(!out.includes("L100:"), "tail-region hit must not appear in signals");
|
|
});
|