Skip to content

add simple example notebook#1

Merged
Harrison Chase (hwchase17) merged 1 commit intomainfrom
harrison/simple-example
Aug 15, 2023
Merged

add simple example notebook#1
Harrison Chase (hwchase17) merged 1 commit intomainfrom
harrison/simple-example

Conversation

@hwchase17
Copy link
Copy Markdown
Contributor

No description provided.

@nfcampos Nuno Campos (nfcampos) deleted the harrison/simple-example branch August 26, 2024 22:30
xingshuozhu1998 pushed a commit to xingshuozhu1998/langgraph that referenced this pull request May 1, 2026
Alaina Hardie (trianglegrrl) referenced this pull request in trianglegrrl/langgraph May 6, 2026
Lands `langgraph-core` with all 9 channel types from the Python baseline:

- LastValue, LastValueAfterFinish
- Topic (with accumulate variant)
- BinaryOperatorAggregate (with Overwrite handling)
- EphemeralValue, AnyValue, UntrackedValue
- NamedBarrierValue, NamedBarrierValueAfterFinish

Plan §6 Step 1.1 listed 6 channels; expanded to 9 after a parity-pass review:
LastValueAfterFinish + the two NamedBarrier variants exercise consume() and
finish() lifecycle hooks that the original 6 don't, closing what would have
been a real gap in the parity gate.

Parity gates (all green):
- Rust unit tests: 48 pass (Python test verbatim ports + source-contract
  ports for the 5 channels with no direct Python tests).
- test_channels_via_bridge.py: 10 channel parity tests run lockstep against
  real Python langgraph (the parity oracle) via `langgraph_rs.run_channel_sequence`.
- test_channels_differential.py: 10,800 hypothesis iterations across 9
  channels, zero divergences, ~7s.
- Phase 0 baseline intact: bridge round-trip 73/73, conformance 58 pass.

Bridge surface: added `run_channel_sequence(kind, init_json, ops_json) -> trace_json`,
JSON-only protocol for the differential harness. Avoids needing PyO3
to expose Rust channel objects as Python BaseChannel ABCs.

Channel trait: typed per-impl `Channel<Value, Update, Checkpoint>` with
Send + Sync (anticipating tokio runtime). Object-safe `dyn ChannelKind`
deferred to Step 1.2 per phase-1-followups.md langchain-ai#2 — designing the erased
layer before Pregel needs it would be speculative.

DeltaChannel (10th channel in the source) deferred to Step 1.3 with full
tracked-by check in phase-1-followups.md #1: reducer-as-callable plus
_DeltaSnapshot codec wiring make it a real scope expansion, and 4 of its
21 Python tests need StateGraph + InMemorySaver anyway.

Test counts: workspace 116 pass (68 Phase 0 + 48 Step 1.1), zero clippy
warnings.
Alaina Hardie (trianglegrrl) referenced this pull request in trianglegrrl/langgraph May 6, 2026
Closes Phase 0 follow-up #1's tracked-by check ("at least one
#[pyfunction(async)] exposed in the bridge, plus a Python async test
that calls it"). First piece of the combined Step 1.2b + 1.3
milestone — see plan amendment in this commit and the locked
architectural decisions in rust/docs/phase-1-followups.md entry langchain-ai#3.

