Repository navigation
AgentCore 0.8.1
Fixed
-
runtime/loop/tokenizer.pyno longer runsimport tiktokenon the daemon
thread it spawns. The import is hoisted to the calling thread; only
tiktoken.get_encoding()stays on the thread. Anatexithook now joins an
in-flight load (1 s cap), followingproviders/nonblocking_stream.py.Rationale:
tiktoken._tiktokenis a Rust extension, so the importdlopens a
shared object, and CPython kills daemon threads mid-flight at finalization
(pthread_exitat the next GIL acquisition). Killed inside the dynamic linker
that is not survivable — losing glibc's_dl_load_locksurfaces as a later
SIGSEGV, unwinding through a Rust /extern "C"frame callsabort(). A
2026-09-05 investigation in ApodexHarness found the thread parked inside that
import at interpreter exit on every short run (the import takes 24-29 ms and
the firstget_encoding_nonblocking()call lands late in a run), with two
observed deaths after a fully correct protocol stream:-11in
test_stateless_across_invocations,-6intest_serve_subprocess_e2e. The
window is wider whereverTIKTOKEN_CACHE_DIRis unset, because the load then
takes the no-timeout network path.The module's loop-protection intent is unchanged: what it defends against is a
minutes-long, no-timeout HTTP fetch insideget_encoding(), and that is still
on the daemon thread. The import is local and needs no network.
Consumer action
None required — get_encoding_nonblocking() keeps its signature and its
contract (returns None while loading; callers still fall back to a heuristic).
One timing difference worth knowing: the first call for an encoding name now
spends 24-29 ms importing tiktoken on the calling thread, where before it
returned instantly. In exchange the encoder becomes available sooner, which
shortens the heuristic-fallback window tokens.py documents as the opening
turns of every process.