From 67dba48daa7bdf522ff2cd715752bf48d52c3144 Mon Sep 17 00:00:00 2001 From: cyre Date: Fri, 17 Jul 2026 02:06:32 +0000 Subject: [PATCH] fix(io): force UTF-8 on stdout/stderr and candidate writes Two related Windows-compatibility fixes: - Reconfigure stdout/stderr to UTF-8 (errors=replace) at import, so a lesson claim containing non-ASCII (arrows, em-dashes, accented text) doesn't raise UnicodeEncodeError under a cp1252 console on Windows. - Write the candidate JSON file with explicit encoding="utf-8" rather than the platform default, so candidates round-trip identically across OSes. Both are additive and platform-safe (the reconfigure is guarded by hasattr, a no-op where unavailable). Found and applied downstream in Perpetua-Tools; contributing back. Stacked on top of the episodic-mirror fix (atomic-01). --- .agent/tools/learn.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.agent/tools/learn.py b/.agent/tools/learn.py index 3154b0e..2b9cbec 100644 --- a/.agent/tools/learn.py +++ b/.agent/tools/learn.py @@ -20,6 +20,10 @@ """ import argparse, datetime, json, os, subprocess, sys +if hasattr(sys.stdout, "reconfigure"): + sys.stdout.reconfigure(encoding="utf-8", errors="replace") + sys.stderr.reconfigure(encoding="utf-8", errors="replace") + BASE = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) CANDIDATES = os.path.join(BASE, "memory/candidates") sys.path.insert(0, os.path.join(BASE, "harness")) @@ -105,7 +109,7 @@ def stage(claim, conditions, source="learn", importance=7): "rejection_count": 0, } path = os.path.join(CANDIDATES, f"{cid}.json") - with open(path, "w") as f: + with open(path, "w", encoding="utf-8") as f: json.dump(candidate, f, indent=2) _append_episodic_mirror(cid, claim, now, source) return cid, path