What lands:

  - rust/Cargo.toml: workspace deps for pyo3 0.28, pyo3-async-runtimes
    0.28, tokio 1 (rt-multi-thread, macros, sync, time). Bridge
    Cargo.toml switches to workspace-versioned pyo3.
  - rust/ffi/langgraph-py/src/async_runtime.rs: new module with
    `async_echo(s) -> awaitable[str]`. Sleeps 1ms on tokio then
    returns s.upper() — a wiring proof, not a feature. Replaced by
    real entry points (run_pregel_async, …) as Step 1.2b's surface
    grows; kept around because its asyncio test is the cheapest
    smoke check that the wiring still works after future bridge
    changes.
  - parity/scripts/test_async_bridge.py: 3 tests (await, gather,
    attribute presence). Uses anyio (matching upstream
    libs/langgraph/tests/test_pregel.py — required for the eventual
    87-test parity gate to run on the same async framework).
  - .omc/plans/langgraph-rust-port-2026-04-30.md: amends §6 to mark
    Step 1.2b + 1.3 as one combined milestone with the locked
    architectural decisions (research-backed via the two
    research/*.md files in this commit).
  - rust/docs/phase-1-followups.md: entry #1 (DeltaChannel) and
    entry langchain-ai#3 (async bridge + LANGGRAPH_BACKEND wiring) re-pointed
    to the combined milestone, with explicit decision log.
  - research/pyo3-async-pregel-2026-05-05.md +
    python-rust-backend-swap-2026-05-05.md: pplx research outputs
    that ground the locked decisions (pyo3-async-runtimes 0.28 is
    the maintained answer; Pattern B monkeypatch from a separate
    package is canonical for accelerating frozen-baseline libs).

GIL discipline (production pattern from polars / pydantic-core /
datafusion-python): release between Python callbacks via short
Python::with_gil scopes. The Rust future itself runs without the
GIL. Wired through pyo3-async-runtimes::tokio::future_into_py.

Parity gate: 3 anyio tests via the bridge venv's Python directly
(SESSION-RESUME's bridge install gotcha applies — uv run python
silently reverts the .so).

What the gate caught: nothing — this is foundation. The first
test_async_echo_awaits_via_tokio failure on commit-day was
"pytest-asyncio not installed" → fixed by switching to anyio
(matches upstream langgraph), which uncovered nothing about the
Rust side.

Verification:
  - 161/161 cargo tests pass (unchanged from 1.2a baseline)
  - cargo clippy --workspace --all-targets -- -D warnings clean
  - 3/3 new asyncio tests pass
  - 73/73 Phase 0 corpus + 49 allowlist + strict-reject pass
  - 58/58 conformance via Rust shadow pass
  - 19/19 Step 1.1 channels parity (10 fixtures + 9 differential)
  - 29/29 Step 1.2a Pregel parity (24 fixtures + 5 hypothesis)
Alaina Hardie (trianglegrrl) referenced this pull request in trianglegrrl/langgraph May 6, 2026
Closes the channel-only portion of Phase 1 follow-up #1's tracked-by
check (≥1,000 hypothesis iterations + dict-reducer Python tests). The
Pregel-coupled portion of follow-up #1 (snapshot scheduling driven by
`is_snapshot_step`, end-to-end filesystem saver) and the
`_messages_delta_reducer` Python tests stay deferred to the
combined Step 1.2b + 1.3 milestone — that's where Python callable
reducers cross the bridge via the async callback runner.

What lands:

  - langgraph-core::channels::delta — new module:
    * `DeltaChannel<T>`: typed Channel impl. State is `Option<T>`
      (None = MISSING). Update accepts `DeltaUpdate<T>` enum:
      `Value(T)` or `Overwrite(Option<T>)` (None = reset to default).
      One Overwrite per superstep is enforced; two raises
      `InvalidUpdateError` matching Python's behavior.
    * `replay_writes(&[DeltaUpdate<T>])`: walks an ancestor write
      log, last-Overwrite-wins on the base, then folds remaining
      values through the reducer. Empty replay is a no-op.
    * `is_snapshot_step(step: i64) -> bool`: matches Python's
      `step > 0 && step % freq == 0` (uses `is_multiple_of` for
      clippy 1.95).
    * `DeltaCheckpoint<T>`: { Sentinel, Snapshot(T) } discriminator.
      Channel.checkpoint() always returns Sentinel for non-empty
      state — the Snapshot path is Pregel-driven (combined milestone).
    * `reducers` submodule: `merge_dicts` (dict union, last-write-
      wins per key), `extend_list` (concat), `merge_files` (dict
      union with `null` → delete). Selectable by name from the
      bridge: arbitrary Python callable reducers cross via the
      async callback runner step in 1.2b proper.
    * 19 unit tests: empty/missing handling, fresh-channel from
      sentinel, basic merge, last-write-wins, Overwrite(Some/None),
      double-Overwrite invalid, batching invariance for both
      reducers, replay_writes mechanics, snapshot-step predicate.

  - langgraph-core::pregel::channel_kind_impls — DeltaChannel
    `ChannelKind` impl. JSON dispatch:
      Update:    raw value → `DeltaUpdate::Value`
                 `{"__overwrite__": v_or_null}` → `DeltaUpdate::Overwrite`
      Checkpoint: `{"__delta_sentinel__": true}` for Sentinel,
                  `{"__delta_snapshot__": v}` for Snapshot.

  - langgraph-py bridge — `Op::Replay { writes }` variant added to
    the channels.rs op enum. Non-Delta drivers return
    `UnsupportedOp` for replay; only `run_delta` actually executes
    it. Init shape extends with `reducer`, `default_kind`, `seed`,
    `snapshot_frequency`.

  - parity/scripts/test_delta_channel_via_bridge.py — 10 tests:
    * 7 dict-reducer fixture scenarios mirroring `test_channels.py`
      (fresh-channel, basic-updates, writes-reconstruction,
      with-deletions update path, with-deletions replay path,
      overwrite-in-update, overwrite-in-writes-replay).
    * 1 InvalidUpdate scenario (two Overwrites in one step).
    * 2 hypothesis differential tests (merge_dicts and extend_list)
      at 600 examples each — 1,200 iterations, 0 divergences.

Parity gate: 10/10 via the bridge venv's Python (anyio + hypothesis).

What the gate caught:
  - Bridge install loop (uv pip install needed VIRTUAL_ENV pointing
    at the bridge venv, not cwd; one wheel-build race between source
    edits and `run_in_background`). Documenting these in the
    SESSION-RESUME bridge gotcha is already covered.
  - Three clippy 1.95 lints: manual modulo (`is_multiple_of`),
    two collapsible-if patterns (`if let && let && let` chain).

Verification (regression):
  - 180/180 cargo tests pass (up from 161; +19 delta unit tests)
  - cargo clippy --workspace --all-targets -- -D warnings clean
  - 73/73 Phase 0 corpus + 49 allowlist + strict-reject
  - 58/58 conformance via Rust shadow saver
  - 19/19 Step 1.1 channels parity (10 fixtures + 9 differential)
  - 29/29 Step 1.2a Pregel parity (24 fixtures + 5 hypothesis)
  - 3/3 Step 1.2b async-bridge wiring (foundation commit)
  - 10/10 Step 1.2b DeltaChannel parity (this commit)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant