fix(toolargs): 在 artifact 唯一出生点封顶,避免超大扫描记录撑爆控制面帧 - #96
Merged
Conversation
A control plane delivers one artifact event as one frame and bounds it: an oversized frame is dropped, or past a hard limit closes the connection and takes every tool call sharing it down with it. A scanner record is the one artifact with no natural bound — a single katana crawl result carries the response body next to the raw transcript of that same response, past the frame limit combined. EmitArtifactResultCtx is the one place every tool's artifact is built, and the record is structured JSON there, before it becomes opaque bytes on the wire. Trim it at birth: cut the bulk from body and transcript, keep the small fields a control plane projects (URL, host, port, status, technology), keep numbers verbatim, and never drop a record — a downstream frame guard working from bytes it cannot parse could only drop the whole thing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
控制面把一个 artifact 事件当作一个 WebSocket 帧接收,并对帧大小设限:超过软限丢弃该消息,超过硬限直接关闭连接——连带把该连接上正在进行的所有工具调用一起中断。
扫描类工具的原生记录是唯一没有自然上限的 artifact:一条 katana 抓取结果会把响应体和同一响应的原始报文各存一份,katana 自身的响应体上限就有 4 MiB,单条记录因此可达 8–10 MiB,足以越过帧限。
改动
EmitArtifactResultCtx是所有工具构造 artifact 的唯一入口(全仓仅此一处toolpb.Artifact{}),katana/gogo/spray/neutron 等全部经它。此处的raw正是刚json.Marshal出来的、保证可解析的结构化 JSON——所以在这里封顶,而不是留给下游帧层。boundArtifactData:记录超过 4 MiB 时,按字符串长度逐级收紧,截短响应体 / 原始报文等大字段,保留控制面要投影进图谱的小字段(URL、host、端口、状态、指纹),数字保留原文本(不会把端口或 ID 四舍五入),并丢弃字节截断留下的半个 rune(否则下游 marshal 失败)。关键性质:永不丢一条扫描记录——最坏也是截到最小再发。这正是出生点相对于传输点的优势:这里 data 是结构化 JSON,能精准截 body / raw;下游帧层拿到的是 opaque bytes,只能整条丢弃。
resultID仍基于未截断的原始 data,记录身份在截断前后保持稳定。测试
tools/toolargs/artifact_budget_test.go,基于 katana 真实 wire 形状(endpoint/body/raw,含request.body):