Skip to content

add notebook for cognitive architectures#2

Closed
Harrison Chase (hwchase17) wants to merge 1 commit intomainfrom
harrison/cog-arch
Closed

add notebook for cognitive architectures#2
Harrison Chase (hwchase17) wants to merge 1 commit intomainfrom
harrison/cog-arch

Conversation

@hwchase17
Copy link
Copy Markdown
Contributor

No description provided.

@nfcampos Nuno Campos (nfcampos) marked this pull request as draft October 23, 2023 13:18
Isaac Francisco (isahers1) added a commit that referenced this pull request Jul 25, 2024
@nfcampos Nuno Campos (nfcampos) deleted the harrison/cog-arch branch August 26, 2024 22:30
Alaina Hardie (trianglegrrl) added a commit to trianglegrrl/langgraph that referenced this pull request 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) added a commit to trianglegrrl/langgraph that referenced this pull request May 6, 2026
Splits Phase 1 §6 Step 1.2 into 1.2a (Pregel core, differential parity
on synthetic fixtures) and 1.2b (LANGGRAPH_BACKEND=rust + async PyO3
bridge). 1.2a closes Phase 1 follow-up langchain-ai#2 (erased dyn ChannelKind);
1.2b takes over the new follow-up langchain-ai#3 (async bridge + LANGGRAPH_BACKEND).

What lands:

  - langgraph-core::pregel — algorithmic core only (no streaming, no
    interrupts, no subgraphs, no Send, no managed values, no callbacks).
    Modules:
      * channel_kind: erased dyn ChannelKind trait + impls for all 9
        Step 1.1 channels, going through serde_json at the boundary.
      * apply_writes: parity port of Python _algo.apply_writes
        (versions_seen, consume, group writes, bump-step idle pass,
        finish-pass on tentatively-last superstep).
      * prepare_tasks: PULL path of prepare_next_tasks. Task ids match
        Python's xxh3-128 byte-for-byte (xxhash-rust, UUID-formatted).
      * loop_: PregelLoop::new + with_versioning + with_parent_ns +
        with_stop builders, tick(), run(), TraceEntry/TraceTask shape
        for the parity comparison.
      * checkpoint_helpers: empty_checkpoint() + checkpoint_id_to_bytes()
        with proper InvalidCheckpointId error variant.
    All submodules private; pub use surface listed in mod.rs.

  - langgraph-py bridge: run_pregel_fixture(name, init_json,
    max_steps=None) entry point with 5 hand-rolled fixtures
    (linear_chain, conditional_fork, fan_out, recursion,
    multi_channel_reducer_mix).

  - parity/scripts/test_pregel_fixtures_via_bridge.py: 24 parametrised
    tests vs Python StateGraph, user-channel parity.

  - parity/scripts/test_pregel_differential.py: 5 hypothesis tests,
    ~1300 random iterations, 0 divergences.

Step + recursion-limit are i64 (matches Python's signed int wire type;
1.2b checkpoint interop needs the negative one-step "before any input"
state). PregelLoop fields are pub(crate); external mutation goes
through put_input/tick/run + the with_* builders. The pregel layer's
runtime channel value type is named ChannelValue (distinct from the
codec's wire-format Decoded — Phase 0 follow-up langchain-ai#2 plans to migrate
Checkpoint::channel_values to codec Decoded later).

Verification: 161 cargo tests, clippy clean, 24+5 fixture/differential
parity tests, Phase 0 round-trip + conformance still all-green.
Alaina Hardie (trianglegrrl) added a commit to trianglegrrl/langgraph that referenced this pull request May 6, 2026
…ler (V0.1 scope)

Minimum-viable Rust `StateGraph` builder that compiles to a runnable
`PregelLoop`. Sub-task langchain-ai#5 of the combined Step 1.2b + 1.3 milestone
(`rust/docs/STEP-1.2B-PARTIAL-HANDOFF.md`); satisfies the original Step
1.3 sub-gate (5 fixture graphs trace-equal vs Python `StateGraph`).

