此前截断分散在多层且互相冲突: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>
pi-overflow
Bounded display for oversized tool results. When a tool result exceeds
thresholdChars, pi-overflow persists the full original to disk and shows the
model a deterministic view — head lines, signal lines (error/fail/warn/…), and
tail lines — plus an overflow_query tool to search or read the stored
original by id.
Two-stage load order
capture.ts— first inpi.extensions. Atool_resulthandler that never modifies anything; it stashes the untouched original text inglobalThis[Symbol.for("my-pi.pi-overflow.stash.v1")](capacity 64) so the bound stage can still reach the pre-RTK original.index.ts— last content extension, right beforesystem-prompt.ts. Itstool_resulthandler sees the final text after every other handler (RTK semantic compaction included) has run, then:- resolves the original:
details.fullOutputPathfile (streamed, capped atmaxEntryByteshead+tail) → stashed raw text → current text; - if the current text still exceeds
thresholdChars, replaces it with the bounded view built from the stored file — line numbers and totals in the view are exactly whatoverflow_querywill read, even when RTK or bash already cut the in-context text (file sources are scanned line-by-line in a stream, never held in memory); - if the current text fits but the original did not (an earlier extension
already cut it), keeps the text and appends a one-line
[pi-overflow id=…]recovery marker; - preserves image parts and
structuredContent, and mergesdetails.overflow = { id, totalLines, totalBytes, truncated }into the existing details.
- resolves the original:
- Exempt tools (
read,edit,write,overflow_query,ask_user_question) and nested calls (parentToolCallId) are never touched.
Stored originals
<agentDir>/my-pi/pi-overflow/<id>.txt + <id>.json metadata, where
id = sha1(sessionId + "\0" + toolCallId)[0:12]. Directories are 0700,
files 0600, writes are atomic. session_start cleans entries older than
retentionDays and evicts oldest-first past maxStoreBytes.
overflow_query
id(required,^[0-9a-f]{12}$— path traversal safe)search— case-insensitive regex; hits come back withcontextlines and adjacent hits merge; capped bymaxResultslines: { start, end }— 1-based inclusive line rangejsonPath— dot/bracket path into stored JSON (a.b[3].c)- No selector → metadata + first-screen view. Output is always bounded by
thresholdCharsand reports whether it was truncated.
Configuration
config/pi-overflow.json inside the installed bundle. Every field is
validated independently and falls back to its default; an uncompilable
signalPattern falls back to the default pattern (case-insensitive).
Development
npm test # node --test test/*.test.ts
npm run check # strip-types syntax check + tests
Tests inject a temporary store root — they never write to a real agent directory.