Skip to content

fix(text): keep binary tool output out of the text pipeline (NUL / invalid UTF-8) - #460

Merged
CjiW merged 1 commit into
masterfrom
agent/peer/fix-pg-nul/fix-pg-nul-binary-read-457
Oct 26, 2026
Merged

CjiW merged 1 commit into
masterfrom
agent/peer/fix-pg-nul/fix-pg-nul-binary-read-457

Conversation

@CjiW

@CjiW CjiW commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

问题(issue #457 后续,生产日志实证)

Read 读到二进制文件后,该轮对话持久化失败:

append message batch item 1: ERROR: invalid byte sequence for encoding "UTF8": 0x00 (SQLSTATE 22021)

日志里共 8 次(如 xbot-2026-10-24.log 04:41:58,session web:chat_18E098316EE7ACF5 turn 30,Read 返回后立即报错)。

关键点:0x00(NUL)是合法 UTF-8(U+0000),所以现有的 pgText → textutil.SanitizeUTF8(只修非法序列)原样放行;但 PG 的 text 类型不能存 NUL,服务端拒绝整批 INSERT。SQLite 把 TEXT 当裸字节存,所以本地完全看不见,切到 PG 才爆。

现场 pgx 事务探针(BEGIN + SELECT + ROLLBACK)实测:

nul      ERROR: invalid byte sequence for encoding "UTF8": 0x00 (SQLSTATE 22021)
bad_utf8 ERROR: invalid byte sequence for encoding "UTF8": 0xff (SQLSTATE 22021)
valid    ok

修复(三层)

  1. 生产方 tools/read.go:新增 detectBinary(本地 + sandbox cat 两条路径共用)。前 8 KiB 内出现 NUL 或 >25% 非法 UTF-8 字节 ⇒ 直接返回
    binary or non-UTF-8 file (NUL byte at offset N): <path> — Read returns UTF-8 text only; use Shell (iconv / xxd / head -c / base64) to inspect or convert it
    不再把原始字节当文本塞进上下文(同时省掉几 MB 垃圾 token)。单字节损坏的文本文件仍在阈值内,正常读取。
  2. 文本管道边界:textutil.SanitizeText = 非法序列 + NUL → U+FFFD(干净输入零分配);在 agent.updateToolResultLine(成功/失败)与 newSyntheticToolPair 统一执行 ⇒ 模型上下文 / SSE / offload 文件 / DB 四处同源干净。SanitizeUTF8 保持"只修编码"语义不变。
  3. 存储边界(最后防线):storage.pgText 改用 SanitizeText;cmd/xbot-migrate 的 sanitizeUTF8 同样委托它(否则 SQLite 历史行里的 NUL 会让迁移失败)。

验证

  • internal/textutil:NUL/非法序列/合法串;SanitizeUTF8 仍保留 NUL(语义不变)
  • cmd/xbot-migrate:含 NUL 的历史行可修复
  • tools/read_binary_test.go:二进制(含 NUL / 纯 0xff)必须拒绝;单字节损坏的文本仍可读;8 KiB 探针边界
  • agent/tool_output_sanitize_test.go:工具结果成功/失败/注入三条路径
  • storage:共享契约用例(SQLite+PG)+ 真实 PG TestPGSessionStoreNULMessageStoredSanitized(写入成功、读回无 NUL 且是合法 UTF-8)
ok  xbot/tools       22.9s
ok  xbot/agent       28.5s
ok  xbot/storage     3.1s   (+ PG 契约套件实测 8.9s,XBOT_PG_TEST_DSN 指向本机 PG)
go build ./...       通过

文档

docs/agent/gotchas-tools.md、docs/agent/storage.md、AGENTS.md 一行索引;docs-site/content/{en,zh-cn}/features/tools.md 的 Read 说明同步(二进制会被拒绝并提示用 Shell)。

…valid UTF-8)

Issue #457 (follow-up): Read on a binary file killed the turn's persistence
with 'ERROR: invalid byte sequence for encoding UTF8: 0x00 (SQLSTATE 22021)'.
NUL is valid UTF-8 (U+0000), so the existing SanitizeUTF8-based pgText passed
it through — but PostgreSQL text cannot store 0x00 at all. SQLite stores it
silently, which is why this only surfaced on the PG backend.

Three layers:
- tools/read.go: reject binary/non-UTF-8 files (NUL in the first 8 KiB, or
  >25% invalid UTF-8 bytes) for both the local and sandbox cat paths, with an
  actionable hint (Shell iconv/xxd/head -c/base64) instead of dumping bytes
  into the context.
- textutil.SanitizeText: single scan repairing invalid sequences AND NUL to
  U+FFFD (zero-alloc for clean input); applied at the agent tool-result
  boundary (success, error and synthetic tool pairs) so context, SSE, offload
  files and DB all agree.
- storage.pgText and cmd/xbot-migrate use SanitizeText as the last line of
  defence (migrated rows stay consistent with runtime writes).

Tests: textutil, migrate, read binary detection, agent boundary sanitisation,
shared contract case (both backends) and a real-PG test asserting a
NUL-carrying message is storable and reads back clean.
@vercel

vercel Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
xbot-preview Ready Ready Preview Oct 24, 2026 4:53pm UTC

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-24T16:53:34.653722Z 76dad12 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@CjiW

CjiW commented Oct 25, 2026

Copy link
Copy Markdown
Contributor Author

@codex preview

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create an environment for this repo.

@CjiW
CjiW merged commit 087dac2 into master Oct 26, 2026
9 checks passed
@CjiW
CjiW deleted the agent/peer/fix-pg-nul/fix-pg-nul-binary-read-457 branch October 26, 2026 04:02

This branch was successfully deployed

1 active deployment
Preview — 76dad12b Deployed Oct 24, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant