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
22 changes: 16 additions & 6 deletions PARITY-STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Rust is the reference; TypeScript, Python, Go and C#/.NET are native ports. Thes
| Provider routing: presets, per-activity slots, fallback chains, per-model quirks, LiteLLM alias resolution | ✅ all five |
| SEP extension host: manifest, capabilities, tool/provider/UI/command lanes, restart backoff, bounded observe lane | ✅ all five |
| Durable-execution **seam** (`AgentExecutor` + activities + `TurnPolicy`) | ✅ all five |
| Durable-execution **backend** (Temporal: crash-safe resume, durable HITL signals, durable-wait timer) | ✅ all five [^durable] |

### Why the claim holds

Expand All @@ -45,14 +46,17 @@ Three shared corpora are generated **from the Rust reference** and replayed by a

On the service side, all five servers replay [`spec/conformance/scenarios`](spec/conformance) — in **this** repo — against the engine's deterministic mock, so they must emit identical protocol output.

[^durable]: The durable backend is a separate, **optional, feature-gated per-language package** — Rust's `smooth-operator-temporal` crate plus new Go / TypeScript / Python / .NET packages ([core-repo PRs #170, #168, #169, #173](https://github.com/SmooAI/smooth-operator-core/pulls)) — each with a client-side `AgentExecutor` that starts the Temporal workflow, durable HITL via approve/deny signals, and a durable-wait timer, e2e-tested against a real ephemeral Temporal server. The server-side selection seam (env `SMOOTH_AGENT_DURABLE_EXECUTOR`, backend **dependency-injected** so the published server keeps no hard Temporal dep) is in all five servers ([this repo PRs #450, #451, #452, #455](https://github.com/SmooAI/smooth-operator/pulls)); no engine pulls a Temporal SDK into your dependency tree by default. **Shared ADR-030 follow-up — the same in every language, Rust reference included, *not* a Rust-vs-others gap:** the durable path yields only a terminal result (no token-delta streaming) and reports `costUsd=0` on the workflow result, and the executor seeds from agent config only (no prior-thread history / per-turn-per-org tool registry). This is the remaining "workflow→streaming adapter bridge" product question.

---

## 2. Rust-first — the engine's two honest exceptions
## 2. Rust-first — the engine's one honest exception

| Surface | Status |
| --- | --- |
| **Extension sandbox / integrity hardening** | **Rust-first.** Capability *declarations* are parsed and honoured in all five, but process-level confinement and manifest-integrity verification are Rust-only. See [Extension-Sandboxing-Design.md](https://github.com/SmooAI/smooth-operator-core/blob/main/docs/Extension-Sandboxing-Design.md). |
| **Durable-execution backend** | **Rust-first.** The `AgentExecutor` seam is in all five with an in-process executor that delegates verbatim to `run`, so the seam changes nothing until something plugs in. Only Rust ships a real backend — the separate, feature-gated `smooth-operator-temporal` crate (turn as a Temporal workflow, model/tool calls as activities: crash-safe resume, durable HITL signals, durable timers). The other four carry a `TODO(ADR-030)` naming the opt-in package their backend belongs in; no engine pulls a Temporal SDK into your dependency tree. |

The **durable-execution backend** used to sit here as the second Rust-first exception; it no longer does. The Temporal backend ships as an optional per-language package in all five, and the server-side selection seam is in all five servers — see the durable backend row in §1 and its footnote for the one shared ADR-030 streaming/cost follow-up that remains (identical across all five, not a parity gap).

---

Expand All @@ -65,14 +69,15 @@ All five servers carry the transport core: frame dispatch, per-turn engine, sess
| Transport core (dispatch · sessions · auth · drain) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Shared scenario conformance corpus | ✅ | ✅ | ✅ | ✅ | ✅ |
| Postgres conversation store | ✅ | ✅ | ✅ | ✅ | ✅ |
| Server `gen_ai.*` OTel telemetry (chat + tool spans · redacted tool args · env-gated OTLP) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Second storage backend (DynamoDB + S3 Vectors) | ✅ | — | — | — | — |
| Persistent checkpoint / knowledge / ACL-knowledge stores | ✅ | ✅ | | | ◐ [^py-knowledge] |
| Persistent checkpoint / knowledge / ACL-knowledge stores [^knowledge] | ✅ | ✅ | | | ◐ |
| Deep ingestion + ACL surface | ✅ | ✅ | ◐ | ◐ | ◐ |
| Backplane `attach`/`detach` | ✅ | — | ✅ | ✅ | ✅ |
| Backplane `publish` (event fan-out) | ✅ | — | ✅ | ✅ | — |
| **Cross-pod backplane (Redis / NATS)** | ✅ | — | — | — | — |

[^py-knowledge]: Python now has the durable **knowledge + ACL-knowledge** stores (`postgres_knowledge.py`: `PostgresVectorKnowledge` / `PostgresAclKnowledge`, on the shared `knowledge_vectors` table + pgvector). The persistent **checkpoint** store is still pending, so the cell is ◐ rather than ✅.
[^knowledge]: The durable **knowledge + ACL-knowledge** Postgres stores now ship in **Go, TypeScript and Python** too ([PRs #442, #443, #444](https://github.com/SmooAI/smooth-operator/pulls)) — on the shared `knowledge_vectors` table + pgvector — alongside Rust and .NET (which already had them, e.g. Python's `postgres_knowledge.py`: `PostgresVectorKnowledge` / `PostgresAclKnowledge`). These three cells stay **◐ rather than ✅** for two honest reasons: the persistent **checkpoint** store is still pending in Go/TS/Python, and the **TS + Python** knowledge stores are shipped and contract-tested but **not yet wired into the live dispatcher** (a sync-engine vs async-pg bridge). The **second storage backend** (DynamoDB + S3-Vectors, the row above) remains Rust-only.

**The operational consequence:** only the **Rust** server scales past one replica today. Go, TypeScript and Python run an in-memory backplane — correct for a single process, silently wrong the moment you run two pods, because an event published on pod A never reaches a socket held by pod B. C# has no backplane surface at all.

Expand All @@ -83,7 +88,7 @@ All five servers carry the transport core: frame dispatch, per-turn engine, sess
Three items, in the order they'd bite:

1. **Cross-pod backplane beyond Rust.** Go and TypeScript have the full `attach`/`detach`/`publish` surface but only an in-memory implementation; **Python has `attach`/`detach` with no `publish`**; **C# has no backplane at all**. Redis/NATS adapters exist only for Rust. Until a language has one, treat its server as single-replica.
2. **Durable backend beyond Rust.** Per-language Temporal packages (the seam is already in place, so this is additive and needs no engine change).
2. **Durable path → streaming/cost adapter bridge (ADR-030) — done shipping, one shared follow-up left.** The Temporal backend now ships as an optional per-language package in **all five** and the server-side selection seam is in **all five** servers (§1 durable backend row + footnote), so this is no longer a language gap. What remains is identical across every language, Rust reference included: the durable path returns only a terminal result (no token-delta streaming) and reports `costUsd=0` on the workflow result, and the executor seeds from agent config only. Bridging the workflow result back onto the streaming/cost surface is the open ADR-030 product question.
3. **`seq` is under-specified in the shared schema.** [`spec/extension/methods/event.schema.json`](spec/extension/methods/event.schema.json) marks `seq` optional (`required: ["event", "context"]`), but **all five** engines always emit it on an `event` frame, and all five correctly omit it on the out-of-band `events_lost` marker. The implementations agree with each other and the schema is looser than all of them — so a sixth implementation could legally omit `seq`, pass conformance, and break the gap-detection that `events_lost` depends on. Tighten the schema to match the implementations rather than the reverse.

---
Expand All @@ -104,8 +109,13 @@ rg -n 'attach|detach|publish' go/server/backplane.go \
rust/smooth-operator/src/backplane.rs
rg -ril backplane dotnet/ # expect: no matches

# Durable backend: expect matches only under rust/
# Durable backend: temporal packages now ship in all five (rust/ go/ typescript/ python/ dotnet/),
# and the server-side selection seam (SMOOTH_AGENT_DURABLE_EXECUTOR) is in all five servers.
find . -iname '*temporal*' -not -path '*/target/*' -not -path '*/node_modules/*'
rg -n 'SMOOTH_AGENT_DURABLE_EXECUTOR' rust/ go/ typescript/ python/ dotnet/

# Server gen_ai OTel telemetry present in all five servers? (chat + tool spans)
rg -n 'gen_ai\.chat|gen_ai\.tool' rust/ go/ typescript/ python/ dotnet/
```

Last verified against `main` on 2026-08-17.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,9 @@ One protocol, defined once in [`spec/`](spec) (JSON Schema). Everything else is

| Surface | Status |
| --- | --- |
| **Engine** ([`smooth-operator-core`](https://github.com/SmooAI/smooth-operator-core)) | **5-language parity engine** — Rust · C# · Python · TypeScript · Go, each published (crates.io / NuGet / PyPI / npm / Go module). Rust is the reference; the others mirror its surface. Every engine capability is in all five today except two, both stated plainly in [PARITY-STATUS.md](PARITY-STATUS.md): the extension **sandbox / integrity hardening** is Rust-first, and the durable-execution **backend** ships only for Rust (the seam it plugs into is in all five). |
| **Engine** ([`smooth-operator-core`](https://github.com/SmooAI/smooth-operator-core)) | **5-language parity engine** — Rust · C# · Python · TypeScript · Go, each published (crates.io / NuGet / PyPI / npm / Go module). Rust is the reference; the others mirror its surface. Every engine capability is in all five today except **one**, stated plainly in [PARITY-STATUS.md](PARITY-STATUS.md): the extension **sandbox / integrity hardening** is Rust-first. The durable-execution **backend** (Temporal) now ships as an optional per-language package in **all five**, with the server-side selection seam in all five servers — leaving only the one shared ADR-030 streaming/cost follow-up that applies equally to every language, Rust included. |
| **Protocol clients** | **All five languages** — TypeScript (`@smooai/smooth-operator`), Go, .NET (with a `Microsoft.Extensions.AI` `IChatClient` facade), Python, Rust. The TS side also ships a **React binding** and an **embeddable widget**. |
| **Servers** | **All five languages** — Rust · C# · Python · TypeScript · Go, each consuming its own language's engine so a host can run the full service in its native stack. All five carry the transport core: frame dispatch · per-turn engine · sessions · auth · graceful drain, plus a Postgres store for conversations/messages/participants/sessions. Depth past that is uneven and worth knowing before you pick one: **Rust** is the only server with pluggable storage backends (Postgres *and* DynamoDB) and the only one with a **cross-pod backplane** (Redis / NATS) — the rest run an in-memory backplane, so they are single-replica. **C#** adds persistent checkpoint, knowledge-base and ACL-knowledge stores, and carries the deepest ingestion/ACL surface after Rust, but ships **no backplane at all** today. **Python/TS/Go** are transport-core servers. **All five run the shared scenario conformance corpus** — driven by the engine's deterministic mock, so they must produce identical protocol output. The corpus already caught and fixed real error-handling divergences in the TS and C# servers. See [PARITY-STATUS.md](PARITY-STATUS.md) for the verified breakdown. |
| **Servers** | **All five languages** — Rust · C# · Python · TypeScript · Go, each consuming its own language's engine so a host can run the full service in its native stack. All five carry the transport core: frame dispatch · per-turn engine · sessions · auth · graceful drain, plus a Postgres store for conversations/messages/participants/sessions. Depth past that is uneven and worth knowing before you pick one: **Rust** is the only server with pluggable storage backends (Postgres *and* DynamoDB) and the only one with a **cross-pod backplane** (Redis / NATS) — the rest run an in-memory backplane, so they are single-replica. **C#** adds persistent checkpoint, knowledge-base and ACL-knowledge stores, and carries the deepest ingestion/ACL surface after Rust, but ships **no backplane at all** today. **Go, TypeScript and Python** now also carry the durable **knowledge + ACL-knowledge** Postgres stores (the persistent **checkpoint** store is still Rust/.NET-only, and the TS/Python knowledge stores aren't yet wired into the live dispatcher). **All five servers now emit `gen_ai.*` OpenTelemetry spans** (chat + tool, redacted tool args, env-gated OTLP). **All five run the shared scenario conformance corpus** — driven by the engine's deterministic mock, so they must produce identical protocol output. The corpus already caught and fixed real error-handling divergences in the TS and C# servers. See [PARITY-STATUS.md](PARITY-STATUS.md) for the verified breakdown. |

---

Expand Down
Loading