Repository navigation
fix: count + warn about OpenAI file parts dropped by the wire codec (#1205) - #1221
Conversation
📦 Built Package ArtifactBranch: Option A — Install from npm PR tag (recommended)npm install -g billion-context@pr-1221Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf billion-context-pr1221.tgz
npm install -g packageInstall instructions are refreshed on each push. |
[bot] 🏷 开始 review PR #1221(fix: count + warn about OpenAI file parts dropped by the wire codec)。已确认:head commit CI 全绿(8/8);PR 基于 |
…#1205) The acp-kernel openai codec keeps only text parts (+ image_url on user messages), so DeepSeek Files API attachments ({type:"file","file_id":…}) vanish on every request before any compression happens. Until the kernel gains opaque part carry-through, mitigate in-repo: - image-tokens: charge type:"file" parts like remote references (inline file_data sized from its base64 payload; opaque id/url refs flat REMOTE_IMAGE_TOKENS), mirroring the google fileData precedent; raw-body probe now also fires on "type":"file" markers. - server: one-time-per-session warn naming the part types the codec will drop (bounded FIFO like #1086's chain warnings) — silent drops become loud. Behavior change: token estimates for sessions with Files-API attachments go up by ~4096 per file ref (conservative overestimate until the kernel ships opaque carry-through, exact after). Root fix tracked in acp-kernel.
9ba6bb8 to
92cbf98
Compare
[bot] 🏷 Review 完成:可以合并。 已把分支 rebase 到当前 master( ① 原 issue(#1205)方向关
② 回归审查(触碰路径的既有行为清单)
行为变更披露核对:PR 描述的「每个 opaque file 引用 +4096」与实际代码一致,方向安全(只让 fit/compress 更保守,不会放行超窗 payload),新增一条限频 warn 日志。无未披露漂移。 ③ 代码审查
④ 测试有效性14 个用例断言都有牙:精确期望值(4096、ceil(800/4)=200、report 结构 deepEqual)、三种 file 形状、紧凑/带空格 JSON 探测、非 user 角色更严保留集、无 type part( ⑤ diff 整洁度4 文件 +219/-4,每一行都与本 PR 目的相关;无空行/重排噪音、无锁文件连带(version 未动,非 release 分支,合规);单一线性 commit。 预检证据(rebase 后的 head
|
Part of #1205 — the in-repo portion only. This does NOT close #1205: the actual part drop happens inside acp-kernel's wire codec (
openaiToCorekeeps onlytextparts +image_urlon user messages), so DeepSeek Files API attachments ({"type":"file","file_id":"file-api-…"}) still vanish on every request until the kernel ships opaque part carry-through. That root fix is cross-repo and awaits owner decision in the issue thread; this PR lands the two in-repo mitigations from the issue's fix list, so accounting stops being blind and the silent drop becomes loud.What changed
src/image-tokens.ts— chargetype:"file"parts (issue fix item 2). The openai branch ofimageTokensInParsedBodynow handles file content parts following the googlefileDataprecedent already in the same function:file.file_datadata-URL → sized from its base64 payload like any other data URL;file_id,file.url) → flatREMOTE_IMAGE_TOKENS(4096), same as unsizeable remote image URLs.The cheap raw-body probe in
imageTokensInRawBodynow also fires on"type":"file"markers, so file-only bodies are no longer short-circuited to 0 before parsing.src/wire-drop-warn.ts+src/server.ts— one-time warn (issue fix item 4). New pure detectordroppedOpenaiParts(body)scans the raw request against the codec's preserved set (user: text + image_url; other roles: text only) and reports count / sorted type union / first affected message index.prepareOpenaicallswarnDroppedOpenaiParts()right afteropenaiToCore(parsed); the proxy logs onewarnper session per distinct type-set (bounded FIFO, same shape as [Bug] 链检测把 bili 自己注入的 ACP 产物判成 bili→bili 链 —— 压缩内核永久跳过,长会话撞 1,048,576 上限 400(v0.1.133 回归) #1086'swarnedChainSessions) naming exactly which part types will be dropped. When the kernel learns opaque carry-through, the call site re-points at what actually survived the round trip (noted in the module header).Not touched here (deliberately):
src/image-note.tsplaceholders depend on the kernel sidecar carrying the part intoBiliMessage— nothing to recognize until the kernel fix exists; the anthropic/responses sibling blind spots are the same kernel-side change.Verification
openaiToCore→coreToOpenaidirectly from acp-kernel 0.0.84:[text, file]degrades to plain string"what is in this image?\n"(the trailing\nis the dropped part's empty slot instringContent's join);[text, image_url]survives intact;[text, file, image_url]loses the file, keeps the image. Matches the issue report case-for-case, with zero compression involved (max_tokens=8000).dist/index.js+ mock upstream, 2 turns resending the same history): client gets HTTP 200; forwarded user content is"\nwhat is in this image?\n"(drop persists, as expected pre-kernel-fix); exactly one warn line across both turns — dedup works end-to-end:wire codec will drop 1 content part(s) with unrecognized type(s) [file] (first at message #0) — e.g. DeepSeek Files API file refs vanish on the wire before any compression (#1205); inline base64 images work around ittests/fix-1205-file-parts.test.ts(14 tests) pins all three shapes' billing, the raw-body probe, the detector's preserved-set logic (incl. non-user roles, typeless parts, degenerate bodies), and the once-per-session-per-type-set rate limit incl. reset.npm run typecheckclean,npm test2365 pass / 0 fail (2 gated e2e skips),npm run buildclean. Base is current master (03dd9c78).Behavior change disclosure
Token estimates for requests carrying OpenAI-family file parts go old → new: +4096 per opaque file ref (or the real base64 size for inline
file_data). Until the kernel fix ships these parts are not actually forwarded, so this is a bounded conservative overestimate (same policy as remote image URLs); after the kernel fix it becomes the accurate value. Direction is safe — higher estimates only make fit/compress decisions more conservative, never looser. A newwarnlog line appears for sessions whose bodies contain unrecognized content-part types (one per session per type-set). No config schema, persistence format, or wire-shape changes.