Repository navigation
Release v0.5.0
Added
CockroachDBStoreandAsyncCockroachDBStore, LangGraph long-term memory stores on CockroachDB. They implement LangGraph'sBaseStorewith the API of langgraph-checkpoint-postgres'sPostgresStore(from_conn_stringwithpipelineandpool_config,setup(),indexandttl), so they work withcreate_agent(store=...),StateGraph.compile(store=...)and Deep Agents'StoreBackend.from_conn_stringalso takesretry_policy,connect_timeout,prepare_thresholdandconnect_kwargs, as the checkpointers do. The two stores,CockroachDBIndexConfig,CockroachDBTTLConfigandPoolConfigare exported fromlangchain_cockroachdb.store, and all of them butPoolConfigfromlangchain_cockroachdbtoo.- Semantic search on CockroachDB's
VECTORtype, with a C-SPANN index that has the namespace as a prefix column.indextakes LangGraph'sdims,embedandfields, plusdistance_type(cosine,l2orinner_product),cspannpartition sizes,flatto skip the index, andbeam_size, which is set for each search. A search under a namespace first lists the namespaces at or under it, then ranks with the index within them, and runs a second, exact query when a filter or expired items leave its page short, unless a count shows that the index returned every vector of those namespaces. A search of the whole store, every search of aflatstore, and a search over more than 1000 namespaces (MAX_SEARCH_NAMESPACES) rank every match exactly instead. So a filter or expired items never leave a page short while more matches exist. - Expiry through CockroachDB row-level TTL. With a
ttlconfiguration,setup()turns on the TTL job for the items and vectors tables, on a schedule fromsweep_interval_minutesorttl_job_cron(@hourlyby default), so no sweeper thread is needed. Vectors carry their item's expiry. Expired items are left out of reads, searches and listings by default, even by a store built withoutttl;ttl={"omit_expired": False}turns that off. Withrefresh_on_read, a read pushes back the expiry of the items it returns, in the same statement.sweep_ttl(),start_ttl_sweeper()andstop_ttl_sweeper()work as in PostgresStore. A store built withoutttlapplies no default expiry, never refreshes one, and itssetup()leaves an existing TTL setting alone. On CockroachDB v25.4,disable_ttl(),adisable_ttl()and the TTL step ofsetup()retry while another process changes the same table. delete_namespace(namespace_prefix)andadelete_namespace, which delete every item and vector in a namespace and its descendants in one transaction and return the number of items deleted.- The sync methods of
AsyncCockroachDBStore(batch,get,put,search,deleteandlist_namespaces) raiseRuntimeErrorinstead of hanging when the store's event loop is closed or not running, or when called from a forked child, as those ofAsyncCockroachDBSaverdo. From the loop's own thread they raiseasyncio.InvalidStateError. - Differences from PostgresStore: the puts and deletes of one batch commit in one transaction; every call retries transient errors under the store's
RetryPolicy; aCockroachDBStoreon a pool runs batches concurrently; putting an item again or deleting it removes its old vectors; a filter that compares with a number matches numeric values only (PostgresStore compares text), nested dictionaries match nested keys, and$nematches items without the key; results with the same score orupdated_atare ordered by namespace and key, so paging is stable;table_nameandschemaconfigure the tables (defaultsstore,store_vectorsandstore_migrationsinpublic); aqueryon a store withoutindexlogs a WARNING and runs a plain search; aftersetup(), a changeddimsordistance_typeraises, and other partition sizes, orflatwith an index present, log a WARNING;disable_ttl()andadisable_ttl()remove the table TTL setting, anddrop_vector_index()andadrop_vector_index()drop the vector index so thatsetup()can build it again, for example with another distance; and there is nodeserializer=argument, because psycopg decodes JSONB before the store sees it. examples/long_term_memory.py, a LangGraph agent that saves a memory in one thread and recalls it in another, and a guide, an example page and an API page for the store in the documentation.
Fixed
enable_ttlanddisable_ttl(andaenable_ttlandadisable_ttl) on the checkpointers no longer fail when several processes run them at once on CockroachDB v25.4. That version refuses to change a table's TTL settings while another schema change on it runs, with SQLSTATE 0A000, which was not retried. These TTL changes now retry that error under the saver's retry policy, even if itsretry_onwould refuse it;max_attempts=1turns this off. The code and phrase are exported asSCHEMA_CHANGE_BUSY_SQLSTATEandSCHEMA_CHANGE_BUSY_MESSAGES, withis_schema_change_busy()andschema_change_policy().- A checkpointer or store on one connection in pipeline mode (
pipe=, orfrom_conn_string(..., pipeline=True)) could hang when a large write met a slow link, such as TLS to a distant cluster. psycopg's pipeline sync can leave the last bytes of a write unsent, so the server waited for them while the client waited for the server. The library now sends them before it waits.CockroachDBSaverandAsyncCockroachDBSaverhad this since 0.2.0;CockroachDBStoreandAsyncCockroachDBStorehave the fix from the start. Pools, and single connections without a pipeline, were not affected.
What's Changed
- ci: release from a ready PR and use the changelog entry as release notes by @viragtripathi in #16
- docs: show the PyPI version badge from shields.io by @viragtripathi in #17
- feat: LangGraph long-term memory store for 0.5.0 by @viragtripathi in #19
Full Changelog: v0.4.1...v0.5.0