@farukada/aws-langgraph-dynamodb-ts 0.2.2 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +224 -512
- package/dist/checkpointer/actions/delete-thread.d.ts +7 -6
- package/dist/checkpointer/actions/delete-thread.d.ts.map +1 -1
- package/dist/checkpointer/actions/delete-thread.js +47 -152
- package/dist/checkpointer/actions/delete-thread.js.map +1 -1
- package/dist/checkpointer/actions/get-tuple.d.ts +6 -14
- package/dist/checkpointer/actions/get-tuple.d.ts.map +1 -1
- package/dist/checkpointer/actions/get-tuple.js +13 -166
- package/dist/checkpointer/actions/get-tuple.js.map +1 -1
- package/dist/checkpointer/actions/list.d.ts +10 -0
- package/dist/checkpointer/actions/list.d.ts.map +1 -0
- package/dist/checkpointer/actions/list.js +51 -0
- package/dist/checkpointer/actions/list.js.map +1 -0
- package/dist/checkpointer/actions/put-writes.d.ts +6 -6
- package/dist/checkpointer/actions/put-writes.d.ts.map +1 -1
- package/dist/checkpointer/actions/put-writes.js +26 -75
- package/dist/checkpointer/actions/put-writes.js.map +1 -1
- package/dist/checkpointer/actions/put.d.ts +6 -11
- package/dist/checkpointer/actions/put.d.ts.map +1 -1
- package/dist/checkpointer/actions/put.js +29 -161
- package/dist/checkpointer/actions/put.js.map +1 -1
- package/dist/checkpointer/internal/assemble.d.ts +10 -0
- package/dist/checkpointer/internal/assemble.d.ts.map +1 -0
- package/dist/checkpointer/internal/assemble.js +37 -0
- package/dist/checkpointer/internal/assemble.js.map +1 -0
- package/dist/checkpointer/internal/configurable.d.ts +13 -0
- package/dist/checkpointer/internal/configurable.d.ts.map +1 -0
- package/dist/checkpointer/internal/configurable.js +23 -0
- package/dist/checkpointer/internal/configurable.js.map +1 -0
- package/dist/checkpointer/internal/fetch.d.ts +10 -0
- package/dist/checkpointer/internal/fetch.d.ts.map +1 -0
- package/dist/checkpointer/internal/fetch.js +46 -0
- package/dist/checkpointer/internal/fetch.js.map +1 -0
- package/dist/checkpointer/internal/filter-match.d.ts +12 -0
- package/dist/checkpointer/internal/filter-match.d.ts.map +1 -0
- package/dist/checkpointer/internal/filter-match.js +14 -0
- package/dist/checkpointer/internal/filter-match.js.map +1 -0
- package/dist/checkpointer/internal/item-reader.d.ts +10 -0
- package/dist/checkpointer/internal/item-reader.d.ts.map +1 -0
- package/dist/checkpointer/internal/item-reader.js +26 -0
- package/dist/checkpointer/internal/item-reader.js.map +1 -0
- package/dist/checkpointer/internal/item-writer.d.ts +14 -0
- package/dist/checkpointer/internal/item-writer.d.ts.map +1 -0
- package/dist/checkpointer/internal/item-writer.js +68 -0
- package/dist/checkpointer/internal/item-writer.js.map +1 -0
- package/dist/checkpointer/internal/keys.d.ts +15 -0
- package/dist/checkpointer/internal/keys.d.ts.map +1 -0
- package/dist/checkpointer/internal/keys.js +52 -0
- package/dist/checkpointer/internal/keys.js.map +1 -0
- package/dist/checkpointer/internal/query.d.ts +16 -0
- package/dist/checkpointer/internal/query.d.ts.map +1 -0
- package/dist/checkpointer/internal/query.js +33 -0
- package/dist/checkpointer/internal/query.js.map +1 -0
- package/dist/checkpointer/internal/setup.d.ts +31 -0
- package/dist/checkpointer/internal/setup.d.ts.map +1 -0
- package/dist/checkpointer/internal/setup.js +29 -0
- package/dist/checkpointer/internal/setup.js.map +1 -0
- package/dist/checkpointer/internal/validation.d.ts +9 -0
- package/dist/checkpointer/internal/validation.d.ts.map +1 -0
- package/dist/checkpointer/internal/validation.js +28 -0
- package/dist/checkpointer/internal/validation.js.map +1 -0
- package/dist/checkpointer/saver.d.ts +21 -0
- package/dist/checkpointer/saver.d.ts.map +1 -0
- package/dist/checkpointer/saver.js +49 -0
- package/dist/checkpointer/saver.js.map +1 -0
- package/dist/checkpointer/types.d.ts +43 -0
- package/dist/checkpointer/types.d.ts.map +1 -0
- package/dist/{store/types/index.js → checkpointer/types.js} +1 -1
- package/dist/checkpointer/types.js.map +1 -0
- package/dist/factory/factory.d.ts +41 -0
- package/dist/factory/factory.d.ts.map +1 -0
- package/dist/factory/factory.js +49 -0
- package/dist/factory/factory.js.map +1 -0
- package/dist/history/actions/add-messages.d.ts +12 -7
- package/dist/history/actions/add-messages.d.ts.map +1 -1
- package/dist/history/actions/add-messages.js +50 -48
- package/dist/history/actions/add-messages.js.map +1 -1
- package/dist/history/actions/clear.d.ts +5 -11
- package/dist/history/actions/clear.d.ts.map +1 -1
- package/dist/history/actions/clear.js +28 -62
- package/dist/history/actions/clear.js.map +1 -1
- package/dist/history/actions/get-messages.d.ts +6 -13
- package/dist/history/actions/get-messages.d.ts.map +1 -1
- package/dist/history/actions/get-messages.js +23 -59
- package/dist/history/actions/get-messages.js.map +1 -1
- package/dist/history/actions/list-sessions.d.ts +6 -22
- package/dist/history/actions/list-sessions.d.ts.map +1 -1
- package/dist/history/actions/list-sessions.js +26 -69
- package/dist/history/actions/list-sessions.js.map +1 -1
- package/dist/history/actions/reconcile-count.d.ts +10 -0
- package/dist/history/actions/reconcile-count.d.ts.map +1 -0
- package/dist/history/actions/reconcile-count.js +39 -0
- package/dist/history/actions/reconcile-count.js.map +1 -0
- package/dist/history/chat-message-history.d.ts +36 -0
- package/dist/history/chat-message-history.d.ts.map +1 -0
- package/dist/history/chat-message-history.js +67 -0
- package/dist/history/chat-message-history.js.map +1 -0
- package/dist/history/internal/append-saga.d.ts +17 -0
- package/dist/history/internal/append-saga.d.ts.map +1 -0
- package/dist/history/internal/append-saga.js +94 -0
- package/dist/history/internal/append-saga.js.map +1 -0
- package/dist/history/internal/item-mapper.d.ts +12 -0
- package/dist/history/internal/item-mapper.d.ts.map +1 -0
- package/dist/history/internal/item-mapper.js +33 -0
- package/dist/history/internal/item-mapper.js.map +1 -0
- package/dist/history/internal/keys.d.ts +9 -0
- package/dist/history/internal/keys.d.ts.map +1 -0
- package/dist/history/internal/keys.js +22 -0
- package/dist/history/internal/keys.js.map +1 -0
- package/dist/history/internal/message-chunker.d.ts +14 -0
- package/dist/history/internal/message-chunker.d.ts.map +1 -0
- package/dist/history/internal/message-chunker.js +60 -0
- package/dist/history/internal/message-chunker.js.map +1 -0
- package/dist/history/internal/message-transaction.d.ts +17 -0
- package/dist/history/internal/message-transaction.d.ts.map +1 -0
- package/dist/history/internal/message-transaction.js +27 -0
- package/dist/history/internal/message-transaction.js.map +1 -0
- package/dist/history/internal/query.d.ts +6 -0
- package/dist/history/internal/query.d.ts.map +1 -0
- package/dist/history/internal/query.js +28 -0
- package/dist/history/internal/query.js.map +1 -0
- package/dist/history/internal/session-update.d.ts +20 -0
- package/dist/history/internal/session-update.d.ts.map +1 -0
- package/dist/history/internal/session-update.js +46 -0
- package/dist/history/internal/session-update.js.map +1 -0
- package/dist/history/internal/setup.d.ts +28 -0
- package/dist/history/internal/setup.d.ts.map +1 -0
- package/dist/history/internal/setup.js +27 -0
- package/dist/history/internal/setup.js.map +1 -0
- package/dist/history/internal/title-generator.d.ts +7 -0
- package/dist/history/internal/title-generator.d.ts.map +1 -0
- package/dist/history/internal/title-generator.js +16 -0
- package/dist/history/internal/title-generator.js.map +1 -0
- package/dist/history/internal/ttl-anchor.d.ts +12 -0
- package/dist/history/internal/ttl-anchor.d.ts.map +1 -0
- package/dist/history/internal/ttl-anchor.js +26 -0
- package/dist/history/internal/ttl-anchor.js.map +1 -0
- package/dist/history/session-adapter.d.ts +10 -26
- package/dist/history/session-adapter.d.ts.map +1 -1
- package/dist/history/session-adapter.js +15 -57
- package/dist/history/session-adapter.js.map +1 -1
- package/dist/history/types.d.ts +36 -0
- package/dist/history/types.d.ts.map +1 -0
- package/dist/history/types.js +3 -0
- package/dist/history/types.js.map +1 -0
- package/dist/index.d.ts +18 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -16
- package/dist/index.js.map +1 -1
- package/dist/shared/clock.d.ts +3 -0
- package/dist/shared/clock.d.ts.map +1 -0
- package/dist/shared/clock.js +8 -0
- package/dist/shared/clock.js.map +1 -0
- package/dist/shared/codec/codec.d.ts +44 -0
- package/dist/shared/codec/codec.d.ts.map +1 -0
- package/dist/shared/codec/codec.js +44 -0
- package/dist/shared/codec/codec.js.map +1 -0
- package/dist/shared/codec/compression.d.ts +25 -0
- package/dist/shared/codec/compression.d.ts.map +1 -0
- package/dist/shared/codec/compression.js +49 -0
- package/dist/shared/codec/compression.js.map +1 -0
- package/dist/shared/codec/descriptor-keys.d.ts +4 -0
- package/dist/shared/codec/descriptor-keys.d.ts.map +1 -0
- package/dist/shared/codec/descriptor-keys.js +14 -0
- package/dist/shared/codec/descriptor-keys.js.map +1 -0
- package/dist/shared/codec/json-serde.d.ts +8 -0
- package/dist/shared/codec/json-serde.d.ts.map +1 -0
- package/dist/shared/codec/json-serde.js +18 -0
- package/dist/shared/codec/json-serde.js.map +1 -0
- package/dist/shared/codec/s3/client.d.ts +6 -0
- package/dist/shared/codec/s3/client.d.ts.map +1 -0
- package/dist/shared/codec/s3/client.js +18 -0
- package/dist/shared/codec/s3/client.js.map +1 -0
- package/dist/shared/codec/s3/config.d.ts +16 -0
- package/dist/shared/codec/s3/config.d.ts.map +1 -0
- package/dist/shared/codec/s3/config.js +14 -0
- package/dist/shared/codec/s3/config.js.map +1 -0
- package/dist/shared/codec/s3/delete.d.ts +8 -0
- package/dist/shared/codec/s3/delete.d.ts.map +1 -0
- package/dist/shared/codec/s3/delete.js +29 -0
- package/dist/shared/codec/s3/delete.js.map +1 -0
- package/dist/shared/codec/s3/lifecycle.d.ts +8 -0
- package/dist/shared/codec/s3/lifecycle.d.ts.map +1 -0
- package/dist/shared/codec/s3/lifecycle.js +47 -0
- package/dist/shared/codec/s3/lifecycle.js.map +1 -0
- package/dist/shared/codec/s3/offloader.d.ts +33 -0
- package/dist/shared/codec/s3/offloader.d.ts.map +1 -0
- package/dist/shared/codec/s3/offloader.js +80 -0
- package/dist/shared/codec/s3/offloader.js.map +1 -0
- package/dist/shared/codec/s3/orphans.d.ts +16 -0
- package/dist/shared/codec/s3/orphans.d.ts.map +1 -0
- package/dist/shared/codec/s3/orphans.js +73 -0
- package/dist/shared/codec/s3/orphans.js.map +1 -0
- package/dist/shared/codec/s3/read-write.d.ts +14 -0
- package/dist/shared/codec/s3/read-write.d.ts.map +1 -0
- package/dist/shared/codec/s3/read-write.js +42 -0
- package/dist/shared/codec/s3/read-write.js.map +1 -0
- package/dist/shared/constants.d.ts +37 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +40 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/dynamodb/backoff.d.ts +15 -0
- package/dist/shared/dynamodb/backoff.d.ts.map +1 -0
- package/dist/shared/dynamodb/backoff.js +48 -0
- package/dist/shared/dynamodb/backoff.js.map +1 -0
- package/dist/shared/dynamodb/batch-write.d.ts +10 -0
- package/dist/shared/dynamodb/batch-write.d.ts.map +1 -0
- package/dist/shared/dynamodb/batch-write.js +17 -0
- package/dist/shared/dynamodb/batch-write.js.map +1 -0
- package/dist/shared/dynamodb/client.d.ts +21 -0
- package/dist/shared/dynamodb/client.d.ts.map +1 -0
- package/dist/shared/dynamodb/client.js +19 -0
- package/dist/shared/dynamodb/client.js.map +1 -0
- package/dist/shared/dynamodb/drain-unprocessed.d.ts +15 -0
- package/dist/shared/dynamodb/drain-unprocessed.d.ts.map +1 -0
- package/dist/shared/dynamodb/drain-unprocessed.js +35 -0
- package/dist/shared/dynamodb/drain-unprocessed.js.map +1 -0
- package/dist/shared/dynamodb/paginate-core.d.ts +22 -0
- package/dist/shared/dynamodb/paginate-core.d.ts.map +1 -0
- package/dist/shared/dynamodb/paginate-core.js +52 -0
- package/dist/shared/dynamodb/paginate-core.js.map +1 -0
- package/dist/shared/dynamodb/paginate.d.ts +15 -0
- package/dist/shared/dynamodb/paginate.d.ts.map +1 -0
- package/dist/shared/dynamodb/paginate.js +20 -0
- package/dist/shared/dynamodb/paginate.js.map +1 -0
- package/dist/shared/dynamodb/retry-classifier.d.ts +9 -0
- package/dist/shared/dynamodb/retry-classifier.d.ts.map +1 -0
- package/dist/shared/dynamodb/retry-classifier.js +75 -0
- package/dist/shared/dynamodb/retry-classifier.js.map +1 -0
- package/dist/shared/dynamodb/retry.d.ts +18 -0
- package/dist/shared/dynamodb/retry.d.ts.map +1 -0
- package/dist/shared/dynamodb/retry.js +53 -0
- package/dist/shared/dynamodb/retry.js.map +1 -0
- package/dist/shared/dynamodb/scan.d.ts +15 -0
- package/dist/shared/dynamodb/scan.d.ts.map +1 -0
- package/dist/shared/dynamodb/scan.js +20 -0
- package/dist/shared/dynamodb/scan.js.map +1 -0
- package/dist/shared/dynamodb/types.d.ts +24 -0
- package/dist/shared/dynamodb/types.d.ts.map +1 -0
- package/dist/shared/dynamodb/types.js +3 -0
- package/dist/shared/dynamodb/types.js.map +1 -0
- package/dist/shared/errors/base-error.d.ts +22 -0
- package/dist/shared/errors/base-error.d.ts.map +1 -0
- package/dist/shared/errors/base-error.js +28 -0
- package/dist/shared/errors/base-error.js.map +1 -0
- package/dist/shared/errors/error-code.d.ts +13 -0
- package/dist/shared/errors/error-code.d.ts.map +1 -0
- package/dist/shared/errors/error-code.js +17 -0
- package/dist/shared/errors/error-code.js.map +1 -0
- package/dist/shared/errors/errors.d.ts +47 -0
- package/dist/shared/errors/errors.d.ts.map +1 -0
- package/dist/shared/errors/errors.js +82 -0
- package/dist/shared/errors/errors.js.map +1 -0
- package/dist/shared/errors/wrap-error.d.ts +16 -0
- package/dist/shared/errors/wrap-error.d.ts.map +1 -0
- package/dist/shared/errors/wrap-error.js +30 -0
- package/dist/shared/errors/wrap-error.js.map +1 -0
- package/dist/shared/logging/logger.d.ts +14 -0
- package/dist/shared/logging/logger.d.ts.map +1 -0
- package/dist/shared/logging/logger.js +16 -0
- package/dist/shared/logging/logger.js.map +1 -0
- package/dist/shared/logging/redaction.d.ts +19 -0
- package/dist/shared/logging/redaction.d.ts.map +1 -0
- package/dist/shared/logging/redaction.js +67 -0
- package/dist/shared/logging/redaction.js.map +1 -0
- package/dist/shared/options.d.ts +32 -0
- package/dist/shared/options.d.ts.map +1 -0
- package/dist/shared/options.js +3 -0
- package/dist/shared/options.js.map +1 -0
- package/dist/shared/ulid.d.ts +10 -0
- package/dist/shared/ulid.d.ts.map +1 -0
- package/dist/shared/ulid.js +65 -0
- package/dist/shared/ulid.js.map +1 -0
- package/dist/shared/validation/primitives.d.ts +17 -0
- package/dist/shared/validation/primitives.d.ts.map +1 -0
- package/dist/shared/validation/primitives.js +71 -0
- package/dist/shared/validation/primitives.js.map +1 -0
- package/dist/shared/validation/ttl.d.ts +16 -0
- package/dist/shared/validation/ttl.d.ts.map +1 -0
- package/dist/shared/validation/ttl.js +26 -0
- package/dist/shared/validation/ttl.js.map +1 -0
- package/dist/store/actions/get.d.ts +5 -0
- package/dist/store/actions/get.d.ts.map +1 -0
- package/dist/store/actions/get.js +21 -0
- package/dist/store/actions/get.js.map +1 -0
- package/dist/store/actions/list-namespaces.d.ts +9 -0
- package/dist/store/actions/list-namespaces.d.ts.map +1 -0
- package/dist/store/actions/list-namespaces.js +46 -0
- package/dist/store/actions/list-namespaces.js.map +1 -0
- package/dist/store/actions/put.d.ts +11 -0
- package/dist/store/actions/put.d.ts.map +1 -0
- package/dist/store/actions/put.js +81 -0
- package/dist/store/actions/put.js.map +1 -0
- package/dist/store/actions/reconcile-vector-index.d.ts +17 -0
- package/dist/store/actions/reconcile-vector-index.d.ts.map +1 -0
- package/dist/store/actions/reconcile-vector-index.js +27 -0
- package/dist/store/actions/reconcile-vector-index.js.map +1 -0
- package/dist/store/actions/search.d.ts +10 -0
- package/dist/store/actions/search.d.ts.map +1 -0
- package/dist/store/actions/search.js +72 -0
- package/dist/store/actions/search.js.map +1 -0
- package/dist/store/internal/filter.d.ts +10 -0
- package/dist/store/internal/filter.d.ts.map +1 -0
- package/dist/store/internal/filter.js +37 -0
- package/dist/store/internal/filter.js.map +1 -0
- package/dist/store/internal/index-reconcile.d.ts +22 -0
- package/dist/store/internal/index-reconcile.d.ts.map +1 -0
- package/dist/store/internal/index-reconcile.js +68 -0
- package/dist/store/internal/index-reconcile.js.map +1 -0
- package/dist/store/internal/index-sync.d.ts +11 -0
- package/dist/store/internal/index-sync.d.ts.map +1 -0
- package/dist/store/internal/index-sync.js +26 -0
- package/dist/store/internal/index-sync.js.map +1 -0
- package/dist/store/internal/item-mapper.d.ts +23 -0
- package/dist/store/internal/item-mapper.d.ts.map +1 -0
- package/dist/store/internal/item-mapper.js +51 -0
- package/dist/store/internal/item-mapper.js.map +1 -0
- package/dist/store/internal/keys.d.ts +18 -0
- package/dist/store/internal/keys.d.ts.map +1 -0
- package/dist/store/internal/keys.js +36 -0
- package/dist/store/internal/keys.js.map +1 -0
- package/dist/store/internal/namespace-match.d.ts +12 -0
- package/dist/store/internal/namespace-match.d.ts.map +1 -0
- package/dist/store/internal/namespace-match.js +41 -0
- package/dist/store/internal/namespace-match.js.map +1 -0
- package/dist/store/internal/query.d.ts +6 -0
- package/dist/store/internal/query.d.ts.map +1 -0
- package/dist/store/internal/query.js +32 -0
- package/dist/store/internal/query.js.map +1 -0
- package/dist/store/internal/ranker.d.ts +13 -0
- package/dist/store/internal/ranker.d.ts.map +1 -0
- package/dist/store/internal/ranker.js +29 -0
- package/dist/store/internal/ranker.js.map +1 -0
- package/dist/store/internal/semantic-search.d.ts +13 -0
- package/dist/store/internal/semantic-search.d.ts.map +1 -0
- package/dist/store/internal/semantic-search.js +47 -0
- package/dist/store/internal/semantic-search.js.map +1 -0
- package/dist/store/internal/setup.d.ts +31 -0
- package/dist/store/internal/setup.d.ts.map +1 -0
- package/dist/store/internal/setup.js +29 -0
- package/dist/store/internal/setup.js.map +1 -0
- package/dist/store/internal/validation.d.ts +7 -0
- package/dist/store/internal/validation.d.ts.map +1 -0
- package/dist/store/internal/validation.js +26 -0
- package/dist/store/internal/validation.js.map +1 -0
- package/dist/store/store.d.ts +24 -0
- package/dist/store/store.d.ts.map +1 -0
- package/dist/store/store.js +58 -0
- package/dist/store/store.js.map +1 -0
- package/dist/store/types.d.ts +28 -0
- package/dist/store/types.d.ts.map +1 -0
- package/dist/store/types.js +3 -0
- package/dist/store/types.js.map +1 -0
- package/dist/store/vector-backend.d.ts +27 -0
- package/dist/store/vector-backend.d.ts.map +1 -0
- package/dist/store/vector-backend.js +3 -0
- package/dist/store/vector-backend.js.map +1 -0
- package/package.json +21 -22
- package/dist/checkpointer/actions/index.d.ts +0 -5
- package/dist/checkpointer/actions/index.d.ts.map +0 -1
- package/dist/checkpointer/actions/index.js +0 -21
- package/dist/checkpointer/actions/index.js.map +0 -1
- package/dist/checkpointer/actions/validate-configurable.d.ts +0 -10
- package/dist/checkpointer/actions/validate-configurable.d.ts.map +0 -1
- package/dist/checkpointer/actions/validate-configurable.js +0 -39
- package/dist/checkpointer/actions/validate-configurable.js.map +0 -1
- package/dist/checkpointer/actions/writer.d.ts +0 -52
- package/dist/checkpointer/actions/writer.d.ts.map +0 -1
- package/dist/checkpointer/actions/writer.js +0 -109
- package/dist/checkpointer/actions/writer.js.map +0 -1
- package/dist/checkpointer/index.d.ts +0 -118
- package/dist/checkpointer/index.d.ts.map +0 -1
- package/dist/checkpointer/index.js +0 -393
- package/dist/checkpointer/index.js.map +0 -1
- package/dist/checkpointer/types/index.d.ts +0 -232
- package/dist/checkpointer/types/index.d.ts.map +0 -1
- package/dist/checkpointer/types/index.js +0 -13
- package/dist/checkpointer/types/index.js.map +0 -1
- package/dist/checkpointer/utils/deserialization.d.ts +0 -20
- package/dist/checkpointer/utils/deserialization.d.ts.map +0 -1
- package/dist/checkpointer/utils/deserialization.js +0 -81
- package/dist/checkpointer/utils/deserialization.js.map +0 -1
- package/dist/checkpointer/utils/index.d.ts +0 -7
- package/dist/checkpointer/utils/index.d.ts.map +0 -1
- package/dist/checkpointer/utils/index.js +0 -27
- package/dist/checkpointer/utils/index.js.map +0 -1
- package/dist/checkpointer/utils/validation.d.ts +0 -48
- package/dist/checkpointer/utils/validation.d.ts.map +0 -1
- package/dist/checkpointer/utils/validation.js +0 -235
- package/dist/checkpointer/utils/validation.js.map +0 -1
- package/dist/factory.d.ts +0 -153
- package/dist/factory.d.ts.map +0 -1
- package/dist/factory.js +0 -206
- package/dist/factory.js.map +0 -1
- package/dist/history/actions/add-message.d.ts +0 -10
- package/dist/history/actions/add-message.d.ts.map +0 -1
- package/dist/history/actions/add-message.js +0 -24
- package/dist/history/actions/add-message.js.map +0 -1
- package/dist/history/actions/index.d.ts +0 -9
- package/dist/history/actions/index.d.ts.map +0 -1
- package/dist/history/actions/index.js +0 -17
- package/dist/history/actions/index.js.map +0 -1
- package/dist/history/index.d.ts +0 -118
- package/dist/history/index.d.ts.map +0 -1
- package/dist/history/index.js +0 -179
- package/dist/history/index.js.map +0 -1
- package/dist/history/types/index.d.ts +0 -184
- package/dist/history/types/index.d.ts.map +0 -1
- package/dist/history/types/index.js +0 -7
- package/dist/history/types/index.js.map +0 -1
- package/dist/history/utils/index.d.ts +0 -9
- package/dist/history/utils/index.d.ts.map +0 -1
- package/dist/history/utils/index.js +0 -27
- package/dist/history/utils/index.js.map +0 -1
- package/dist/history/utils/optimistic-retry.d.ts +0 -31
- package/dist/history/utils/optimistic-retry.d.ts.map +0 -1
- package/dist/history/utils/optimistic-retry.js +0 -74
- package/dist/history/utils/optimistic-retry.js.map +0 -1
- package/dist/history/utils/title-generator.d.ts +0 -12
- package/dist/history/utils/title-generator.d.ts.map +0 -1
- package/dist/history/utils/title-generator.js +0 -57
- package/dist/history/utils/title-generator.js.map +0 -1
- package/dist/history/utils/update-expression-builder.d.ts +0 -55
- package/dist/history/utils/update-expression-builder.d.ts.map +0 -1
- package/dist/history/utils/update-expression-builder.js +0 -112
- package/dist/history/utils/update-expression-builder.js.map +0 -1
- package/dist/history/utils/validation.d.ts +0 -68
- package/dist/history/utils/validation.d.ts.map +0 -1
- package/dist/history/utils/validation.js +0 -213
- package/dist/history/utils/validation.js.map +0 -1
- package/dist/shared/index.d.ts +0 -5
- package/dist/shared/index.d.ts.map +0 -1
- package/dist/shared/index.js +0 -21
- package/dist/shared/index.js.map +0 -1
- package/dist/shared/utils/batch-write.d.ts +0 -74
- package/dist/shared/utils/batch-write.d.ts.map +0 -1
- package/dist/shared/utils/batch-write.js +0 -110
- package/dist/shared/utils/batch-write.js.map +0 -1
- package/dist/shared/utils/client-factory.d.ts +0 -25
- package/dist/shared/utils/client-factory.d.ts.map +0 -1
- package/dist/shared/utils/client-factory.js +0 -23
- package/dist/shared/utils/client-factory.js.map +0 -1
- package/dist/shared/utils/compressor.d.ts +0 -66
- package/dist/shared/utils/compressor.d.ts.map +0 -1
- package/dist/shared/utils/compressor.js +0 -133
- package/dist/shared/utils/compressor.js.map +0 -1
- package/dist/shared/utils/constants.d.ts +0 -13
- package/dist/shared/utils/constants.d.ts.map +0 -1
- package/dist/shared/utils/constants.js +0 -35
- package/dist/shared/utils/constants.js.map +0 -1
- package/dist/shared/utils/index.d.ts +0 -14
- package/dist/shared/utils/index.d.ts.map +0 -1
- package/dist/shared/utils/index.js +0 -30
- package/dist/shared/utils/index.js.map +0 -1
- package/dist/shared/utils/logger.d.ts +0 -75
- package/dist/shared/utils/logger.d.ts.map +0 -1
- package/dist/shared/utils/logger.js +0 -148
- package/dist/shared/utils/logger.js.map +0 -1
- package/dist/shared/utils/retry.d.ts +0 -26
- package/dist/shared/utils/retry.d.ts.map +0 -1
- package/dist/shared/utils/retry.js +0 -169
- package/dist/shared/utils/retry.js.map +0 -1
- package/dist/shared/utils/s3-offloader.d.ts +0 -153
- package/dist/shared/utils/s3-offloader.d.ts.map +0 -1
- package/dist/shared/utils/s3-offloader.js +0 -281
- package/dist/shared/utils/s3-offloader.js.map +0 -1
- package/dist/shared/utils/s3-orphans.d.ts +0 -16
- package/dist/shared/utils/s3-orphans.d.ts.map +0 -1
- package/dist/shared/utils/s3-orphans.js +0 -79
- package/dist/shared/utils/s3-orphans.js.map +0 -1
- package/dist/shared/utils/sleep.d.ts +0 -48
- package/dist/shared/utils/sleep.d.ts.map +0 -1
- package/dist/shared/utils/sleep.js +0 -82
- package/dist/shared/utils/sleep.js.map +0 -1
- package/dist/shared/utils/ttl.d.ts +0 -24
- package/dist/shared/utils/ttl.d.ts.map +0 -1
- package/dist/shared/utils/ttl.js +0 -43
- package/dist/shared/utils/ttl.js.map +0 -1
- package/dist/store/actions/get-operation.d.ts +0 -11
- package/dist/store/actions/get-operation.d.ts.map +0 -1
- package/dist/store/actions/get-operation.js +0 -42
- package/dist/store/actions/get-operation.js.map +0 -1
- package/dist/store/actions/index.d.ts +0 -5
- package/dist/store/actions/index.d.ts.map +0 -1
- package/dist/store/actions/index.js +0 -21
- package/dist/store/actions/index.js.map +0 -1
- package/dist/store/actions/list-namespaces-operation.d.ts +0 -10
- package/dist/store/actions/list-namespaces-operation.d.ts.map +0 -1
- package/dist/store/actions/list-namespaces-operation.js +0 -227
- package/dist/store/actions/list-namespaces-operation.js.map +0 -1
- package/dist/store/actions/put-operation.d.ts +0 -9
- package/dist/store/actions/put-operation.d.ts.map +0 -1
- package/dist/store/actions/put-operation.js +0 -107
- package/dist/store/actions/put-operation.js.map +0 -1
- package/dist/store/actions/search-operation.d.ts +0 -17
- package/dist/store/actions/search-operation.d.ts.map +0 -1
- package/dist/store/actions/search-operation.js +0 -203
- package/dist/store/actions/search-operation.js.map +0 -1
- package/dist/store/index.d.ts +0 -82
- package/dist/store/index.d.ts.map +0 -1
- package/dist/store/index.js +0 -172
- package/dist/store/index.js.map +0 -1
- package/dist/store/types/index.d.ts +0 -131
- package/dist/store/types/index.d.ts.map +0 -1
- package/dist/store/types/index.js.map +0 -1
- package/dist/store/utils/filter.d.ts +0 -16
- package/dist/store/utils/filter.d.ts.map +0 -1
- package/dist/store/utils/filter.js +0 -133
- package/dist/store/utils/filter.js.map +0 -1
- package/dist/store/utils/index.d.ts +0 -7
- package/dist/store/utils/index.d.ts.map +0 -1
- package/dist/store/utils/index.js +0 -27
- package/dist/store/utils/index.js.map +0 -1
- package/dist/store/utils/validation.d.ts +0 -61
- package/dist/store/utils/validation.d.ts.map +0 -1
- package/dist/store/utils/validation.js +0 -260
- package/dist/store/utils/validation.js.map +0 -1
package/README.md
CHANGED
|
@@ -3,649 +3,361 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@farukada/aws-langgraph-dynamodb-ts)
|
|
4
4
|
[](https://github.com/sponsors/FarukAda)
|
|
5
5
|

|
|
6
|
-

|
|
7
7
|

|
|
8
8
|

|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
A DynamoDB persistence layer for [LangGraph](https://langchain-ai.github.io/langgraphjs/) in TypeScript (CommonJS build, consumable from both ESM and CommonJS; Node ≥ 22). It provides three LangGraph/LangChain adapters plus a factory:
|
|
11
|
+
|
|
12
|
+
- **`DynamoDBSaver`** — checkpoint + pending-writes persistence (`extends BaseCheckpointSaver`).
|
|
13
|
+
- **`DynamoDBStore`** — long-term memory with optional semantic search (`extends BaseStore`).
|
|
14
|
+
- **`DynamoDBChatMessageHistory`** — multi-session chat history, with a single-session adapter for `RunnableWithMessageHistory`.
|
|
15
|
+
- **`DynamoDBFactory`** — convenience constructors, including `createAll` (one shared client + a `destroy()`).
|
|
16
|
+
|
|
17
|
+
Every adapter supports optional **gzip compression**, **S3 offloading** of payloads over DynamoDB's 400 KB item limit, and **TTL-based expiry**. The store additionally supports **vector semantic search** — in-DynamoDB by default, or delegated to a **pluggable `VectorBackend`** (e.g. OpenSearch / pgvector) for large corpora — via any LangChain `Embeddings` implementation.
|
|
11
18
|
|
|
12
19
|
## Table of Contents
|
|
13
20
|
|
|
21
|
+
- [Install](#install)
|
|
22
|
+
- [Table schema](#table-schema)
|
|
23
|
+
- [Quick start](#quick-start)
|
|
24
|
+
- [Checkpointer](#checkpointer)
|
|
25
|
+
- [Store + semantic search](#store--semantic-search)
|
|
26
|
+
- [Chat history](#chat-history)
|
|
27
|
+
- [Factory](#factory)
|
|
28
|
+
- [Options](#options)
|
|
14
29
|
- [Features](#features)
|
|
15
|
-
- [
|
|
16
|
-
- [
|
|
17
|
-
- [Infrastructure
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
20
|
-
- [IAM Permissions](#iam-permissions)
|
|
21
|
-
- [Documentation](#documentation)
|
|
30
|
+
- [Error handling](#error-handling)
|
|
31
|
+
- [Logging](#logging)
|
|
32
|
+
- [Infrastructure setup](#infrastructure-setup)
|
|
33
|
+
- [IAM permissions](#iam-permissions)
|
|
34
|
+
- [Migrating from earlier versions](#migrating-from-earlier-versions)
|
|
22
35
|
- [Testing](#testing)
|
|
23
|
-
- [Project Structure](#project-structure)
|
|
24
|
-
- [Contributing](#contributing)
|
|
25
36
|
- [License](#license)
|
|
26
37
|
|
|
27
38
|
---
|
|
28
39
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
## Features
|
|
40
|
+
## Install
|
|
32
41
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
| 💬 **Chat History** | Persistent chat message storage with auto-generated session titles |
|
|
38
|
-
| 🗜️ **Compression** | Optional gzip compression with smart thresholds (auto-detect on read) |
|
|
39
|
-
| ☁️ **S3 Offloading** | Transparent S3 offloading for payloads exceeding DynamoDB's 400 KB limit |
|
|
40
|
-
| ⚡ **Performance** | Composite keys, batch operations, exponential-backoff retry |
|
|
41
|
-
| ♻️ **TTL Support** | Automatic data expiration (days or seconds) |
|
|
42
|
-
| 🔒 **Type-Safe** | Full TypeScript with comprehensive type definitions |
|
|
43
|
-
| 🏭 **Factory** | One-line setup via `DynamoDBFactory.createAll()` |
|
|
44
|
-
|
|
45
|
-
<a id="architecture"></a>
|
|
46
|
-
|
|
47
|
-
## Architecture
|
|
48
|
-
|
|
49
|
-
```mermaid
|
|
50
|
-
flowchart LR
|
|
51
|
-
subgraph yourApp ["Your Application"]
|
|
52
|
-
graph_node["LangGraph Node"]
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
subgraph library ["@farukada/aws-langgraph-dynamodb-ts"]
|
|
56
|
-
saver["DynamoDBSaver"]
|
|
57
|
-
store["DynamoDBStore"]
|
|
58
|
-
history["DynamoDBChatMessageHistory"]
|
|
59
|
-
compressor["Compressor"]
|
|
60
|
-
offloader["S3Offloader"]
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
subgraph aws ["AWS"]
|
|
64
|
-
ddb[(DynamoDB)]
|
|
65
|
-
s3[(S3)]
|
|
66
|
-
bedrock["Bedrock Embeddings"]
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
graph_node --> saver
|
|
70
|
-
graph_node --> store
|
|
71
|
-
graph_node --> history
|
|
72
|
-
saver --> compressor
|
|
73
|
-
compressor --> offloader
|
|
74
|
-
offloader --> s3
|
|
75
|
-
saver --> ddb
|
|
76
|
-
store --> ddb
|
|
77
|
-
store -.-> bedrock
|
|
78
|
-
history --> ddb
|
|
42
|
+
```bash
|
|
43
|
+
npm install @farukada/aws-langgraph-dynamodb-ts \
|
|
44
|
+
@aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb \
|
|
45
|
+
@langchain/core @langchain/langgraph @langchain/langgraph-checkpoint
|
|
79
46
|
```
|
|
80
47
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
## Quick Start
|
|
84
|
-
|
|
85
|
-
### Install
|
|
48
|
+
Optional peer dependencies, installed only if you use the matching feature:
|
|
86
49
|
|
|
87
50
|
```bash
|
|
88
|
-
|
|
51
|
+
# Required only when S3 offloading is enabled
|
|
52
|
+
npm install @aws-sdk/client-s3
|
|
53
|
+
|
|
54
|
+
# Required only for semantic search in the store (any LangChain Embeddings works)
|
|
55
|
+
npm install @langchain/aws # e.g. Bedrock Titan embeddings
|
|
89
56
|
```
|
|
90
57
|
|
|
91
|
-
|
|
58
|
+
## Table schema
|
|
92
59
|
|
|
93
|
-
|
|
94
|
-
npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb \
|
|
95
|
-
@langchain/core @langchain/langgraph @langchain/langgraph-checkpoint
|
|
60
|
+
Every adapter uses the **same simple key schema**: a string partition key `PK`, a string sort key `SK`, and an optional Number `ttl` attribute for expiry. Because the key spaces never collide, **a single table can back all three adapters**, or you can use a separate table per adapter — your choice via the `tableName` option.
|
|
96
61
|
|
|
97
|
-
|
|
98
|
-
|
|
62
|
+
| Attribute | Type | Role |
|
|
63
|
+
| --- | --- | --- |
|
|
64
|
+
| `PK` | String (HASH) | partition key |
|
|
65
|
+
| `SK` | String (RANGE) | sort key |
|
|
66
|
+
| `ttl` | Number | (optional) Unix-epoch-seconds expiry; enable DynamoDB TTL on this attribute |
|
|
99
67
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
68
|
+
How each adapter lays out keys (informational — you don't manage this):
|
|
69
|
+
|
|
70
|
+
- **Checkpointer** — `PK = <thread_id>`; `SK` = `META#<ns>#<checkpoint_id>` (metadata), `PAYLOAD#<ns>#<checkpoint_id>` (checkpoint), `WRITE#<ns>#<checkpoint_id>#<task>#<idx>` (pending writes).
|
|
71
|
+
- **Store** — `PK = <namespace[0]>` (the scope root); `SK = <namespace[1..]>#<key>`. This makes a scoped prefix search a native `Query` (`PK = root AND begins_with(SK, …)`); only a rootless "search everything" falls back to a `Scan`.
|
|
72
|
+
- **Chat history** — `PK = <sessionId>`; one item per message at `SK = MSG#<ULID>` (ordered, append-only) plus one `SK = SESSION` metadata item.
|
|
73
|
+
|
|
74
|
+
## Quick start
|
|
103
75
|
|
|
104
|
-
###
|
|
76
|
+
### Checkpointer
|
|
105
77
|
|
|
106
78
|
```typescript
|
|
107
|
-
import { StateGraph } from '@langchain/langgraph';
|
|
108
79
|
import { DynamoDBSaver } from '@farukada/aws-langgraph-dynamodb-ts';
|
|
109
80
|
|
|
110
81
|
const checkpointer = new DynamoDBSaver({
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
ttlDays: 30,
|
|
114
|
-
clientConfig: { region: 'us-east-1' },
|
|
82
|
+
tableName: 'langgraph',
|
|
83
|
+
clientConfig: { region: 'eu-west-1' },
|
|
115
84
|
});
|
|
116
85
|
|
|
117
|
-
const
|
|
86
|
+
const graph = workflow.compile({ checkpointer });
|
|
118
87
|
|
|
119
|
-
|
|
120
|
-
await
|
|
121
|
-
|
|
122
|
-
|
|
88
|
+
const config = { configurable: { thread_id: 'user-42' } };
|
|
89
|
+
await graph.invoke({ messages: [/* ... */] }, config);
|
|
90
|
+
|
|
91
|
+
// Resume later (even in a new process) — state is loaded from DynamoDB.
|
|
92
|
+
const resumed = await graph.invoke({ messages: [/* ... */] }, config);
|
|
93
|
+
|
|
94
|
+
checkpointer.destroy(); // releases the client this instance created
|
|
123
95
|
```
|
|
124
96
|
|
|
125
|
-
###
|
|
97
|
+
### Store + semantic search
|
|
126
98
|
|
|
127
99
|
```typescript
|
|
128
100
|
import { DynamoDBStore } from '@farukada/aws-langgraph-dynamodb-ts';
|
|
129
101
|
import { BedrockEmbeddings } from '@langchain/aws';
|
|
130
102
|
|
|
131
103
|
const store = new DynamoDBStore({
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
104
|
+
tableName: 'langgraph',
|
|
105
|
+
clientConfig: { region: 'eu-west-1' },
|
|
106
|
+
index: {
|
|
107
|
+
dims: 1024,
|
|
108
|
+
embeddings: new BedrockEmbeddings({ model: 'amazon.titan-embed-text-v2:0', region: 'eu-west-1' }),
|
|
109
|
+
fields: ['text'], // which fields to embed; defaults to the whole document ('$')
|
|
110
|
+
},
|
|
138
111
|
});
|
|
139
112
|
|
|
140
|
-
|
|
141
|
-
await store.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
value: { color: 'dark', fontSize: 14 },
|
|
146
|
-
},
|
|
147
|
-
], { configurable: { user_id: 'user-123' } });
|
|
113
|
+
await store.put(['library'], 'doc-1', { text: 'Amazon DynamoDB is a serverless NoSQL database' });
|
|
114
|
+
await store.put(['library'], 'doc-2', { text: 'Espresso is a concentrated coffee' });
|
|
115
|
+
|
|
116
|
+
// Metadata filtering (operators: $eq, $ne, $gt, $gte, $lt, $lte)
|
|
117
|
+
await store.search(['library'], { filter: { type: 'note', score: { $gte: 5 } } });
|
|
148
118
|
|
|
149
|
-
// Semantic search
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
119
|
+
// Semantic search — ranked by cosine similarity to the query embedding
|
|
120
|
+
const hits = await store.search(['library'], { query: 'cloud database', limit: 5 });
|
|
121
|
+
//=> doc-1 ranks first, with a `score` on each SearchItem
|
|
122
|
+
|
|
123
|
+
await store.get(['library'], 'doc-1');
|
|
124
|
+
await store.delete(['library'], 'doc-1');
|
|
125
|
+
await store.listNamespaces({ prefix: ['library'], maxDepth: 1 });
|
|
153
126
|
```
|
|
154
127
|
|
|
155
|
-
### Chat
|
|
128
|
+
### Chat history
|
|
156
129
|
|
|
157
130
|
```typescript
|
|
158
131
|
import { DynamoDBChatMessageHistory } from '@farukada/aws-langgraph-dynamodb-ts';
|
|
159
|
-
import { HumanMessage
|
|
132
|
+
import { HumanMessage } from '@langchain/core/messages';
|
|
160
133
|
|
|
161
134
|
const history = new DynamoDBChatMessageHistory({
|
|
162
|
-
tableName: 'langgraph
|
|
163
|
-
|
|
135
|
+
tableName: 'langgraph',
|
|
136
|
+
clientConfig: { region: 'eu-west-1' },
|
|
164
137
|
});
|
|
165
138
|
|
|
166
|
-
await history.addMessages('
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const sessions = await history.listSessions('user-123');
|
|
139
|
+
await history.addMessages('session-1', [new HumanMessage('Hello!')]);
|
|
140
|
+
const messages = await history.getMessages('session-1');
|
|
141
|
+
const sessions = await history.listSessions(); // [{ sessionId, title, messageCount, ... }]
|
|
142
|
+
await history.clear('session-1');
|
|
172
143
|
```
|
|
173
144
|
|
|
174
|
-
|
|
175
|
-
> `addMessage`/`addMessages` call, so `listSessions()` keeps reporting the
|
|
176
|
-
> session as live while activity continues. Individual message items get their
|
|
177
|
-
> TTL stamped at write time and expire independently — a long-lived session can
|
|
178
|
-
> develop gaps where older messages drop out while recent ones persist. If that
|
|
179
|
-
> isn't acceptable, set `ttlDays` well above your expected session lifetime or
|
|
180
|
-
> manage deletion explicitly via `clear()`.
|
|
181
|
-
|
|
182
|
-
### Factory (One-Liner)
|
|
145
|
+
Use it with LangChain's `RunnableWithMessageHistory` via the single-session adapter:
|
|
183
146
|
|
|
184
147
|
```typescript
|
|
185
|
-
import {
|
|
148
|
+
import { RunnableWithMessageHistory } from '@langchain/core/runnables';
|
|
186
149
|
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
150
|
+
const withHistory = new RunnableWithMessageHistory({
|
|
151
|
+
runnable: chain,
|
|
152
|
+
getMessageHistory: (sessionId) => history.forSession(sessionId),
|
|
153
|
+
inputMessagesKey: 'input',
|
|
154
|
+
historyMessagesKey: 'history',
|
|
191
155
|
});
|
|
192
|
-
|
|
193
|
-
// When done, release the shared DynamoDB client
|
|
194
|
-
destroy();
|
|
195
156
|
```
|
|
196
157
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
## Infrastructure Setup
|
|
158
|
+
### Factory
|
|
200
159
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
<details>
|
|
204
|
-
<summary><strong>AWS CDK (TypeScript)</strong></summary>
|
|
160
|
+
`createAll` builds all three adapters on **one shared DynamoDB client** and returns a single `destroy()` that tears everything down.
|
|
205
161
|
|
|
206
162
|
```typescript
|
|
207
|
-
import
|
|
163
|
+
import { DynamoDBFactory } from '@farukada/aws-langgraph-dynamodb-ts';
|
|
208
164
|
|
|
209
|
-
|
|
210
|
-
new dynamodb.Table(this, 'Checkpoints', {
|
|
211
|
-
tableName: 'langgraph-checkpoints',
|
|
212
|
-
partitionKey: { name: 'thread_id', type: dynamodb.AttributeType.STRING },
|
|
213
|
-
sortKey: { name: 'checkpoint_id', type: dynamodb.AttributeType.STRING },
|
|
214
|
-
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
|
|
215
|
-
timeToLiveAttribute: 'ttl',
|
|
216
|
-
});
|
|
165
|
+
const factory = new DynamoDBFactory({ clientConfig: { region: 'eu-west-1' } });
|
|
217
166
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
tableName: 'langgraph
|
|
221
|
-
|
|
222
|
-
sortKey: { name: 'task_id_idx', type: dynamodb.AttributeType.STRING },
|
|
223
|
-
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
|
|
224
|
-
timeToLiveAttribute: 'ttl',
|
|
167
|
+
const { saver, store, history, destroy } = factory.createAll({
|
|
168
|
+
saver: { tableName: 'langgraph' },
|
|
169
|
+
store: { tableName: 'langgraph', index: { dims: 1024, embeddings } },
|
|
170
|
+
history: { tableName: 'langgraph' },
|
|
225
171
|
});
|
|
226
172
|
|
|
227
|
-
//
|
|
228
|
-
new dynamodb.Table(this, 'Memory', {
|
|
229
|
-
tableName: 'langgraph-memory',
|
|
230
|
-
partitionKey: { name: 'user_id', type: dynamodb.AttributeType.STRING },
|
|
231
|
-
sortKey: { name: 'namespace_key', type: dynamodb.AttributeType.STRING },
|
|
232
|
-
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
|
|
233
|
-
timeToLiveAttribute: 'ttl',
|
|
234
|
-
});
|
|
173
|
+
// ... use saver / store / history ...
|
|
235
174
|
|
|
236
|
-
//
|
|
237
|
-
new dynamodb.Table(this, 'ChatHistory', {
|
|
238
|
-
tableName: 'langgraph-chat-history',
|
|
239
|
-
partitionKey: { name: 'userId', type: dynamodb.AttributeType.STRING },
|
|
240
|
-
sortKey: { name: 'sessionId', type: dynamodb.AttributeType.STRING },
|
|
241
|
-
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
|
|
242
|
-
timeToLiveAttribute: 'ttl',
|
|
243
|
-
});
|
|
175
|
+
destroy(); // closes the one shared client
|
|
244
176
|
```
|
|
245
177
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
<details>
|
|
249
|
-
<summary><strong>Terraform</strong></summary>
|
|
250
|
-
|
|
251
|
-
```hcl
|
|
252
|
-
resource "aws_dynamodb_table" "checkpoints" {
|
|
253
|
-
name = "langgraph-checkpoints"
|
|
254
|
-
billing_mode = "PAY_PER_REQUEST"
|
|
255
|
-
hash_key = "thread_id"
|
|
256
|
-
range_key = "checkpoint_id"
|
|
257
|
-
attribute { name = "thread_id" type = "S" }
|
|
258
|
-
attribute { name = "checkpoint_id" type = "S" }
|
|
259
|
-
ttl { attribute_name = "ttl" enabled = true }
|
|
260
|
-
}
|
|
178
|
+
## Options
|
|
261
179
|
|
|
262
|
-
|
|
263
|
-
name = "langgraph-writes"
|
|
264
|
-
billing_mode = "PAY_PER_REQUEST"
|
|
265
|
-
hash_key = "thread_id_checkpoint_id_checkpoint_ns"
|
|
266
|
-
range_key = "task_id_idx"
|
|
267
|
-
attribute { name = "thread_id_checkpoint_id_checkpoint_ns" type = "S" }
|
|
268
|
-
attribute { name = "task_id_idx" type = "S" }
|
|
269
|
-
ttl { attribute_name = "ttl" enabled = true }
|
|
270
|
-
}
|
|
180
|
+
All adapters share a common base. Provide **either** a prebuilt `client` (which the adapter will not own/close) **or** `clientConfig` (the adapter builds and owns the client).
|
|
271
181
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
hash_key = "userId"
|
|
286
|
-
range_key = "sessionId"
|
|
287
|
-
attribute { name = "userId" type = "S" }
|
|
288
|
-
attribute { name = "sessionId" type = "S" }
|
|
289
|
-
ttl { attribute_name = "ttl" enabled = true }
|
|
290
|
-
}
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
</details>
|
|
182
|
+
| Option | Type | Applies to | Notes |
|
|
183
|
+
| --- | --- | --- | --- |
|
|
184
|
+
| `tableName` | `string` | all | **required** |
|
|
185
|
+
| `client` | `DynamoDBDocument` | all | reuse an existing client; not closed by `destroy()` |
|
|
186
|
+
| `clientConfig` | `DynamoDBClientConfig` | all | used to build a client when `client` is omitted |
|
|
187
|
+
| `ttl` | `{ days: number }` \| `{ seconds: number }` | all | expiry written to the `ttl` attribute |
|
|
188
|
+
| `logger` | `Logger` | all | per-instance logger (default: silent) |
|
|
189
|
+
| `compression` | `CompressionConfig` | all | `{ enabled, minSizeBytes?, level?, maxDecompressedBytes? }` |
|
|
190
|
+
| `s3` | `S3OffloadConfig` | all | offload large payloads to S3 (see below) |
|
|
191
|
+
| `serde` | `SerializerProtocol` | all | serializer override (checkpointer defaults to LangGraph's; store/history to JSON) |
|
|
192
|
+
| `index` | `IndexConfig` | store only | `{ dims, embeddings, fields? }` for semantic search |
|
|
193
|
+
| `vectorBackend` | `VectorBackend` | store only | delegate similarity search to an external index; DynamoDB keeps the canonical item |
|
|
194
|
+
| `maxSearchCandidates` | `number` | store only | cap for the in-DB ranker before it errors (default 1000) |
|
|
294
195
|
|
|
295
|
-
|
|
196
|
+
`S3OffloadConfig`: `{ bucketName, keyPrefix?, thresholdBytes?, serverSideEncryption?, sseKmsKeyId?, clientConfig? }`.
|
|
296
197
|
|
|
297
|
-
##
|
|
198
|
+
## Features
|
|
298
199
|
|
|
299
|
-
|
|
200
|
+
**Gzip compression** — set `compression: { enabled: true }`. Payloads at or above `minSizeBytes` (default 1 KB) are gzipped transparently; decompression auto-detects on read and is guarded against decompression-bomb expansion (`maxDecompressedBytes`, default 50 MiB).
|
|
300
201
|
|
|
301
|
-
|
|
202
|
+
**S3 offloading** — set `s3: { bucketName }`. Any serialized payload at or above `thresholdBytes` (default 350 KB) is written to S3, with only a reference stored in DynamoDB; reads rehydrate transparently. Requires the optional `@aws-sdk/client-s3` peer. When a `ttl` is also configured the library best-effort installs a matching S3 lifecycle expiration rule (logged, never fatal). Deleting a checkpoint thread / chat session also best-effort deletes its offloaded objects.
|
|
302
203
|
|
|
303
|
-
|
|
304
|
-
const checkpointer = new DynamoDBSaver({
|
|
305
|
-
checkpointsTableName: 'langgraph-checkpoints',
|
|
306
|
-
writesTableName: 'langgraph-writes',
|
|
307
|
-
compression: {
|
|
308
|
-
enabled: true,
|
|
309
|
-
minSizeBytes: 1024, // Only compress payloads ≥ 1 KB
|
|
310
|
-
},
|
|
311
|
-
});
|
|
312
|
-
```
|
|
204
|
+
**TTL expiry** — set `ttl: { days }` or `ttl: { seconds }`. The `ttl` attribute is written as a Unix-epoch-seconds timestamp; enable DynamoDB TTL on the `ttl` attribute for automatic deletion. Chat history anchors a single **uniform whole-conversation TTL** at session creation (via `if_not_exists`), shared by every message, so a live session never develops mid-history gaps; expired messages are also filtered out on read.
|
|
313
205
|
|
|
314
|
-
|
|
206
|
+
**Semantic search** (store) — provide `index` with a LangChain `Embeddings` implementation. On `put`, the configured `fields` are embedded; on `search` with a `query`, results are ranked by cosine similarity. By default the embedding is stored on the item and ranking happens in-process over the scoped candidate set (bounded by `maxSearchCandidates`, default 1000 — exceeding it throws, steering you to an external index). For large corpora, pass a `vectorBackend`: the embedding is sent there instead, similarity search is delegated to it, and DynamoDB still holds the canonical item. Per-item indexing can be overridden via the `index` argument to `put` (`false` to skip, or a `string[]` of fields).
|
|
315
207
|
|
|
316
|
-
|
|
208
|
+
**Vector index consistency** — when a `vectorBackend` is configured, **DynamoDB holds the canonical item** and the backend is a rebuildable index. After each canonical write the embedding is synced to the backend best-effort: a failure is logged (not thrown), so a backend hiccup never fails an otherwise-successful `put`/`delete`. To repair drift, call `store.reconcileVectorIndex(namespacePrefix)` — it re-pushes every live embedding and, when the backend implements the optional `listKeys`, prunes vectors with no canonical item; it returns `{ upserted, pruned }`. Run it when the namespace is idle. Caveats: reconciliation re-embeds with the store's **configured** index fields, so per-`put` field overrides are not reproduced; prune happens only when `listKeys` is implemented (otherwise reconcile re-pushes only and logs that prune was skipped); the prefix must be a non-empty namespace.
|
|
317
209
|
|
|
318
|
-
|
|
319
|
-
const checkpointer = new DynamoDBSaver({
|
|
320
|
-
checkpointsTableName: 'langgraph-checkpoints',
|
|
321
|
-
writesTableName: 'langgraph-writes',
|
|
322
|
-
s3OffloadConfig: {
|
|
323
|
-
bucketName: 'my-checkpoints-bucket',
|
|
324
|
-
keyPrefix: 'langgraph/', // default: 'langgraph-checkpoints/'
|
|
325
|
-
thresholdBytes: 350 * 1024, // default: 350 KB
|
|
326
|
-
serverSideEncryption: 'aws:kms', // optional: 'AES256' or 'aws:kms'
|
|
327
|
-
sseKmsKeyId: 'alias/my-key', // optional: KMS key ID/ARN
|
|
328
|
-
clientConfig: { region: 'us-east-1' },
|
|
329
|
-
},
|
|
330
|
-
});
|
|
331
|
-
```
|
|
210
|
+
**Strong consistency** — checkpointer read-your-writes (`getTuple`) and every `store.get` use `ConsistentRead`, so a value written and immediately read back is never served a stale replica. Bulk reads (`list`, `listNamespaces`, `listSessions`) stay eventually consistent for lower cost.
|
|
332
211
|
|
|
333
|
-
|
|
212
|
+
## Error handling
|
|
334
213
|
|
|
335
|
-
|
|
214
|
+
All errors thrown by the library extend `DynamoDbLangGraphError` and carry a stable `code` from the `ErrorCode` enum plus a native `cause` chain. Branch on `code`:
|
|
336
215
|
|
|
337
216
|
```typescript
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
status: { $ne: 'archived' },
|
|
348
|
-
},
|
|
349
|
-
limit: 10,
|
|
350
|
-
},
|
|
351
|
-
], { configurable: { user_id: 'user-123' } });
|
|
217
|
+
import { ErrorCode, DynamoDbLangGraphError } from '@farukada/aws-langgraph-dynamodb-ts';
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
await store.put([''], 'k', { v: 1 });
|
|
221
|
+
} catch (error) {
|
|
222
|
+
if (error instanceof DynamoDbLangGraphError && error.code === ErrorCode.VALIDATION) {
|
|
223
|
+
// bad input
|
|
224
|
+
}
|
|
225
|
+
}
|
|
352
226
|
```
|
|
353
227
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
```typescript
|
|
357
|
-
// Hierarchical namespace patterns
|
|
358
|
-
['user', userId, 'preferences']
|
|
359
|
-
['user', userId, 'conversations', threadId]
|
|
360
|
-
['documents', 'category', 'subcategory']
|
|
361
|
-
```
|
|
228
|
+
`ErrorCode` values: `VALIDATION`, `CONDITION_CONFLICT`, `RETRY_EXHAUSTED`, `BATCH_WRITE_INCOMPLETE`, `COMPRESSION_LIMIT`, `S3_OFFLOAD_FAILED`, `ABORTED`. Typed subclasses are exported where callers commonly branch: `ValidationError`, `ConflictError`, `RetryExhaustedError`, `BatchWriteIncompleteError`, `AbortError`.
|
|
362
229
|
|
|
363
|
-
|
|
230
|
+
## Logging
|
|
364
231
|
|
|
365
|
-
|
|
366
|
-
`(userId, sessionId)` pair to LangChain's `RunnableWithMessageHistory`, bind it
|
|
367
|
-
with `forSession()` which returns a `BaseListChatMessageHistory` compatible
|
|
368
|
-
instance:
|
|
232
|
+
Logging is **per-instance and silent by default** — the library never writes to your console uninvited. Pass any object matching the `Logger` interface (`info`/`warn`/`error`/`debug`):
|
|
369
233
|
|
|
370
234
|
```typescript
|
|
371
|
-
import {
|
|
372
|
-
import { DynamoDBChatMessageHistory } from '@farukada/aws-langgraph-dynamodb-ts';
|
|
235
|
+
import { redactLogger, type Logger } from '@farukada/aws-langgraph-dynamodb-ts';
|
|
373
236
|
|
|
374
|
-
const
|
|
237
|
+
const logger: Logger = {
|
|
238
|
+
info: (m, ...a) => console.info(m, ...a),
|
|
239
|
+
warn: (m, ...a) => console.warn(m, ...a),
|
|
240
|
+
error: (m, ...a) => console.error(m, ...a),
|
|
241
|
+
debug: () => {},
|
|
242
|
+
};
|
|
375
243
|
|
|
376
|
-
const
|
|
377
|
-
runnable,
|
|
378
|
-
getMessageHistory: (sessionId) => store.forSession(userId, sessionId),
|
|
379
|
-
inputMessagesKey: 'input',
|
|
380
|
-
historyMessagesKey: 'history',
|
|
381
|
-
});
|
|
244
|
+
const store = new DynamoDBStore({ tableName: 'langgraph', logger: redactLogger(logger) });
|
|
382
245
|
```
|
|
383
246
|
|
|
384
|
-
|
|
247
|
+
`redactLogger` wraps a logger so secret-looking fields (access keys, tokens, passwords, …) are replaced with `[REDACTED]` in structured log arguments. `redactSecrets` exposes the same redaction for arbitrary objects.
|
|
385
248
|
|
|
386
|
-
|
|
387
|
-
|---|---|---|
|
|
388
|
-
| `DynamoDBSaver.put()` | Single `TransactWrite` on the **checkpoints** table. Both the metadata item and the payload item either both persist or neither does. | Throws; any S3 objects already uploaded are best-effort cleaned, otherwise swept by the S3 lifecycle rule. |
|
|
389
|
-
| `DynamoDBSaver.putWrites()` | `BatchWriteItem` against the **writes** table, chunked in groups of 25. Each 25-item batch is independently atomic at the DynamoDB level; batches are *not* transactional with each other. | On retry exhaustion, throws `BatchWriteIncompleteError` with `.succeededCount` and `.unprocessed` so callers can drive reconciliation. Items already acked by DynamoDB remain persisted. |
|
|
390
|
-
| `put()` ↔ `putWrites()` | **Not** atomic across tables. LangGraph calls them as distinct steps; a crash between them leaves a checkpoint without its writes (or vice versa). | LangGraph's node-retry loop will re-invoke both; the idempotency guard on `put()` makes re-submission safe. |
|
|
391
|
-
| `DynamoDBChatMessageHistory.addMessage(s)` | `TransactWriteItems` — up to 99 message items plus the metadata counter update, guarded by an optimistic `messageCount` condition. All-or-nothing per call. | Throws on conflict; the helper retries up to 5× on `ConditionalCheckFailed` sub-reasons. |
|
|
392
|
-
| `DynamoDBStore.batch()` (Put) | Per-item `UpdateItem` / `PutItem`. Batch failure is per-operation. | Each op's error propagates via `Promise.all`. |
|
|
249
|
+
## Infrastructure setup
|
|
393
250
|
|
|
394
|
-
|
|
251
|
+
One table backs all three adapters. Create it with **AWS CDK** or **Terraform**.
|
|
395
252
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
disagrees on `parent_checkpoint_id` or serializer `type`. Effect:
|
|
253
|
+
<details>
|
|
254
|
+
<summary><strong>AWS CDK (TypeScript)</strong></summary>
|
|
399
255
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
`(parent, type)` and succeeds as if idempotent.
|
|
403
|
-
- Two concurrent workers writing the same `checkpoint_id` but with different
|
|
404
|
-
lineage surface a `ConditionalCheckFailedException` instead of silently
|
|
405
|
-
last-writer-wins. Treat it as a signal that your application is accidentally
|
|
406
|
-
racing two graphs on the same thread.
|
|
256
|
+
```typescript
|
|
257
|
+
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
|
|
407
258
|
|
|
408
|
-
|
|
259
|
+
new dynamodb.Table(this, 'LangGraph', {
|
|
260
|
+
tableName: 'langgraph',
|
|
261
|
+
partitionKey: { name: 'PK', type: dynamodb.AttributeType.STRING },
|
|
262
|
+
sortKey: { name: 'SK', type: dynamodb.AttributeType.STRING },
|
|
263
|
+
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
|
|
264
|
+
timeToLiveAttribute: 'ttl', // optional; only needed if you use the `ttl` option
|
|
265
|
+
});
|
|
266
|
+
```
|
|
409
267
|
|
|
410
|
-
|
|
411
|
-
errors before DynamoDB / zlib / memory blow up on pathological inputs. All of
|
|
412
|
-
them are configurable or can be raised if a legitimate workload needs more.
|
|
268
|
+
</details>
|
|
413
269
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
| Decompressed checkpoint size | 50 MiB | `compression.maxDecompressedBytes` | Gzip payload expands beyond the cap — defends against gzip bombs. |
|
|
417
|
-
| Filter expression string | 3.5 KiB | not configurable — simplify the filter | Complex / deeply-nested `Store.batch` searches. DynamoDB's hard limit is 4 KiB. |
|
|
418
|
-
| `$in` / `$nin` array size | 50 values | not configurable — split the query | Store filter with oversized enum sets. |
|
|
419
|
-
| `list()` page iterations | 1000 pages | not configurable — narrow the filter or add a GSI | Filters that match almost nothing across a very large thread. |
|
|
420
|
-
| `deleteThread()` page iterations | 10 000 pages | not configurable — investigate the thread | Effectively "unbounded for real workloads"; only trips on extreme datasets. |
|
|
421
|
-
| Retry `cause`-chain depth | 32 | not configurable | Hostile error with an absurd nesting depth; prevents stack-overflow DoS. |
|
|
270
|
+
<details>
|
|
271
|
+
<summary><strong>Terraform</strong></summary>
|
|
422
272
|
|
|
423
|
-
|
|
273
|
+
```hcl
|
|
274
|
+
resource "aws_dynamodb_table" "langgraph" {
|
|
275
|
+
name = "langgraph"
|
|
276
|
+
billing_mode = "PAY_PER_REQUEST"
|
|
277
|
+
hash_key = "PK"
|
|
278
|
+
range_key = "SK"
|
|
424
279
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
enforces a different algorithm (e.g. `aws:kms`), set it explicitly:
|
|
280
|
+
attribute { name = "PK" type = "S" }
|
|
281
|
+
attribute { name = "SK" type = "S" }
|
|
428
282
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
sseKmsKeyId: 'alias/my-key',
|
|
283
|
+
ttl {
|
|
284
|
+
attribute_name = "ttl"
|
|
285
|
+
enabled = true
|
|
286
|
+
}
|
|
434
287
|
}
|
|
435
288
|
```
|
|
436
289
|
|
|
437
|
-
|
|
438
|
-
sufficient. If your bucket policy denies the `AES256` algorithm, either grant
|
|
439
|
-
the key permissions required for `aws:kms` or set `serverSideEncryption`
|
|
440
|
-
explicitly to match the bucket policy.
|
|
441
|
-
|
|
442
|
-
### Checkpoint data migration (v<4)
|
|
443
|
-
|
|
444
|
-
LangGraph bumped the `Checkpoint.v` field to **4** in `@langchain/langgraph-checkpoint@1.0`. Reading data written by older versions (v<4) requires synthesizing the `TASKS` channel from parent-checkpoint writes — this library does not migrate on read. If you have pre-1.0 data, run LangGraph's reference migration before switching to this saver, or drop the older checkpoints.
|
|
445
|
-
|
|
446
|
-
<a id="configuration-reference"></a>
|
|
447
|
-
|
|
448
|
-
## Configuration Reference
|
|
449
|
-
|
|
450
|
-
### DynamoDBSaver
|
|
451
|
-
|
|
452
|
-
| Option | Type | Default | Description |
|
|
453
|
-
|---|---|---|---|
|
|
454
|
-
| `checkpointsTableName` | `string` | — | Checkpoints table name (**required**) |
|
|
455
|
-
| `writesTableName` | `string` | — | Writes table name (**required**) |
|
|
456
|
-
| `ttlDays` | `number` | — | TTL in days |
|
|
457
|
-
| `ttlSeconds` | `number` | — | TTL in seconds (overrides `ttlDays`) |
|
|
458
|
-
| `compression` | `object` | — | `{ enabled, minSizeBytes?, level? }` |
|
|
459
|
-
| `s3OffloadConfig` | `object` | — | `{ bucketName, keyPrefix?, thresholdBytes?, serverSideEncryption?, sseKmsKeyId?, clientConfig? }` |
|
|
460
|
-
| `clientConfig` | `object` | — | AWS SDK `DynamoDBClientConfig` |
|
|
461
|
-
| `client` | `DynamoDBDocument` | — | Pre-built client (takes precedence over `clientConfig`) |
|
|
462
|
-
|
|
463
|
-
### DynamoDBStore
|
|
464
|
-
|
|
465
|
-
| Option | Type | Default | Description |
|
|
466
|
-
|---|---|---|---|
|
|
467
|
-
| `memoryTableName` | `string` | — | Memory table name (**required**) |
|
|
468
|
-
| `embedding` | `EmbeddingsInterface` | — | Any LangChain embeddings provider for semantic search |
|
|
469
|
-
| `ttlDays` | `number` | — | TTL in days |
|
|
470
|
-
| `clientConfig` | `object` | — | AWS SDK `DynamoDBClientConfig` |
|
|
471
|
-
| `client` | `DynamoDBDocument` | — | Pre-built client (takes precedence over `clientConfig`) |
|
|
472
|
-
|
|
473
|
-
### DynamoDBChatMessageHistory
|
|
474
|
-
|
|
475
|
-
| Option | Type | Default | Description |
|
|
476
|
-
|---|---|---|---|
|
|
477
|
-
| `tableName` | `string` | — | Chat history table name (**required**) |
|
|
478
|
-
| `ttlDays` | `number` | — | TTL in days |
|
|
479
|
-
| `clientConfig` | `object` | — | AWS SDK `DynamoDBClientConfig` |
|
|
480
|
-
| `client` | `DynamoDBDocument` | — | Pre-built client (takes precedence over `clientConfig`) |
|
|
290
|
+
</details>
|
|
481
291
|
|
|
482
|
-
|
|
292
|
+
## IAM permissions
|
|
483
293
|
|
|
484
|
-
|
|
294
|
+
Minimum DynamoDB actions on the table:
|
|
485
295
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
"Effect": "Allow",
|
|
496
|
-
"Action": [
|
|
497
|
-
"dynamodb:GetItem",
|
|
498
|
-
"dynamodb:PutItem",
|
|
499
|
-
"dynamodb:Query",
|
|
500
|
-
"dynamodb:BatchGetItem",
|
|
501
|
-
"dynamodb:BatchWriteItem",
|
|
502
|
-
"dynamodb:TransactWriteItems"
|
|
503
|
-
],
|
|
504
|
-
"Resource": [
|
|
505
|
-
"arn:aws:dynamodb:REGION:ACCOUNT:table/langgraph-checkpoints",
|
|
506
|
-
"arn:aws:dynamodb:REGION:ACCOUNT:table/langgraph-writes"
|
|
507
|
-
]
|
|
508
|
-
},
|
|
509
|
-
{
|
|
510
|
-
"Sid": "StoreAndHistoryAccess",
|
|
511
|
-
"Effect": "Allow",
|
|
512
|
-
"Action": [
|
|
513
|
-
"dynamodb:GetItem",
|
|
514
|
-
"dynamodb:PutItem",
|
|
515
|
-
"dynamodb:UpdateItem",
|
|
516
|
-
"dynamodb:DeleteItem",
|
|
517
|
-
"dynamodb:Query",
|
|
518
|
-
"dynamodb:BatchWriteItem"
|
|
519
|
-
],
|
|
520
|
-
"Resource": [
|
|
521
|
-
"arn:aws:dynamodb:REGION:ACCOUNT:table/langgraph-memory",
|
|
522
|
-
"arn:aws:dynamodb:REGION:ACCOUNT:table/langgraph-chat-history"
|
|
523
|
-
]
|
|
524
|
-
},
|
|
525
|
-
{
|
|
526
|
-
"Sid": "OptionalSemanticSearch",
|
|
527
|
-
"Effect": "Allow",
|
|
528
|
-
"Action": ["bedrock:InvokeModel"],
|
|
529
|
-
"Resource": "arn:aws:bedrock:REGION::foundation-model/amazon.titan-embed-text-v1"
|
|
530
|
-
},
|
|
531
|
-
{
|
|
532
|
-
"Sid": "OptionalS3Offloading",
|
|
533
|
-
"Effect": "Allow",
|
|
534
|
-
"Action": [
|
|
535
|
-
"s3:PutObject",
|
|
536
|
-
"s3:GetObject",
|
|
537
|
-
"s3:DeleteObject",
|
|
538
|
-
"s3:DeleteObjects"
|
|
539
|
-
],
|
|
540
|
-
"Resource": "arn:aws:s3:::YOUR-BUCKET/langgraph-checkpoints/*"
|
|
541
|
-
},
|
|
542
|
-
{
|
|
543
|
-
"Sid": "OptionalS3LifecycleManagement",
|
|
544
|
-
"Effect": "Allow",
|
|
545
|
-
"Action": [
|
|
546
|
-
"s3:GetBucketLifecycleConfiguration",
|
|
547
|
-
"s3:PutBucketLifecycleConfiguration"
|
|
548
|
-
],
|
|
549
|
-
"Resource": "arn:aws:s3:::YOUR-BUCKET"
|
|
550
|
-
}
|
|
551
|
-
]
|
|
552
|
-
}
|
|
296
|
+
```
|
|
297
|
+
dynamodb:GetItem
|
|
298
|
+
dynamodb:PutItem
|
|
299
|
+
dynamodb:DeleteItem
|
|
300
|
+
dynamodb:Query
|
|
301
|
+
dynamodb:Scan
|
|
302
|
+
dynamodb:BatchGetItem
|
|
303
|
+
dynamodb:BatchWriteItem
|
|
304
|
+
dynamodb:TransactWriteItems
|
|
553
305
|
```
|
|
554
306
|
|
|
555
|
-
|
|
307
|
+
When S3 offloading is enabled, on the bucket/objects: `s3:GetObject`, `s3:PutObject`, `s3:DeleteObject`, `s3:ListBucket`, and — only if TTL-driven lifecycle rules are desired — `s3:GetBucketLifecycleConfiguration` and `s3:PutBucketLifecycleConfiguration`. For semantic search via Bedrock embeddings: `bedrock:InvokeModel`.
|
|
556
308
|
|
|
557
|
-
|
|
309
|
+
## Migrating from earlier versions
|
|
558
310
|
|
|
559
|
-
|
|
311
|
+
**0.2.x → 0.3.0** is a complete, ground-up rewrite. The public API is similar, but the table schema, on-disk layout, and several options changed, so existing data is **not compatible** — create a new table.
|
|
560
312
|
|
|
561
|
-
- **
|
|
562
|
-
- **
|
|
563
|
-
- **
|
|
564
|
-
- **
|
|
313
|
+
- **Table schema is now `PK`/`SK` strings** (one table for all adapters) instead of per-adapter custom key names. The key attribute names changed, so CDK/Terraform definitions need updating.
|
|
314
|
+
- **Store keys** are `PK = namespace[0]`, `SK = namespace[1..]#key` (was `PK = full namespace`, `SK = key`).
|
|
315
|
+
- **Chat history is one item per message** (`SK = MSG#<ULID>`) plus a `SESSION` metadata item, replacing the single per-session item.
|
|
316
|
+
- **Single `tableName` option** per adapter (was `checkpointsTableName`/`writesTableName`, etc.).
|
|
317
|
+
- **One `ttl` option** — `{ days }` or `{ seconds }` — replaces `ttlDays`/`ttlSeconds`.
|
|
318
|
+
- **S3 config option renamed** `s3OffloadConfig` → `s3`.
|
|
319
|
+
- **Per-instance `logger` option** replaces the global `setGlobalLogger` singleton; default logging is now silent.
|
|
320
|
+
- **Unified error model** — all errors extend `DynamoDbLangGraphError` with an `ErrorCode`.
|
|
565
321
|
|
|
566
|
-
|
|
322
|
+
## Production notes
|
|
567
323
|
|
|
568
|
-
|
|
324
|
+
- **Sharing one table** across all three adapters is supported — their key spaces don't collide, and table-wide reads filter to their own items. Checkpointer, chat-history, and *scoped* store reads are all partition-scoped (`Query`/`GetItem`).
|
|
325
|
+
- **Scoped reads are `Query`s.** `store.search`/`store.listNamespaces` with a concrete namespace prefix and `history.getMessages` are native `Query`s. Only a rootless `store.search([])` / unprefixed `listNamespaces` and `history.listSessions` fall back to `Scan` (cost scales with table size) — keep those rare or use a dedicated table.
|
|
326
|
+
- **Hot partitions.** The store's partition key is `namespace[0]` and chat history's is `sessionId`. A single partition tops out around ~1000 WCU / 3000 RCU, so avoid funneling very high write throughput through one tenant/session id; spread load across scope roots (e.g. include a tenant id as `namespace[0]`).
|
|
327
|
+
- **Very large vector corpora** outgrow the in-DB ranker (`maxSearchCandidates`). Configure a `vectorBackend` (OpenSearch, pgvector, …) — the library keeps DynamoDB as the source of truth and only delegates similarity ranking.
|
|
328
|
+
- **TTL deletion timing** is governed by DynamoDB (typically within 48 h of expiry) and S3 lifecycle expiry is day-granular — the library writes the correct expiry timestamp / lifecycle rule (and filters expired chat messages on read) but does not guarantee instant deletion.
|
|
569
329
|
|
|
570
|
-
|
|
330
|
+
## Testing
|
|
571
331
|
|
|
572
332
|
```bash
|
|
573
|
-
npm test
|
|
574
|
-
npm
|
|
575
|
-
npm run
|
|
576
|
-
npm run
|
|
333
|
+
npm test # unit + static-guard + type tests, 100% coverage
|
|
334
|
+
npm run typecheck
|
|
335
|
+
npm run lint
|
|
336
|
+
npm run build
|
|
577
337
|
```
|
|
578
338
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
A dedicated integration tier verifies the library against a real DynamoDB API
|
|
582
|
-
(catches things `aws-sdk-client-mock` cannot, such as `ValidationException` on
|
|
583
|
-
malformed filter expressions, `ConditionExpression` enforcement, primary-key
|
|
584
|
-
attribute rules, and lex-sort assumptions on sort keys).
|
|
339
|
+
Integration and contract tiers run against DynamoDB Local (Docker) and are kept out of the default `npm test`:
|
|
585
340
|
|
|
586
341
|
```bash
|
|
587
|
-
npm run test:integration:up
|
|
588
|
-
npm run test:integration
|
|
589
|
-
npm run test:integration:down
|
|
342
|
+
npm run test:integration:up # docker compose up -d (DynamoDB Local)
|
|
343
|
+
npm run test:integration # integration flows + LangGraph/LangChain contract conformance
|
|
344
|
+
npm run test:integration:down
|
|
590
345
|
```
|
|
591
346
|
|
|
592
|
-
|
|
593
|
-
on every pull request.
|
|
594
|
-
|
|
595
|
-
### Mutation testing (Stryker)
|
|
596
|
-
|
|
597
|
-
Line coverage tells you what code ran; **mutation coverage** tells you what
|
|
598
|
-
tests would *catch regressions*. Run against a hot spot:
|
|
347
|
+
Real-AWS verification scripts live in `examples/` (each creates and tears down its own resources):
|
|
599
348
|
|
|
600
349
|
```bash
|
|
601
|
-
|
|
602
|
-
|
|
350
|
+
node examples/verify-checkpointer.mjs # save/resume/writes/list/delete, compression, S3, TTL
|
|
351
|
+
node examples/verify-store.mjs # filters, semantic search, S3 offload, TTL
|
|
352
|
+
node examples/verify-history.mjs # per-message model, concurrency, RunnableWithMessageHistory agent
|
|
353
|
+
node examples/verify-factory.mjs # shared-client createAll across all three adapters
|
|
354
|
+
node examples/verify-agents.mjs # real LangGraph agents using the saver + store as memory
|
|
355
|
+
node examples/verify-edge-cases.mjs # filter operators, multi-page reads, compression+S3, scale
|
|
603
356
|
```
|
|
604
357
|
|
|
605
|
-
Stryker runs with `incremental: true`, so re-runs only re-check files that
|
|
606
|
-
changed since the last run. Baseline kill-rate goal: **≥80%** for new code in
|
|
607
|
-
`src/shared/` and `src/checkpointer/`.
|
|
608
|
-
|
|
609
|
-
<a id="project-structure"></a>
|
|
610
|
-
|
|
611
|
-
## Project Structure
|
|
612
|
-
|
|
613
|
-
```text
|
|
614
|
-
src/
|
|
615
|
-
├── checkpointer/ # DynamoDBSaver — checkpoint persistence
|
|
616
|
-
│ ├── actions/ # put, putWrites, getTuple, deleteThread, writer
|
|
617
|
-
│ ├── types/ # TypeScript interfaces & constants
|
|
618
|
-
│ └── utils/ # Deserialization, validation
|
|
619
|
-
├── store/ # DynamoDBStore — long-term memory
|
|
620
|
-
│ ├── actions/ # get, put, search, listNamespaces
|
|
621
|
-
│ ├── types/ # TypeScript interfaces
|
|
622
|
-
│ └── utils/ # Validation, filtering
|
|
623
|
-
├── history/ # DynamoDBChatMessageHistory — chat sessions
|
|
624
|
-
│ ├── actions/ # getMessages, addMessage(s), clear, listSessions
|
|
625
|
-
│ ├── types/ # TypeScript interfaces
|
|
626
|
-
│ └── utils/ # Validation, title generation
|
|
627
|
-
├── shared/ # Cross-cutting utilities
|
|
628
|
-
│ └── utils/ # Compressor, S3Offloader, retry, TTL, batch-write, logger
|
|
629
|
-
└── factory.ts # DynamoDBFactory one-liner setup
|
|
630
|
-
```
|
|
631
|
-
|
|
632
|
-
<a id="contributing"></a>
|
|
633
|
-
|
|
634
|
-
## Contributing
|
|
635
|
-
|
|
636
|
-
Contributions welcome! Please:
|
|
637
|
-
|
|
638
|
-
1. Check existing issues or create a new one
|
|
639
|
-
2. Fork the repository
|
|
640
|
-
3. Create a feature branch
|
|
641
|
-
4. Add tests for your changes
|
|
642
|
-
5. Submit a pull request
|
|
643
|
-
|
|
644
|
-
<a id="license"></a>
|
|
645
|
-
|
|
646
358
|
## License
|
|
647
359
|
|
|
648
|
-
MIT © [
|
|
360
|
+
MIT © [Faruk Ada](https://github.com/FarukAda)
|
|
649
361
|
|
|
650
362
|
---
|
|
651
363
|
|