Skip to content

feat(agent-core-v2): read UTF-16 text files by transcoding to UTF-8 - #2647

Merged
sailist merged 1 commit into
MoonshotAI:mainfrom
sailist:feat/read-utf16-text-files
Aug 6, 2026
Merged

feat(agent-core-v2): read UTF-16 text files by transcoding to UTF-8#2647
sailist merged 1 commit into
MoonshotAI:mainfrom
sailist:feat/read-utf16-text-files

Conversation

@sailist

@sailist sailist commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Related Issue

No linked issue — the problem is explained below.

Problem

The Read tool and the web UI file viewer refuse UTF-16 text files as binary. UTF-16 is what Windows Notepad uses when saving .txt, so opening such a file fails with "not readable as UTF-8 text" even though it is plain text. Non-UTF encodings such as GBK are also refused with a generic message that gives no hint about the actual cause.

What changed

Adds encoding detection derived from VS Code (detectEncodingFromBuffer, MIT) and transcodes UTF-16 text to UTF-8 for display:

  • New detection helper: trusts a BOM first (FF FE / FE FF / EF BB BF), then recognizes BOM-less UTF-16 LE/BE via zero-byte placement — zeros at least twice and at exactly one index parity. This deliberately deviates from VS Code's stricter every-pair rule so mixed Latin/CJK content (whose UTF-16 units carry no zero byte) is still detected; real binaries (zeros at both parities, or an isolated zero byte) stay refused.
  • The Read tool transcodes detected UTF-16 files up to 10 MiB and notes the detected encoding in the status block, including a hint that Edit/Write still expect UTF-8 (convert first, e.g. via iconv). Other non-UTF encodings (e.g. GBK) are refused with a clearer message that names the supported encodings and the conversion workaround.
  • The workspace fs.read endpoint behind the web UI file viewer transcodes UTF-16 the same way (windowing applies to the decoded UTF-8 bytes); explicit base64 requests keep raw bytes. No protocol schema changes.
  • Known limitation (same as VS Code): BOM-less UTF-16 whose content carries no zero bytes at all (e.g. purely CJK text) is not detectable without statistical guessing, which is intentionally out of scope — no new dependencies.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

@changeset-bot

changeset-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9845c71

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

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

@pkg-pr-new

pkg-pr-new Bot commented Aug 5, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@9845c71
npx https://pkg.pr.new/@moonshot-ai/kimi-code@9845c71

commit: 9845c71

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9f304c25ab

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +299 to +300
if (fileType.kind === 'unknown') {
return {
isError: true,
output: notReadableFileOutput(args.path),
};
const detection = detectTextEncoding(header);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Run UTF-16 detection before the text fallback

For a UTF-16 file that has a BOM but no NUL byte in the 512-byte header (for example an empty UTF-16 file or CJK-only content), detectFileType(...) returns text, so this branch is skipped and the readLines(...errors: 'strict') path tries to decode FF FE as UTF-8. Those valid BOM-marked UTF-16 files are still rejected instead of transcoded; run detectTextEncoding/BOM handling before falling through to the UTF-8 text path.

Useful? React with 👍 / 👎.

Comment on lines +265 to +266
if (isBinary && req.encoding !== 'base64') {
const detection = detectTextEncoding(sample);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Trust UTF-16 BOMs before the binary heuristic

For fs.read, a BOM-marked UTF-16 file can have no NUL bytes in the sample (e.g. repeated 你好), so detectBinary(sample) is false and this guard never runs. The response then slices raw UTF-16 bytes and labels them UTF-8, causing the web UI file viewer to show replacement/garbage for a valid UTF-16 file; trust detectTextEncoding's BOM result before gating on isBinary.

Useful? React with 👍 / 👎.

- detect UTF-16 LE/BE from a BOM or a zero-byte parity heuristic
  (tolerant of CJK content), derived from VS Code's encoding detection
- Read tool and workspace fs.read transcode UTF-16 text to UTF-8
  instead of refusing it as binary; larger than 10 MiB still refused
- refuse other non-UTF encodings (e.g. GBK) with a clearer message
@sailist
sailist force-pushed the feat/read-utf16-text-files branch from 9f304c2 to 9845c71 Compare August 5, 2026 12:11
@sailist
sailist merged commit 7bd3fd9 into MoonshotAI:main Aug 6, 2026
14 checks passed
@github-actions github-actions Bot mentioned this pull request Aug 6, 2026
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