docs: consolidate design documentation and standardize crate English
This commit is contained in:
@@ -1,31 +1,13 @@
|
||||
# protocol
|
||||
|
||||
## Role
|
||||
`protocol` defines input, control, event, and public history types shared by Workers
|
||||
and clients. It does not own transport, stored-log replay, or rendering. It separates
|
||||
live state from committed history so clients can reconnect without depending on storage formats.
|
||||
|
||||
`protocol` defines the JSONL message boundary between Worker clients and Worker servers.
|
||||
## Design entry points
|
||||
|
||||
## Boundaries
|
||||
|
||||
Owns:
|
||||
|
||||
- transport-neutral method/event/result types
|
||||
- request/reply and broadcast event shapes
|
||||
- protocol error categories shared by clients and servers
|
||||
|
||||
Does not own:
|
||||
|
||||
- Unix socket implementation details (`client`, `worker`)
|
||||
- TUI rendering (`tui`)
|
||||
- Engine history semantics (`agen`)
|
||||
- durable storage (`session-store`, `session-store` worker metadata)
|
||||
|
||||
## Design notes
|
||||
|
||||
The exact enum variants are code authority. The README should describe the boundary, not duplicate every message shape.
|
||||
|
||||
Protocol events can inform UI and orchestration, but durable state changes still need to flow through Worker/session/metadata records.
|
||||
|
||||
## See also
|
||||
|
||||
- [`../../docs/design/worker-session-state.md`](../../docs/design/worker-session-state.md)
|
||||
- [`../../docs/design/context-history.md`](../../docs/design/context-history.md)
|
||||
- [`Method`] / [`Event`]: input acceptance versus live updates and history commits
|
||||
- [`WorkerStateSnapshot`]: controller state versus Runtime catalog state
|
||||
- [`SessionSnapshot`]: public representation of committed history
|
||||
- [`subscription`]: ordering of snapshots and subsequent events
|
||||
- [`invocation`]: validation of typed Feature input
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
pub mod identity;
|
||||
pub mod invocation;
|
||||
#[cfg(feature = "stream")]
|
||||
@@ -211,6 +213,10 @@ pub struct WorkerStateSnapshot {
|
||||
pub state: WorkerState,
|
||||
}
|
||||
|
||||
/// Handles current controller state; input admission is not inferred from past history.
|
||||
///
|
||||
/// Distinguishes Run from maintenance. The Runtime catalog's `Stopped` state persists
|
||||
/// after shutdown and is not part of this controller snapshot.
|
||||
impl WorkerStateSnapshot {
|
||||
pub fn initial() -> Self {
|
||||
Self {
|
||||
@@ -445,6 +451,11 @@ pub enum WorkerEvent {
|
||||
},
|
||||
}
|
||||
|
||||
/// Separates child reports into control handling and model-facing notifications.
|
||||
///
|
||||
/// Scope registration updates are control-only and do not wake the parent's model.
|
||||
/// Messages may arrive out of order; child notifications prompt state checks,
|
||||
/// not proof of completed artifacts or validation.
|
||||
impl WorkerEvent {
|
||||
/// Whether this event should become an agent-visible notification/history item.
|
||||
///
|
||||
@@ -732,6 +743,13 @@ impl Segment {
|
||||
}
|
||||
}
|
||||
|
||||
/// Treats input acceptance and model-history inclusion as separate boundaries.
|
||||
///
|
||||
/// Submit/Notify receipts do not imply execution success; the corresponding Event
|
||||
/// reports committed history. Human Submit requests use a waiting FIFO, while agents
|
||||
/// use SubmitIfIdle only when Idle, never implicitly scheduling the next Run.
|
||||
/// Pause/Resume suspend and resume a Run independently of new Submit acceptance;
|
||||
/// Resume does not create a new user message.
|
||||
impl Method {
|
||||
/// Convenience: a `Submit` carrying a single `Segment::Text`.
|
||||
/// Used by dumb clients, inter-Worker tools, and tests that only have
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
//! Shared subscription-multiplexer wire contract.
|
||||
//! Transport contract for multiple subscriptions over one connection.
|
||||
//!
|
||||
//! This protocol is distinct from the single-Worker [`crate::Method`] / [`crate::Event`]
|
||||
//! protocol. A connection carries many independently managed subscriptions. The
|
||||
//! connection endpoint owns authorization and maps the typed selectors below to
|
||||
//! visible resources; clients cannot provide Workspace scope as selector input.
|
||||
//! Manages subscriptions separately from a single Worker's [`crate::Method`] and
|
||||
//! [`crate::Event`]. The endpoint owns authorization and selector resolution;
|
||||
//! it does not accept Workspace scope from clients. Each subscription snapshot
|
||||
//! anchors subsequent events; reconnecting replaces public state.
|
||||
//!
|
||||
//! Worker snapshots use public DTOs, not stored logs, keeping storage replay rules
|
||||
//! out of clients. Committed history and uncommitted output stay separate;
|
||||
//! subsequent history-commit events are matched by entry ID. Reasoning and internal
|
||||
//! extension payloads are not exposed in conversation views.
|
||||
//!
|
||||
//! Input acceptance, stream deltas, and history commits are distinct boundaries;
|
||||
//! live notifications alone do not establish durable state or completed results.
|
||||
//! Turn boundaries also differ from individual generation requests. Transport
|
||||
//! retries before streaming are retry notifications for the same generation request.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
|
||||
@@ -173,11 +173,13 @@ pub fn generated_protocol_types() -> String {
|
||||
normalize_typescript(output)
|
||||
}
|
||||
|
||||
/// Render the strict runtime validator paired with the generated declarations.
|
||||
/// Generates the Browser receive validator paired with TypeScript declarations.
|
||||
///
|
||||
/// `schemars` projects the reachable Serde shape from [`SubscriptionFrame`]. The
|
||||
/// normalization closes every object and expands flattened enum payloads before
|
||||
/// embedding that schema into the dependency-free Browser validator template.
|
||||
/// Normalizes schemas reachable from [`SubscriptionFrame`] to Rust's actual wire shape.
|
||||
/// Corrects required/nullable fields and integer bounds rather than adopting Serde's
|
||||
/// decode-time omission rules as the receive contract. Expands common flattened-enum
|
||||
/// fields into each variant before closing objects, then embeds the schema in a
|
||||
/// validator template that rejects unknown fields.
|
||||
pub fn generated_protocol_validator() -> String {
|
||||
let mut schema = serde_json::to_value(schemars::schema_for!(SubscriptionFrame))
|
||||
.expect("SubscriptionFrame schema must serialize");
|
||||
@@ -365,6 +367,8 @@ fn close_object_shapes(schema: &mut Value) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Makes schemas with `default: null` accept null in their types as well.
|
||||
/// A null default with a string-only or similar type would reject null sent by Rust.
|
||||
fn normalize_null_default(schema: &mut Map<String, Value>) {
|
||||
if schema.get("default") != Some(&Value::Null) || schema.contains_key("anyOf") {
|
||||
return;
|
||||
@@ -386,6 +390,10 @@ fn normalize_null_default(schema: &mut Map<String, Value>) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Limits JSON integers to the intersection of Rust's type range and JavaScript's
|
||||
/// safe-integer range for TypeScript `number`. Never relaxes explicit bounds;
|
||||
/// rejects unknown formats during generation rather than emitting integer types
|
||||
/// with unknown ranges as if they could be validated.
|
||||
fn normalize_integer_format(schema: &mut Map<String, Value>) {
|
||||
let is_integer = match schema.get("type") {
|
||||
Some(Value::String(value)) => value == "integer",
|
||||
@@ -426,6 +434,9 @@ fn tighten_numeric_bound(
|
||||
);
|
||||
}
|
||||
|
||||
/// Serde decode-time defaults do not imply omitted fields on the wire.
|
||||
/// Restores fields with schema defaults to required to match the serialized shape.
|
||||
/// Does not fill missing fields with defaults in the Browser.
|
||||
fn require_serialized_defaults(schema: &mut Map<String, Value>) {
|
||||
if schema.get("type").and_then(Value::as_str) != Some("object") {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user