fix(core): Support large text range reads - #6404
Conversation
Allow text reads to stream bounded line ranges for files larger than the previous 10MB guard, while preserving media size limits and forwarding cancellation through read_file/read_many_files/ACP paths. Refs #6403 Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
|
Thanks for the PR! (Updated on re-run — 5 new commits since last review.) Template looks good ✓ Problem: this is an observed bug — issue #6403 has a concrete error from a 15.30MB CI log rejected by the 10MB guard. Real user workflow blocked. Direction: aligned. Bounded range reads for large text files is standard tooling (Claude Code ships the same). The area is clearly in-scope for a CLI coding agent. Size: 639 production logic lines, 785 test lines, 0 generated/schema. Above the 500-line core-awareness threshold but this is a Approach: scope feels right for the goal. Five fixup commits since the initial review addressed all Moving on to code review. 🔍 中文说明感谢贡献!(Re-run 更新——自上次审查以来有 5 个新提交。) 模板完整 ✓ 问题:已观测到的 bug — issue #6403 中有具体的报错信息,一个 15.30MB 的 CI 日志被 10MB 限制拒绝。真实用户工作流被阻断。 方向:对齐。大文本文件的有界范围读取是标准工具能力(Claude Code 也有同样功能)。这个方向明显在 CLI 编码代理的职责范围内。 规模:639 行生产逻辑,785 行测试,0 行生成/schema。超过 500 行核心路径关注阈值,但这是 方案:范围合理。自上次审查以来的 5 个修复提交解决了所有 进入代码审查 🔍 — Qwen Code · qwen3.7-max |
There was a problem hiding this comment.
Pull request overview
This PR updates the core file-read pipeline so large text files can be read via bounded line-range windows (with truncation metadata) instead of failing the prior 10MB guard, while keeping existing size protections for non-text/media.
Changes:
- Added
readTextRange(small-file decode vs large-file streaming) to serve bounded line ranges from large UTF-8/UTF-8-compatible text files. - Updated core read flows (
processSingleFileContent,readManyFiles,read_file,FileSystemService) to support range reads, truncation markers/metadata, and AbortSignal propagation. - Expanded/updated test coverage across core + CLI (including ACP boundary conversion and
@attachments).
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/core/src/utils/readTextRange.ts | New range-read utility with fast-path decode and large-file streaming. |
| packages/core/src/utils/readTextRange.test.ts | Unit tests for range reads, CRLF/BOM handling, large-file streaming, and aborts. |
| packages/core/src/utils/readManyFiles.ts | Plumbs signal through batch reads and abort propagation. |
| packages/core/src/utils/readManyFiles.test.ts | Ensures large text files are included via truncation (not size error). |
| packages/core/src/utils/pathReader.test.ts | Updates expectation: large text reads truncate instead of failing at 10MB. |
| packages/core/src/utils/fileUtils.ts | Switches text reads to bounded range reads; adds truncation metadata handling + abort plumbing. |
| packages/core/src/utils/fileUtils.test.ts | Updates tests for large text handling and preserves media size gating. |
| packages/core/src/tools/read-file.ts | Passes AbortSignal through read_file execution path. |
| packages/core/src/tools/read-file.test.ts | Validates large text truncation behavior and abort propagation. |
| packages/core/src/services/fileSystemService.ts | Introduces CoreReadTextFileRequest (0-based line offsets) and threads maxOutputBytes/signal. |
| packages/core/src/services/fileSystemService.test.ts | Tests byte-truncation metadata passthrough and maxOutputBytes forwarding. |
| packages/cli/src/ui/hooks/atCommandProcessor.test.ts | Ensures @ attachments can include truncated large text files. |
| packages/cli/src/serve/fs/policy.ts | Updates docs to reflect bounded reads vs full-snapshot behavior. |
| packages/cli/src/acp-integration/service/filesystem.ts | Converts core-only read params at ACP boundary (0-based → 1-based). |
| packages/cli/src/acp-integration/service/filesystem.test.ts | Tests ACP boundary conversion and fallback forwarding of core-only params. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Code Review (re-run — 5 fixup commits addressed prior feedback)The five fixup commits since the initial review are well-targeted:
The The No correctness bugs, no security issues, no AGENTS.md violations found. Unit TestsAll pass from the worktree:
Total: 394/394 tests pass. Build and typecheck both clean. Real-Scenario TestingCreated a 15MB CI pipeline log (100,000 lines) at Before (installed qwen v0.19.1)The installed version served the read (the model used After (PR code via
|
|
This is a well-executed fix that's been through several rounds of review and iteration. The author addressed every The problem is real (15.30MB CI logs rejected outright), the solution is the minimal change needed (new streaming reader + one-line gate relaxation + boundary conversion), and the test coverage is thorough — 394 unit tests plus real-scenario confirmation with a 15MB file on both the installed build and the PR code. The implementation makes the right tradeoffs: fast path for <10MB files (reuse existing reader), streaming path for ≥10MB UTF-8 files (bounded memory), clear error for large non-UTF-8 files. The ACP boundary conversion is explicit about what the protocol can't represent. The The maintainer has already approved. LGTM. ✅ 中文说明这是一个经过多轮审查迭代的良好修复。作者通过 5 个针对性修复提交解决了所有 问题真实(15.30MB CI 日志被直接拒绝),解决方案是最小化改动(新的流式读取器 + 一行限制放宽 + 边界转换),测试覆盖充分——394 个单元测试加真实场景确认。维护者已批准。LGTM. ✅ — Qwen Code · qwen3.7-max |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Suggestions — commit
|
| File | Issue | Suggested fix |
|---|---|---|
readTextRange.ts:9 + fileUtils.ts:26 |
Circular module dependency: readTextRange.ts imports from fileUtils.ts and vice versa. Works at runtime under ESM live bindings but fragile if either module adds top-level initialization. |
Extract detectFileEncoding and readFileWithEncodingInfo into a shared low-level module (e.g., fileEncoding.ts) that both import from. |
filesystem.ts:108 (ACP) |
toAcpReadTextFileRequest silently drops maxOutputBytes and signal when converting to ACP protocol. Remote ACP reads have no byte budget and no cancellation propagation. |
Document this limitation in a code comment. If the ACP protocol can be extended, add maxOutputBytes to the schema. |
fileUtils.ts:1114 |
countFileLines fallback loads the entire file via readFileWithEncodingInfo. Any FileSystemService that omits originalLineCount from _meta would trigger full-file read on >10MB files. |
Add a comment documenting that originalLineCount MUST be populated for files >10MB, or skip countFileLines when file size exceeds the threshold. |
readTextRange.ts:70 |
The fallback byte limit 25_000 is repeated as a magic number in three places across two files (readTextRange.ts:70, fileUtils.ts:307, fileUtils.ts:1329). |
Extract a shared constant (e.g., DEFAULT_RANGE_READ_MAX_BYTES = 25_000) to prevent drift. |
— qwen3.7-max via Qwen Code /review
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Code Coverage Summary
CLI Package - Full Text ReportCore Package - Full Text ReportFor detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run. |
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Review Summary
This PR adds a streaming range reader for large text files (>10MB), replacing the hard size rejection with bounded line-range reads. The architecture is sound — small/large split, UTF-8 streaming with byte budget, and proper signal forwarding.
3 Critical issues need attention before merge:
- Untested
truncatedByBytesbranch in artifact-tool — new error path has no test coverage. - Mid-stream abort untested —
throwIfAborted()inside the streaming loop is a new behavioral path without a test. - No hard streaming cap for large text files — the 10MB guard is relaxed for text files, but the streaming reader can still process the entire file (e.g., for line counting) without a byte-level safety net.
6 Suggestions cover redundant syscalls, missing debug logging, a misleading line-count fallback, untested abort propagation, a cross-chunk CRLF test gap, and a missing signal in readDirectory.
— qwen3.7-max via Qwen Code /review
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Pass artifact execution abort signals into source file reads and preserve cancellation semantics when the read is aborted. Add regression coverage for unbounded large UTF-8 range reads and offsets beyond EOF. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
wenshao
left a comment
There was a problem hiding this comment.
No review findings. LGTM! ✅
— qwen3.7-max via Qwen Code /review
|
@qwen-code /triage |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM on re-run — 5 fixup commits addressed all prior feedback. 394/394 tests pass, build and typecheck clean, real-scenario test confirms 15MB file reads correctly. ✅
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
|
@qwen-code /resolve |
1 similar comment
|
@qwen-code /resolve |
Combine PR's AbortSignal forwarding with main's largePdfBehavior: - fileUtils.ts: keep both signal and largePdfBehavior interface fields and destructuring; retain main's PDF page-range size checks and full-text fallback gate; apply PR's fileType !== 'text' refinement to the generic 10MB size guard - readManyFiles.ts: pass both signal and largePdfBehavior: 'reference' to processSingleFileContent
|
Qwen Code resolved the merge conflicts and pushed the branch update. Merge Conflict Resolution Summary — PR #6404Base branch
Conflicted files
Root causePR #6404 added Resolution per conflictfileUtils.ts — conflict 1 (interface definition)
fileUtils.ts — conflict 2 (destructuring)
fileUtils.ts — conflict 3 (file-size guard logic)
readManyFiles.ts — conflict (options passed to processSingleFileContent)
|
|
Qwen Code did not run conflict resolution for this request. PR #6404 does not currently have merge conflicts with main. |
🔬 Runtime verification — large text range readsI built PR HEAD ( ❌ Blocking regression:
|
| # | Finding | Anchor | Status |
|---|---|---|---|
| 1 | edit/write/notebook ≥10 MB hard‑fail |
fileUtils.ts:331‑332 |
❌ OPEN — reproduced (above) |
| 2 | Non‑UTF‑8 corruption past the 8 KB detection sample | read-text-range.ts:124 |
✅ Fixed — fatal TextDecoder now throws LargeNonUtf8TextError. Reproduced GPT‑5’s exact case (12 KB ASCII prefix + GBK bytes, 11 MB) → throws, no U+FFFD |
| 3 | Unbounded scan for bounded reads | read-text-range.ts:171 |
✅ Fixed — reading lines 1‑10 of a 60 MB file returns in 3.3 ms, originalLineCount=11 (early break; author’s defense holds) |
| 4 | Disabled truncation → 25 KB cap | fileUtils.ts:1371 |
✅ Fixed — Infinity now preserved through getRangeReadByteLimit |
| 5 | maxOutputBytes ignored without a finite limit |
fileUtils.ts:318 |
✅ Fixed — routing condition now includes maxOutputBytes !== undefined |
Merge readiness
⚠️ PR is currently CONFLICTING withmain— needs a rebase.- ✅ PR’s new suite is green locally (
read-text-range.test.ts13/13). - ℹ️ Confirmed on Linux (PR test matrix lists macOS only).
How this was verified (method)
- Two worktrees: PR
ed5b9efb1and merge‑basecb4963336;node_modulessymlinked from the main checkout. - Harnesses run with
tsxdirectly against each worktree'ssrc(the file‑read modules use relative imports, so there is no@qwen-code/qwen-code-coreself‑import — the code under test is the actual PR/base source, revert‑proof). - Real
StandardFileSystemService,EditTool,ReadFileTool, andFileReadCache. TheConfigis the same accessor‑bag mock the repo's ownedit.test.tsuses (which itself drives a realStandardFileSystemService+ realFileReadCache). - Layer 2 runs with the read‑cache disabled to reach the read directly; Layer 3 runs with the cache enabled and a real
read_filefirst, to prove the prior‑read gate doesn't save it.
Full raw transcript
LAYER 1 — core readTextFile({ path }) on an 11MB log
BASE main@cb4963336 : [OK] readTextFile({ path }) on 11MB log -> content 11534336 chars
PR #6404 ed5b9efb1: [THROW] readTextFile({ path }) on 11MB log -> Error: File too large for full read (11534336 bytes). Use offset/limit to read a range.
(PR range reads still work: {limit:50} -> 51 lines; {maxOutputBytes:25000} -> 25000 chars truncatedByBytes:true)
LAYER 2 — REAL EditTool.execute() on an 11MB file
BASE : tool SUCCEEDED — first line = "CONFIG version=2 build=beta", size after = 11.00 MB (tail preserved: YES)
PR : tool FAILED — error.type = edit_preparation_failure
error.message = File too large for full read (11534396 bytes). Use offset/limit to read a range.
LAYER 3 — REALISTIC cache-ENABLED flow on PR (real read_file -> real edit)
STEP 1 read_file -> error=none returnDisplay="Read lines 1-1032 of at least 2001 from app.log (truncated)"
cache entry = state:fresh cacheable:true full:false
STEP 2 edit -> FAILED edit_preparation_failure: File too large for full read (11534396 bytes)...
file first line unchanged: "CONFIG version=1 build=alpha"
LAYER 4 — status of two fixed Criticals
(B) non-UTF-8 (11.03MB, 12KB ASCII prefix + GBK): THREW LargeNonUtf8TextError (fix works)
(C) bounded read of 60MB file, lines 1-10: originalLineCount=11 exact=false in 3.3 ms (early stop; defense holds)
🇨🇳 中文版(合并参考)
我在本地从源码分别构建了 PR HEAD(ed5b9efb1)与 base(main@cb4963336),并在 Linux(PR 标注为“未测试”的系统;Node v22.22.2)上驱动了真实的读取/编辑链路。功能本身可用,5 个 fixup 提交也修掉了绝大多数预先标注的 Critical。但仍有一个阻断性回归,并且我端到端复现了它 —— 这印证了 fileUtils.ts:331‑332 上已标注的 Critical。
❌ 阻断性回归:edit / write_file / notebook_edit 对任何 ≥ 10 MB 的文本文件硬失败
readFileWithLineAndLimit 为“完整快照”读取路径新增了一个 guard(fileUtils.ts:331):文件 ≥ 10 MB 时 throw new Error("File too large for full read ...")。当 limit 为 ∞ 且 maxOutputBytes 为 undefined 时触发 —— 而这正是所有写入类工具的调用方式:edit.ts:199、write-file.ts:179/317、notebook-edit.ts:489、shell.ts:1588 都以 readTextFile({ path }) 调用,且它们的 catch 只吞掉 ENOENT,因此异常会向上抛给用户。
- Layer 1(核心调用 base vs PR):11MB 日志上
readTextFile({ path })—— BASE 返回[OK] 11534336 字符;PR[THROW] File too large for full read。 - Layer 2(真实 EditTool):编辑同一个 11MB 文件的一行 —— BASE 成功(首行被改、11MB 尾部保留);PR 失败
edit_preparation_failure。 - Layer 3(真实场景,缓存开启,未禁用任何东西):先
read_file(成功,返回截断范围,cacheable:true),再edit—— 仍然 失败。checkPriorRead依据的是lastReadCacheable而非lastReadWasFull,所以截断读取能通过 prior‑read 校验,但随后edit自己的完整读取又抛异常。没有任何恢复路径:≥ 10 MB 的文本文件彻底无法编辑。
范围:edit、write_file、notebook_edit 均硬失败(已确认);shell 的 sed -i 部分受影响(交互确认路径会退化成原始 shell 命令,非交互执行路径返回硬错误 READ_CONTENT_FAILURE)。
这是行为回归:本 PR 之前,这些工具会把整文件读入内存(仅受内存限制)并正常工作 —— Layer 2 显示 base 能成功编辑同一个 11MB 文件。(本 PR 更早的修订版会给 edit 一份被截断的 25KB 快照 → 静默写回造成数据丢失;当前 guard 用抛异常来堵住它 —— 即用“硬失败”换掉了“静默数据丢失”。数据丢失被消除是好事,但硬失败仍然阻断了原本可用的工作流。)
建议方向:把这个 throw 限定为“调用方明确要求有界读取”时才触发(即加上 maxOutputBytes !== undefined 条件),让需要整文件的写入类调用方继续工作;或者,如果 ≥ 10 MB 的编辑限制是有意为之,则给出一个符合“编辑”语境的明确拒绝信息(而不是 “use offset/limit”,编辑根本无法照做),并把它作为 breaking change 写进文档 + 补测试。目前 没有任何测试覆盖 edit/write_file 在 ≥ 10 MB 文件上的行为,这也是它能绿着通过 CI 的原因。
✅ 其余预先标注的 Critical 已修复(均已运行时复核)
| # | 问题 | 位置 | 状态 |
|---|---|---|---|
| 1 | edit/write/notebook ≥10MB 硬失败 |
fileUtils.ts:331‑332 |
❌ 未解决 —— 已复现 |
| 2 | 超过 8KB 检测样本后的非 UTF‑8 损坏 | read-text-range.ts:124 |
✅ 已修 —— fatal TextDecoder 现在抛 LargeNonUtf8TextError;已复现 GPT‑5 的原始场景(12KB ASCII 前缀 + GBK),抛异常、无 U+FFFD |
| 3 | 有界读取却全量扫描 | read-text-range.ts:171 |
✅ 已修 —— 60MB 文件读取 1‑10 行,3.3ms 返回、originalLineCount=11(提前 break,作者的辩护成立) |
| 4 | 禁用截断却退回 25KB 上限 | fileUtils.ts:1371 |
✅ 已修 —— Infinity 现已被 getRangeReadByteLimit 正确保留 |
| 5 | 无有限 limit 时 maxOutputBytes 被忽略 |
fileUtils.ts:318 |
✅ 已修 —— 路由条件已包含 maxOutputBytes !== undefined |
合并就绪度
⚠️ PR 目前与main冲突(CONFLICTING),需要 rebase。- ✅ 本地 PR 新增用例通过(
read-text-range.test.ts13/13)。 - ℹ️ 本次在 Linux 验证(PR 测试矩阵仅列了 macOS)。
Independent runtime verification, built from source on Linux · base cb4963336 vs PR ed5b9efb1.
Allow default unbounded readTextFile calls to keep reading full large text files so mutation tools can prepare complete snapshots after a prior ranged read. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
🔬 Re-verification — the blocking regression is resolved ✅Re-ran the same harnesses after The regression is fixed — and, critically, no data loss was reintroduced (the real risk when un-doing the throw: Layer 1 — Layer 2 — real Layer 3 — realistic cache-enabled flow (
Status vs. the prior review
Minor, non-blocking: with the guard gone, unbounded mutation reads are memory-bound again — but that's exactly the pre-PR behavior (base loads the whole file too), so it's not a new risk, just no upper bound on From the runtime side this now LGTM — every finding from the previous verification is addressed. Raw transcript🇨🇳 中文版在 阻断性回归已修复 —— 且关键是没有重新引入数据丢失(撤销 throw 时的真正风险:
次要、非阻断:guard 移除后,无界的写入类读取又变回受内存限制 —— 但这正是本 PR 之前的行为(base 也是整文件读入),并非新增风险,只是对超大文件的 从运行时角度,现在 LGTM —— 上一轮验证中的所有问题均已解决。 Independent runtime re-verification · base |
Build Failure Analysis / 构建失败分析The CI failure is not related to the PR's code changes — it's a transient CI infrastructure issue. CI 失败与本 PR 的代码改动无关 — 属于 CI 基础设施的临时性问题。 Root Cause / 根因🔍 详细分析 (点击展开)Test (ubuntu-latest, Node 22.x) 在 下载 shellcheck 时 Post Coverage Comment 失败是因为测试 job 未产出 coverage artifact,属于级联失败。 建议操作
Recommended ActionRe-run the failed jobs — this should pass on retry since it's a network connectivity issue, not a code defect. |
yiliang114
left a comment
There was a problem hiding this comment.
Thanks for iterating on this. The core fix makes sense to me: supporting bounded reads for large text files necessarily touches the text reader, FileSystemService, read_file display metadata, and the tests around truncation / non-UTF-8 / mutation safety.
These are non-blocking scope comments. I don't think they should block this PR once the code and CI are otherwise good; the main ask is to keep future core read-path fixes smaller and easier to review.
The current PR also includes a few follow-up-level cleanups, such as stats threading, artifact read cancellation, and broader readManyFiles abort propagation. They are reasonable changes individually, but they make the bugfix harder to review as one unit. If we still want to reduce this PR's risk before merge, the first things I would move out are artifact cancellation and stats threading.
| line?: number | null; | ||
| maxOutputBytes?: number; | ||
| signal?: AbortSignal; | ||
| stats?: Stats; |
There was a problem hiding this comment.
Non-blocking scope note: maxOutputBytes and signal are part of the large-text read behavior, but stats feels more like an internal optimization / TOCTOU cleanup than part of the public FileSystemService read contract.
Could we keep the main PR focused on the large-text range behavior and either avoid threading stats through this shared request type, or split that optimization into a follow-up? The current version is understandable, but it broadens the service API beyond the core bugfix.
| .readTextFile({ path: file_path }); | ||
| .readTextFile({ | ||
| path: file_path, | ||
| maxOutputBytes: MAX_ARTIFACT_BYTES, |
There was a problem hiding this comment.
Non-blocking scope note: forwarding cancellation here is a good cleanup, but artifact publishing is not directly part of the large text read_file failure fixed by this PR.
This might be easier to review as a small follow-up PR. Keeping this PR limited to text range reads would make the risk surface clearer, especially since the main change already touches the core read pipeline.
| const projectRoot = config.getProjectRoot(); | ||
|
|
||
| for (const rawPattern of inputPatterns) { | ||
| signal?.throwIfAborted(); |
There was a problem hiding this comment.
Non-blocking scope note: the abort propagation is directionally right, but it is another cross-cutting behavior change on top of the large-file read fix.
If we want to keep this PR minimal, I would consider moving the readManyFiles cancellation cleanup into a follow-up. The essential path for #6403 is bounded text reads; broader cancellation consistency can land separately.
yiliang114
left a comment
There was a problem hiding this comment.
LGTM from a code review perspective. The main large-text range read path looks sound now, and the previous mutation-read/data-loss concerns have been addressed.
I left a few non-blocking scope comments about keeping future core read-path fixes smaller, but I don't think those should block this PR. The remaining failing check appears to be an infrastructure download timeout during linter setup, so it should be rerun before merge.
What this PR does
This PR teaches text reads to serve bounded line ranges from large files instead of rejecting every text file above the previous 10MB guard. It adds a small/large split for text range reads, preserves encoding and line-ending metadata where possible, forwards cancellation through read_file, read_many_files, and ACP-backed reads, and keeps binary, image, audio, video, and PDF size protections intact.
Why it's needed
Users can hit a hard failure when asking Qwen Code to analyze CI logs or other plain-text artifacts larger than 10MB. The linked report shows a 15.30MB unit-test log rejected before the model can inspect any useful lines. Returning a bounded range gives the model enough context to proceed while keeping memory and output size controlled.
Reviewer Test Plan
How to verify
Run
npm run buildandnpm run typecheckfrom the repository root; both should exit 0. Frompackages/core, runnpx vitest run src/utils/readTextRange.test.ts src/utils/fileUtils.test.ts src/services/fileSystemService.test.ts src/tools/read-file.test.ts src/utils/readManyFiles.test.ts src/utils/pathReader.test.ts; all 263 tests should pass. Frompackages/cli, runnpx vitest run src/ui/hooks/atCommandProcessor.test.ts src/acp-integration/service/filesystem.test.ts; all 91 tests should pass. Reviewers can also create a text file larger than 10MB and confirmread_filewith default settings returns a marked line range rather thanFILE_TOO_LARGE, while large media files still return the existing size-limit error.Evidence (Before & After)
Before: attaching or reading a 15.30MB text log failed with
File size exceeds the 10MB limit, which prevented CI-log analysis. After: covered large-text range reads return bounded text with truncation metadata, defaultread_fileoutput identifies the displayed line range, and explicit offset/limit requests are served without reading the full file into memory. Local evidence is the passing build, typecheck, and targeted tests listed above.Tested on
Environment (optional)
macOS 26.4.1, Node.js v22.22.3, npm 10.9.8.
Risk & Scope
file_unchangeddeduplication, and Claude-style line-numbered output are intentionally left out.Linked Issues
Closes #6403
中文说明
What this PR does
这个 PR 让文本读取在遇到大文件时返回有界的行范围,而不是因为文件超过之前的 10MB 限制就直接拒绝。它为文本范围读取增加了小文件和大文件两条路径,在可行时保留编码和换行元数据,把取消信号传递到 read_file、read_many_files 和 ACP 文件读取链路,并保持二进制、图片、音频、视频和 PDF 的既有大小保护不变。
Why it's needed
当用户让 Qwen Code 分析 CI 日志或其他超过 10MB 的纯文本产物时,当前行为可能直接失败。关联 issue 中的复现场景是一个 15.30MB 的单测日志在模型能看到任何有效内容前就被拒绝。返回有界范围可以给模型足够上下文继续排查,同时仍然控制内存和输出大小。
Reviewer Test Plan
How to verify
在仓库根目录运行
npm run build和npm run typecheck,两者都应退出 0。在packages/core中运行npx vitest run src/utils/readTextRange.test.ts src/utils/fileUtils.test.ts src/services/fileSystemService.test.ts src/tools/read-file.test.ts src/utils/readManyFiles.test.ts src/utils/pathReader.test.ts,应通过全部 263 个测试。在packages/cli中运行npx vitest run src/ui/hooks/atCommandProcessor.test.ts src/acp-integration/service/filesystem.test.ts,应通过全部 91 个测试。评审者也可以创建一个超过 10MB 的文本文件,确认默认read_file返回带范围标记的内容而不是FILE_TOO_LARGE,同时大型媒体文件仍返回既有大小限制错误。Evidence (Before & After)
Before:读取或附加一个 15.30MB 文本日志会失败,报错为
File size exceeds the 10MB limit,导致无法分析 CI 日志。After:已覆盖的大文本范围读取会返回有界文本和截断元数据,默认read_file输出会标明展示的行范围,显式 offset/limit 请求无需整文件读入内存即可返回。当前本地证据是上面列出的 build、typecheck 和定向测试均通过。Tested on
Environment (optional)
macOS 26.4.1,Node.js v22.22.3,npm 10.9.8。
Risk & Scope
file_unchanged去重,以及 Claude 风格的逐行编号输出都刻意留到后续。Linked Issues
Closes #6403