@@ -5,6 +5,96 @@ All notable changes to this project will be documented in this file.
55The format is based on [ Keep a Changelog] ( https://keepachangelog.com/en/1.0.0/ ) ,
66and this project adheres to [ Semantic Versioning] ( https://semver.org/spec/v2.0.0.html ) .
77
8+ ## [ 3.3.0] - 2026-05-29
9+
10+ Cluster-grade runtime: everything needed for a host platform (e.g. 书安OS)
11+ to run long-lived agent sessions across many nodes — graceful shutdown,
12+ multi-tenant identity, cost governance, deterministic replay, crash-tolerant
13+ runs, and bounded in-memory state — plus an adversarial-review hardening
14+ pass. All additions are backward compatible (new methods, new optional
15+ fields, new ` SessionStore ` trait methods with default no-op impls).
16+
17+ ### Added
18+
19+ - ** Session / Agent lifecycle control.**
20+ - ` AgentSession::close() ` is now a full graceful stop: flips ` is_closed `
21+ (further ` send ` /` stream ` fast-fail with ` CodeError::SessionClosed ` ),
22+ cancels the active run, all in-flight delegated subagent tasks, and
23+ pending HITL confirmations. ` AgentSession::is_closed() ` accessor.
24+ - Agent-side session registry: ` Agent::list_sessions() ` ,
25+ ` close_session(id) ` , ` close() ` (also disconnects global MCP), and
26+ ` is_closed() ` . Sessions are tracked by ` Weak ` ref and pruned lazily.
27+ - Session-level ` CancellationToken ` parent: every run derives its token
28+ via ` child_token() ` , so ` close() ` cascades to all in-flight work.
29+ ` AgentSession::session_cancel_token() ` exposes it for embedders.
30+ - ** Host-provided identity labels** — ` tenant_id ` , ` principal ` ,
31+ ` agent_template_id ` , ` correlation_id ` on ` SessionOptions ` (builder
32+ methods + accessors), persisted in ` SessionData ` , restored on resume.
33+ Framework treats them as opaque; the host drives multi-tenant
34+ aggregation / billing / tracing. Exposed on both SDKs.
35+ - ** ` BudgetGuard ` cost/quota contract** (` budget ` module) — host-supplied
36+ ` check_before_llm ` / ` record_after_llm ` / ` check_before_tool ` , consulted
37+ at the LLM call site. ` Deny ` aborts with ` CodeError::BudgetExhausted ` ;
38+ ` SoftLimit ` emits an event and proceeds. SDK bridges: a Python class
39+ (` opts.budget_guard ` ) and Node ` session.setBudgetGuard({...}) ` . The Node
40+ bridge fails ** closed** (timeout / unreadable return → deny).
41+ - ** ` HostEnv ` (IdGenerator + Clock) injection** (` host_env ` module) —
42+ replace the default UUID + wall-clock pair for deterministic replay of a
43+ run on another node. ` SequentialIdGenerator ` / ` FixedClock ` helpers.
44+ - ** Loop checkpoints + run resumption** (` loop_checkpoint ` module) — the
45+ agent loop persists a ` LoopCheckpoint ` after each completed tool round
46+ (when a ` SessionStore ` is configured); ` AgentSession::resume_run(run_id) `
47+ replays from the last boundary on any node sharing the store, continuing
48+ cumulative token/tool-call accounting. ` SessionStore ` gains
49+ ` save/load/delete_loop_checkpoint ` ; file writes are crash-atomic.
50+ - ** ` SessionRetentionLimits ` ** (` retention ` module) — optional FIFO caps on
51+ the in-memory run store (runs + per-run events), trace sink, and terminal
52+ subagent task snapshots, so long-running sessions don't grow unbounded.
53+ Exposed on both SDKs. Default is unbounded (no behavior change).
54+ - ** MCP idle disconnect** — ` McpManager::disconnect_idle(threshold_ms) ` and
55+ ` Agent::disconnect_idle_mcp(...) ` (both SDKs) reap quiet MCP servers
56+ (releasing FDs / background workers) while keeping their config for
57+ on-demand reconnect.
58+ - ** Cluster ` AgentEvent ` variants** — ` BudgetThresholdHit ` ,
59+ ` PassivationRequested ` , ` PeerInvocation ` : platform-level events a host
60+ emits via ` HookExecutor ` so in-session code can react uniformly.
61+ - ` SessionStore ` now persists the subagent task tracker across
62+ save/resume (` save/load_subagent_tasks ` ), so a migrated session keeps a
63+ queryable history of its delegated child runs.
64+ - New errors: ` CodeError::SessionClosed ` , ` CodeError::BudgetExhausted ` .
65+
66+ ### Changed
67+
68+ - ` resume_run ` continues cumulative metrics (` total_usage ` ,
69+ ` tool_calls_count ` ) from the checkpoint instead of restarting at zero.
70+ - Run-store and subagent-tracker FIFO eviction now hold their parallel
71+ maps under a single canonical lock order, so eviction is atomic with
72+ respect to concurrent record/cancel (no transient map inconsistency).
73+
74+ ### Fixed
75+
76+ - ** Loop checkpoint leak** : checkpoints were written after every tool round
77+ but never deleted — unbounded disk/memory growth on every completed run.
78+ They are now removed when a run reaches a terminal state in-process; only
79+ a true crash leaves one for resume.
80+ - ** ` event_count ` corruption** : restoring a session whose per-run event
81+ buffer had been trimmed reset the cumulative ` event_count ` to the trimmed
82+ length. The persisted cumulative count is now preserved.
83+ - ** Node ` BudgetGuard ` fail-open** : a hung or slow guard silently * allowed*
84+ the LLM call (disabling enforcement). It now fails ** closed** (deny) on
85+ timeout and on an unreadable return.
86+ - ** MCP timestamp leak** : ` touch() ` -without-connect orphan timestamps are
87+ now purged by ` disconnect_idle ` .
88+ - Session registry dangling ` Weak ` entries are pruned on ` Agent::close() ` .
89+
90+ ### Known limitations
91+
92+ - Node ` BudgetGuard ` callbacks ** must not throw** — due to a napi-rs
93+ constraint a thrown exception aborts the host process at return-value
94+ conversion. Wrap guard logic in try/catch and return a decision. Hangs
95+ are handled safely (fail-closed timeout). The Python ` BudgetGuard `
96+ catches exceptions and is unaffected.
97+
898## [ 3.2.1] - 2026-05-24
999
10100### Added
0 commit comments