Skip to content

fix: bindings/python: keep non-ASCII text as UTF-8 when marshalling JSON to the engine - #804

Open
Rasaboun wants to merge 1 commit into
cactus-compute:mainfrom
Rasaboun:fix/python-binding-ensure-ascii
Open

Rasaboun wants to merge 1 commit into
cactus-compute:mainfrom
Rasaboun:fix/python-binding-ensure-ascii

Conversation

@Rasaboun

@Rasaboun Rasaboun commented Sep 2, 2026

Copy link
Copy Markdown

Fixes #803.

What

One-line change in python/cactus/bindings/cactus.py::_to_json: json.dumps(obj, ensure_ascii=False).

Why

json.dumps defaults to ensure_ascii=True, rewriting every non-ASCII character as \uXXXX. The engine's messages/chat-template path does not decode those escapes, so the model literally receives escape text (~3 tokens per character, semantic noise). Accented Latin degrades; Japanese/Korean become unusable. Full evidence in #803.

Verification (Python-side change only, no C++ touched)

  • usage.prompt_tokens vs the HF tokenizer for identical messages+tools, before → after:
    en +42 → +42, fr +58 → +42, ko +87 → +42, ja +124 → +44 (the constant +42 is template overhead).
  • 808-row multilingual tool-calling eval on a fine-tuned LFM2.5-230M (CQ4): ja/ko false-action rates 88–100% → 0–16% (bf16 reference level); ko remember accuracy 17% → 94%; en/de unchanged.
  • The bytes handed to C are still valid UTF-8 (.encode() unchanged); ensure_ascii=False only stops the escaping.

Complementary hardening (not in this PR, kept lean per CONTRIBUTING): have the C++ messages JSON reader decode \uXXXX so non-Python bindings that escape are also safe — utils.h already has a correct decoder used elsewhere.

Copilot AI lite review requested due to automatic review settings September 2, 2026 08:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

…o the engine

json.dumps defaults to ensure_ascii=True, which rewrites every non-ASCII
character as \uXXXX. The engine's messages/chat-template path does not
decode these escapes, so the model receives literal escape text: ~3
tokens per character and semantic noise. Accented Latin degrades,
Japanese/Korean become unusable.

With ensure_ascii=False, prompt_tokens exceed the HF tokenizer by a
constant template offset in all tested languages (en/fr/ja/ko), and an
808-row multilingual tool-calling eval returns to the bf16 reference.

Fixes cactus-compute#803

Signed-off-by: Rasaboun <40967731+Rasaboun@users.noreply.github.com>
@Rasaboun
Rasaboun force-pushed the fix/python-binding-ensure-ascii branch from 45bc96d to c1b4550 Compare September 2, 2026 08:27
@Rasaboun Rasaboun changed the title bindings/python: keep non-ASCII text as UTF-8 when marshalling JSON to the engine fix: bindings/python: keep non-ASCII text as UTF-8 when marshalling JSON to the engine Sep 5, 2026

This branch has not been deployed

No deployments
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.

Non-ASCII input corrupted: Python binding escapes to \uXXXX (ensure_ascii) and the engine never decodes it

2 participants