@farukada/aws-langgraph-dynamodb-ts 1.0.0-rc.2 → 1.0.0
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 +390 -193
- package/dist/{backfill → cjs/backfill}/backfill.d.ts +15 -12
- package/dist/cjs/backfill/backfill.js +177 -0
- package/dist/{checkpointer → cjs/checkpointer}/actions/delete-thread.d.ts +1 -1
- package/dist/cjs/checkpointer/actions/delete-thread.js +26 -0
- package/dist/{checkpointer → cjs/checkpointer}/actions/get-tuple.d.ts +4 -3
- package/dist/cjs/checkpointer/actions/get-tuple.js +22 -0
- package/dist/{checkpointer → cjs/checkpointer}/actions/list.d.ts +7 -4
- package/dist/cjs/checkpointer/actions/list.js +70 -0
- package/dist/{checkpointer → cjs/checkpointer}/actions/put-writes.d.ts +8 -6
- package/dist/cjs/checkpointer/actions/put-writes.js +21 -0
- package/dist/{checkpointer → cjs/checkpointer}/actions/put.d.ts +21 -15
- package/dist/cjs/checkpointer/actions/put.js +79 -0
- package/dist/{checkpointer → cjs/checkpointer}/internal/delta-history.d.ts +38 -26
- package/dist/cjs/checkpointer/internal/delta-history.js +131 -0
- package/dist/{checkpointer → cjs/checkpointer}/internal/listing.d.ts +4 -4
- package/dist/cjs/checkpointer/internal/listing.js +104 -0
- package/dist/{checkpointer → cjs/checkpointer}/internal/parse.d.ts +51 -15
- package/dist/cjs/checkpointer/internal/parse.js +184 -0
- package/dist/{checkpointer → cjs/checkpointer}/internal/pending-writes.d.ts +64 -25
- package/dist/cjs/checkpointer/internal/pending-writes.js +241 -0
- package/dist/{checkpointer → cjs/checkpointer}/internal/read.d.ts +15 -10
- package/dist/cjs/checkpointer/internal/read.js +132 -0
- package/dist/{checkpointer → cjs/checkpointer}/internal/rows.d.ts +94 -21
- package/dist/cjs/checkpointer/internal/rows.js +356 -0
- package/dist/{checkpointer → cjs/checkpointer}/internal/setup.d.ts +13 -20
- package/dist/cjs/checkpointer/internal/setup.js +25 -0
- package/dist/{checkpointer → cjs/checkpointer}/saver.d.ts +72 -36
- package/dist/cjs/checkpointer/saver.js +56 -0
- package/dist/{checkpointer → cjs/checkpointer}/types.d.ts +1 -1
- package/dist/cjs/checkpointer/types.js +2 -0
- package/dist/{factory → cjs/factory}/factory.d.ts +25 -20
- package/dist/cjs/factory/factory.js +137 -0
- package/dist/{factory → cjs/factory}/types.d.ts +12 -12
- package/dist/cjs/factory/types.js +2 -0
- package/dist/{history → cjs/history}/actions/add-messages.d.ts +18 -10
- package/dist/cjs/history/actions/add-messages.js +17 -0
- package/dist/{history → cjs/history}/actions/clear.d.ts +1 -1
- package/dist/cjs/history/actions/clear.js +29 -0
- package/dist/{history → cjs/history}/actions/get-messages.d.ts +11 -9
- package/dist/cjs/history/actions/get-messages.js +58 -0
- package/dist/{history → cjs/history}/actions/list-sessions.d.ts +3 -3
- package/dist/cjs/history/actions/list-sessions.js +67 -0
- package/dist/{history → cjs/history}/actions/reconcile-count.d.ts +13 -9
- package/dist/cjs/history/actions/reconcile-count.js +8 -0
- package/dist/{history → cjs/history}/chat-message-history.d.ts +62 -30
- package/dist/cjs/history/chat-message-history.js +61 -0
- package/dist/{history → cjs/history}/internal/append.d.ts +64 -32
- package/dist/cjs/history/internal/append.js +267 -0
- package/dist/{history → cjs/history}/internal/message-read.d.ts +3 -3
- package/dist/cjs/history/internal/message-read.js +93 -0
- package/dist/{history → cjs/history}/internal/parse.d.ts +2 -2
- package/dist/cjs/history/internal/parse.js +113 -0
- package/dist/{history → cjs/history}/internal/rows.d.ts +11 -10
- package/dist/cjs/history/internal/rows.js +96 -0
- package/dist/{history → cjs/history}/internal/session.d.ts +41 -22
- package/dist/cjs/history/internal/session.js +296 -0
- package/dist/{history → cjs/history}/internal/setup.d.ts +2 -2
- package/dist/cjs/history/internal/setup.js +60 -0
- package/dist/{history → cjs/history}/session-adapter.d.ts +0 -6
- package/dist/cjs/history/session-adapter.js +38 -0
- package/dist/{history → cjs/history}/types.d.ts +18 -15
- package/dist/cjs/history/types.js +2 -0
- package/dist/{index.d.ts → cjs/index.d.ts} +27 -27
- package/dist/cjs/index.js +25 -0
- package/dist/cjs/package.json +1 -0
- package/dist/{shared → cjs/shared}/adapter.d.ts +27 -16
- package/dist/cjs/shared/adapter.js +70 -0
- package/dist/cjs/shared/clock.js +14 -0
- package/dist/{shared → cjs/shared}/codec/codec.d.ts +37 -20
- package/dist/cjs/shared/codec/codec.js +162 -0
- package/dist/{shared → cjs/shared}/codec/compression.d.ts +9 -4
- package/dist/cjs/shared/codec/compression.js +45 -0
- package/dist/cjs/shared/codec/json-serde.js +58 -0
- package/dist/{shared → cjs/shared}/codec/s3/client-types.d.ts +2 -1
- package/dist/cjs/shared/codec/s3/client-types.js +6 -0
- package/dist/{shared → cjs/shared}/codec/s3/client.d.ts +25 -7
- package/dist/cjs/shared/codec/s3/client.js +78 -0
- package/dist/{shared → cjs/shared}/codec/s3/config.d.ts +12 -7
- package/dist/cjs/shared/codec/s3/config.js +92 -0
- package/dist/{shared → cjs/shared}/codec/s3/lifecycle.d.ts +71 -17
- package/dist/cjs/shared/codec/s3/lifecycle.js +223 -0
- package/dist/{shared → cjs/shared}/codec/s3/offloader.d.ts +42 -29
- package/dist/cjs/shared/codec/s3/offloader.js +289 -0
- package/dist/cjs/shared/concurrency.js +31 -0
- package/dist/{shared → cjs/shared}/dynamodb/abort.d.ts +2 -2
- package/dist/cjs/shared/dynamodb/abort.js +16 -0
- package/dist/{shared → cjs/shared}/dynamodb/batch-write.d.ts +2 -2
- package/dist/cjs/shared/dynamodb/batch-write.js +79 -0
- package/dist/cjs/shared/dynamodb/cancellation.js +37 -0
- package/dist/{shared → cjs/shared}/dynamodb/client.d.ts +24 -22
- package/dist/cjs/shared/dynamodb/client.js +40 -0
- package/dist/{shared → cjs/shared}/dynamodb/idempotent-write.d.ts +64 -19
- package/dist/cjs/shared/dynamodb/idempotent-write.js +173 -0
- package/dist/{shared → cjs/shared}/dynamodb/paginate.d.ts +2 -2
- package/dist/cjs/shared/dynamodb/paginate.js +90 -0
- package/dist/{shared → cjs/shared}/dynamodb/partition-delete.d.ts +6 -6
- package/dist/cjs/shared/dynamodb/partition-delete.js +177 -0
- package/dist/{shared → cjs/shared}/dynamodb/recency-index.d.ts +27 -15
- package/dist/cjs/shared/dynamodb/recency-index.js +146 -0
- package/dist/{shared → cjs/shared}/dynamodb/retry.d.ts +37 -6
- package/dist/cjs/shared/dynamodb/retry.js +193 -0
- package/dist/cjs/shared/dynamodb/row-size.d.ts +33 -0
- package/dist/cjs/shared/dynamodb/row-size.js +30 -0
- package/dist/{shared → cjs/shared}/dynamodb/table-schema.d.ts +27 -18
- package/dist/cjs/shared/dynamodb/table-schema.js +52 -0
- package/dist/{shared → cjs/shared}/errors/base-error.d.ts +42 -7
- package/dist/cjs/shared/errors/base-error.js +73 -0
- package/dist/{shared → cjs/shared}/errors/boundary.d.ts +29 -14
- package/dist/cjs/shared/errors/boundary.js +61 -0
- package/dist/cjs/shared/errors/classify.d.ts +206 -0
- package/dist/cjs/shared/errors/classify.js +232 -0
- package/dist/{shared → cjs/shared}/errors/error-code.d.ts +17 -10
- package/dist/cjs/shared/errors/error-code.js +27 -0
- package/dist/{shared → cjs/shared}/errors/errors.d.ts +75 -9
- package/dist/cjs/shared/errors/errors.js +123 -0
- package/dist/cjs/shared/logging/logger.js +30 -0
- package/dist/{shared → cjs/shared}/logging/redaction.d.ts +8 -4
- package/dist/cjs/shared/logging/redaction.js +145 -0
- package/dist/{shared → cjs/shared}/logging/secret-patterns.d.ts +30 -7
- package/dist/cjs/shared/logging/secret-patterns.js +93 -0
- package/dist/cjs/shared/logging/truncate.js +31 -0
- package/dist/{shared → cjs/shared}/options.d.ts +27 -11
- package/dist/cjs/shared/options.js +2 -0
- package/dist/cjs/shared/ulid.js +83 -0
- package/dist/{shared → cjs/shared}/validation/collaborators.d.ts +21 -2
- package/dist/cjs/shared/validation/collaborators.js +79 -0
- package/dist/{shared → cjs/shared}/validation/option-shape.d.ts +7 -5
- package/dist/cjs/shared/validation/option-shape.js +31 -0
- package/dist/{shared → cjs/shared}/validation/options.d.ts +4 -4
- package/dist/cjs/shared/validation/options.js +166 -0
- package/dist/cjs/shared/validation/primitives.js +114 -0
- package/dist/{shared → cjs/shared}/validation/ttl.d.ts +26 -9
- package/dist/cjs/shared/validation/ttl.js +52 -0
- package/dist/{store → cjs/store}/actions/list-namespaces.d.ts +5 -5
- package/dist/cjs/store/actions/list-namespaces.js +92 -0
- package/dist/{store → cjs/store}/actions/put.d.ts +11 -4
- package/dist/cjs/store/actions/put.js +49 -0
- package/dist/{store → cjs/store}/actions/reconcile-vector-index.d.ts +5 -5
- package/dist/cjs/store/actions/reconcile-vector-index.js +13 -0
- package/dist/{store → cjs/store}/actions/search.d.ts +2 -2
- package/dist/cjs/store/actions/search.js +26 -0
- package/dist/cjs/store/internal/batch-plan.d.ts +56 -0
- package/dist/cjs/store/internal/batch-plan.js +32 -0
- package/dist/{store → cjs/store}/internal/filter.d.ts +3 -3
- package/dist/cjs/store/internal/filter.js +64 -0
- package/dist/cjs/store/internal/get-item.d.ts +77 -0
- package/dist/cjs/store/internal/get-item.js +58 -0
- package/dist/{store → cjs/store}/internal/item-write.d.ts +72 -32
- package/dist/cjs/store/internal/item-write.js +181 -0
- package/dist/{store → cjs/store}/internal/parse.d.ts +15 -10
- package/dist/cjs/store/internal/parse.js +180 -0
- package/dist/{store → cjs/store}/internal/rows.d.ts +38 -34
- package/dist/cjs/store/internal/rows.js +166 -0
- package/dist/{store → cjs/store}/internal/semantic-search.d.ts +2 -2
- package/dist/cjs/store/internal/semantic-search.js +211 -0
- package/dist/{store → cjs/store}/internal/setup.d.ts +10 -15
- package/dist/cjs/store/internal/setup.js +103 -0
- package/dist/{store → cjs/store}/internal/table-search.d.ts +5 -5
- package/dist/cjs/store/internal/table-search.js +123 -0
- package/dist/{store → cjs/store}/internal/vector-index.d.ts +26 -15
- package/dist/cjs/store/internal/vector-index.js +269 -0
- package/dist/{store → cjs/store}/store.d.ts +82 -39
- package/dist/cjs/store/store.js +97 -0
- package/dist/{store → cjs/store}/types.d.ts +25 -10
- package/dist/cjs/store/types.js +2 -0
- package/dist/cjs/store/vector-backend.js +4 -0
- package/dist/esm/backfill/backfill.d.ts +171 -0
- package/dist/esm/backfill/backfill.js +170 -0
- package/dist/{checkpointer/actions/delete-thread.js → esm/checkpointer/actions/delete-thread.d.ts} +4 -26
- package/dist/esm/checkpointer/actions/delete-thread.js +23 -0
- package/dist/{checkpointer/actions/get-tuple.js → esm/checkpointer/actions/get-tuple.d.ts} +7 -24
- package/dist/esm/checkpointer/actions/get-tuple.js +19 -0
- package/dist/esm/checkpointer/actions/list.d.ts +55 -0
- package/dist/esm/checkpointer/actions/list.js +67 -0
- package/dist/{checkpointer/actions/put-writes.js → esm/checkpointer/actions/put-writes.d.ts} +10 -37
- package/dist/esm/checkpointer/actions/put-writes.js +18 -0
- package/dist/esm/checkpointer/actions/put.d.ts +95 -0
- package/dist/esm/checkpointer/actions/put.js +75 -0
- package/dist/esm/checkpointer/internal/delta-history.d.ts +124 -0
- package/dist/esm/checkpointer/internal/delta-history.js +126 -0
- package/dist/{checkpointer/internal/listing.js → esm/checkpointer/internal/listing.d.ts} +22 -118
- package/dist/esm/checkpointer/internal/listing.js +95 -0
- package/dist/esm/checkpointer/internal/parse.d.ts +298 -0
- package/dist/esm/checkpointer/internal/parse.js +169 -0
- package/dist/esm/checkpointer/internal/pending-writes.d.ts +314 -0
- package/dist/esm/checkpointer/internal/pending-writes.js +229 -0
- package/dist/esm/checkpointer/internal/read.d.ts +135 -0
- package/dist/esm/checkpointer/internal/read.js +125 -0
- package/dist/esm/checkpointer/internal/rows.d.ts +644 -0
- package/dist/esm/checkpointer/internal/rows.js +323 -0
- package/dist/esm/checkpointer/internal/setup.d.ts +47 -0
- package/dist/esm/checkpointer/internal/setup.js +21 -0
- package/dist/{checkpointer/saver.js → esm/checkpointer/saver.d.ts} +84 -87
- package/dist/esm/checkpointer/saver.js +52 -0
- package/dist/esm/checkpointer/types.d.ts +51 -0
- package/dist/esm/checkpointer/types.js +1 -0
- package/dist/esm/factory/factory.d.ts +154 -0
- package/dist/esm/factory/factory.js +133 -0
- package/dist/esm/factory/types.d.ts +76 -0
- package/dist/esm/factory/types.js +1 -0
- package/dist/{history/actions/add-messages.js → esm/history/actions/add-messages.d.ts} +20 -26
- package/dist/esm/history/actions/add-messages.js +14 -0
- package/dist/{history/actions/clear.js → esm/history/actions/clear.d.ts} +4 -35
- package/dist/esm/history/actions/clear.js +26 -0
- package/dist/esm/history/actions/get-messages.d.ts +60 -0
- package/dist/esm/history/actions/get-messages.js +55 -0
- package/dist/esm/history/actions/list-sessions.d.ts +55 -0
- package/dist/esm/history/actions/list-sessions.js +64 -0
- package/dist/{history/actions/reconcile-count.js → esm/history/actions/reconcile-count.d.ts} +14 -16
- package/dist/esm/history/actions/reconcile-count.js +5 -0
- package/dist/{history/chat-message-history.js → esm/history/chat-message-history.d.ts} +76 -87
- package/dist/esm/history/chat-message-history.js +57 -0
- package/dist/esm/history/internal/append.d.ts +244 -0
- package/dist/esm/history/internal/append.js +259 -0
- package/dist/esm/history/internal/message-read.d.ts +84 -0
- package/dist/esm/history/internal/message-read.js +89 -0
- package/dist/esm/history/internal/parse.d.ts +153 -0
- package/dist/esm/history/internal/parse.js +105 -0
- package/dist/{history/internal/rows.js → esm/history/internal/rows.d.ts} +58 -112
- package/dist/esm/history/internal/rows.js +83 -0
- package/dist/esm/history/internal/session.d.ts +350 -0
- package/dist/esm/history/internal/session.js +285 -0
- package/dist/esm/history/internal/setup.d.ts +64 -0
- package/dist/esm/history/internal/setup.js +56 -0
- package/dist/{history/session-adapter.js → esm/history/session-adapter.d.ts} +25 -39
- package/dist/esm/history/session-adapter.js +34 -0
- package/dist/esm/history/types.d.ts +102 -0
- package/dist/esm/history/types.js +1 -0
- package/dist/esm/index.d.ts +53 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/shared/adapter.d.ts +146 -0
- package/dist/esm/shared/adapter.js +65 -0
- package/dist/{shared/clock.js → esm/shared/clock.d.ts} +3 -14
- package/dist/esm/shared/clock.js +9 -0
- package/dist/esm/shared/codec/codec.d.ts +336 -0
- package/dist/esm/shared/codec/codec.js +150 -0
- package/dist/esm/shared/codec/compression.d.ts +66 -0
- package/dist/esm/shared/codec/compression.js +40 -0
- package/dist/esm/shared/codec/json-serde.d.ts +80 -0
- package/dist/esm/shared/codec/json-serde.js +54 -0
- package/dist/esm/shared/codec/s3/client-types.d.ts +54 -0
- package/dist/esm/shared/codec/s3/client-types.js +3 -0
- package/dist/esm/shared/codec/s3/client.d.ts +63 -0
- package/dist/esm/shared/codec/s3/client.js +40 -0
- package/dist/{shared/codec/s3/config.js → esm/shared/codec/s3/config.d.ts} +45 -93
- package/dist/esm/shared/codec/s3/config.js +79 -0
- package/dist/esm/shared/codec/s3/lifecycle.d.ts +220 -0
- package/dist/esm/shared/codec/s3/lifecycle.js +214 -0
- package/dist/esm/shared/codec/s3/offloader.d.ts +428 -0
- package/dist/esm/shared/codec/s3/offloader.js +278 -0
- package/dist/{shared/concurrency.js → esm/shared/concurrency.d.ts} +2 -37
- package/dist/esm/shared/concurrency.js +27 -0
- package/dist/{shared/dynamodb/abort.js → esm/shared/dynamodb/abort.d.ts} +4 -16
- package/dist/esm/shared/dynamodb/abort.js +12 -0
- package/dist/esm/shared/dynamodb/batch-write.d.ts +86 -0
- package/dist/esm/shared/dynamodb/batch-write.js +74 -0
- package/dist/{shared/dynamodb/cancellation.js → esm/shared/dynamodb/cancellation.d.ts} +25 -53
- package/dist/esm/shared/dynamodb/cancellation.js +30 -0
- package/dist/{shared/dynamodb/client.js → esm/shared/dynamodb/client.d.ts} +74 -64
- package/dist/esm/shared/dynamodb/client.js +35 -0
- package/dist/{shared/dynamodb/idempotent-write.js → esm/shared/dynamodb/idempotent-write.d.ts} +172 -169
- package/dist/esm/shared/dynamodb/idempotent-write.js +153 -0
- package/dist/esm/shared/dynamodb/paginate.d.ts +111 -0
- package/dist/esm/shared/dynamodb/paginate.js +84 -0
- package/dist/esm/shared/dynamodb/partition-delete.d.ts +204 -0
- package/dist/esm/shared/dynamodb/partition-delete.js +171 -0
- package/dist/esm/shared/dynamodb/recency-index.d.ts +243 -0
- package/dist/esm/shared/dynamodb/recency-index.js +136 -0
- package/dist/esm/shared/dynamodb/retry.d.ts +317 -0
- package/dist/esm/shared/dynamodb/retry.js +180 -0
- package/dist/esm/shared/dynamodb/row-size.d.ts +33 -0
- package/dist/esm/shared/dynamodb/row-size.js +26 -0
- package/dist/{shared/dynamodb/table-schema.js → esm/shared/dynamodb/table-schema.d.ts} +57 -67
- package/dist/esm/shared/dynamodb/table-schema.js +43 -0
- package/dist/esm/shared/errors/base-error.d.ts +231 -0
- package/dist/esm/shared/errors/base-error.js +64 -0
- package/dist/esm/shared/errors/boundary.d.ts +86 -0
- package/dist/esm/shared/errors/boundary.js +54 -0
- package/dist/esm/shared/errors/classify.d.ts +206 -0
- package/dist/esm/shared/errors/classify.js +220 -0
- package/dist/{shared/errors/error-code.js → esm/shared/errors/error-code.d.ts} +39 -43
- package/dist/esm/shared/errors/error-code.js +24 -0
- package/dist/{shared/errors/errors.js → esm/shared/errors/errors.d.ts} +92 -98
- package/dist/esm/shared/errors/errors.js +110 -0
- package/dist/{shared/logging/logger.js → esm/shared/logging/logger.d.ts} +22 -52
- package/dist/esm/shared/logging/logger.js +25 -0
- package/dist/esm/shared/logging/redaction.d.ts +123 -0
- package/dist/esm/shared/logging/redaction.js +140 -0
- package/dist/{shared/logging/secret-patterns.js → esm/shared/logging/secret-patterns.d.ts} +46 -87
- package/dist/esm/shared/logging/secret-patterns.js +83 -0
- package/dist/{shared/logging/truncate.js → esm/shared/logging/truncate.d.ts} +6 -40
- package/dist/esm/shared/logging/truncate.js +25 -0
- package/dist/esm/shared/options.d.ts +100 -0
- package/dist/esm/shared/options.js +1 -0
- package/dist/{shared/ulid.js → esm/shared/ulid.d.ts} +4 -84
- package/dist/esm/shared/ulid.js +77 -0
- package/dist/{shared/validation/collaborators.js → esm/shared/validation/collaborators.d.ts} +37 -65
- package/dist/esm/shared/validation/collaborators.js +70 -0
- package/dist/{shared/validation/option-shape.js → esm/shared/validation/option-shape.d.ts} +14 -36
- package/dist/esm/shared/validation/option-shape.js +24 -0
- package/dist/esm/shared/validation/options.d.ts +145 -0
- package/dist/esm/shared/validation/options.js +156 -0
- package/dist/{shared/validation/primitives.js → esm/shared/validation/primitives.d.ts} +30 -125
- package/dist/esm/shared/validation/primitives.js +100 -0
- package/dist/esm/shared/validation/ttl.d.ts +94 -0
- package/dist/esm/shared/validation/ttl.js +46 -0
- package/dist/esm/store/actions/list-namespaces.d.ts +79 -0
- package/dist/esm/store/actions/list-namespaces.js +86 -0
- package/dist/esm/store/actions/put.d.ts +43 -0
- package/dist/esm/store/actions/put.js +46 -0
- package/dist/{store/actions/reconcile-vector-index.js → esm/store/actions/reconcile-vector-index.d.ts} +8 -16
- package/dist/esm/store/actions/reconcile-vector-index.js +10 -0
- package/dist/esm/store/actions/search.d.ts +38 -0
- package/dist/esm/store/actions/search.js +23 -0
- package/dist/esm/store/internal/batch-plan.d.ts +56 -0
- package/dist/esm/store/internal/batch-plan.js +28 -0
- package/dist/esm/store/internal/filter.d.ts +43 -0
- package/dist/esm/store/internal/filter.js +60 -0
- package/dist/esm/store/internal/get-item.d.ts +77 -0
- package/dist/esm/store/internal/get-item.js +54 -0
- package/dist/esm/store/internal/item-write.d.ts +270 -0
- package/dist/esm/store/internal/item-write.js +173 -0
- package/dist/esm/store/internal/parse.d.ts +230 -0
- package/dist/esm/store/internal/parse.js +169 -0
- package/dist/{store/internal/rows.js → esm/store/internal/rows.d.ts} +111 -199
- package/dist/esm/store/internal/rows.js +147 -0
- package/dist/esm/store/internal/semantic-search.d.ts +168 -0
- package/dist/esm/store/internal/semantic-search.js +200 -0
- package/dist/esm/store/internal/setup.d.ts +96 -0
- package/dist/esm/store/internal/setup.js +98 -0
- package/dist/esm/store/internal/table-search.d.ts +100 -0
- package/dist/esm/store/internal/table-search.js +119 -0
- package/dist/esm/store/internal/vector-index.d.ts +258 -0
- package/dist/esm/store/internal/vector-index.js +256 -0
- package/dist/{store/store.js → esm/store/store.d.ts} +99 -133
- package/dist/esm/store/store.js +93 -0
- package/dist/esm/store/types.d.ts +111 -0
- package/dist/esm/store/types.js +1 -0
- package/dist/esm/store/vector-backend.d.ts +104 -0
- package/dist/esm/store/vector-backend.js +1 -0
- package/package.json +50 -44
- package/dist/backfill/backfill.js +0 -393
- package/dist/checkpointer/actions/list.js +0 -142
- package/dist/checkpointer/actions/put.js +0 -195
- package/dist/checkpointer/internal/delta-history.js +0 -252
- package/dist/checkpointer/internal/parse.js +0 -372
- package/dist/checkpointer/internal/pending-writes.js +0 -588
- package/dist/checkpointer/internal/read.js +0 -264
- package/dist/checkpointer/internal/rows.js +0 -834
- package/dist/checkpointer/internal/setup.js +0 -72
- package/dist/checkpointer/types.js +0 -12
- package/dist/factory/factory.js +0 -266
- package/dist/factory/types.js +0 -10
- package/dist/history/actions/get-messages.js +0 -141
- package/dist/history/actions/list-sessions.js +0 -156
- package/dist/history/internal/append.js +0 -500
- package/dist/history/internal/message-read.js +0 -204
- package/dist/history/internal/parse.js +0 -252
- package/dist/history/internal/session.js +0 -628
- package/dist/history/internal/setup.js +0 -106
- package/dist/history/types.js +0 -12
- package/dist/index.js +0 -51
- package/dist/shared/adapter.js +0 -143
- package/dist/shared/codec/codec.js +0 -441
- package/dist/shared/codec/compression.js +0 -89
- package/dist/shared/codec/json-serde.js +0 -191
- package/dist/shared/codec/s3/client-types.js +0 -26
- package/dist/shared/codec/s3/client.js +0 -97
- package/dist/shared/codec/s3/lifecycle.js +0 -355
- package/dist/shared/codec/s3/offloader.js +0 -658
- package/dist/shared/dynamodb/batch-write.js +0 -173
- package/dist/shared/dynamodb/paginate.js +0 -188
- package/dist/shared/dynamodb/partition-delete.js +0 -340
- package/dist/shared/dynamodb/recency-index.js +0 -377
- package/dist/shared/dynamodb/retry.js +0 -463
- package/dist/shared/errors/base-error.js +0 -174
- package/dist/shared/errors/boundary.js +0 -143
- package/dist/shared/errors/classify.d.ts +0 -97
- package/dist/shared/errors/classify.js +0 -257
- package/dist/shared/logging/redaction.js +0 -316
- package/dist/shared/options.js +0 -11
- package/dist/shared/validation/options.js +0 -328
- package/dist/shared/validation/ttl.js +0 -132
- package/dist/store/actions/list-namespaces.js +0 -197
- package/dist/store/actions/put.js +0 -78
- package/dist/store/actions/search.js +0 -66
- package/dist/store/internal/batch-plan.d.ts +0 -26
- package/dist/store/internal/batch-plan.js +0 -109
- package/dist/store/internal/filter.js +0 -137
- package/dist/store/internal/get-item.d.ts +0 -45
- package/dist/store/internal/get-item.js +0 -115
- package/dist/store/internal/item-write.js +0 -463
- package/dist/store/internal/parse.js +0 -350
- package/dist/store/internal/semantic-search.js +0 -389
- package/dist/store/internal/setup.js +0 -223
- package/dist/store/internal/table-search.js +0 -213
- package/dist/store/internal/vector-index.js +0 -546
- package/dist/store/types.js +0 -15
- package/dist/store/vector-backend.js +0 -17
- /package/dist/{shared → cjs/shared}/clock.d.ts +0 -0
- /package/dist/{shared → cjs/shared}/codec/json-serde.d.ts +0 -0
- /package/dist/{shared → cjs/shared}/concurrency.d.ts +0 -0
- /package/dist/{shared → cjs/shared}/dynamodb/cancellation.d.ts +0 -0
- /package/dist/{shared → cjs/shared}/logging/logger.d.ts +0 -0
- /package/dist/{shared → cjs/shared}/logging/truncate.d.ts +0 -0
- /package/dist/{shared → cjs/shared}/ulid.d.ts +0 -0
- /package/dist/{shared → cjs/shared}/validation/primitives.d.ts +0 -0
- /package/dist/{store → cjs/store}/vector-backend.d.ts +0 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hides when a listing reads, and when it stops.
|
|
3
|
+
*
|
|
4
|
+
* A `limit` of `0` is answered before any request is built, a config that
|
|
5
|
+
* pins one checkpoint in a known namespace is a single direct read rather than
|
|
6
|
+
* a range, and every other listing streams tuples until the caller stops
|
|
7
|
+
* pulling or `limit` is reached. The read is deliberately unbounded and
|
|
8
|
+
* eventually consistent; past a threshold an operator is warned instead of the
|
|
9
|
+
* caller being refused. Where the rows come from is `listing`'s concern.
|
|
10
|
+
*/
|
|
11
|
+
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
12
|
+
import type { CheckpointListOptions, CheckpointTuple } from '@langchain/langgraph-checkpoint';
|
|
13
|
+
import type { CheckpointerContext } from '../internal/setup.js';
|
|
14
|
+
/**
|
|
15
|
+
* Yield checkpoint tuples for a thread, newest first: every namespace when the
|
|
16
|
+
* config names none (grouped by namespace, newest first within each), else the
|
|
17
|
+
* one namespace given. Without a `thread_id` every thread in the table is
|
|
18
|
+
* listed: through a table scan, as the reference savers do, which is unordered
|
|
19
|
+
* across threads, or through the recency index when `indexName` is set. Either
|
|
20
|
+
* read is cross-tenant by construction. Honors `options.before` (only
|
|
21
|
+
* checkpoints older than the given id), `options.filter` (metadata equality),
|
|
22
|
+
* and `options.limit` (max tuples yielded; the read stops right after the
|
|
23
|
+
* yield that reaches it).
|
|
24
|
+
*
|
|
25
|
+
* Accepts: `config` — `thread_id` scopes the read to one thread and its absence
|
|
26
|
+
* lists every thread in the table, through a scan as the reference savers do or
|
|
27
|
+
* through the recency index when `indexName` is set; `checkpoint_ns` scopes to
|
|
28
|
+
* one namespace and its absence spans every namespace of the thread.
|
|
29
|
+
* `options.before` — only checkpoints older than that id. `options.filter` —
|
|
30
|
+
* metadata equality. `options.limit` — at most this many tuples, up to the
|
|
31
|
+
* package's page ceiling; `0` yields nothing, which is what the reference
|
|
32
|
+
* returns, and a negative value is refused.
|
|
33
|
+
*
|
|
34
|
+
* Returns: an async generator over the tuples. With a `thread_id`, newest
|
|
35
|
+
* first within each namespace; without one, newest first across threads
|
|
36
|
+
* through the recency index, and on the scan path in the table's own order —
|
|
37
|
+
* oldest first within a thread, as DynamoDB stores an item collection, and
|
|
38
|
+
* threads in no particular order. The read stops right after the yield that
|
|
39
|
+
* reaches `limit`, and abandoning the generator stops it too.
|
|
40
|
+
*
|
|
41
|
+
* Throws: `VALIDATION`, from the first `.next()` and before any read, for
|
|
42
|
+
* a config of the wrong shape (`config`, `configurable`, `signal`), a
|
|
43
|
+
* malformed identifier, or options that fail the checks
|
|
44
|
+
* {@link parseListScope} makes;
|
|
45
|
+
* `FORMAT_UNSUPPORTED` for a row of ours written by a newer version; whatever
|
|
46
|
+
* the reads and decodes throw.
|
|
47
|
+
*
|
|
48
|
+
* Guarantees: eventually consistent — a listing tolerates the replica lag
|
|
49
|
+
* `getTuple` does not. The read is deliberately unbounded: this generator
|
|
50
|
+
* streams and never accumulates, `limit` returns early, and a raw-row cap would
|
|
51
|
+
* turn a caller asking for a handful of rare matches over a large thread into a
|
|
52
|
+
* hard error instead of the true (possibly empty) answer. Past the warning
|
|
53
|
+
* threshold an operator is told to narrow the filter or pass a limit.
|
|
54
|
+
*/
|
|
55
|
+
export declare function listCheckpoints(context: CheckpointerContext, config: RunnableConfig, options?: CheckpointListOptions): AsyncGenerator<CheckpointTuple>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { nowSeconds } from '../../shared/clock.js';
|
|
2
|
+
import { LIST_SCAN_WARN_THRESHOLD } from '../../shared/dynamodb/paginate.js';
|
|
3
|
+
import { isExpiredRow } from '../../shared/dynamodb/table-schema.js';
|
|
4
|
+
import { metaRows, parseListedRow, passesKeyFilters, passesMetadataFilter, } from '../internal/listing.js';
|
|
5
|
+
import { parseListScope, } from '../internal/parse.js';
|
|
6
|
+
import { assembleTuple, fetchTargetMeta } from '../internal/read.js';
|
|
7
|
+
async function tupleFor(context, meta, scope) {
|
|
8
|
+
if (!passesKeyFilters(meta, scope))
|
|
9
|
+
return undefined;
|
|
10
|
+
const verdict = await passesMetadataFilter(context, meta, scope);
|
|
11
|
+
if (!verdict.pass)
|
|
12
|
+
return undefined;
|
|
13
|
+
return assembleTuple(context, { threadId: meta.threadId, checkpointNs: meta.checkpointNs }, meta, {
|
|
14
|
+
signal: scope.signal,
|
|
15
|
+
consistent: false,
|
|
16
|
+
metadata: verdict.metadata,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async function* listOne(context, scope) {
|
|
20
|
+
const meta = await fetchTargetMeta(context, {
|
|
21
|
+
threadId: scope.threadId,
|
|
22
|
+
checkpointNs: scope.checkpointNs,
|
|
23
|
+
checkpointId: scope.checkpointId,
|
|
24
|
+
}, scope.signal, 'list');
|
|
25
|
+
if (!meta)
|
|
26
|
+
return;
|
|
27
|
+
const tuple = await tupleFor(context, meta, scope);
|
|
28
|
+
if (tuple)
|
|
29
|
+
yield tuple;
|
|
30
|
+
}
|
|
31
|
+
function asksForNothing(scope) {
|
|
32
|
+
return scope.limit === 0;
|
|
33
|
+
}
|
|
34
|
+
function addressesOneRow(scope) {
|
|
35
|
+
return (scope.threadId !== undefined &&
|
|
36
|
+
scope.checkpointId !== undefined &&
|
|
37
|
+
scope.checkpointNs !== undefined);
|
|
38
|
+
}
|
|
39
|
+
export async function* listCheckpoints(context, config, options) {
|
|
40
|
+
const scope = parseListScope(config, options);
|
|
41
|
+
if (asksForNothing(scope))
|
|
42
|
+
return;
|
|
43
|
+
if (addressesOneRow(scope)) {
|
|
44
|
+
yield* listOne(context, scope);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const now = nowSeconds();
|
|
48
|
+
let yielded = 0;
|
|
49
|
+
let scanned = 0;
|
|
50
|
+
for await (const raw of metaRows(context, scope, now)) {
|
|
51
|
+
scanned += 1;
|
|
52
|
+
if (scanned === LIST_SCAN_WARN_THRESHOLD) {
|
|
53
|
+
context.logger.warn('list: scanned a large number of rows without the caller stopping; this read is ' +
|
|
54
|
+
'deliberately unbounded, so narrow the filter or pass options.limit', { threadId: scope.threadId, checkpointNs: scope.checkpointNs, scanned });
|
|
55
|
+
}
|
|
56
|
+
const meta = parseListedRow(context, raw);
|
|
57
|
+
if (!meta || isExpiredRow(meta, now))
|
|
58
|
+
continue;
|
|
59
|
+
const tuple = await tupleFor(context, meta, scope);
|
|
60
|
+
if (!tuple)
|
|
61
|
+
continue;
|
|
62
|
+
yield tuple;
|
|
63
|
+
yielded += 1;
|
|
64
|
+
if (scope.limit !== undefined && yielded >= scope.limit)
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
}
|
package/dist/{checkpointer/actions/put-writes.js → esm/checkpointer/actions/put-writes.d.ts}
RENAMED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Hides how one `putWrites` call's rows are known to be one call's.
|
|
4
3
|
*
|
|
@@ -9,34 +8,19 @@
|
|
|
9
8
|
* pick the earliest call that wrote a channel. A caller passes writes and a
|
|
10
9
|
* task id and never sees the group.
|
|
11
10
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const ttl_1 = require("../../shared/validation/ttl");
|
|
16
|
-
const parse_1 = require("../internal/parse");
|
|
17
|
-
const pending_writes_1 = require("../internal/pending-writes");
|
|
18
|
-
const rows_1 = require("../internal/rows");
|
|
19
|
-
/**
|
|
20
|
-
* Stamps each `putWrites` call, identifying its rows as one group.
|
|
21
|
-
*
|
|
22
|
-
* It is what a guard rejection is compared against to tell "another call holds
|
|
23
|
-
* this row" from "my own retry does", it is the object id every offloaded write
|
|
24
|
-
* of the call is uploaded under, and — because ULIDs are lexicographically
|
|
25
|
-
* time-ordered, and this factory is strictly monotonic even within a single
|
|
26
|
-
* millisecond — it lets the read side identify the *earliest* call that wrote a
|
|
27
|
-
* given channel (see `dropSupersededWrites`). A random UUID would identify a
|
|
28
|
-
* call just as well but carries no ordering, which would leave that choice
|
|
29
|
-
* arbitrary.
|
|
30
|
-
*/
|
|
31
|
-
const nextWriteGroup = (0, ulid_1.createUlidFactory)();
|
|
11
|
+
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
12
|
+
import type { PendingWrite } from '@langchain/langgraph-checkpoint';
|
|
13
|
+
import type { CheckpointerContext } from '../internal/setup.js';
|
|
32
14
|
/**
|
|
33
15
|
* Persist a task's intermediate writes for a checkpoint, one row per write.
|
|
34
16
|
*
|
|
35
17
|
* Accepts: `config` — must name a `checkpoint_id`, since writes always attach
|
|
36
18
|
* to a checkpoint. `writes` — one task's, in order; their channels are
|
|
37
19
|
* validated before anything is encoded or uploaded. `taskId` — validated as the
|
|
38
|
-
* sort-key segment it becomes. `
|
|
39
|
-
*
|
|
20
|
+
* sort-key segment it becomes. `taskPath` — the task's serialized path, which
|
|
21
|
+
* LangGraph 1.5 passes and earlier LangGraphs do not; stored beside every row
|
|
22
|
+
* of the call, to lead the order the writes are read back in. `config.signal`
|
|
23
|
+
* — cancels the writes' retries; checked before anything is encoded.
|
|
40
24
|
*
|
|
41
25
|
* Returns: nothing. Every write is attempted; a regular write that loses its
|
|
42
26
|
* first-write-wins race is a normal outcome, not a failure.
|
|
@@ -44,8 +28,8 @@ const nextWriteGroup = (0, ulid_1.createUlidFactory)();
|
|
|
44
28
|
* Throws: `VALIDATION` naming `config`, `configurable` or `signal` for a
|
|
45
29
|
* config of the wrong shape; `thread_id`, `checkpoint_ns`, `checkpoint_id` or
|
|
46
30
|
* `thread_ts` for a malformed identifier, and `checkpoint_id` when the config
|
|
47
|
-
* names none; `taskId`, `writes`, `channel`, `sortKey` — every one
|
|
48
|
-
* before anything is encoded or uploaded — `payload` or `s3Key`; the first
|
|
31
|
+
* names none; `taskId`, `taskPath`, `writes`, `channel`, `sortKey` — every one
|
|
32
|
+
* of them before anything is encoded or uploaded — `payload` or `s3Key`; the first
|
|
49
33
|
* genuine write failure, after every write has settled and the cleanup has
|
|
50
34
|
* run.
|
|
51
35
|
*
|
|
@@ -62,15 +46,4 @@ const nextWriteGroup = (0, ulid_1.createUlidFactory)();
|
|
|
62
46
|
* so no row another call writes names one of this call's uploads, and no
|
|
63
47
|
* release reads the row again first.
|
|
64
48
|
*/
|
|
65
|
-
|
|
66
|
-
const request = (0, parse_1.parsePutWritesRequest)(config, writes, taskId);
|
|
67
|
-
if (request.writes.length === 0)
|
|
68
|
-
return;
|
|
69
|
-
const ttlTimestamp = context.ttl ? (0, ttl_1.calculateTtlTimestamp)(context.ttl) : undefined;
|
|
70
|
-
const items = await (0, rows_1.buildWriteRows)(context, request, nextWriteGroup(), ttlTimestamp);
|
|
71
|
-
await (0, pending_writes_1.commitPendingWrites)(context, {
|
|
72
|
-
threadId: request.address.threadId,
|
|
73
|
-
items,
|
|
74
|
-
signal: request.signal,
|
|
75
|
-
});
|
|
76
|
-
}
|
|
49
|
+
export declare function putWrites(context: CheckpointerContext, config: RunnableConfig, writes: PendingWrite[], taskId: string, taskPath?: string): Promise<void>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createUlidFactory } from '../../shared/ulid.js';
|
|
2
|
+
import { calculateTtlTimestamp } from '../../shared/validation/ttl.js';
|
|
3
|
+
import { parsePutWritesRequest } from '../internal/parse.js';
|
|
4
|
+
import { commitPendingWrites } from '../internal/pending-writes.js';
|
|
5
|
+
import { buildWriteRows } from '../internal/rows.js';
|
|
6
|
+
const nextWriteGroup = createUlidFactory();
|
|
7
|
+
export async function putWrites(context, config, writes, taskId, taskPath) {
|
|
8
|
+
const request = parsePutWritesRequest(config, writes, taskId, taskPath);
|
|
9
|
+
if (request.writes.length === 0)
|
|
10
|
+
return;
|
|
11
|
+
const ttlTimestamp = context.ttl ? calculateTtlTimestamp(context.ttl) : undefined;
|
|
12
|
+
const items = await buildWriteRows(context, request, nextWriteGroup(), ttlTimestamp);
|
|
13
|
+
await commitPendingWrites(context, {
|
|
14
|
+
threadId: request.address.threadId,
|
|
15
|
+
items,
|
|
16
|
+
signal: request.signal,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hides what it takes for a checkpoint to land exactly once.
|
|
3
|
+
*
|
|
4
|
+
* The META and PAYLOAD rows go out as one transaction under a request token
|
|
5
|
+
* drawn once, and a failure with S3 offload configured is read back before
|
|
6
|
+
* any upload is released, so a lost acknowledgement reports success and only a
|
|
7
|
+
* confirmed non-commit cleans up (record 6). Every channel value is stored
|
|
8
|
+
* whatever `newVersions` says (record 10). A caller gets back the config that
|
|
9
|
+
* addresses the stored checkpoint and none of this.
|
|
10
|
+
*/
|
|
11
|
+
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
12
|
+
import type { Checkpoint, CheckpointMetadata } from '@langchain/langgraph-checkpoint';
|
|
13
|
+
import { type WriteVerdict } from '../../shared/dynamodb/idempotent-write.js';
|
|
14
|
+
import { type CheckpointMetaRow, type CheckpointPayloadRow } from '../internal/rows.js';
|
|
15
|
+
import type { CheckpointerContext } from '../internal/setup.js';
|
|
16
|
+
/**
|
|
17
|
+
* Persist a checkpoint and its metadata as a transactional pair of META and
|
|
18
|
+
* PAYLOAD rows, returning the config that addresses the stored checkpoint. The
|
|
19
|
+
* incoming `checkpoint_id` (if any) becomes the new checkpoint's parent.
|
|
20
|
+
*
|
|
21
|
+
* **Every channel value the checkpoint carries is stored.** The saver's
|
|
22
|
+
* `put` accepts a `newVersions` argument because `BaseCheckpointSaver.put`
|
|
23
|
+
* declares it (`@langchain/langgraph-checkpoint@1.1.5` `dist/base.d.ts:68`)
|
|
24
|
+
* and does not hand it on: narrowing the stored values to the ones it names, and
|
|
25
|
+
* carrying the rest forward from the parent, made a put whose `newVersions` is
|
|
26
|
+
* `{}` write no values at all. LangGraph passes `{}` when forking a checkpoint
|
|
27
|
+
* and when writing an empty-checkpoint update (`@langchain/langgraph@1.4.13`
|
|
28
|
+
* `dist/pregel/index.js:668` and `:613`), so that put silently dropped user
|
|
29
|
+
* state. The reference saver does not narrow either: `MemorySaver.put` takes
|
|
30
|
+
* three parameters and stores the whole checkpoint (`dist/memory.js:206`).
|
|
31
|
+
*
|
|
32
|
+
* Accepts: `config` — its `checkpoint_id`, when present, becomes the new
|
|
33
|
+
* checkpoint's parent. `checkpoint.id` — validated as the sort-key segment it
|
|
34
|
+
* becomes. `metadata` — stored beside it, on the light row a listing reads.
|
|
35
|
+
* `config.signal` — cancels the writes' retries; checked before anything is
|
|
36
|
+
* encoded.
|
|
37
|
+
*
|
|
38
|
+
* Returns: the config addressing the stored checkpoint, which is what the
|
|
39
|
+
* caller passes back to continue the thread.
|
|
40
|
+
*
|
|
41
|
+
* Throws: `VALIDATION` naming `config`, `configurable` or `signal` for a
|
|
42
|
+
* config of the wrong shape, `thread_id`, `checkpoint_ns`, `checkpoint_id` or
|
|
43
|
+
* `thread_ts` for a malformed identifier, `checkpoint` for a `null` or
|
|
44
|
+
* `undefined` checkpoint, `checkpoint_id` for a malformed `checkpoint.id`,
|
|
45
|
+
* `payload` for a payload too large to store inline without `s3`, or, once
|
|
46
|
+
* offloaded, larger than `s3.maxDownloadBytes`; `s3Key` for an offloaded
|
|
47
|
+
* object's key over S3's cap; `S3_OFFLOAD_FAILED`; whatever the transaction
|
|
48
|
+
* throws once the outcome is established.
|
|
49
|
+
*
|
|
50
|
+
* Guarantees: both rows land or neither does — they are one transaction, so a
|
|
51
|
+
* META row never names a payload that is not there. That transaction goes out
|
|
52
|
+
* under a client request token drawn once, with the request it travels on, so
|
|
53
|
+
* a retry that follows a lost acknowledgement is discarded by the service
|
|
54
|
+
* rather than applied a second time. Writing the same `checkpoint.id` again
|
|
55
|
+
* replaces both, which is what a retry and a repair tool both need; the objects
|
|
56
|
+
* the replaced rows named are not deleted by the put, and are left to the
|
|
57
|
+
* lifecycle rule. A payload the serde refuses is refused before any write and
|
|
58
|
+
* releases whatever the same call had already uploaded, so an encode that fails
|
|
59
|
+
* halfway leaves nothing behind either. On failure with S3 offload configured
|
|
60
|
+
* the row carrying an offloaded descriptor is read back before any upload is
|
|
61
|
+
* deleted (see {@link verifyCheckpointLanded}): a transaction that committed
|
|
62
|
+
* and lost its response is reported as success, a confirmed non-commit cleans
|
|
63
|
+
* up the objects this call uploaded, and an unverifiable outcome — a failed
|
|
64
|
+
* read, or a failure after which DynamoDB may still apply the write, because
|
|
65
|
+
* an attempt of its budget got no answer, was answered
|
|
66
|
+
* `TransactionInProgressException` or failed with a server error (5xx) —
|
|
67
|
+
* leaks them rather than risk stranding a live row, and a put
|
|
68
|
+
* whose signal fired before the transaction was sent sends nothing and
|
|
69
|
+
* releases its uploads. Each put uploads under an object id of its own, so no
|
|
70
|
+
* row another put commits names this call's uploads.
|
|
71
|
+
*/
|
|
72
|
+
export declare function putCheckpoint(context: CheckpointerContext, config: RunnableConfig, checkpoint: Checkpoint, metadata: CheckpointMetadata): Promise<RunnableConfig>;
|
|
73
|
+
/**
|
|
74
|
+
* Read one of the two rows back after the META+PAYLOAD transaction failed and
|
|
75
|
+
* report what that failure actually did — never assuming it did nothing.
|
|
76
|
+
*
|
|
77
|
+
* Accepts: `meta` and `payload` — the two rows the failed transaction carried.
|
|
78
|
+
* Whichever of them has something offloaded is the one read back; a fully
|
|
79
|
+
* inline write has no object at stake and spends no read.
|
|
80
|
+
*
|
|
81
|
+
* Returns: the verdict. See {@link WriteVerdict} for what each answer licenses
|
|
82
|
+
* the caller to do. `'landed'` when the row holds this attempt's key,
|
|
83
|
+
* `'not-landed'` when it holds another or none, `'unverified'` when the read
|
|
84
|
+
* failed.
|
|
85
|
+
*
|
|
86
|
+
* Throws: nothing — a failed read is the `'unverified'` answer.
|
|
87
|
+
*
|
|
88
|
+
* Guarantees: both descriptors' keys end in the object id this put drew, which
|
|
89
|
+
* no other put uses. The row holds this attempt's key only if this put's
|
|
90
|
+
* transaction committed, and the other row commits with it, so one read decides
|
|
91
|
+
* the landing. A row holding any other key was committed by another put, whose
|
|
92
|
+
* rows name only that put's objects, so a `'not-landed'` answer leaves both of
|
|
93
|
+
* this put's uploads named by no row.
|
|
94
|
+
*/
|
|
95
|
+
export declare function verifyCheckpointLanded(context: CheckpointerContext, meta: CheckpointMetaRow, payload: CheckpointPayloadRow): Promise<WriteVerdict>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { collectS3Keys } from '../../shared/codec/codec.js';
|
|
2
|
+
import { cleanUpS3Orphans } from '../../shared/codec/s3/offloader.js';
|
|
3
|
+
import { abortErrorFrom } from '../../shared/dynamodb/abort.js';
|
|
4
|
+
import { offloadedKey, settledVerdict, transactIdempotently, verifyRow, } from '../../shared/dynamodb/idempotent-write.js';
|
|
5
|
+
import { rowKeyOf } from '../../shared/dynamodb/table-schema.js';
|
|
6
|
+
import { calculateTtlTimestamp } from '../../shared/validation/ttl.js';
|
|
7
|
+
import { parsePutRequest } from '../internal/parse.js';
|
|
8
|
+
import { buildCheckpointRows, } from '../internal/rows.js';
|
|
9
|
+
export async function putCheckpoint(context, config, checkpoint, metadata) {
|
|
10
|
+
const request = parsePutRequest(config, checkpoint, metadata);
|
|
11
|
+
const { threadId, checkpointNs, checkpointId } = request.address;
|
|
12
|
+
const ttlTimestamp = context.ttl ? calculateTtlTimestamp(context.ttl) : undefined;
|
|
13
|
+
const { meta, payload } = await buildCheckpointRows(context, request, ttlTimestamp);
|
|
14
|
+
const stored = {
|
|
15
|
+
configurable: { thread_id: threadId, checkpoint_ns: checkpointNs, checkpoint_id: checkpointId },
|
|
16
|
+
};
|
|
17
|
+
if (request.signal?.aborted) {
|
|
18
|
+
await releaseOwnUploads(context, meta, payload);
|
|
19
|
+
throw abortErrorFrom(request.signal);
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
await transactIdempotently(context, [
|
|
23
|
+
{ Put: { TableName: context.tableName, Item: meta } },
|
|
24
|
+
{ Put: { TableName: context.tableName, Item: payload } },
|
|
25
|
+
], { signal: request.signal });
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (!context.offloader)
|
|
29
|
+
throw error;
|
|
30
|
+
const verdict = settledVerdict(await verifyCheckpointLanded(context, meta, payload), error);
|
|
31
|
+
if (verdict === 'landed') {
|
|
32
|
+
context.logger.debug('put: transaction committed although its response was lost', {
|
|
33
|
+
threadId,
|
|
34
|
+
checkpointId,
|
|
35
|
+
});
|
|
36
|
+
return stored;
|
|
37
|
+
}
|
|
38
|
+
if (verdict === 'not-landed')
|
|
39
|
+
await releaseOwnUploads(context, meta, payload);
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
return stored;
|
|
43
|
+
}
|
|
44
|
+
async function releaseOwnUploads(context, meta, payload) {
|
|
45
|
+
if (!context.offloader)
|
|
46
|
+
return;
|
|
47
|
+
await cleanUpS3Orphans(context.offloader, {
|
|
48
|
+
keys: collectS3Keys([meta.metadata, payload.checkpoint]),
|
|
49
|
+
operation: 'put',
|
|
50
|
+
logger: context.logger,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function chooseProbe(meta, payload) {
|
|
54
|
+
const metaKey = offloadedKey(meta.metadata);
|
|
55
|
+
if (metaKey !== undefined) {
|
|
56
|
+
return {
|
|
57
|
+
key: rowKeyOf(meta),
|
|
58
|
+
kind: 'descriptor',
|
|
59
|
+
attribute: 'metadata',
|
|
60
|
+
expected: metaKey,
|
|
61
|
+
descriptors: ['metadata'],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
key: rowKeyOf(payload),
|
|
66
|
+
kind: 'descriptor',
|
|
67
|
+
attribute: 'checkpoint',
|
|
68
|
+
expected: offloadedKey(payload.checkpoint),
|
|
69
|
+
descriptors: ['checkpoint'],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export async function verifyCheckpointLanded(context, meta, payload) {
|
|
73
|
+
const { verdict } = await verifyRow(context, chooseProbe(meta, payload));
|
|
74
|
+
return verdict;
|
|
75
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hides how a delta channel's history is rebuilt, and what a hole in it means.
|
|
3
|
+
*
|
|
4
|
+
* A delta channel stores a full value only every `snapshotFrequency` updates,
|
|
5
|
+
* so its value at a checkpoint is its last snapshot plus the writes since,
|
|
6
|
+
* collected by walking parent pointers. The walk, the order the writes are
|
|
7
|
+
* collected in, and what a pointer the walk cannot follow means — a hole to
|
|
8
|
+
* report, whether its row is still stored past its ttl or already swept, and
|
|
9
|
+
* never the history's true start, which is a checkpoint with no pointer at all
|
|
10
|
+
* — are decided here.
|
|
11
|
+
*/
|
|
12
|
+
import type { RunnableConfig } from '@langchain/core/runnables';
|
|
13
|
+
import type { CheckpointTuple, DeltaChannelHistory } from '@langchain/langgraph-checkpoint';
|
|
14
|
+
import { DynamoDBLangGraphError } from '../../shared/errors/base-error.js';
|
|
15
|
+
import type { CheckpointerContext } from './setup.js';
|
|
16
|
+
/**
|
|
17
|
+
* Walk a checkpoint's ancestors for the delta channels named, accumulating
|
|
18
|
+
* their writes oldest-first and the nearest stored value of each.
|
|
19
|
+
*
|
|
20
|
+
* Same contract and same result as the inherited implementation
|
|
21
|
+
* (`@langchain/langgraph-checkpoint@1.1.5` `dist/base.js:78`), with one
|
|
22
|
+
* difference that is the reason for overriding it: where the inherited walk
|
|
23
|
+
* meets an ancestor it cannot read it simply stops (`if (tup === void 0)
|
|
24
|
+
* break`), reports no seed, and the consumer rebuilds the channel from its
|
|
25
|
+
* initial value (`@langchain/langgraph@1.4.13` `dist/channels/delta.js:65`).
|
|
26
|
+
* That is silent state loss, and this package can produce it: a ttl is computed
|
|
27
|
+
* per put, so a long-running thread expires its own older checkpoints while the
|
|
28
|
+
* newer ones live on.
|
|
29
|
+
*
|
|
30
|
+
* Accepts: `channels` — the delta channels to rebuild; none returns nothing and
|
|
31
|
+
* reads nothing. `getTuple` — the saver's own, so the walk sees exactly what a
|
|
32
|
+
* reader would. `config` — the checkpoint to walk back from. `config.signal` —
|
|
33
|
+
* cancels the whole walk: it is re-attached to each ancestor cursor
|
|
34
|
+
* ({@link cursorFor}), because the pointer a tuple carries is a bare address.
|
|
35
|
+
*
|
|
36
|
+
* Returns: per channel, its on-path writes oldest-first and the nearest stored
|
|
37
|
+
* value found. A channel whose value was never stored gets none, which is the
|
|
38
|
+
* consumer's cue to start from its initial value — correctly, because there is
|
|
39
|
+
* nothing to lose.
|
|
40
|
+
*
|
|
41
|
+
* Throws: `ANCESTOR_EXPIRED` when a channel still needs an ancestor the walk
|
|
42
|
+
* cannot read — its row stored but past its ttl, or already removed by the
|
|
43
|
+
* sweep — or when the chain points back to a checkpoint already read
|
|
44
|
+
* ({@link ancestorExpired}). A checkpoint with no parent pointer ends the walk
|
|
45
|
+
* quietly — that is a thread's true start. `ABORTED` when the signal fires,
|
|
46
|
+
* at whichever hop it fires on, and in preference to a diagnosis of the stop:
|
|
47
|
+
* a walk cancelled just as it reached an expired ancestor reports the cancel,
|
|
48
|
+
* since the caller stopped waiting for the answer either way.
|
|
49
|
+
*
|
|
50
|
+
* Guarantees: the walk stops at the first ancestor that answers for every
|
|
51
|
+
* channel, so a deep thread costs reads only as far back as the nearest
|
|
52
|
+
* snapshot.
|
|
53
|
+
*/
|
|
54
|
+
export declare function deltaChannelHistory(context: CheckpointerContext, getTuple: (config: RunnableConfig) => Promise<CheckpointTuple | undefined>, config: RunnableConfig, channels: string[]): Promise<Record<string, DeltaChannelHistory>>;
|
|
55
|
+
/** Where an ancestor walk stopped, and what kind of hole in the thread it found there. */
|
|
56
|
+
export interface WalkStop {
|
|
57
|
+
threadId: string;
|
|
58
|
+
checkpointId: string;
|
|
59
|
+
/**
|
|
60
|
+
* `'expired'` — the row is still stored, past its `ttl`; `'gone'` — no row at
|
|
61
|
+
* all, the sweep having removed it (or something else having deleted it);
|
|
62
|
+
* `'revisited'` — the chain pointed back to a checkpoint already read.
|
|
63
|
+
*/
|
|
64
|
+
stop: 'expired' | 'gone' | 'revisited';
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Read the META row an ancestor walk could not follow, **ignoring expiry**, to
|
|
68
|
+
* tell "this checkpoint is still stored but has expired" apart from "it is
|
|
69
|
+
* gone" — the sweep has removed it, which every expired row becomes within
|
|
70
|
+
* days. Both are holes; the read decides only what the error says.
|
|
71
|
+
*
|
|
72
|
+
* Every other read in this package hides an expired row, which is the right
|
|
73
|
+
* rule for a reader asking for state: checkpoint META, store and history rows
|
|
74
|
+
* by their own ttl, and a checkpoint's PAYLOAD and pending-WRITE rows by their
|
|
75
|
+
* checkpoint's META row, which is the only one checked (a pre-v4 checkpoint's
|
|
76
|
+
* migration is the exception: it reads its parent's pending writes under the
|
|
77
|
+
* child's META row). Here the row is wanted expired or not.
|
|
78
|
+
*
|
|
79
|
+
* Accepts: `config` — the parent pointer a walk stopped at. `config.signal` —
|
|
80
|
+
* cancels the read, and is read before it is sent. The walk re-attaches the
|
|
81
|
+
* caller's signal to every cursor, so the probe takes its cancel from the same
|
|
82
|
+
* place every other reader in this package takes it, rather than from a
|
|
83
|
+
* parameter of its own.
|
|
84
|
+
*
|
|
85
|
+
* Returns: whether that checkpoint is still stored and expired, or gone, or
|
|
86
|
+
* `undefined` when the config names no thread or no checkpoint — such a pointer
|
|
87
|
+
* addresses nothing that could have expired, so the walk has simply run out of
|
|
88
|
+
* chain.
|
|
89
|
+
*
|
|
90
|
+
* Throws: whatever the read throws after retries; `ABORTED` when the signal
|
|
91
|
+
* has already fired, which is answered in preference to the expiry this read
|
|
92
|
+
* exists to diagnose — a caller who cancelled is owed its own stop, and is no
|
|
93
|
+
* longer waiting to be told why the walk ended.
|
|
94
|
+
*
|
|
95
|
+
* Guarantees: the read ignores the ttl, deliberately. Every other read in this
|
|
96
|
+
* package hides an expired row by the rule above — META, store and history rows
|
|
97
|
+
* by their own ttl, PAYLOAD and WRITE rows by their checkpoint's META row, with
|
|
98
|
+
* the pre-v4 migration the exception — which is right for a reader asking for
|
|
99
|
+
* state; here an expired row is the evidence the error names.
|
|
100
|
+
*/
|
|
101
|
+
export declare function probeAncestor(context: CheckpointerContext, config: RunnableConfig): Promise<WalkStop | undefined>;
|
|
102
|
+
/**
|
|
103
|
+
* The error a read raises when a delta channel's history has a hole in it.
|
|
104
|
+
*
|
|
105
|
+
* Accepts: `stop` — the ancestor the walk could not follow, and why. `channels`
|
|
106
|
+
* — the delta channels that still needed it, named in the message so the
|
|
107
|
+
* operator knows what was lost.
|
|
108
|
+
*
|
|
109
|
+
* Returns: the error, coded `ANCESTOR_EXPIRED` and carrying the thread and
|
|
110
|
+
* checkpoint. The message bounds all three: after the first hop the walk's
|
|
111
|
+
* cursor is a row's own `parentConfig`, so the identifiers it names come off a
|
|
112
|
+
* row, and `channels` is checked for being an array of strings and for nothing
|
|
113
|
+
* else — neither how many nor how long. `context` carries both identifiers
|
|
114
|
+
* whole, which is what a caller branches on.
|
|
115
|
+
*
|
|
116
|
+
* Throws: nothing — it builds the error, the caller throws it.
|
|
117
|
+
*
|
|
118
|
+
* Guarantees: returning the partial history instead would hand the caller a
|
|
119
|
+
* channel rebuilt from its initial value plus whatever writes survived — a
|
|
120
|
+
* shorter message list, say, with nothing to say that anything is missing. The
|
|
121
|
+
* reference contract has no way to express "incomplete", so refusing the read
|
|
122
|
+
* is the only honest answer.
|
|
123
|
+
*/
|
|
124
|
+
export declare function ancestorExpired(stop: WalkStop, channels: string[]): DynamoDBLangGraphError;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { nowSeconds } from '../../shared/clock.js';
|
|
2
|
+
import { withDynamoDBRetry, retryFor } from '../../shared/dynamodb/retry.js';
|
|
3
|
+
import { isExpiredRow } from '../../shared/dynamodb/table-schema.js';
|
|
4
|
+
import { DynamoDBLangGraphError } from '../../shared/errors/base-error.js';
|
|
5
|
+
import { ErrorCode } from '../../shared/errors/error-code.js';
|
|
6
|
+
import { truncateForLog, truncateLabelsForLog } from '../../shared/logging/truncate.js';
|
|
7
|
+
import { metaRowKey } from './rows.js';
|
|
8
|
+
function startWalk(channels) {
|
|
9
|
+
const writes = {};
|
|
10
|
+
for (const channel of channels)
|
|
11
|
+
writes[channel] = [];
|
|
12
|
+
return { remaining: new Set(channels), writes, seeds: {}, visited: new Set() };
|
|
13
|
+
}
|
|
14
|
+
function collectWrites(tuple, walk) {
|
|
15
|
+
const perChannel = {};
|
|
16
|
+
for (const write of tuple.pendingWrites ?? []) {
|
|
17
|
+
const channel = write[1];
|
|
18
|
+
if (walk.remaining.has(channel))
|
|
19
|
+
(perChannel[channel] ??= []).push(write);
|
|
20
|
+
}
|
|
21
|
+
for (const channel of Object.keys(perChannel)) {
|
|
22
|
+
const block = perChannel[channel];
|
|
23
|
+
for (let i = block.length - 1; i >= 0; i -= 1)
|
|
24
|
+
walk.writes[channel].push(block[i]);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function takeSeeds(tuple, walk) {
|
|
28
|
+
for (const channel of [...walk.remaining]) {
|
|
29
|
+
if (Object.prototype.hasOwnProperty.call(tuple.checkpoint.channel_values, channel)) {
|
|
30
|
+
walk.seeds[channel] = tuple.checkpoint.channel_values[channel];
|
|
31
|
+
walk.remaining.delete(channel);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function cursorFor(parent, signal) {
|
|
36
|
+
if (parent === undefined || signal === undefined)
|
|
37
|
+
return parent;
|
|
38
|
+
return { ...parent, signal };
|
|
39
|
+
}
|
|
40
|
+
async function walkAncestors(context, getTuple, walk, from) {
|
|
41
|
+
let cursor = cursorFor(from.start, from.signal);
|
|
42
|
+
while (cursor !== undefined && walk.remaining.size > 0) {
|
|
43
|
+
const revisit = revisitOf(cursor, walk);
|
|
44
|
+
if (revisit !== undefined)
|
|
45
|
+
throw ancestorExpired(revisit, [...walk.remaining]);
|
|
46
|
+
const tuple = await getTuple(cursor);
|
|
47
|
+
if (tuple === undefined) {
|
|
48
|
+
const stop = await probeAncestor(context, cursor);
|
|
49
|
+
if (stop === undefined)
|
|
50
|
+
return;
|
|
51
|
+
throw ancestorExpired(stop, [...walk.remaining]);
|
|
52
|
+
}
|
|
53
|
+
collectWrites(tuple, walk);
|
|
54
|
+
takeSeeds(tuple, walk);
|
|
55
|
+
cursor = cursorFor(tuple.parentConfig, from.signal);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function revisitOf(cursor, walk) {
|
|
59
|
+
const ids = cursor.configurable;
|
|
60
|
+
const threadId = ids?.thread_id;
|
|
61
|
+
const checkpointId = ids?.checkpoint_id;
|
|
62
|
+
if (typeof threadId !== 'string' || typeof checkpointId !== 'string')
|
|
63
|
+
return undefined;
|
|
64
|
+
const key = `${ids?.checkpoint_ns ?? ''}#${checkpointId}`;
|
|
65
|
+
if (walk.visited.has(key))
|
|
66
|
+
return { threadId, checkpointId, stop: 'revisited' };
|
|
67
|
+
walk.visited.add(key);
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
function historyOf(walk, channel) {
|
|
71
|
+
const writes = walk.writes[channel].slice().reverse();
|
|
72
|
+
return Object.prototype.hasOwnProperty.call(walk.seeds, channel)
|
|
73
|
+
? { writes, seed: walk.seeds[channel] }
|
|
74
|
+
: { writes };
|
|
75
|
+
}
|
|
76
|
+
export async function deltaChannelHistory(context, getTuple, config, channels) {
|
|
77
|
+
if (channels.length === 0)
|
|
78
|
+
return {};
|
|
79
|
+
const walk = startWalk(channels);
|
|
80
|
+
const target = await getTuple(config);
|
|
81
|
+
await walkAncestors(context, getTuple, walk, {
|
|
82
|
+
start: target?.parentConfig,
|
|
83
|
+
signal: config.signal,
|
|
84
|
+
});
|
|
85
|
+
const result = {};
|
|
86
|
+
for (const channel of channels)
|
|
87
|
+
result[channel] = historyOf(walk, channel);
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
export async function probeAncestor(context, config) {
|
|
91
|
+
const ids = config.configurable;
|
|
92
|
+
const threadId = ids?.thread_id;
|
|
93
|
+
const checkpointId = ids?.checkpoint_id;
|
|
94
|
+
if (typeof threadId !== 'string' || typeof checkpointId !== 'string')
|
|
95
|
+
return undefined;
|
|
96
|
+
const checkpointNs = ids?.checkpoint_ns ?? '';
|
|
97
|
+
const result = await withDynamoDBRetry((request) => context.client.get({
|
|
98
|
+
TableName: context.tableName,
|
|
99
|
+
Key: metaRowKey({ threadId, checkpointNs, checkpointId }),
|
|
100
|
+
ConsistentRead: true,
|
|
101
|
+
}, request), retryFor(context, config.signal));
|
|
102
|
+
const row = result.Item;
|
|
103
|
+
return {
|
|
104
|
+
threadId,
|
|
105
|
+
checkpointId,
|
|
106
|
+
stop: row !== undefined && isExpiredRow(row, nowSeconds()) ? 'expired' : 'gone',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function ancestorExpired(stop, channels) {
|
|
110
|
+
const named = truncateLabelsForLog(channels)
|
|
111
|
+
.map((channel) => `"${channel}"`)
|
|
112
|
+
.join(', ');
|
|
113
|
+
const what = stop.stop === 'expired'
|
|
114
|
+
? 'has expired'
|
|
115
|
+
: stop.stop === 'gone'
|
|
116
|
+
? 'is gone (expired and removed by DynamoDB, or deleted)'
|
|
117
|
+
: 'is named as its own ancestor, so the chain never reaches a stored value';
|
|
118
|
+
return new DynamoDBLangGraphError(`checkpoint "${truncateForLog(stop.checkpointId)}" of thread ` +
|
|
119
|
+
`"${truncateForLog(stop.threadId)}" ${what}, but later ` +
|
|
120
|
+
`checkpoints still need it to reconstruct ${named}. ` +
|
|
121
|
+
'A delta channel writes a full snapshot only every `snapshotFrequency` updates and leaves ' +
|
|
122
|
+
'itself out of the checkpoints in between, so its value is rebuilt from an earlier ' +
|
|
123
|
+
'ancestor — which a per-checkpoint ttl expires while its descendants live on. Lower ' +
|
|
124
|
+
'`snapshotFrequency` (1 makes every checkpoint self-contained), or do not configure a ttl ' +
|
|
125
|
+
'on threads that use delta channels.', ErrorCode.ANCESTOR_EXPIRED, { threadId: stop.threadId, checkpointId: stop.checkpointId });
|
|
126
|
+
}
|