Repository navigation
fix(agent-core-v2): cap Read at about 25k tokens and trim file tool results - #4553
Conversation
…esults - Cap the max_chars a Read call can request at 100k characters (was 500k) and drop the description sentence that told the model to request a larger budget for whole large files; the event log note now points to Next Read instead of a larger max_chars. - Stop a page at about max_chars / 4 estimated tokens. The limit is applied while the page is assembled: drop whole lines, or cut a single long line by token weight, without re-reading the file. It rounds up, so pages of ASCII text never reach it and keep their exact character pagination. A tail read whose last line cannot fit returns the bounded forward recovery. - Omit the Read status block when a call returns the whole file with nothing to report. - On an incomplete page, point to Grep for a specific section instead of answering from that page alone. - After a successful Edit or Write, tell the model it does not need to Read the file back.
🦋 Changeset detectedLatest commit: e67be49 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
commit: |
When a call names a range, with n_lines or a negative line_offset, and those lines exceed the estimated token limit, return an error that says how many lines fit and suggests the exact arguments, instead of a page that silently covers only part of the range. Whole-file reads, reads from an offset to the end, single-line requests, and column continuations still page with Next Read.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5c3b1eb7f4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The named-range check ran before character trimming, so an ASCII range longer than max_chars, whose status block pushed the page over both limits, returned a range error instead of a page with Next Read. Run the check only once the page fits max_chars, so it rejects a range only when the token limit would cut it shorter than the character limit does.
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Every incomplete Read page now carries one more status sentence, so with a 500-character budget and a long attachment path the status took about 490 characters and the read could not finish within the test's 80 pages.
Requirement or Bug
Read 读进来的内容会一直留在上下文里,在压缩前每一步都随请求重发。但单次 Read 的上限只按字符计,模型最多能申请 500,000 字符;同样 100,000 个字符,中文按 Kimi Code 自己的估算是代码的 4 倍 token。这个 PR 把单次 Read 限制在约 25k token,并去掉 Read、Edit、Write 结果里不必要的文本。
Bug Reproduction Steps
n_lines地 Read 一个十几万字的中文 Markdown 文件。estimateTokens约 100k token;模型如果按描述的建议带上更大的max_chars,一次最多返回 500,000 个字符。Next Read继续。Root Cause
read.md还要求「需要全文时第一次就申请更大的max_chars」。前两点是预算的根本修复;后两点降低每次结果的固定开销和回读倾向。
Code Changes
核心思路:保留现有按字符分页、
Next Read续读和长行分片的全部机制,在组装每一页时多加一个估算 token 的约束(算法与estimateTokens一致):超了就在当前页上收缩,多行丢行,单行按 token 找切点,不重读文件。上限是「字符上限 ÷ 4」向上取整,纯 ASCII 页面永远碰不到它,原来的字符分页不变;中文页面从约 100k 字符缩到约 25k 字符。指定了范围的读取(带n_lines或负的line_offset)先照旧按字符上限收缩;如果字符上限内放得下的行仍超过 token 上限,就不返回其中一部分,而是直接报错并建议一个放得下的范围,避免模型把半截范围当成完整范围。只被字符上限截短的范围(例如大段代码、日志尾部)、整文件读和只给起始行的读取,仍然截短后翻页。结果文本也同步瘦身:整文件读完时不附状态块,没读完时提示可以用 Grep 定位,Edit/Write 成功后告诉模型不需要回读。execution(source, args, eventLog) limits = [read] config ?? { default: 100k, max: 100k (was 500k) } + request = { maxChars, tokenLimit: ceil(max / 4) } return readForward or readTail(request) finishPage(page) loop - fits = renderedChars <= maxChars + fits = renderedChars <= maxChars && estimatedTokens <= tokenLimit - note = <system>summary + notices</system> + note = whole file && no notices ? none : <system>summary + notices</system> + if a named range fits maxChars but still overflows tokens: return an error that suggests a range that fits if fits: return page + if only tokens overflow: drop enough lines at once, or cut a single line by token weight otherwise: drop one line, or cut a single line by characters (unchanged) if incomplete Next Read { max_chars: maxChars } + "If the answer may be further on, continue with Next Read or find the section with Grep instead of answering from this page alone."token 约束和字符约束在同一个组装循环里生效:只有字符超限时,仍按原来的方式一次丢一行或按字符切分;token 超限时,一次丢够行或按 token 切分(指定范围的多行页不走这一步,而是报错)。所以不需要重读文件,一次就满足上限;从尾部读一个放不下的长行时,会落到原有的「正向续读」恢复路径。
max_chars ÷ 4向上取整,随[read] max_chars一起调max_tokens配置项Next Read;或者整个范围一超 token 就报错,不先按字符收缩Next Readnote,只给模型看output阅读指南:
packages/agent-core-v2/src/agent/tools/os/read/readTool.ts:finishPage里的字符和 token 双约束,以及状态块拆成 summary 和 notices 后的组装。packages/agent-core-v2/src/llm-adapter/contract/tokens.ts:拆出的计数函数,estimateTokens的结果不变。packages/agent-core-v2/src/agent/tools/os/read/read.md的两处改动,以及editTool.ts、writeTool.ts的 note。其余是测试和中英文文档。
Behavior Changes and Affected Users
影响范围:所有带 Read、Edit、Write 工具的 agent(主 agent 和子 agent),所有客户端(TUI、print 模式、经 kap-server 的 desktop 和 web、SDK),所有 provider。
max_chars上限[read] max_charsmax_chars ÷ 4估算 token(默认 25,000),超了在当前页上丢行或切分,照常给出Next Read;从尾部读放不下单个长行时返回正向续读提示[read] max_charsn_lines或负的line_offset)在字符上限内放得下的行超过 token 上限Next Read[read] max_charsNext ReadNext Read加一句:答案可能在后面时用Next Read继续或用 Grep 定位,不要只凭这一页作答wire.jsonl事件日志时的备注Read 工具描述的改动(所有带 Read 的 agent 每次请求都会收到),逐句:
<line-number>\t<content>per line, followed by a<system>status block that is not part of the file." 改为 "Output is<line-number>\t<content>per line. A<system>status block may follow; it is not part of the file."max_charsin the first call."Next Read翻页取得,描述里续读的那条规则不变测试覆盖:
maxChars: 500_000的配置下跑,钉住调大配置后的旧行为。Next Read保留原预算;单个长中文行按 token 分片;从尾部读放不下的长中文行时返回有界的正向续读提示。原来验证「按字符不按字节计」的多字节用例改为在调高上限的配置下跑。n_lines和尾部读取)照旧返回一页,并给出接得上的Next Read。验证:类型检查和
pnpm lint通过,相关测试全部通过。agent-core-v2 全量测试中,单独重跑后仍失败的只有子 agent 超时用例(base 上同样失败)和 MCP OAuth 的两个超时用例;它们不涉及 Read,本 PR 没有改动相关代码。Checklist
/approve).gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.