The full Python `StateGraph` is 1833 lines + branch helpers; the V0.1
port is sharply scoped to what the 5-fixture sub-gate needs and what
the 87-test gate (langchain-ai#7) ultimately requires from the compiler. Everything
beyond that is documented as deferred to follow-ups so langchain-ai#5 doesn't drag
features the runner monkeypatch (langchain-ai#6) doesn't need.

What landed
-----------
- New `crates/langgraph-core/src/state_graph/mod.rs`:
  - `StateGraph::new(channels)` (explicit channel map; no
    `Annotated[T, reducer]` schema inference).
  - `add_node`, `add_edge`, `add_conditional_edges`,
    `set_entry_point`, `set_finish_point`, `compile`.
  - `compile()` lowers to a `PregelLoop` by generating synthetic
    `branch:to:NODE` `LastValue<Value>` trigger channels for every
    incoming-edge target. User node callables are wrapped to emit
    sentinel writes for direct outgoing edges + conditional-branch
    resolutions after the user's state-channel writes.
  - `START` / `END` constants. `BRANCH_PREFIX` reserved namespace
    (compile rejects collisions). `START -> node` edges return the
    corresponding synthetic input channel via `CompiledGraph.input_channels`
    so the caller knows what to put_input.
  - 9 cargo unit tests covering compile validation + linear chain +
    conditional fork + fan-out + branch error path.
- New `rust/ffi/langgraph-py/src/state_graph_fixtures.rs` — bridge
  module that builds the 5 fixture graphs (linear_chain,
  conditional_fork, fan_out, conditional_join, recursion) via the new
  `StateGraph` builder. New PyO3 entry point
  `run_state_graph_fixture(name, init_json) -> trace_json`.
- New `parity/scripts/test_state_graph_via_bridge.py` — 25 tests
  driving each fixture against the upstream Python `StateGraph` and
  comparing user-visible state + node execution sequence.

Out of scope (V0.1, deferred to follow-ups)
-------------------------------------------
- Schema inference from `Annotated[T, reducer]`. Caller passes a
  `dyn ChannelKind` map directly. Rationale: Rust has no runtime
  reflection over `Annotated`-style metadata; bringing that surface
  in is a Step 4.5-style concern (Phase 0 follow-up langchain-ai#2).
- Subgraphs. `add_node` does not accept a nested `CompiledGraph`.
- `defer=True` deferred nodes.
- Async-only nodes / `astream`. Sub-step langchain-ai#6 owns the async
  monkeypatch path.
- Runtime context object.
- `add_sequence` (chains of nodes).
- Node return-value coercion. Rust nodes return explicit
  `Vec<Write>`; Python's "return dict → infer state writes" is
  handled at the runner boundary in langchain-ai#6.

Parity gate
-----------
For each of the 5 fixtures: build the same logical graph with Rust
`StateGraph` AND Python `StateGraph`, drive with the same input,
compare:
  * user-visible state-channel final values (must match);
  * node execution order (must match for deterministic graphs);
  * for parallel branches (fan_out, conditional_join), the *set* of
    nodes that fired per superstep (parallel ordering canonicalised by
    Pregel).

What the gate caught
--------------------
- `recursion` final counter matches Python; total `step` fire count
  is documented-divergent: Python's `add_conditional_edges` evaluates
  the branch on POST-write state while the V0.1 Rust builder evaluates
  on PRE-write state. Same divergence as the Step 1.2a hand-rolled
  recursion fixture; final-state parity is the actual claim.
- Branch path-map keys must match the resolved-key lookup. An unknown
  key surfaces as `PregelError::NodeFailed { node, message }` (the
  same path Python exception classes use in #4b).
- `thiserror` magic-treats fields named `source` as `#[source]` —
  caught at compile time, renamed to `node`.
- `PregelLoop` / `CompiledGraph` need explicit `Debug` (the bridge
  fields are PyO3-flavoured and don't auto-derive). Manual impl on
  `CompiledGraph` keeps the public surface usable from `unwrap_err()`
  in tests.

Test counts
-----------
- Cargo workspace: 220 passed (was 211; +9 state_graph unit tests).
  Clippy clean.
- Phase 0: 73/73 + 49 + strict reject; 58 conformance.
- Phase 1 + 1.2b foundation + #4c + langchain-ai#5: 129 passed (was 104; +25
  StateGraph parity tests).
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.

2 participants