Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

Programmable, deterministic multi-agent orchestration — a grammar for
expressing fan-out, pipelines, and resumable workflows in code (not only via
model-driven delegation), drawn along the framework / host (书安OS) boundary:
model-driven delegation), drawn along the framework / host boundary:
the framework owns the grammar + serializable contracts; the host owns
placement, transport, and scheduling. All additions are backward compatible
(new types/methods, new optional fields, new `SessionStore` methods with
Expand Down Expand Up @@ -80,7 +80,7 @@ default no-op impls).

## [3.3.0] - 2026-05-29

Cluster-grade runtime: everything needed for a host platform (e.g. 书安OS)
Cluster-grade runtime: everything needed for a host platform
to run long-lived agent sessions across many nodes — graceful shutdown,
multi-tenant identity, cost governance, deterministic replay, crash-tolerant
runs, and bounded in-memory state — plus an adversarial-review hardening
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ session2.setBudgetGuard({
Beyond *model-driven* delegation (the agent calling `task`/`parallel_task`), a
session exposes a **deterministic, programmable** orchestration grammar: you
decide the fan-out, chaining, and resume in code. Steps run through the
session's `AgentExecutor`; a host (书安OS) can substitute its own executor to
session's `AgentExecutor`; a host can substitute its own executor to
place steps across a cluster — the grammar is identical either way.

A **step** is `{ task_id, agent, description, prompt, max_steps?,
Expand Down
2 changes: 1 addition & 1 deletion core/src/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ pub enum AgentEvent {
// ========================================================================
// Cluster / platform events
//
// These variants are emitted by the host platform (e.g. 书安OS) via
// These variants are emitted by the host platform via
// `HookExecutor` and are not produced by the agent loop itself. They
// give in-session code a uniform way to observe platform-level
// decisions (budget exhaustion, scheduled passivation, peer
Expand Down
4 changes: 2 additions & 2 deletions core/src/agent_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ pub struct SessionOptions {
/// Explicit session ID (auto-generated if not set)
pub session_id: Option<String>,
/// Multi-tenant identifier. Framework only transports this string;
/// the host (e.g. 书安OS) decides what "tenant" means and how to
/// the host decides what "tenant" means and how to
/// aggregate/bill on it. Emitted to hooks/traces, persisted in
/// `SessionData`, never interpreted by core.
pub tenant_id: Option<String>,
Expand Down Expand Up @@ -717,7 +717,7 @@ impl AgentSession {
/// stored under `checkpoint_run_id` and replays the agent loop from
/// that boundary state. A **new** run id is allocated for the
/// resumed work; the relationship between the old and new run is
/// host-tracked (e.g. by 书安OS) — the framework does not interpret
/// host-tracked — the framework does not interpret
/// it.
///
/// Returns an error when no `SessionStore` is configured on this
Expand Down
2 changes: 1 addition & 1 deletion core/src/agent_api/conversation_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub(super) async fn stream(
/// for `checkpoint_run_id` from the session's `SessionStore` and replays
/// the agent loop from that boundary state. A **new** run id is
/// generated for the resumed work — the relationship between the old
/// and new run is metadata 书安OS tracks externally.
/// and new run is metadata the host tracks externally.
///
/// Returns an error when the session has no store configured, or when
/// no checkpoint exists for `checkpoint_run_id`.
Expand Down
2 changes: 1 addition & 1 deletion core/src/agent_api/session_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ impl SessionOptions {
/// Install a host-provided [`HostEnv`](crate::host_env::HostEnv) for
/// deterministic ID generation and time. Replaces the framework
/// default of `uuid::Uuid::new_v4()` + wall clock — used by
/// 书安OS replay infrastructure to recreate a run bit-identical on
/// host replay infrastructure to recreate a run bit-identical on
/// another node.
pub fn with_host_env(mut self, env: Arc<crate::host_env::HostEnv>) -> Self {
self.host_env = Some(env);
Expand Down
4 changes: 2 additions & 2 deletions core/src/agent_api/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1314,7 +1314,7 @@ async fn test_budget_guard_deny_aborts_llm_call() {
#[test]
fn test_cluster_agent_events_serialize_with_expected_tags() {
// Lock the wire schema for cluster-event variants — these are
// emitted by the host (书安OS) through HookExecutor and need
// emitted by the host through HookExecutor and need
// stable JSON tags so external producers can target them.
let budget = AgentEvent::BudgetThresholdHit {
resource: "llm_tokens".to_string(),
Expand Down Expand Up @@ -2245,7 +2245,7 @@ async fn test_completed_run_clears_its_loop_checkpoint() {
/// resumed run is allocated a **fresh** run id (not the
/// checkpoint's).
///
/// This exercises the contract surface 书安OS will sit on: write a
/// This exercises the contract surface the host will sit on: write a
/// checkpoint on node A, hand the run id to node B which builds a
/// session against the shared store and calls `resume_run`. Crash
/// simulation is reduced to a manual checkpoint seed because the
Expand Down
2 changes: 1 addition & 1 deletion core/src/budget.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Budget / cost / quota contract for cluster-grade hosts.
//!
//! The framework does not enforce budgets itself — it only defines the
//! decision points and emits structured events. The host (e.g. 书安OS)
//! decision points and emits structured events. The host
//! implements [`BudgetGuard`] with whatever backend it likes
//! (per-tenant counters in Redis, per-day USD caps in Postgres, etc.)
//! and plugs it into [`SessionOptions::with_budget_guard`].
Expand Down
2 changes: 1 addition & 1 deletion core/src/host_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ impl Clock for SystemClock {
/// Deterministic ID generator that yields a configured prefix followed
/// by a monotonic counter (`<prefix>-0`, `<prefix>-1`, …).
///
/// Public so external host crates (e.g. 书安OS replay tooling) can use it
/// Public so external host crates (e.g. replay tooling) can use it
/// without re-implementing the pattern.
#[derive(Debug, Default)]
pub struct SequentialIdGenerator {
Expand Down
2 changes: 1 addition & 1 deletion core/src/loop_checkpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! The agent loop persists a [`LoopCheckpoint`] after each completed tool
//! round. The checkpoint captures the minimum state needed to recreate
//! the loop's position so a future process — typically on a different
//! node, dispatched by 书安OS after a crash or planned migration — can
//! node, dispatched by the host after a crash or planned migration — can
//! resume from the last consistent boundary.
//!
//! Boundary policy: checkpoints are taken **only** between tool rounds,
Expand Down
4 changes: 2 additions & 2 deletions core/src/orchestration/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use tokio::sync::broadcast;
/// A single unit of orchestrated agent work — *what* to run, independent of
/// *where* it runs.
///
/// Serializable on purpose: a host (书安OS) may ship it to another node, and
/// Serializable on purpose: a host may ship it to another node, and
/// a future workflow checkpoint persists it. The orchestration layer assigns
/// `task_id`; everything else mirrors a delegated task.
// `serde_json::Value` (in `output_schema`) is not `Eq`, so this derives
Expand Down Expand Up @@ -119,7 +119,7 @@ impl StepOutcome {
/// and the host's placement / transport / scheduling.
///
/// The in-box [`TaskExecutor`](crate::tools::TaskExecutor) runs every step
/// locally (in-process, tokio). A host such as 书安OS implements this trait to
/// locally (in-process, tokio). A host such as a cluster runtime implements this trait to
/// place steps on remote nodes; the orchestration combinators are written
/// purely against the trait and never observe where a step actually ran. The
/// framework deliberately does **not** own placement, transport, or
Expand Down
2 changes: 1 addition & 1 deletion core/src/orchestration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//! [`AgentStepSpec`] / [`StepOutcome`]) and ships a default executor that runs
//! every step locally. The **placement** of those steps across a cluster —
//! transport, scheduling, where a step actually executes — belongs to the
//! host (书安OS), which implements [`AgentExecutor`]. The combinators never
//! host, which implements [`AgentExecutor`]. The combinators never
//! observe where a step ran, so the same orchestration scales from one process
//! to a cluster without change.
//!
Expand Down
2 changes: 1 addition & 1 deletion core/src/store/session_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ pub struct SessionData {
pub parent_id: Option<String>,

/// Multi-tenant identifier. The framework only transports this string;
/// the host (e.g. 书安OS) decides what "tenant" means and how to
/// the host decides what "tenant" means and how to
/// aggregate/bill on it.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tenant_id: Option<String>,
Expand Down
2 changes: 1 addition & 1 deletion core/src/tools/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ impl From<StepOutcome> for TaskResult {
}

/// The local, in-process executor: every step runs as a child `AgentLoop` on
/// this node's tokio runtime. This is the default; a host (书安OS) substitutes
/// this node's tokio runtime. This is the default; a host substitutes
/// its own [`AgentExecutor`] to place steps across a cluster.
#[async_trait]
impl AgentExecutor for TaskExecutor {
Expand Down
16 changes: 8 additions & 8 deletions core/tests/test_session_close_lifecycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ async fn subagent_tasks_persist_across_save_and_resume() {
/// IT-5 (Pillar 5): identity labels (tenant / principal / agent template /
/// correlation id) survive a session save/resume round trip and are
/// restored verbatim. These are framework-opaque strings that the host
/// (书安OS) uses for multi-tenancy / accounting / tracing — losing
/// uses for multi-tenancy / accounting / tracing — losing
/// them on migration breaks audit trails.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn identity_labels_persist_across_save_and_resume() {
Expand Down Expand Up @@ -449,7 +449,7 @@ async fn identity_labels_persist_across_save_and_resume() {

/// IT-CONSOLIDATED (cluster ops): exercise the full cluster-grade
/// API surface in one realistic two-node lifecycle. This is the
/// reference flow 书安OS-side scheduling code targets.
/// reference flow host-side scheduling code targets.
///
/// Two **separate** Agents share one MemorySessionStore (simulating
/// two cluster nodes mounting the same persistent store):
Expand All @@ -460,7 +460,7 @@ async fn identity_labels_persist_across_save_and_resume() {
///
/// The host-supplied identity labels, retention caps, and persisted
/// subagent task snapshots must all survive the cross-node hop —
/// these are exactly the invariants 书安OS relies on for billing,
/// these are exactly the invariants the host relies on for billing,
/// audit, and memory safety in a long-lived fleet.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn cluster_ops_consolidated_session_lifecycle() {
Expand Down Expand Up @@ -597,7 +597,7 @@ async fn cluster_ops_consolidated_session_lifecycle() {
assert_eq!(cp_after.total_usage.total_tokens, 1000);

// Node B can decide to clean up the old run id once it's done with
// resumption — the host (书安OS) tracks the old→new run mapping.
// resumption — the host tracks the old→new run mapping.
// The framework does not auto-delete checkpoints; that's the
// host's call.
}
Expand All @@ -606,7 +606,7 @@ async fn cluster_ops_consolidated_session_lifecycle() {
/// through to the session's in-memory subagent task tracker so a
/// long-running session's terminal entries don't accumulate
/// unboundedly. Verified via the public tracker accessor — same
/// surface 书安OS would inspect / drive externally.
/// surface the host would inspect / drive externally.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn retention_limits_are_plumbed_into_subagent_tracker() {
use a3s_code_core::retention::SessionRetentionLimits;
Expand Down Expand Up @@ -660,7 +660,7 @@ async fn retention_limits_are_plumbed_into_subagent_tracker() {
}

/// IT-6 (Pillar 3 cut 1): a `LoopCheckpoint` round-trips through the
/// `SessionStore` — this is the data contract 书安OS will sit on to
/// `SessionStore` — this is the data contract the host will sit on to
/// migrate / replay a run on another node.
///
/// Cut 1 lands the data + persistence path. The actual in-loop
Expand Down Expand Up @@ -774,7 +774,7 @@ async fn send_without_tool_calls_does_not_emit_loop_checkpoint() {
// assert the *negative* property: with no run yet executed, no
// checkpoint exists for any run id we choose to query.
//
// This also documents the contract for 书安OS-side tooling: a
// This also documents the contract for host-side tooling: a
// session that hasn't completed a tool round has no checkpoint.
let probe = store
.load_loop_checkpoint("any-fake-run-id")
Expand All @@ -790,7 +790,7 @@ async fn send_without_tool_calls_does_not_emit_loop_checkpoint() {
/// IT-8 (Pillar 3 cut 2): `AgentSession::resume_run` fails fast with a
/// helpful error when there is no checkpoint for the given run id, and
/// with a different error when no `SessionStore` is configured at all.
/// These are the error paths 书安OS-side scheduling code needs to
/// These are the error paths host-side scheduling code needs to
/// distinguish to decide between "retry later" and "fall back to a
/// fresh session".
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
Expand Down
Loading