Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
fc3a68c
chore(checkpoint): add drivers module
senamakel Oct 9, 2026
7a0fba4
chore(checkpoint): add drivers module
senamakel Oct 9, 2026
bf81680
feat(caps): add capability drivers for checkpointing
senamakel Oct 9, 2026
a217c43
fix(tinyflows): map storage errors to capability errors
senamakel Oct 9, 2026
4b369d5
test(checkpoint): cover driver checkpoint round-trips
senamakel Oct 9, 2026
e939d65
refactor(checkpoint): tidy imports and test helpers
senamakel Oct 9, 2026
313a9d0
test(checkpoint): use crate-relative path for resume index
senamakel Oct 9, 2026
3f3e341
docs: document storage-driver backends feature
senamakel Oct 9, 2026
d479906
feat(drivers): add checkpoint and state store driver capabilities
senamakel Oct 9, 2026
5fe9db4
refactor(caps): remove storage-drivers feature and driver state store
senamakel Oct 9, 2026
90dd5b1
feat(checkpoint): add checkpoint and state store drivers
senamakel Oct 9, 2026
e349461
feat(checkpoint): add indexed state history lookup
senamakel Oct 9, 2026
4ac94a4
refactor(checkpoint): import merge_writes directly
senamakel Oct 9, 2026
4a81db5
test(drivers): cover thread deletion, checkpoint pruning and state hi…
senamakel Oct 9, 2026
b4c89eb
test(checkpoint): use from_ref for single-element write slice
senamakel Oct 9, 2026
ac54524
feat(checkpoint): add checkpoint history and key listing
senamakel Oct 9, 2026
bf5d844
feat(state_store): add checkpoint persistence tests
senamakel Oct 9, 2026
04fa4a9
test(checkpoint): cover documents missing a value field
senamakel Oct 9, 2026
7ce8740
test(checkpoint): import StorageError in checkpoint tests
senamakel Oct 9, 2026
9fd522e
Merge origin/main into storage-drivers
senamakel Oct 9, 2026
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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **`tinyflows-drivers` (new, unpublished crate).** `DriverStateStore`
implements the engine's `StateStore` and `DriverCheckpointer` the graph
`Checkpointer` over a `tinystoragedrivers` document port (git dependency at
`v0.4.0`, so a host that vendors the storage crates once can `[patch]` it).
The checkpointer stores one document per checkpoint with a per-thread
compare-and-swap sequence, merges pending writes under compare-and-swap,
pushes namespace-scoped reads down to one indexed query, reads a whole
`state_history` in two queries, length-prefixes every key component and
hashes over-long ids with SHA-256. A separate crate rather than an engine
feature because the published `tinyflows` package cannot carry a git
dependency; the engine is unchanged and keeps its MSRV, this crate needs

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority medium critique confident

Keep the new crate compatible with the repository MSRV

The repository rules require Rust 1.85, but this entry explicitly introduces a workspace crate requiring Rust 1.88. That makes the new crate incompatible with the declared MSRV for users and CI environments pinned to 1.85. Either lower the crate's requirement to Rust 1.85 or update the repository's MSRV policy and all affected compatibility guarantees together.

[RULE] msrv-compatibility ·

Rust 1.88.

- **`tinyflows-sqlite` opens `flows.db` and `jobs.db` through the
tinystoragedrivers SQLite driver's native mode.** The tables, SQL,
`user_version` gate and column migrations are unchanged, and existing
Expand Down
14 changes: 14 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ Rust 2024 · MSRV 1.85 · `#![forbid(unsafe_code)]` · GPL-3.0-or-later.
- Host-injected capability traits: `LlmProvider`, `ToolInvoker`, `HttpClient`,
`CodeRunner`, `ShellRunner`, and `StateStore`. Deterministic in-memory mocks ship behind the
`mock` cargo feature (`caps::mock::mock_capabilities()`).
- Storage-driver backends in the companion `tinyflows-drivers` crate:
`DriverStateStore` (a `StateStore`) and `DriverCheckpointer` (a graph
`Checkpointer`) over a
[tinystoragedrivers](https://github.com/tinyhumansai/tinystoragedrivers)
document port, so a host keeps run state and checkpoints in the SQLite,
MongoDB or memory backend it already opened.
- Opaque `connection_ref` credential references — the host resolves them to real
secrets; the crate never sees them.
- Versioned wire format: graph `schema_version` and per-node `type_version`, with
Expand Down
31 changes: 31 additions & 0 deletions crates/tinyflows-drivers/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# `tinyflows` capabilities and checkpoints on `tinystoragedrivers` ports.
#
# A crate of its own rather than a feature of the engine: the storage crates
# are git dependencies (OpenHuman vendors them once and `[patch]`es the URL),
# and the published `tinyflows` package cannot carry a git dependency, even an
# optional one. It also keeps the engine's MSRV where it is; this crate needs
# the storage crates' 1.88.
[package]
name = "tinyflows-drivers"
version = "0.1.0"
description = "tinyflows StateStore and graph Checkpointer over tinystoragedrivers document ports"
edition.workspace = true
rust-version = "1.88"
Comment thread
senamakel marked this conversation as resolved.
license.workspace = true
repository.workspace = true
homepage.workspace = true
readme = "README.md"
publish = false

[dependencies]
tinyflows = { workspace = true }
tinystoragedrivers-core = { git = "https://github.com/tinyhumansai/tinystoragedrivers", tag = "v0.4.0" }
async-trait = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
sha2 = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }

[dev-dependencies]
tokio = { workspace = true }
46 changes: 46 additions & 0 deletions crates/tinyflows-drivers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# tinyflows-drivers

`tinyflows` run state and graph checkpoints on
[tinystoragedrivers](https://github.com/tinyhumansai/tinystoragedrivers)
document ports. A host that has opened a storage backend (SQLite on a desktop,
MongoDB in the cloud, memory in tests) gets the engine's durable pieces on it,
scoped per tenant by the document handle it passes in.

| Type | Implements | Layout |
| --- | --- | --- |
| `DriverStateStore` | `tinyflows::caps::StateStore` | one document per key in `flows_state` |
| `DriverCheckpointer<State>` | `tinyflows::graph::Checkpointer<State>` | `flows_graph_checkpoints`, `_threads`, `_writes` |

```rust
use std::sync::Arc;
use tinyflows_drivers::{DriverCheckpointer, DriverStateStore};

let docs = Arc::clone(scoped_storage.documents());
let state = Arc::new(DriverStateStore::new(Arc::clone(&docs)));
let checkpointer = DriverCheckpointer::<serde_json::Value>::new(docs);
```

## Checkpointer guarantees

- One document per checkpoint with a per-thread `seq` advanced by
compare-and-swap, so listing is insertion order and a re-used checkpoint id
resolves to its latest write, as in the SQLite and file backends.
- `get_scoped` is one indexed `(thread, namespace, seq)` query, so a parent
run and its subgraphs never load each other's checkpoints, even when ids
repeat.
- `state_history` reads the namespace's checkpoints and pending writes in two
queries and walks the lineage in memory, rather than two round trips per
ancestor.
- Pending writes merge with `merge_writes` under compare-and-swap.
- Key components are length-prefixed and namespaces encoded injectively; ids
over 400 bytes become their SHA-256.

## Why a separate crate

`tinystoragedrivers` is a git dependency: OpenHuman vendors it once (through
TinyAgents) and points the URL at that copy with
`[patch."https://github.com/tinyhumansai/tinystoragedrivers"]`, so there is
exactly one `DocumentStore` trait in its graph. The published `tinyflows`
package cannot carry a git dependency, so these adapters live here
(`publish = false`). The engine stays dependency-free and keeps its MSRV; this
crate needs Rust 1.88, the storage crates' MSRV.
Loading
Loading