@abloatai/ablo 0.25.0 → 0.27.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/AGENTS.md +5 -3
- package/CHANGELOG.md +34 -0
- package/README.md +104 -88
- package/dist/BaseSyncedStore.d.ts +140 -266
- package/dist/BaseSyncedStore.js +338 -739
- package/dist/Database.d.ts +62 -77
- package/dist/Database.js +106 -127
- package/dist/{ObjectPool.d.ts → InstanceCache.d.ts} +10 -13
- package/dist/{ObjectPool.js → InstanceCache.js} +91 -83
- package/dist/LazyReferenceCollection.d.ts +11 -15
- package/dist/LazyReferenceCollection.js +16 -15
- package/dist/Model.d.ts +37 -52
- package/dist/Model.js +52 -69
- package/dist/ModelRegistry.d.ts +46 -25
- package/dist/ModelRegistry.js +32 -30
- package/dist/NetworkMonitor.d.ts +5 -6
- package/dist/NetworkMonitor.js +6 -7
- package/dist/SyncClient.d.ts +119 -109
- package/dist/SyncClient.js +303 -224
- package/dist/SyncEngineContext.d.ts +1 -3
- package/dist/SyncEngineContext.js +1 -2
- package/dist/adapters/alwaysOnline.d.ts +6 -8
- package/dist/adapters/alwaysOnline.js +6 -8
- package/dist/adapters/inMemoryStorage.d.ts +9 -9
- package/dist/adapters/inMemoryStorage.js +9 -9
- package/dist/agent/Agent.d.ts +39 -31
- package/dist/agent/Agent.js +35 -23
- package/dist/agent/index.d.ts +4 -4
- package/dist/agent/index.js +5 -5
- package/dist/agent/session.d.ts +47 -44
- package/dist/agent/session.js +37 -48
- package/dist/agent/types.d.ts +26 -31
- package/dist/agent/types.js +6 -7
- package/dist/ai-sdk/coordinatedTool.d.ts +108 -0
- package/dist/ai-sdk/{coordinated-tool.js → coordinatedTool.js} +44 -38
- package/dist/ai-sdk/coordinationContext.d.ts +46 -0
- package/dist/ai-sdk/{coordination-context.js → coordinationContext.js} +30 -31
- package/dist/ai-sdk/index.d.ts +25 -22
- package/dist/ai-sdk/index.js +25 -22
- package/dist/ai-sdk/wrap.d.ts +7 -8
- package/dist/ai-sdk/wrap.js +2 -2
- package/dist/auth/credentialPolicy.d.ts +74 -71
- package/dist/auth/credentialPolicy.js +51 -56
- package/dist/auth/credentialSource.d.ts +7 -18
- package/dist/auth/credentialSource.js +10 -18
- package/dist/auth/index.d.ts +59 -58
- package/dist/auth/index.js +34 -40
- package/dist/auth/schemas.d.ts +5 -4
- package/dist/auth/schemas.js +5 -4
- package/dist/batching/index.d.ts +19 -21
- package/dist/batching/index.js +14 -17
- package/dist/cli.cjs +483 -369
- package/dist/client/Ablo.d.ts +107 -836
- package/dist/client/Ablo.js +174 -833
- package/dist/client/ApiClient.d.ts +44 -20
- package/dist/client/ApiClient.js +193 -44
- package/dist/client/auth.d.ts +51 -60
- package/dist/client/auth.js +137 -110
- package/dist/client/claimHeartbeatLoop.d.ts +50 -0
- package/dist/client/claimHeartbeatLoop.js +88 -0
- package/dist/client/consoleLogger.d.ts +35 -0
- package/dist/client/consoleLogger.js +44 -0
- package/dist/client/createInternalComponents.d.ts +14 -17
- package/dist/client/createInternalComponents.js +26 -31
- package/dist/client/createModelProxy.d.ts +130 -120
- package/dist/client/createModelProxy.js +158 -124
- package/dist/client/credentialEndpoint.d.ts +61 -0
- package/dist/client/credentialEndpoint.js +86 -0
- package/dist/client/functionalUpdate.d.ts +29 -27
- package/dist/client/functionalUpdate.js +21 -21
- package/dist/client/hostedEndpoints.d.ts +21 -0
- package/dist/client/hostedEndpoints.js +21 -0
- package/dist/client/httpClient.d.ts +58 -54
- package/dist/client/httpClient.js +29 -31
- package/dist/client/identity.d.ts +15 -20
- package/dist/client/identity.js +49 -59
- package/dist/client/modelRegistration.d.ts +10 -0
- package/dist/client/modelRegistration.js +301 -0
- package/dist/client/options.d.ts +373 -0
- package/dist/client/options.js +6 -0
- package/dist/client/registerDataSource.d.ts +9 -9
- package/dist/client/registerDataSource.js +15 -16
- package/dist/client/resourceTypes.d.ts +333 -0
- package/dist/client/resourceTypes.js +7 -0
- package/dist/client/schemaConfig.d.ts +44 -0
- package/dist/client/schemaConfig.js +176 -0
- package/dist/client/sessionMint.d.ts +17 -13
- package/dist/client/sessionMint.js +26 -31
- package/dist/client/validateAbloOptions.d.ts +12 -14
- package/dist/client/validateAbloOptions.js +9 -10
- package/dist/client/writeOptionsSchema.d.ts +18 -16
- package/dist/client/writeOptionsSchema.js +23 -20
- package/dist/client/wsMutationExecutor.d.ts +28 -0
- package/dist/client/wsMutationExecutor.js +71 -0
- package/dist/context.d.ts +6 -4
- package/dist/context.js +6 -7
- package/dist/coordination/index.d.ts +13 -4
- package/dist/coordination/index.js +29 -4
- package/dist/coordination/schema.d.ts +176 -128
- package/dist/coordination/schema.js +197 -133
- package/dist/coordination/trace.d.ts +9 -11
- package/dist/coordination/trace.js +13 -15
- package/dist/core/DatabaseManager.d.ts +5 -8
- package/dist/core/DatabaseManager.js +38 -40
- package/dist/core/QueryProcessor.d.ts +7 -9
- package/dist/core/QueryProcessor.js +27 -34
- package/dist/core/QueryView.d.ts +17 -5
- package/dist/core/QueryView.js +6 -7
- package/dist/core/StoreManager.d.ts +14 -16
- package/dist/core/StoreManager.js +26 -25
- package/dist/core/ViewRegistry.d.ts +5 -5
- package/dist/core/ViewRegistry.js +4 -4
- package/dist/core/index.d.ts +18 -13
- package/dist/core/index.js +32 -26
- package/dist/core/openIDBWithTimeout.d.ts +38 -36
- package/dist/core/openIDBWithTimeout.js +57 -54
- package/dist/core/queryUtils.d.ts +45 -0
- package/dist/core/queryUtils.js +69 -0
- package/dist/core/storeContract.d.ts +145 -0
- package/dist/core/storeContract.js +12 -0
- package/dist/environment.d.ts +28 -0
- package/dist/environment.js +21 -0
- package/dist/errorCodes.d.ts +118 -101
- package/dist/errorCodes.js +277 -260
- package/dist/errors.d.ts +170 -165
- package/dist/errors.js +161 -151
- package/dist/index.d.ts +30 -27
- package/dist/index.js +90 -82
- package/dist/interfaces/index.d.ts +108 -133
- package/dist/interfaces/index.js +5 -4
- package/dist/keys/index.d.ts +27 -29
- package/dist/keys/index.js +59 -49
- package/dist/mutators/RecordingTransaction.d.ts +16 -16
- package/dist/mutators/RecordingTransaction.js +31 -37
- package/dist/mutators/Transaction.d.ts +18 -26
- package/dist/mutators/Transaction.js +14 -20
- package/dist/mutators/UndoManager.d.ts +122 -131
- package/dist/mutators/UndoManager.js +149 -155
- package/dist/mutators/defineMutators.d.ts +24 -37
- package/dist/mutators/defineMutators.js +14 -20
- package/dist/mutators/inverseOp.d.ts +12 -15
- package/dist/mutators/inverseOp.js +12 -15
- package/dist/mutators/mutateActions.d.ts +10 -9
- package/dist/mutators/mutateActions.js +1 -1
- package/dist/mutators/readerActions.d.ts +9 -8
- package/dist/mutators/readerActions.js +2 -2
- package/dist/mutators/undoApply.d.ts +31 -27
- package/dist/mutators/undoApply.js +26 -24
- package/dist/policy/index.d.ts +5 -3
- package/dist/policy/index.js +5 -3
- package/dist/policy/types.d.ts +105 -101
- package/dist/policy/types.js +67 -66
- package/dist/query/client.d.ts +32 -16
- package/dist/query/client.js +103 -72
- package/dist/query/types.d.ts +37 -60
- package/dist/query/types.js +13 -33
- package/dist/react/AbloProvider.d.ts +7 -11
- package/dist/react/AbloProvider.js +24 -17
- package/dist/react/context.d.ts +27 -146
- package/dist/react/context.js +9 -10
- package/dist/react/index.d.ts +41 -42
- package/dist/react/index.js +37 -38
- package/dist/react/internalContext.d.ts +17 -19
- package/dist/react/useAblo.d.ts +23 -22
- package/dist/react/useAblo.js +17 -15
- package/dist/react/useCurrentUserId.d.ts +8 -7
- package/dist/react/useCurrentUserId.js +8 -7
- package/dist/react/useErrorListener.d.ts +7 -7
- package/dist/react/useErrorListener.js +11 -12
- package/dist/react/useMutationFailureListener.d.ts +8 -8
- package/dist/react/useMutationFailureListener.js +9 -9
- package/dist/react/useMutators.d.ts +11 -11
- package/dist/react/useMutators.js +10 -4
- package/dist/react/useReactive.js +2 -3
- package/dist/react/useSyncStatus.d.ts +4 -6
- package/dist/react/useUndoScope.d.ts +7 -9
- package/dist/react/useUndoScope.js +3 -3
- package/dist/schema/coordination.d.ts +21 -25
- package/dist/schema/coordination.js +21 -25
- package/dist/schema/ddl.d.ts +43 -39
- package/dist/schema/ddl.js +75 -68
- package/dist/schema/ddlLock.d.ts +35 -0
- package/dist/schema/ddlLock.js +46 -0
- package/dist/schema/diff.d.ts +99 -61
- package/dist/schema/diff.js +43 -34
- package/dist/schema/field.d.ts +37 -42
- package/dist/schema/field.js +36 -49
- package/dist/schema/generate.d.ts +12 -12
- package/dist/schema/generate.js +12 -12
- package/dist/schema/index.d.ts +5 -4
- package/dist/schema/index.js +29 -21
- package/dist/schema/model.d.ts +121 -146
- package/dist/schema/model.js +24 -35
- package/dist/schema/openapi.d.ts +10 -9
- package/dist/schema/openapi.js +7 -1
- package/dist/schema/queries.d.ts +30 -32
- package/dist/schema/queries.js +24 -25
- package/dist/schema/relation.d.ts +89 -99
- package/dist/schema/relation.js +13 -13
- package/dist/schema/residency.d.ts +38 -0
- package/dist/schema/residency.js +30 -0
- package/dist/schema/roles.d.ts +45 -27
- package/dist/schema/roles.js +52 -21
- package/dist/schema/schema.d.ts +36 -45
- package/dist/schema/schema.js +42 -39
- package/dist/schema/select.d.ts +13 -13
- package/dist/schema/select.js +13 -13
- package/dist/schema/serialize.d.ts +36 -39
- package/dist/schema/serialize.js +27 -31
- package/dist/schema/sugar.d.ts +17 -32
- package/dist/schema/sugar.js +14 -29
- package/dist/schema/{sync-delta-row.d.ts → syncDeltaRow.d.ts} +27 -50
- package/dist/schema/syncDeltaRow.js +89 -0
- package/dist/schema/tenancy.d.ts +44 -46
- package/dist/schema/tenancy.js +46 -48
- package/dist/server/adapter.d.ts +58 -58
- package/dist/server/adapter.js +13 -14
- package/dist/server/commit.d.ts +60 -64
- package/dist/server/index.d.ts +9 -10
- package/dist/server/index.js +1 -1
- package/dist/server/readConfig.d.ts +70 -0
- package/dist/server/readConfig.js +8 -0
- package/dist/server/storageMode.d.ts +23 -0
- package/dist/server/storageMode.js +17 -0
- package/dist/source/adapter.d.ts +31 -26
- package/dist/source/adapter.js +10 -10
- package/dist/source/adapters/drizzle.d.ts +28 -23
- package/dist/source/adapters/drizzle.js +34 -28
- package/dist/source/adapters/kysely.d.ts +27 -25
- package/dist/source/adapters/kysely.js +28 -26
- package/dist/source/adapters/memory.d.ts +8 -7
- package/dist/source/adapters/memory.js +10 -9
- package/dist/source/adapters/prisma.d.ts +13 -12
- package/dist/source/adapters/prisma.js +27 -29
- package/dist/source/conformance.d.ts +18 -11
- package/dist/source/conformance.js +27 -19
- package/dist/source/connector.d.ts +31 -32
- package/dist/source/connector.js +30 -28
- package/dist/source/connectorProtocol.d.ts +160 -0
- package/dist/source/connectorProtocol.js +162 -0
- package/dist/source/contract.d.ts +26 -27
- package/dist/source/contract.js +28 -29
- package/dist/source/factory.d.ts +94 -0
- package/dist/source/factory.js +268 -0
- package/dist/source/index.d.ts +10 -462
- package/dist/source/index.js +17 -421
- package/dist/source/migrations.d.ts +9 -9
- package/dist/source/migrations.js +9 -9
- package/dist/source/next.d.ts +10 -11
- package/dist/source/next.js +7 -8
- package/dist/source/pushQueue.d.ts +70 -48
- package/dist/source/pushQueue.js +36 -29
- package/dist/source/signing.d.ts +88 -0
- package/dist/source/signing.js +159 -0
- package/dist/source/types.d.ts +351 -0
- package/dist/source/types.js +43 -0
- package/dist/stores/ObjectStore.d.ts +11 -12
- package/dist/stores/ObjectStore.js +34 -35
- package/dist/stores/ObjectStoreContract.d.ts +12 -15
- package/dist/stores/SyncActionStore.d.ts +8 -12
- package/dist/stores/SyncActionStore.js +77 -46
- package/dist/surface.d.ts +28 -21
- package/dist/surface.js +28 -20
- package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +37 -45
- package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +101 -80
- package/dist/sync/ConnectionManager.d.ts +47 -50
- package/dist/sync/ConnectionManager.js +74 -70
- package/dist/sync/NetworkProbe.d.ts +27 -31
- package/dist/sync/NetworkProbe.js +67 -72
- package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +49 -36
- package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +79 -54
- package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +45 -59
- package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +44 -52
- package/dist/sync/SyncWebSocket.d.ts +175 -250
- package/dist/sync/SyncWebSocket.js +431 -769
- package/dist/sync/awaitClaimGrant.d.ts +18 -18
- package/dist/sync/awaitClaimGrant.js +38 -30
- package/dist/sync/bootstrapApply.d.ts +70 -0
- package/dist/sync/bootstrapApply.js +73 -0
- package/dist/sync/commitFrames.d.ts +44 -0
- package/dist/sync/commitFrames.js +94 -0
- package/dist/sync/createClaimStream.d.ts +23 -22
- package/dist/sync/createClaimStream.js +108 -25
- package/dist/sync/createPresenceStream.d.ts +19 -18
- package/dist/sync/createPresenceStream.js +25 -26
- package/dist/sync/createSnapshot.d.ts +13 -17
- package/dist/sync/createSnapshot.js +20 -26
- package/dist/sync/credentialLifecycle.d.ts +175 -0
- package/dist/sync/credentialLifecycle.js +322 -0
- package/dist/sync/deltaPipeline.d.ts +113 -0
- package/dist/sync/deltaPipeline.js +261 -0
- package/dist/sync/groupChange.d.ts +113 -0
- package/dist/sync/groupChange.js +242 -0
- package/dist/sync/heartbeat.d.ts +63 -0
- package/dist/sync/heartbeat.js +91 -0
- package/dist/sync/participants.d.ts +27 -27
- package/dist/sync/schemas.d.ts +3 -2
- package/dist/sync/schemas.js +14 -10
- package/dist/sync/syncCursor.d.ts +40 -0
- package/dist/sync/syncCursor.js +55 -0
- package/dist/sync/syncPlan.d.ts +54 -0
- package/dist/sync/syncPlan.js +50 -0
- package/dist/sync/syncPosition.d.ts +54 -49
- package/dist/sync/syncPosition.js +57 -52
- package/dist/sync/wsFrameHandlers.d.ts +116 -0
- package/dist/sync/wsFrameHandlers.js +374 -0
- package/dist/testing/fixtures/bootstrap.d.ts +21 -17
- package/dist/testing/fixtures/bootstrap.js +12 -6
- package/dist/testing/fixtures/deltas.d.ts +31 -34
- package/dist/testing/fixtures/deltas.js +30 -33
- package/dist/testing/fixtures/models.d.ts +11 -10
- package/dist/testing/fixtures/models.js +12 -10
- package/dist/testing/helpers/{react-wrapper.d.ts → reactWrapper.d.ts} +13 -10
- package/dist/testing/helpers/{react-wrapper.js → reactWrapper.js} +15 -12
- package/dist/testing/helpers/{sync-engine-harness.d.ts → syncEngineHarness.d.ts} +17 -18
- package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +14 -11
- package/dist/testing/helpers/wait.d.ts +13 -8
- package/dist/testing/helpers/wait.js +13 -8
- package/dist/testing/index.d.ts +4 -4
- package/dist/testing/index.js +3 -3
- package/dist/testing/mocks/MockMutationExecutor.d.ts +18 -17
- package/dist/testing/mocks/MockMutationExecutor.js +15 -14
- package/dist/testing/mocks/MockNetworkMonitor.d.ts +8 -8
- package/dist/testing/mocks/MockNetworkMonitor.js +8 -8
- package/dist/testing/mocks/MockSyncContext.d.ts +21 -34
- package/dist/testing/mocks/MockSyncContext.js +16 -45
- package/dist/testing/mocks/MockSyncStore.d.ts +14 -14
- package/dist/testing/mocks/MockSyncStore.js +11 -11
- package/dist/testing/mocks/MockWebSocket.d.ts +28 -24
- package/dist/testing/mocks/MockWebSocket.js +22 -21
- package/dist/transactions/TransactionQueue.d.ts +190 -221
- package/dist/transactions/TransactionQueue.js +424 -822
- package/dist/transactions/TransactionStore.d.ts +20 -0
- package/dist/transactions/TransactionStore.js +53 -0
- package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
- package/dist/transactions/UnconfirmedWrites.js +104 -0
- package/dist/transactions/coalesceRules.d.ts +58 -0
- package/dist/transactions/coalesceRules.js +140 -0
- package/dist/transactions/commitPayload.d.ts +130 -0
- package/dist/transactions/commitPayload.js +143 -0
- package/dist/transactions/deltaConfirmation.d.ts +58 -0
- package/dist/transactions/deltaConfirmation.js +215 -0
- package/dist/transactions/optimisticApply.d.ts +49 -0
- package/dist/transactions/optimisticApply.js +65 -0
- package/dist/transactions/replayValidation.d.ts +99 -0
- package/dist/transactions/replayValidation.js +111 -0
- package/dist/types/global.d.ts +46 -41
- package/dist/types/global.js +20 -19
- package/dist/types/index.d.ts +74 -80
- package/dist/types/index.js +22 -27
- package/dist/types/modelData.d.ts +10 -0
- package/dist/types/modelData.js +9 -0
- package/dist/types/participant.d.ts +20 -0
- package/dist/types/participant.js +10 -0
- package/dist/types/streams.d.ts +216 -209
- package/dist/types/streams.js +7 -7
- package/dist/utils/asyncIterator.d.ts +25 -32
- package/dist/utils/asyncIterator.js +25 -32
- package/dist/utils/duration.d.ts +12 -15
- package/dist/utils/duration.js +12 -15
- package/dist/utils/mobxSetup.d.ts +53 -0
- package/dist/utils/{mobx-setup.js → mobxSetup.js} +44 -100
- package/dist/webhooks/events.d.ts +21 -16
- package/dist/webhooks/events.js +10 -8
- package/dist/webhooks/index.d.ts +5 -7
- package/dist/webhooks/index.js +5 -7
- package/dist/{schema/sync-delta-wire.d.ts → wire/delta.d.ts} +58 -41
- package/dist/wire/delta.js +114 -0
- package/dist/wire/errorEnvelope.d.ts +35 -27
- package/dist/wire/errorEnvelope.js +38 -32
- package/dist/wire/frames.d.ts +150 -67
- package/dist/wire/frames.js +48 -1
- package/dist/wire/index.d.ts +18 -13
- package/dist/wire/index.js +36 -13
- package/dist/wire/listEnvelope.d.ts +16 -23
- package/dist/wire/listEnvelope.js +7 -6
- package/dist/wire/protocol.d.ts +38 -0
- package/dist/wire/protocol.js +38 -0
- package/dist/wire/protocolVersion.d.ts +60 -0
- package/dist/wire/protocolVersion.js +67 -0
- package/docs/api-keys.md +4 -3
- package/docs/coordination.md +59 -0
- package/docs/examples/existing-python-backend.md +3 -3
- package/docs/identity.md +4 -4
- package/docs/integration-guide.md +1 -1
- package/docs/react.md +1 -1
- package/docs/sessions.md +5 -7
- package/package.json +24 -21
- package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
- package/dist/ai-sdk/coordination-context.d.ts +0 -52
- package/dist/client/index.d.ts +0 -36
- package/dist/client/index.js +0 -33
- package/dist/config/index.d.ts +0 -10
- package/dist/config/index.js +0 -12
- package/dist/core/query-utils.d.ts +0 -34
- package/dist/core/query-utils.js +0 -59
- package/dist/interfaces/headless.d.ts +0 -95
- package/dist/interfaces/headless.js +0 -41
- package/dist/query/index.d.ts +0 -6
- package/dist/query/index.js +0 -5
- package/dist/realtime/index.d.ts +0 -10
- package/dist/realtime/index.js +0 -9
- package/dist/schema/plane.d.ts +0 -23
- package/dist/schema/plane.js +0 -19
- package/dist/schema/sync-delta-row.js +0 -103
- package/dist/schema/sync-delta-wire.js +0 -102
- package/dist/server/next.d.ts +0 -51
- package/dist/server/next.js +0 -47
- package/dist/server/read-config.d.ts +0 -67
- package/dist/server/read-config.js +0 -8
- package/dist/server/storage-mode.d.ts +0 -1
- package/dist/server/storage-mode.js +0 -18
- package/dist/source/connector-protocol.d.ts +0 -159
- package/dist/source/connector-protocol.js +0 -161
- package/dist/sync/OfflineFlush.d.ts +0 -9
- package/dist/sync/OfflineFlush.js +0 -22
- package/dist/sync/OfflineTransactionStore.d.ts +0 -37
- package/dist/sync/OfflineTransactionStore.js +0 -263
- package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
- package/dist/transactions/OptimisticEchoTracker.js +0 -104
- package/dist/transactions/index.d.ts +0 -16
- package/dist/transactions/index.js +0 -7
- package/dist/transactions/mutation-error-handler.d.ts +0 -5
- package/dist/transactions/mutation-error-handler.js +0 -39
- package/dist/utils/mobx-setup.d.ts +0 -42
package/dist/agent/session.js
CHANGED
|
@@ -1,37 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Caches and manages the lifecycle of long-lived agent connections on a server.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
4
|
+
* Server code that runs AI agents typically needs the same four things, and this
|
|
5
|
+
* module handles all of them:
|
|
6
|
+
* 1. Reuse one connected agent per (organization, user, surface, target)
|
|
7
|
+
* instead of connecting anew on every request.
|
|
8
|
+
* 2. Re-issue the agent's capability token before it expires.
|
|
9
|
+
* 3. Request exactly the sync groups the token allows, so the two lists
|
|
10
|
+
* overlap. If they don't, the agent subscribes to nothing and every
|
|
11
|
+
* broadcast is silently filtered out.
|
|
12
|
+
* 4. Connect, disconnect, and dispose cleanly.
|
|
11
13
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* exchange, OAuth, etc.). Consumer provides via the
|
|
18
|
-
* `issueToken` callback.
|
|
19
|
-
*
|
|
20
|
-
* The helper itself imports nothing app-specific. Open-source-clean.
|
|
14
|
+
* Everything except obtaining the token is the same for every caller and lives
|
|
15
|
+
* here. Obtaining the token depends on how you authenticate — cookie forwarding,
|
|
16
|
+
* API-key exchange, OAuth, and so on — so you supply that step through the
|
|
17
|
+
* {@link AgentSessionOptions.issueToken} callback. The module itself depends on
|
|
18
|
+
* nothing outside this package.
|
|
21
19
|
*/
|
|
22
20
|
import { Ablo } from '../client/Ablo.js';
|
|
23
21
|
import { AbloConnectionError } from '../errors.js';
|
|
24
22
|
import { getContext } from '../context.js';
|
|
25
23
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
24
|
+
* Creates a session that hands out connected agents on demand. Its `getAgent`
|
|
25
|
+
* method handles caching, token issuance, sync-group alignment, and connection
|
|
26
|
+
* lifecycle; call `disposeAll` from your process's shutdown hook to close every
|
|
27
|
+
* open connection.
|
|
29
28
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* independent agents.
|
|
29
|
+
* Treat the session as a long-lived singleton shared across requests. The cache
|
|
30
|
+
* key combines organization, user, surface, and target, so two concurrent
|
|
31
|
+
* requests for the same combination share one agent and one WebSocket, while
|
|
32
|
+
* requests for different combinations get independent agents.
|
|
35
33
|
*/
|
|
36
34
|
export function createAgentSession(options) {
|
|
37
35
|
const reissueBufferMs = options.reissueBufferMs ?? 30_000;
|
|
@@ -61,21 +59,14 @@ export function createAgentSession(options) {
|
|
|
61
59
|
}
|
|
62
60
|
}
|
|
63
61
|
const minted = await options.issueToken(identity);
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
// `
|
|
72
|
-
// silently dropped the unknown field (the cast below masked the
|
|
73
|
-
// type error) and `resolveBaseURL` fell through to the hosted
|
|
74
|
-
// default `wss://api.abloatai.com`. Staging surfaced the bug
|
|
75
|
-
// 2026-05-07 — DNS lookup hit the wrong
|
|
76
|
-
// host even though the caller threaded `syncServerUrl` through
|
|
77
|
-
// correctly. Forward as `baseURL` so the caller's URL is the only
|
|
78
|
-
// source of truth and the package default never silently applies.
|
|
62
|
+
// Request the same sync groups the token grants. The groups requested here
|
|
63
|
+
// and the groups the token allows must overlap; otherwise their intersection
|
|
64
|
+
// is empty and every broadcast is filtered out. The token's allowed list is
|
|
65
|
+
// exactly what to request, since the caller decided what went into it.
|
|
66
|
+
//
|
|
67
|
+
// Pass the URL as `baseURL`, the field the client reads. Any other field name
|
|
68
|
+
// is ignored, in which case the client would fall back to its default host,
|
|
69
|
+
// so `baseURL` keeps the caller's URL the single source of truth.
|
|
79
70
|
const wsUrl = toWsUrl(options.syncServerUrl);
|
|
80
71
|
const agentOptions = {
|
|
81
72
|
baseURL: wsUrl,
|
|
@@ -101,11 +92,9 @@ export function createAgentSession(options) {
|
|
|
101
92
|
await agent.dispose();
|
|
102
93
|
}
|
|
103
94
|
catch { /* ignore */ }
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
// companion's shape matches the cap-mint logger in `connectAgent.ts` so a
|
|
108
|
-
// single search picks both up.
|
|
95
|
+
// Log through the level-gated logger so it honors ABLO_LOG_LEVEL: an
|
|
96
|
+
// `error` headline naming the unreachable URL and code, plus a `debug`
|
|
97
|
+
// companion carrying the structured fields for deeper diagnosis.
|
|
109
98
|
const log = getContext().logger;
|
|
110
99
|
log.error(`Agent could not connect to the sync server at ${wsUrl}${code ? ` (${code})` : ''}.`);
|
|
111
100
|
log.debug('[Agent.session] ws bootstrap failed', {
|
|
@@ -135,9 +124,9 @@ export function createAgentSession(options) {
|
|
|
135
124
|
cacheByKey.clear();
|
|
136
125
|
}
|
|
137
126
|
/**
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
127
|
+
* Removes and disposes one cached agent. Call it when you know the agent's
|
|
128
|
+
* token is no longer valid — after a revocation or role change, for example —
|
|
129
|
+
* so the next `getAgent` call issues a fresh one.
|
|
141
130
|
*/
|
|
142
131
|
function evict(identity) {
|
|
143
132
|
const key = cacheKey(identity);
|
package/dist/agent/types.d.ts
CHANGED
|
@@ -1,37 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* `
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* SDK `experimental_context` bag).
|
|
2
|
+
* Types specific to running AI agents. The shared data vocabulary — `Peer`,
|
|
3
|
+
* {@link Activity}, `Claim`, `ActiveClaim`, `PresenceUpdatePayload`, and
|
|
4
|
+
* `PresenceKind` — lives in the streams module. This file adds only the two
|
|
5
|
+
* pieces the agent layer needs on top of it: {@link PresenceAnnouncer}, a
|
|
6
|
+
* transport-agnostic way to announce presence, and {@link AgentContext}, the bag
|
|
7
|
+
* of ambient state passed to AI SDK tools.
|
|
9
8
|
*/
|
|
10
9
|
import type { Activity } from '../types/streams.js';
|
|
11
10
|
/**
|
|
12
|
-
* A minimal interface for announcing presence
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* A minimal interface for announcing an agent's presence, independent of how it
|
|
12
|
+
* connects. Both the WebSocket-based agent client and the REST-based agent
|
|
13
|
+
* implement it, so higher-level code can depend on this interface without caring
|
|
14
|
+
* which transport is in use.
|
|
16
15
|
*/
|
|
17
16
|
export interface PresenceAnnouncer {
|
|
18
17
|
announce(status: 'online' | 'away' | 'offline', activity?: Activity): Promise<void>;
|
|
19
18
|
}
|
|
20
19
|
/**
|
|
21
|
-
*
|
|
20
|
+
* The ambient state passed to AI SDK tools through the AI SDK's
|
|
21
|
+
* `experimental_context`. Build one {@link AgentContext} per agent invocation and
|
|
22
|
+
* pass it as `experimental_context`; each tool's `execute` function then reads
|
|
23
|
+
* what it needs from `options.experimental_context` rather than closing over
|
|
24
|
+
* shared module state.
|
|
22
25
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* state.
|
|
28
|
-
*
|
|
29
|
-
* Benefits over closure-based tool wiring:
|
|
30
|
-
* - Tools are framework-agnostic module exports (portable across agents)
|
|
31
|
-
* - The context is typed in one place, not scattered across closures
|
|
32
|
-
* - New tools can access any field without changing tool signatures
|
|
33
|
-
*
|
|
34
|
-
* Ported from the vercel-labs/open-agents pattern.
|
|
26
|
+
* Passing context this way, rather than capturing it in each tool's closure,
|
|
27
|
+
* keeps tools as plain module exports that any agent can reuse, types the context
|
|
28
|
+
* in one place, and lets a new tool read any field without changing its
|
|
29
|
+
* signature.
|
|
35
30
|
*
|
|
36
31
|
* ```ts
|
|
37
32
|
* import { generateText, tool } from 'ai';
|
|
@@ -54,20 +49,20 @@ export interface PresenceAnnouncer {
|
|
|
54
49
|
* });
|
|
55
50
|
* ```
|
|
56
51
|
*
|
|
57
|
-
*
|
|
58
|
-
* intersecting with
|
|
52
|
+
* Extend {@link AgentContext} with your own fields through module augmentation or
|
|
53
|
+
* by intersecting it with your own context type.
|
|
59
54
|
*/
|
|
60
55
|
export interface AgentContext {
|
|
61
|
-
/**
|
|
56
|
+
/** Announces presence and checks whether an entity has changed since a given time. Required. */
|
|
62
57
|
perception: PresenceAnnouncer & {
|
|
63
58
|
checkFreshness?: (entityType: string, entityId: string, lastSeenAt: number) => Promise<unknown>;
|
|
64
59
|
};
|
|
65
|
-
/**
|
|
60
|
+
/** The organization every operation is scoped to. */
|
|
66
61
|
organizationId?: string;
|
|
67
|
-
/**
|
|
62
|
+
/** Identifier for the user or agent. Agents use the form `agent:<id>`. */
|
|
68
63
|
userId?: string;
|
|
69
|
-
/**
|
|
64
|
+
/** The sync groups this agent belongs to. */
|
|
70
65
|
syncGroups?: string[];
|
|
71
|
-
/**
|
|
66
|
+
/** Room for your own product-specific fields. */
|
|
72
67
|
[key: string]: unknown;
|
|
73
68
|
}
|
package/dist/agent/types.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* `
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* SDK `experimental_context` bag).
|
|
2
|
+
* Types specific to running AI agents. The shared data vocabulary — `Peer`,
|
|
3
|
+
* {@link Activity}, `Claim`, `ActiveClaim`, `PresenceUpdatePayload`, and
|
|
4
|
+
* `PresenceKind` — lives in the streams module. This file adds only the two
|
|
5
|
+
* pieces the agent layer needs on top of it: {@link PresenceAnnouncer}, a
|
|
6
|
+
* transport-agnostic way to announce presence, and {@link AgentContext}, the bag
|
|
7
|
+
* of ambient state passed to AI SDK tools.
|
|
9
8
|
*/
|
|
10
9
|
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turns a write to one of your models into a Vercel AI SDK tool that handles
|
|
3
|
+
* multi-agent coordination for you, so an agent can contribute to shared state
|
|
4
|
+
* without silently overwriting another writer's concurrent change.
|
|
5
|
+
*
|
|
6
|
+
* The lower-level approach is to write your own `tool()` and call
|
|
7
|
+
* `ablo.<model>.update({ id, data, claim })` inside its `execute` — the right
|
|
8
|
+
* amount of control for a bespoke tool. This helper covers the common case
|
|
9
|
+
* instead: the agent produced some content and you want to save it into a shared
|
|
10
|
+
* row, without re-deriving optimistic concurrency each time. You declare the
|
|
11
|
+
* write:
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { coordinatedTool } from '@abloatai/ablo/ai-sdk';
|
|
15
|
+
* import { z } from 'zod';
|
|
16
|
+
*
|
|
17
|
+
* const saveSection = coordinatedTool(ablo.documents, {
|
|
18
|
+
* description: 'Save your section into the shared document.',
|
|
19
|
+
* inputSchema: z.object({ text: z.string() }),
|
|
20
|
+
* id: () => DOC_ID,
|
|
21
|
+
* apply: (current, { text }) => ({ content: appendBlock(current.content, text) }),
|
|
22
|
+
* // strategy: 'merge' ← the default
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* await streamText({ model, messages, tools: { saveSection } });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* The {@link CoordinatedToolOptions.apply} function is the whole API: a pure
|
|
29
|
+
* function from the freshest row and the tool input to a patch, in the same
|
|
30
|
+
* spirit as a functional state update. Everything beneath it — reading the latest
|
|
31
|
+
* row, the compare-and-swap, backing off between retries, and releasing claims —
|
|
32
|
+
* is the runtime's job.
|
|
33
|
+
*
|
|
34
|
+
* ## Strategies
|
|
35
|
+
*
|
|
36
|
+
* Choose a strategy by how you want concurrent writers to relate. Each is
|
|
37
|
+
* designed to converge under many agents writing at once.
|
|
38
|
+
*
|
|
39
|
+
* - `'merge'` (the default) delegates to the functional update
|
|
40
|
+
* `ablo.<model>.update(id, current => apply(current, input))`. The runtime
|
|
41
|
+
* re-reads and re-applies `apply` on top of every concurrent write, backing off
|
|
42
|
+
* between rounds, so many agents accumulate into one row and the model never
|
|
43
|
+
* sees a conflict. This requires the model's agent conflict policy to be
|
|
44
|
+
* `reject` (the default, or `agentsReject()`). A model that declares
|
|
45
|
+
* `agentsNotify()` holds the losing write instead of rejecting it, which
|
|
46
|
+
* defeats the reconcile loop — there, use `'claim'` or `'queue'`, or change the
|
|
47
|
+
* policy.
|
|
48
|
+
*
|
|
49
|
+
* - `'claim'` gives mutual exclusion. It takes a fail-fast claim; if another
|
|
50
|
+
* participant holds the row, it returns `{ status: 'claimed' }` and leaves the
|
|
51
|
+
* decision to retry up to the model. A visible signal serves the agent better
|
|
52
|
+
* than a hidden wait when it might spend its turn on something else. Works under
|
|
53
|
+
* any conflict policy.
|
|
54
|
+
*
|
|
55
|
+
* - `'queue'` serializes writers over stateless HTTP. The tool polls to acquire
|
|
56
|
+
* the claim until it is granted or `poll.timeoutMs` elapses, so the model calls
|
|
57
|
+
* once and the tool waits its turn. Ordering is approximate rather than strict
|
|
58
|
+
* first-in-first-out, which would require a persistent connection.
|
|
59
|
+
*/
|
|
60
|
+
import type { z } from 'zod';
|
|
61
|
+
import type { ModelOperations } from '../client/createModelProxy.js';
|
|
62
|
+
export type CoordinationStrategy = 'merge' | 'claim' | 'queue';
|
|
63
|
+
/** The structured result the tool hands back to the model (or the caller). */
|
|
64
|
+
export interface CoordinatedWriteResult<T> {
|
|
65
|
+
/**
|
|
66
|
+
* `'written'` means the change was saved. `'claimed'` means another participant
|
|
67
|
+
* holds the row, so nothing was saved and the model should try again.
|
|
68
|
+
* `'timeout'` means the `'queue'` strategy could not acquire the row within
|
|
69
|
+
* `poll.timeoutMs`.
|
|
70
|
+
*/
|
|
71
|
+
status: 'written' | 'claimed' | 'timeout';
|
|
72
|
+
/** The reconciled row, on `'written'`. */
|
|
73
|
+
row?: T;
|
|
74
|
+
message?: string;
|
|
75
|
+
/** On `'written'` via the `queue` strategy, how long the tool waited in line. */
|
|
76
|
+
waitedMs?: number;
|
|
77
|
+
}
|
|
78
|
+
export interface CoordinatedToolOptions<TInput, T> {
|
|
79
|
+
/** Tool description shown to the model. */
|
|
80
|
+
description: string;
|
|
81
|
+
/** The schema of what the model may send, as a standard AI SDK / Zod input schema. */
|
|
82
|
+
inputSchema: z.ZodType<TInput>;
|
|
83
|
+
/** Which row this write targets, derived from the tool input. */
|
|
84
|
+
id: (input: TInput) => string;
|
|
85
|
+
/**
|
|
86
|
+
* Produces the write patch from the freshest current row and the tool input, as
|
|
87
|
+
* a pure function of the two. Under `'merge'` it re-runs on top of every
|
|
88
|
+
* concurrent write, so it must be idempotent with respect to its own
|
|
89
|
+
* contribution — for example, skip its change when its marker is already
|
|
90
|
+
* present — to stay correct across retries.
|
|
91
|
+
*/
|
|
92
|
+
apply: (current: T, input: TInput) => Partial<T>;
|
|
93
|
+
/** How concurrent writers relate. Defaults to `'merge'`. */
|
|
94
|
+
strategy?: CoordinationStrategy;
|
|
95
|
+
/** Human-readable coordination metadata attached to the claim, used by the `'claim'` and `'queue'` strategies. */
|
|
96
|
+
claim?: {
|
|
97
|
+
reason?: string;
|
|
98
|
+
description?: string;
|
|
99
|
+
};
|
|
100
|
+
/** How many reconcile rounds `'merge'` may take before it gives up with `AbloContentionError`. */
|
|
101
|
+
retries?: number;
|
|
102
|
+
/** Poll interval and overall timeout for `'queue'`. Defaults to 250ms and 30s. */
|
|
103
|
+
poll?: {
|
|
104
|
+
intervalMs?: number;
|
|
105
|
+
timeoutMs?: number;
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
export declare function coordinatedTool<TInput, T = Record<string, unknown>, CreateInput = Partial<T>>(model: ModelOperations<T, CreateInput>, options: CoordinatedToolOptions<TInput, T>): import("ai").Tool<TInput, CoordinatedWriteResult<T>>;
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* writer.
|
|
2
|
+
* Turns a write to one of your models into a Vercel AI SDK tool that handles
|
|
3
|
+
* multi-agent coordination for you, so an agent can contribute to shared state
|
|
4
|
+
* without silently overwriting another writer's concurrent change.
|
|
6
5
|
*
|
|
7
|
-
* The
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
6
|
+
* The lower-level approach is to write your own `tool()` and call
|
|
7
|
+
* `ablo.<model>.update({ id, data, claim })` inside its `execute` — the right
|
|
8
|
+
* amount of control for a bespoke tool. This helper covers the common case
|
|
9
|
+
* instead: the agent produced some content and you want to save it into a shared
|
|
10
|
+
* row, without re-deriving optimistic concurrency each time. You declare the
|
|
11
|
+
* write:
|
|
13
12
|
*
|
|
14
13
|
* ```ts
|
|
15
14
|
* import { coordinatedTool } from '@abloatai/ablo/ai-sdk';
|
|
@@ -26,31 +25,37 @@
|
|
|
26
25
|
* await streamText({ model, messages, tools: { saveSection } });
|
|
27
26
|
* ```
|
|
28
27
|
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
28
|
+
* The {@link CoordinatedToolOptions.apply} function is the whole API: a pure
|
|
29
|
+
* function from the freshest row and the tool input to a patch, in the same
|
|
30
|
+
* spirit as a functional state update. Everything beneath it — reading the latest
|
|
31
|
+
* row, the compare-and-swap, backing off between retries, and releasing claims —
|
|
32
|
+
* is the runtime's job.
|
|
33
33
|
*
|
|
34
|
-
* ## Strategies
|
|
35
|
-
* under N-way agent contention)
|
|
34
|
+
* ## Strategies
|
|
36
35
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* and re-applies `apply` on top of every concurrent write and backs off between
|
|
40
|
-
* rounds, so N agents *accumulate* into one row and the model never sees a
|
|
41
|
-
* conflict. **Requires the model's agent conflict policy to be `reject`** (the
|
|
42
|
-
* default, or `agentsReject()`); a model declaring `agentsNotify()` HOLDS the
|
|
43
|
-
* losing write instead of rejecting it, which defeats the reconcile — use
|
|
44
|
-
* `claim`/`queue` there, or switch the policy.
|
|
36
|
+
* Choose a strategy by how you want concurrent writers to relate. Each is
|
|
37
|
+
* designed to converge under many agents writing at once.
|
|
45
38
|
*
|
|
46
|
-
* - `'
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
39
|
+
* - `'merge'` (the default) delegates to the functional update
|
|
40
|
+
* `ablo.<model>.update(id, current => apply(current, input))`. The runtime
|
|
41
|
+
* re-reads and re-applies `apply` on top of every concurrent write, backing off
|
|
42
|
+
* between rounds, so many agents accumulate into one row and the model never
|
|
43
|
+
* sees a conflict. This requires the model's agent conflict policy to be
|
|
44
|
+
* `reject` (the default, or `agentsReject()`). A model that declares
|
|
45
|
+
* `agentsNotify()` holds the losing write instead of rejecting it, which
|
|
46
|
+
* defeats the reconcile loop — there, use `'claim'` or `'queue'`, or change the
|
|
47
|
+
* policy.
|
|
50
48
|
*
|
|
51
|
-
* - `'
|
|
52
|
-
*
|
|
53
|
-
*
|
|
49
|
+
* - `'claim'` gives mutual exclusion. It takes a fail-fast claim; if another
|
|
50
|
+
* participant holds the row, it returns `{ status: 'claimed' }` and leaves the
|
|
51
|
+
* decision to retry up to the model. A visible signal serves the agent better
|
|
52
|
+
* than a hidden wait when it might spend its turn on something else. Works under
|
|
53
|
+
* any conflict policy.
|
|
54
|
+
*
|
|
55
|
+
* - `'queue'` serializes writers over stateless HTTP. The tool polls to acquire
|
|
56
|
+
* the claim until it is granted or `poll.timeoutMs` elapses, so the model calls
|
|
57
|
+
* once and the tool waits its turn. Ordering is approximate rather than strict
|
|
58
|
+
* first-in-first-out, which would require a persistent connection.
|
|
54
59
|
*/
|
|
55
60
|
import { tool } from 'ai';
|
|
56
61
|
import { AbloClaimedError, AbloNotFoundError } from '../errors.js';
|
|
@@ -63,17 +68,18 @@ export function coordinatedTool(model, options) {
|
|
|
63
68
|
execute: async (input) => {
|
|
64
69
|
const id = options.id(input);
|
|
65
70
|
if (strategy === 'merge') {
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
// never sees a conflict.
|
|
71
|
+
// Read the freshest row, apply the patch, and commit it with a
|
|
72
|
+
// compare-and-swap; on any concurrent write, re-read and re-apply with
|
|
73
|
+
// backoff. The model never sees a conflict.
|
|
69
74
|
const row = await model.update(id, (current) => options.apply(current, input), {
|
|
70
75
|
retries: options.retries,
|
|
71
76
|
});
|
|
72
77
|
return { status: 'written', row: row ?? undefined };
|
|
73
78
|
}
|
|
74
|
-
// claim
|
|
75
|
-
//
|
|
76
|
-
// signal to the model
|
|
79
|
+
// The 'claim' and 'queue' strategies both acquire a claim, write under it,
|
|
80
|
+
// and release it. They differ only in what they do when the row is already
|
|
81
|
+
// held: 'claim' returns a signal to the model, while 'queue' waits and
|
|
82
|
+
// retries by polling to acquire.
|
|
77
83
|
const acquireWriteRelease = async () => {
|
|
78
84
|
const claim = await model.claim({
|
|
79
85
|
id,
|
|
@@ -104,7 +110,7 @@ export function coordinatedTool(model, options) {
|
|
|
104
110
|
throw e;
|
|
105
111
|
}
|
|
106
112
|
}
|
|
107
|
-
// strategy === 'queue':
|
|
113
|
+
// strategy === 'queue': poll to acquire the claim over stateless HTTP.
|
|
108
114
|
const interval = options.poll?.intervalMs ?? 250;
|
|
109
115
|
const timeout = options.poll?.timeoutMs ?? 30_000;
|
|
110
116
|
const start = Date.now();
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Language-model middleware that tells the model when other participants are
|
|
3
|
+
* editing the same entity. It reads peer claims on the target from the agent's
|
|
4
|
+
* live presence stream and, when it finds any, injects a short coordination note
|
|
5
|
+
* into the prompt before the model runs.
|
|
6
|
+
*
|
|
7
|
+
* This is the counterpart to the claim-broadcast middleware: that one announces
|
|
8
|
+
* what this agent is about to do, while this one reads what others are doing and
|
|
9
|
+
* passes it to the model. Together they let the model notice when a person or
|
|
10
|
+
* another agent is mid-edit and respond — deferring, framing its work as
|
|
11
|
+
* complementary, or suggesting it wait.
|
|
12
|
+
*
|
|
13
|
+
* It depends only on the AI SDK's provider types and a connected agent from this
|
|
14
|
+
* package, and you compose it with the AI SDK's `wrapLanguageModel`. Reading
|
|
15
|
+
* peers costs no extra model calls: the presence stream is already in memory from
|
|
16
|
+
* the agent's subscription. It adds only a few sentences to the system prompt,
|
|
17
|
+
* and only while peers are actively editing.
|
|
18
|
+
*/
|
|
19
|
+
import type { LanguageModelV3Middleware } from '@ai-sdk/provider';
|
|
20
|
+
import type { Ablo } from '../client/Ablo.js';
|
|
21
|
+
import type { SchemaRecord } from '../schema/schema.js';
|
|
22
|
+
import type { ClaimTarget } from '../types/streams.js';
|
|
23
|
+
export type { ClaimTarget };
|
|
24
|
+
export interface CoordinationContextMiddlewareOptions<R extends SchemaRecord = SchemaRecord> {
|
|
25
|
+
readonly agent: Ablo<R> | null;
|
|
26
|
+
readonly target: ClaimTarget | null;
|
|
27
|
+
/**
|
|
28
|
+
* Claim identifiers to leave out of the read, typically this agent's own active
|
|
29
|
+
* claim so the note doesn't report that the agent is editing against itself. In
|
|
30
|
+
* the usual composition with the claim-broadcast middleware, `transformParams`
|
|
31
|
+
* runs before that middleware declares its claim, so the agent's own claim
|
|
32
|
+
* isn't in the presence stream yet and no filtering is needed. This option is
|
|
33
|
+
* here for callers that compose the middleware differently, or that coordinate a
|
|
34
|
+
* fleet and want to exclude sibling workers' claims.
|
|
35
|
+
*/
|
|
36
|
+
readonly excludeClaimIds?: readonly string[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Builds the coordination-context middleware. If `agent` or `target` is null, the
|
|
40
|
+
* middleware passes the prompt through unchanged.
|
|
41
|
+
*
|
|
42
|
+
* The generic over the schema record matches the claim-broadcast middleware: a
|
|
43
|
+
* typed `Ablo<S>` and the widened `Ablo<SchemaRecord>` are not structurally
|
|
44
|
+
* assignable, so the parameter stays generic to spare callers a cast.
|
|
45
|
+
*/
|
|
46
|
+
export declare function coordinationContextMiddleware<R extends SchemaRecord = SchemaRecord>(options: CoordinationContextMiddlewareOptions<R>): LanguageModelV3Middleware;
|
|
@@ -1,32 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* entity
|
|
4
|
-
*
|
|
2
|
+
* Language-model middleware that tells the model when other participants are
|
|
3
|
+
* editing the same entity. It reads peer claims on the target from the agent's
|
|
4
|
+
* live presence stream and, when it finds any, injects a short coordination note
|
|
5
|
+
* into the prompt before the model runs.
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* "while you finish that, I'll …" / suggest waiting / coordinate
|
|
12
|
-
* explicitly.
|
|
7
|
+
* This is the counterpart to the claim-broadcast middleware: that one announces
|
|
8
|
+
* what this agent is about to do, while this one reads what others are doing and
|
|
9
|
+
* passes it to the model. Together they let the model notice when a person or
|
|
10
|
+
* another agent is mid-edit and respond — deferring, framing its work as
|
|
11
|
+
* complementary, or suggesting it wait.
|
|
13
12
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* cached presence stream — already in memory from the WS subscription).
|
|
20
|
-
* Adds a few sentences to the system prompt (typically <100 tokens)
|
|
21
|
-
* only when peers are actively editing.
|
|
13
|
+
* It depends only on the AI SDK's provider types and a connected agent from this
|
|
14
|
+
* package, and you compose it with the AI SDK's `wrapLanguageModel`. Reading
|
|
15
|
+
* peers costs no extra model calls: the presence stream is already in memory from
|
|
16
|
+
* the agent's subscription. It adds only a few sentences to the system prompt,
|
|
17
|
+
* and only while peers are actively editing.
|
|
22
18
|
*/
|
|
23
19
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
20
|
+
* Builds the coordination-context middleware. If `agent` or `target` is null, the
|
|
21
|
+
* middleware passes the prompt through unchanged.
|
|
26
22
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* assignable.
|
|
23
|
+
* The generic over the schema record matches the claim-broadcast middleware: a
|
|
24
|
+
* typed `Ablo<S>` and the widened `Ablo<SchemaRecord>` are not structurally
|
|
25
|
+
* assignable, so the parameter stays generic to spare callers a cast.
|
|
30
26
|
*/
|
|
31
27
|
export function coordinationContextMiddleware(options) {
|
|
32
28
|
const { agent, target } = options;
|
|
@@ -36,9 +32,12 @@ export function coordinationContextMiddleware(options) {
|
|
|
36
32
|
transformParams: async ({ params }) => {
|
|
37
33
|
if (!agent || !target)
|
|
38
34
|
return params;
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
|
|
35
|
+
// Look up peer claims on the same target. This reads the agent's reactive
|
|
36
|
+
// `claims.others` array in memory, with no I/O. The type is compared
|
|
37
|
+
// case-insensitively: observed claims carry a lowercased type name (such as
|
|
38
|
+
// `slidedeck`) while callers write the schema's type name (`SlideDeck`).
|
|
39
|
+
const wantedType = target.type.toLowerCase();
|
|
40
|
+
const peerClaims = agent.claims.others.filter((claim) => claim.target.type.toLowerCase() === wantedType &&
|
|
42
41
|
claim.target.id === target.id &&
|
|
43
42
|
targetsOverlap(claim.target, target) &&
|
|
44
43
|
!excludeClaimIds.has(claim.id));
|
|
@@ -72,14 +71,14 @@ function targetsOverlap(claimTarget, target) {
|
|
|
72
71
|
return fieldOverlaps && rangeOverlaps;
|
|
73
72
|
}
|
|
74
73
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
74
|
+
* Formats a one-paragraph coordination note for the model. It names who is
|
|
75
|
+
* editing and, when known, what they are doing. The note stays short: the goal is
|
|
76
|
+
* to make the model aware, not to flood the prompt.
|
|
78
77
|
*/
|
|
79
78
|
function formatCoordinationNote(claims, target) {
|
|
80
79
|
const entityLabel = target.type.toLowerCase();
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
const c = claims.length === 1 ? claims[0] : undefined;
|
|
81
|
+
if (c) {
|
|
83
82
|
const details = c.description ? `Declared work: ${c.description}. ` : '';
|
|
84
83
|
return (`<multiplayer_context>\n` +
|
|
85
84
|
`Another participant is currently editing this ${entityLabel}. ` +
|