@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.
Files changed (425) hide show
  1. package/AGENTS.md +5 -3
  2. package/CHANGELOG.md +34 -0
  3. package/README.md +104 -88
  4. package/dist/BaseSyncedStore.d.ts +140 -266
  5. package/dist/BaseSyncedStore.js +338 -739
  6. package/dist/Database.d.ts +62 -77
  7. package/dist/Database.js +106 -127
  8. package/dist/{ObjectPool.d.ts → InstanceCache.d.ts} +10 -13
  9. package/dist/{ObjectPool.js → InstanceCache.js} +91 -83
  10. package/dist/LazyReferenceCollection.d.ts +11 -15
  11. package/dist/LazyReferenceCollection.js +16 -15
  12. package/dist/Model.d.ts +37 -52
  13. package/dist/Model.js +52 -69
  14. package/dist/ModelRegistry.d.ts +46 -25
  15. package/dist/ModelRegistry.js +32 -30
  16. package/dist/NetworkMonitor.d.ts +5 -6
  17. package/dist/NetworkMonitor.js +6 -7
  18. package/dist/SyncClient.d.ts +119 -109
  19. package/dist/SyncClient.js +303 -224
  20. package/dist/SyncEngineContext.d.ts +1 -3
  21. package/dist/SyncEngineContext.js +1 -2
  22. package/dist/adapters/alwaysOnline.d.ts +6 -8
  23. package/dist/adapters/alwaysOnline.js +6 -8
  24. package/dist/adapters/inMemoryStorage.d.ts +9 -9
  25. package/dist/adapters/inMemoryStorage.js +9 -9
  26. package/dist/agent/Agent.d.ts +39 -31
  27. package/dist/agent/Agent.js +35 -23
  28. package/dist/agent/index.d.ts +4 -4
  29. package/dist/agent/index.js +5 -5
  30. package/dist/agent/session.d.ts +47 -44
  31. package/dist/agent/session.js +37 -48
  32. package/dist/agent/types.d.ts +26 -31
  33. package/dist/agent/types.js +6 -7
  34. package/dist/ai-sdk/coordinatedTool.d.ts +108 -0
  35. package/dist/ai-sdk/{coordinated-tool.js → coordinatedTool.js} +44 -38
  36. package/dist/ai-sdk/coordinationContext.d.ts +46 -0
  37. package/dist/ai-sdk/{coordination-context.js → coordinationContext.js} +30 -31
  38. package/dist/ai-sdk/index.d.ts +25 -22
  39. package/dist/ai-sdk/index.js +25 -22
  40. package/dist/ai-sdk/wrap.d.ts +7 -8
  41. package/dist/ai-sdk/wrap.js +2 -2
  42. package/dist/auth/credentialPolicy.d.ts +74 -71
  43. package/dist/auth/credentialPolicy.js +51 -56
  44. package/dist/auth/credentialSource.d.ts +7 -18
  45. package/dist/auth/credentialSource.js +10 -18
  46. package/dist/auth/index.d.ts +59 -58
  47. package/dist/auth/index.js +34 -40
  48. package/dist/auth/schemas.d.ts +5 -4
  49. package/dist/auth/schemas.js +5 -4
  50. package/dist/batching/index.d.ts +19 -21
  51. package/dist/batching/index.js +14 -17
  52. package/dist/cli.cjs +483 -369
  53. package/dist/client/Ablo.d.ts +107 -836
  54. package/dist/client/Ablo.js +174 -833
  55. package/dist/client/ApiClient.d.ts +44 -20
  56. package/dist/client/ApiClient.js +193 -44
  57. package/dist/client/auth.d.ts +51 -60
  58. package/dist/client/auth.js +137 -110
  59. package/dist/client/claimHeartbeatLoop.d.ts +50 -0
  60. package/dist/client/claimHeartbeatLoop.js +88 -0
  61. package/dist/client/consoleLogger.d.ts +35 -0
  62. package/dist/client/consoleLogger.js +44 -0
  63. package/dist/client/createInternalComponents.d.ts +14 -17
  64. package/dist/client/createInternalComponents.js +26 -31
  65. package/dist/client/createModelProxy.d.ts +130 -120
  66. package/dist/client/createModelProxy.js +158 -124
  67. package/dist/client/credentialEndpoint.d.ts +61 -0
  68. package/dist/client/credentialEndpoint.js +86 -0
  69. package/dist/client/functionalUpdate.d.ts +29 -27
  70. package/dist/client/functionalUpdate.js +21 -21
  71. package/dist/client/hostedEndpoints.d.ts +21 -0
  72. package/dist/client/hostedEndpoints.js +21 -0
  73. package/dist/client/httpClient.d.ts +58 -54
  74. package/dist/client/httpClient.js +29 -31
  75. package/dist/client/identity.d.ts +15 -20
  76. package/dist/client/identity.js +49 -59
  77. package/dist/client/modelRegistration.d.ts +10 -0
  78. package/dist/client/modelRegistration.js +301 -0
  79. package/dist/client/options.d.ts +373 -0
  80. package/dist/client/options.js +6 -0
  81. package/dist/client/registerDataSource.d.ts +9 -9
  82. package/dist/client/registerDataSource.js +15 -16
  83. package/dist/client/resourceTypes.d.ts +333 -0
  84. package/dist/client/resourceTypes.js +7 -0
  85. package/dist/client/schemaConfig.d.ts +44 -0
  86. package/dist/client/schemaConfig.js +176 -0
  87. package/dist/client/sessionMint.d.ts +17 -13
  88. package/dist/client/sessionMint.js +26 -31
  89. package/dist/client/validateAbloOptions.d.ts +12 -14
  90. package/dist/client/validateAbloOptions.js +9 -10
  91. package/dist/client/writeOptionsSchema.d.ts +18 -16
  92. package/dist/client/writeOptionsSchema.js +23 -20
  93. package/dist/client/wsMutationExecutor.d.ts +28 -0
  94. package/dist/client/wsMutationExecutor.js +71 -0
  95. package/dist/context.d.ts +6 -4
  96. package/dist/context.js +6 -7
  97. package/dist/coordination/index.d.ts +13 -4
  98. package/dist/coordination/index.js +29 -4
  99. package/dist/coordination/schema.d.ts +176 -128
  100. package/dist/coordination/schema.js +197 -133
  101. package/dist/coordination/trace.d.ts +9 -11
  102. package/dist/coordination/trace.js +13 -15
  103. package/dist/core/DatabaseManager.d.ts +5 -8
  104. package/dist/core/DatabaseManager.js +38 -40
  105. package/dist/core/QueryProcessor.d.ts +7 -9
  106. package/dist/core/QueryProcessor.js +27 -34
  107. package/dist/core/QueryView.d.ts +17 -5
  108. package/dist/core/QueryView.js +6 -7
  109. package/dist/core/StoreManager.d.ts +14 -16
  110. package/dist/core/StoreManager.js +26 -25
  111. package/dist/core/ViewRegistry.d.ts +5 -5
  112. package/dist/core/ViewRegistry.js +4 -4
  113. package/dist/core/index.d.ts +18 -13
  114. package/dist/core/index.js +32 -26
  115. package/dist/core/openIDBWithTimeout.d.ts +38 -36
  116. package/dist/core/openIDBWithTimeout.js +57 -54
  117. package/dist/core/queryUtils.d.ts +45 -0
  118. package/dist/core/queryUtils.js +69 -0
  119. package/dist/core/storeContract.d.ts +145 -0
  120. package/dist/core/storeContract.js +12 -0
  121. package/dist/environment.d.ts +28 -0
  122. package/dist/environment.js +21 -0
  123. package/dist/errorCodes.d.ts +118 -101
  124. package/dist/errorCodes.js +277 -260
  125. package/dist/errors.d.ts +170 -165
  126. package/dist/errors.js +161 -151
  127. package/dist/index.d.ts +30 -27
  128. package/dist/index.js +90 -82
  129. package/dist/interfaces/index.d.ts +108 -133
  130. package/dist/interfaces/index.js +5 -4
  131. package/dist/keys/index.d.ts +27 -29
  132. package/dist/keys/index.js +59 -49
  133. package/dist/mutators/RecordingTransaction.d.ts +16 -16
  134. package/dist/mutators/RecordingTransaction.js +31 -37
  135. package/dist/mutators/Transaction.d.ts +18 -26
  136. package/dist/mutators/Transaction.js +14 -20
  137. package/dist/mutators/UndoManager.d.ts +122 -131
  138. package/dist/mutators/UndoManager.js +149 -155
  139. package/dist/mutators/defineMutators.d.ts +24 -37
  140. package/dist/mutators/defineMutators.js +14 -20
  141. package/dist/mutators/inverseOp.d.ts +12 -15
  142. package/dist/mutators/inverseOp.js +12 -15
  143. package/dist/mutators/mutateActions.d.ts +10 -9
  144. package/dist/mutators/mutateActions.js +1 -1
  145. package/dist/mutators/readerActions.d.ts +9 -8
  146. package/dist/mutators/readerActions.js +2 -2
  147. package/dist/mutators/undoApply.d.ts +31 -27
  148. package/dist/mutators/undoApply.js +26 -24
  149. package/dist/policy/index.d.ts +5 -3
  150. package/dist/policy/index.js +5 -3
  151. package/dist/policy/types.d.ts +105 -101
  152. package/dist/policy/types.js +67 -66
  153. package/dist/query/client.d.ts +32 -16
  154. package/dist/query/client.js +103 -72
  155. package/dist/query/types.d.ts +37 -60
  156. package/dist/query/types.js +13 -33
  157. package/dist/react/AbloProvider.d.ts +7 -11
  158. package/dist/react/AbloProvider.js +24 -17
  159. package/dist/react/context.d.ts +27 -146
  160. package/dist/react/context.js +9 -10
  161. package/dist/react/index.d.ts +41 -42
  162. package/dist/react/index.js +37 -38
  163. package/dist/react/internalContext.d.ts +17 -19
  164. package/dist/react/useAblo.d.ts +23 -22
  165. package/dist/react/useAblo.js +17 -15
  166. package/dist/react/useCurrentUserId.d.ts +8 -7
  167. package/dist/react/useCurrentUserId.js +8 -7
  168. package/dist/react/useErrorListener.d.ts +7 -7
  169. package/dist/react/useErrorListener.js +11 -12
  170. package/dist/react/useMutationFailureListener.d.ts +8 -8
  171. package/dist/react/useMutationFailureListener.js +9 -9
  172. package/dist/react/useMutators.d.ts +11 -11
  173. package/dist/react/useMutators.js +10 -4
  174. package/dist/react/useReactive.js +2 -3
  175. package/dist/react/useSyncStatus.d.ts +4 -6
  176. package/dist/react/useUndoScope.d.ts +7 -9
  177. package/dist/react/useUndoScope.js +3 -3
  178. package/dist/schema/coordination.d.ts +21 -25
  179. package/dist/schema/coordination.js +21 -25
  180. package/dist/schema/ddl.d.ts +43 -39
  181. package/dist/schema/ddl.js +75 -68
  182. package/dist/schema/ddlLock.d.ts +35 -0
  183. package/dist/schema/ddlLock.js +46 -0
  184. package/dist/schema/diff.d.ts +99 -61
  185. package/dist/schema/diff.js +43 -34
  186. package/dist/schema/field.d.ts +37 -42
  187. package/dist/schema/field.js +36 -49
  188. package/dist/schema/generate.d.ts +12 -12
  189. package/dist/schema/generate.js +12 -12
  190. package/dist/schema/index.d.ts +5 -4
  191. package/dist/schema/index.js +29 -21
  192. package/dist/schema/model.d.ts +121 -146
  193. package/dist/schema/model.js +24 -35
  194. package/dist/schema/openapi.d.ts +10 -9
  195. package/dist/schema/openapi.js +7 -1
  196. package/dist/schema/queries.d.ts +30 -32
  197. package/dist/schema/queries.js +24 -25
  198. package/dist/schema/relation.d.ts +89 -99
  199. package/dist/schema/relation.js +13 -13
  200. package/dist/schema/residency.d.ts +38 -0
  201. package/dist/schema/residency.js +30 -0
  202. package/dist/schema/roles.d.ts +45 -27
  203. package/dist/schema/roles.js +52 -21
  204. package/dist/schema/schema.d.ts +36 -45
  205. package/dist/schema/schema.js +42 -39
  206. package/dist/schema/select.d.ts +13 -13
  207. package/dist/schema/select.js +13 -13
  208. package/dist/schema/serialize.d.ts +36 -39
  209. package/dist/schema/serialize.js +27 -31
  210. package/dist/schema/sugar.d.ts +17 -32
  211. package/dist/schema/sugar.js +14 -29
  212. package/dist/schema/{sync-delta-row.d.ts → syncDeltaRow.d.ts} +27 -50
  213. package/dist/schema/syncDeltaRow.js +89 -0
  214. package/dist/schema/tenancy.d.ts +44 -46
  215. package/dist/schema/tenancy.js +46 -48
  216. package/dist/server/adapter.d.ts +58 -58
  217. package/dist/server/adapter.js +13 -14
  218. package/dist/server/commit.d.ts +60 -64
  219. package/dist/server/index.d.ts +9 -10
  220. package/dist/server/index.js +1 -1
  221. package/dist/server/readConfig.d.ts +70 -0
  222. package/dist/server/readConfig.js +8 -0
  223. package/dist/server/storageMode.d.ts +23 -0
  224. package/dist/server/storageMode.js +17 -0
  225. package/dist/source/adapter.d.ts +31 -26
  226. package/dist/source/adapter.js +10 -10
  227. package/dist/source/adapters/drizzle.d.ts +28 -23
  228. package/dist/source/adapters/drizzle.js +34 -28
  229. package/dist/source/adapters/kysely.d.ts +27 -25
  230. package/dist/source/adapters/kysely.js +28 -26
  231. package/dist/source/adapters/memory.d.ts +8 -7
  232. package/dist/source/adapters/memory.js +10 -9
  233. package/dist/source/adapters/prisma.d.ts +13 -12
  234. package/dist/source/adapters/prisma.js +27 -29
  235. package/dist/source/conformance.d.ts +18 -11
  236. package/dist/source/conformance.js +27 -19
  237. package/dist/source/connector.d.ts +31 -32
  238. package/dist/source/connector.js +30 -28
  239. package/dist/source/connectorProtocol.d.ts +160 -0
  240. package/dist/source/connectorProtocol.js +162 -0
  241. package/dist/source/contract.d.ts +26 -27
  242. package/dist/source/contract.js +28 -29
  243. package/dist/source/factory.d.ts +94 -0
  244. package/dist/source/factory.js +268 -0
  245. package/dist/source/index.d.ts +10 -462
  246. package/dist/source/index.js +17 -421
  247. package/dist/source/migrations.d.ts +9 -9
  248. package/dist/source/migrations.js +9 -9
  249. package/dist/source/next.d.ts +10 -11
  250. package/dist/source/next.js +7 -8
  251. package/dist/source/pushQueue.d.ts +70 -48
  252. package/dist/source/pushQueue.js +36 -29
  253. package/dist/source/signing.d.ts +88 -0
  254. package/dist/source/signing.js +159 -0
  255. package/dist/source/types.d.ts +351 -0
  256. package/dist/source/types.js +43 -0
  257. package/dist/stores/ObjectStore.d.ts +11 -12
  258. package/dist/stores/ObjectStore.js +34 -35
  259. package/dist/stores/ObjectStoreContract.d.ts +12 -15
  260. package/dist/stores/SyncActionStore.d.ts +8 -12
  261. package/dist/stores/SyncActionStore.js +77 -46
  262. package/dist/surface.d.ts +28 -21
  263. package/dist/surface.js +28 -20
  264. package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +37 -45
  265. package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +101 -80
  266. package/dist/sync/ConnectionManager.d.ts +47 -50
  267. package/dist/sync/ConnectionManager.js +74 -70
  268. package/dist/sync/NetworkProbe.d.ts +27 -31
  269. package/dist/sync/NetworkProbe.js +67 -72
  270. package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +49 -36
  271. package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +79 -54
  272. package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +45 -59
  273. package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +44 -52
  274. package/dist/sync/SyncWebSocket.d.ts +175 -250
  275. package/dist/sync/SyncWebSocket.js +431 -769
  276. package/dist/sync/awaitClaimGrant.d.ts +18 -18
  277. package/dist/sync/awaitClaimGrant.js +38 -30
  278. package/dist/sync/bootstrapApply.d.ts +70 -0
  279. package/dist/sync/bootstrapApply.js +73 -0
  280. package/dist/sync/commitFrames.d.ts +44 -0
  281. package/dist/sync/commitFrames.js +94 -0
  282. package/dist/sync/createClaimStream.d.ts +23 -22
  283. package/dist/sync/createClaimStream.js +108 -25
  284. package/dist/sync/createPresenceStream.d.ts +19 -18
  285. package/dist/sync/createPresenceStream.js +25 -26
  286. package/dist/sync/createSnapshot.d.ts +13 -17
  287. package/dist/sync/createSnapshot.js +20 -26
  288. package/dist/sync/credentialLifecycle.d.ts +175 -0
  289. package/dist/sync/credentialLifecycle.js +322 -0
  290. package/dist/sync/deltaPipeline.d.ts +113 -0
  291. package/dist/sync/deltaPipeline.js +261 -0
  292. package/dist/sync/groupChange.d.ts +113 -0
  293. package/dist/sync/groupChange.js +242 -0
  294. package/dist/sync/heartbeat.d.ts +63 -0
  295. package/dist/sync/heartbeat.js +91 -0
  296. package/dist/sync/participants.d.ts +27 -27
  297. package/dist/sync/schemas.d.ts +3 -2
  298. package/dist/sync/schemas.js +14 -10
  299. package/dist/sync/syncCursor.d.ts +40 -0
  300. package/dist/sync/syncCursor.js +55 -0
  301. package/dist/sync/syncPlan.d.ts +54 -0
  302. package/dist/sync/syncPlan.js +50 -0
  303. package/dist/sync/syncPosition.d.ts +54 -49
  304. package/dist/sync/syncPosition.js +57 -52
  305. package/dist/sync/wsFrameHandlers.d.ts +116 -0
  306. package/dist/sync/wsFrameHandlers.js +374 -0
  307. package/dist/testing/fixtures/bootstrap.d.ts +21 -17
  308. package/dist/testing/fixtures/bootstrap.js +12 -6
  309. package/dist/testing/fixtures/deltas.d.ts +31 -34
  310. package/dist/testing/fixtures/deltas.js +30 -33
  311. package/dist/testing/fixtures/models.d.ts +11 -10
  312. package/dist/testing/fixtures/models.js +12 -10
  313. package/dist/testing/helpers/{react-wrapper.d.ts → reactWrapper.d.ts} +13 -10
  314. package/dist/testing/helpers/{react-wrapper.js → reactWrapper.js} +15 -12
  315. package/dist/testing/helpers/{sync-engine-harness.d.ts → syncEngineHarness.d.ts} +17 -18
  316. package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +14 -11
  317. package/dist/testing/helpers/wait.d.ts +13 -8
  318. package/dist/testing/helpers/wait.js +13 -8
  319. package/dist/testing/index.d.ts +4 -4
  320. package/dist/testing/index.js +3 -3
  321. package/dist/testing/mocks/MockMutationExecutor.d.ts +18 -17
  322. package/dist/testing/mocks/MockMutationExecutor.js +15 -14
  323. package/dist/testing/mocks/MockNetworkMonitor.d.ts +8 -8
  324. package/dist/testing/mocks/MockNetworkMonitor.js +8 -8
  325. package/dist/testing/mocks/MockSyncContext.d.ts +21 -34
  326. package/dist/testing/mocks/MockSyncContext.js +16 -45
  327. package/dist/testing/mocks/MockSyncStore.d.ts +14 -14
  328. package/dist/testing/mocks/MockSyncStore.js +11 -11
  329. package/dist/testing/mocks/MockWebSocket.d.ts +28 -24
  330. package/dist/testing/mocks/MockWebSocket.js +22 -21
  331. package/dist/transactions/TransactionQueue.d.ts +190 -221
  332. package/dist/transactions/TransactionQueue.js +424 -822
  333. package/dist/transactions/TransactionStore.d.ts +20 -0
  334. package/dist/transactions/TransactionStore.js +53 -0
  335. package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
  336. package/dist/transactions/UnconfirmedWrites.js +104 -0
  337. package/dist/transactions/coalesceRules.d.ts +58 -0
  338. package/dist/transactions/coalesceRules.js +140 -0
  339. package/dist/transactions/commitPayload.d.ts +130 -0
  340. package/dist/transactions/commitPayload.js +143 -0
  341. package/dist/transactions/deltaConfirmation.d.ts +58 -0
  342. package/dist/transactions/deltaConfirmation.js +215 -0
  343. package/dist/transactions/optimisticApply.d.ts +49 -0
  344. package/dist/transactions/optimisticApply.js +65 -0
  345. package/dist/transactions/replayValidation.d.ts +99 -0
  346. package/dist/transactions/replayValidation.js +111 -0
  347. package/dist/types/global.d.ts +46 -41
  348. package/dist/types/global.js +20 -19
  349. package/dist/types/index.d.ts +74 -80
  350. package/dist/types/index.js +22 -27
  351. package/dist/types/modelData.d.ts +10 -0
  352. package/dist/types/modelData.js +9 -0
  353. package/dist/types/participant.d.ts +20 -0
  354. package/dist/types/participant.js +10 -0
  355. package/dist/types/streams.d.ts +216 -209
  356. package/dist/types/streams.js +7 -7
  357. package/dist/utils/asyncIterator.d.ts +25 -32
  358. package/dist/utils/asyncIterator.js +25 -32
  359. package/dist/utils/duration.d.ts +12 -15
  360. package/dist/utils/duration.js +12 -15
  361. package/dist/utils/mobxSetup.d.ts +53 -0
  362. package/dist/utils/{mobx-setup.js → mobxSetup.js} +44 -100
  363. package/dist/webhooks/events.d.ts +21 -16
  364. package/dist/webhooks/events.js +10 -8
  365. package/dist/webhooks/index.d.ts +5 -7
  366. package/dist/webhooks/index.js +5 -7
  367. package/dist/{schema/sync-delta-wire.d.ts → wire/delta.d.ts} +58 -41
  368. package/dist/wire/delta.js +114 -0
  369. package/dist/wire/errorEnvelope.d.ts +35 -27
  370. package/dist/wire/errorEnvelope.js +38 -32
  371. package/dist/wire/frames.d.ts +150 -67
  372. package/dist/wire/frames.js +48 -1
  373. package/dist/wire/index.d.ts +18 -13
  374. package/dist/wire/index.js +36 -13
  375. package/dist/wire/listEnvelope.d.ts +16 -23
  376. package/dist/wire/listEnvelope.js +7 -6
  377. package/dist/wire/protocol.d.ts +38 -0
  378. package/dist/wire/protocol.js +38 -0
  379. package/dist/wire/protocolVersion.d.ts +60 -0
  380. package/dist/wire/protocolVersion.js +67 -0
  381. package/docs/api-keys.md +4 -3
  382. package/docs/coordination.md +59 -0
  383. package/docs/examples/existing-python-backend.md +3 -3
  384. package/docs/identity.md +4 -4
  385. package/docs/integration-guide.md +1 -1
  386. package/docs/react.md +1 -1
  387. package/docs/sessions.md +5 -7
  388. package/package.json +24 -21
  389. package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
  390. package/dist/ai-sdk/coordination-context.d.ts +0 -52
  391. package/dist/client/index.d.ts +0 -36
  392. package/dist/client/index.js +0 -33
  393. package/dist/config/index.d.ts +0 -10
  394. package/dist/config/index.js +0 -12
  395. package/dist/core/query-utils.d.ts +0 -34
  396. package/dist/core/query-utils.js +0 -59
  397. package/dist/interfaces/headless.d.ts +0 -95
  398. package/dist/interfaces/headless.js +0 -41
  399. package/dist/query/index.d.ts +0 -6
  400. package/dist/query/index.js +0 -5
  401. package/dist/realtime/index.d.ts +0 -10
  402. package/dist/realtime/index.js +0 -9
  403. package/dist/schema/plane.d.ts +0 -23
  404. package/dist/schema/plane.js +0 -19
  405. package/dist/schema/sync-delta-row.js +0 -103
  406. package/dist/schema/sync-delta-wire.js +0 -102
  407. package/dist/server/next.d.ts +0 -51
  408. package/dist/server/next.js +0 -47
  409. package/dist/server/read-config.d.ts +0 -67
  410. package/dist/server/read-config.js +0 -8
  411. package/dist/server/storage-mode.d.ts +0 -1
  412. package/dist/server/storage-mode.js +0 -18
  413. package/dist/source/connector-protocol.d.ts +0 -159
  414. package/dist/source/connector-protocol.js +0 -161
  415. package/dist/sync/OfflineFlush.d.ts +0 -9
  416. package/dist/sync/OfflineFlush.js +0 -22
  417. package/dist/sync/OfflineTransactionStore.d.ts +0 -37
  418. package/dist/sync/OfflineTransactionStore.js +0 -263
  419. package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
  420. package/dist/transactions/OptimisticEchoTracker.js +0 -104
  421. package/dist/transactions/index.d.ts +0 -16
  422. package/dist/transactions/index.js +0 -7
  423. package/dist/transactions/mutation-error-handler.d.ts +0 -5
  424. package/dist/transactions/mutation-error-handler.js +0 -39
  425. package/dist/utils/mobx-setup.d.ts +0 -42
@@ -1,37 +1,35 @@
1
1
  /**
2
- * Agent session cache + lifecycle for server-side `SyncAgent`s.
2
+ * Caches and manages the lifecycle of long-lived agent connections on a server.
3
3
  *
4
- * Captures the pattern every server-side consumer needs:
5
- * 1. Cache `SyncAgent` instances per (org, user, surface, target).
6
- * 2. Re-mint capabilities before TTL elapses.
7
- * 3. Align the SyncAgent ctor's `syncGroups` with the cap allowlist
8
- * so the upgrade-time intersection is non-empty (avoid the
9
- * silent black-hole-broadcast bug).
10
- * 4. Connect / disconnect / dispose lifecycle.
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
- * What's generic, what isn't:
13
- * - Cache, TTL, sync_groups alignment, lifecycle: SAME for every
14
- * consumer. Lives here.
15
- * - Cap mint: AUTH-FLOW-SPECIFIC. Every consumer has a different
16
- * way to obtain a token (Better Auth cookie forwarding, API key
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
- * Returns a session whose `getAgent` method handles cache, mint,
27
- * sync_groups alignment, and lifecycle. Call `disposeAll()` from
28
- * the consumer's process shutdown hook.
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
- * Threading: the session is intended to be a long-lived singleton
31
- * shared across requests. The cache is keyed precisely so two
32
- * concurrent requests for the same (user, org, surface, target)
33
- * share one agent + one WS, while different requests get
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
- // Sync_groups alignment is the load-bearing detail. The SDK
65
- // ctor's `syncGroups` and the cap mint's `syncGroups`
66
- // MUST overlap or the upgrade intersection is empty and every
67
- // broadcast filter returns false. Use the cap's allowed list
68
- // verbatim — the caller controlled what went in there, so it's
69
- // exactly what the SDK should request.
70
- // `AbloOptions` exposes the URL as `baseURL` (resolved by
71
- // `resolveBaseURL`). Earlier code passed `url:` here `Ablo()`
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
- // Route through the gated logger so this obeys ABLO_LOG_LEVEL like every
105
- // other line: a plain consumer-register `error` headline (the unreachable
106
- // URL + code), with the structured fields on a `debug` companion. The
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
- * Eject a specific cached agent useful when the consumer knows
139
- * the underlying token is invalidated (revocation, role change)
140
- * and wants the next `getAgent` call to mint fresh.
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);
@@ -1,37 +1,32 @@
1
1
  /**
2
- * Agent-SDK abstractions. The engine's data vocabulary
3
- * (`Peer`, `Activity`, `Claim`, `ActiveClaim`,
4
- * `PresenceUpdatePayload`, `PresenceKind`) lives in
5
- * `../types/streams.ts`. This file holds only the bits that are
6
- * specific to the agent module: the `PresenceAnnouncer` abstraction
7
- * (transport-agnostic announce contract) and `AgentContext` (the AI
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 abstract over WebSocket
13
- * (`Ablo({kind: 'agent'})`) and REST (`Agent`). Both
14
- * implementations satisfy this, so higher-level code can depend on it
15
- * without caring about transport.
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
- * Ambient context threaded into AI SDK tools via `experimental_context`.
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
- * The pattern: the caller constructs an AgentContext once per agent
24
- * invocation and passes it as `experimental_context`. Each tool's
25
- * `execute` function extracts what it needs from
26
- * `options.experimental_context` instead of closing over module-level
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
- * Consumers can extend AgentContext via module augmentation or by
58
- * intersecting with their own context type.
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
- /** Presence / freshness / AI SDK hook primitives. Required. */
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
- /** Organization scope for all operations. */
60
+ /** The organization every operation is scoped to. */
66
61
  organizationId?: string;
67
- /** User or agent identifier format: "agent:<id>" for agents. */
62
+ /** Identifier for the user or agent. Agents use the form `agent:<id>`. */
68
63
  userId?: string;
69
- /** Sync groups the agent belongs to. */
64
+ /** The sync groups this agent belongs to. */
70
65
  syncGroups?: string[];
71
- /** Allow extension with product-specific fields. */
66
+ /** Room for your own product-specific fields. */
72
67
  [key: string]: unknown;
73
68
  }
@@ -1,10 +1,9 @@
1
1
  /**
2
- * Agent-SDK abstractions. The engine's data vocabulary
3
- * (`Peer`, `Activity`, `Claim`, `ActiveClaim`,
4
- * `PresenceUpdatePayload`, `PresenceKind`) lives in
5
- * `../types/streams.ts`. This file holds only the bits that are
6
- * specific to the agent module: the `PresenceAnnouncer` abstraction
7
- * (transport-agnostic announce contract) and `AgentContext` (the AI
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
- * `coordinatedTool` the one-liner that turns an Ablo model write into a Vercel
3
- * AI SDK tool with multi-agent coordination already handled, so an AI agent can
4
- * contribute to shared state without ever silently clobbering a concurrent
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 base `./ai-sdk` pattern (see index.ts) is "write your own `tool()` and
8
- * call `ablo.<model>.update({ id, data, claim })` inside `execute`". That's the
9
- * right amount of control when a tool does something bespoke. But the *common*
10
- * case — "the agent produced some content; save it into the shared row" — should
11
- * not require every integration to re-derive optimistic concurrency by hand. This
12
- * collapses it to a declaration:
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
- * `apply` is the whole API: a pure function of `(freshest row, tool input) →
30
- * patch`, exactly like React's `setState(prev => next)`. Everything underneath
31
- * reading the latest row, the compare-and-swap, the jittered backoff between
32
- * reconcile rounds, releasing claims is the runtime's job, not yours.
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 (pick by how writers should relate; all verified to converge
35
- * under N-way agent contention)
34
+ * ## Strategies
36
35
  *
37
- * - `'merge'` *(default)* delegates straight to the functional update
38
- * `ablo.<model>.update(id, current => apply(current, input))`. The SDK re-reads
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
- * - `'claim'` mutual exclusion. Takes a fail-fast claim; if another participant
47
- * holds the row it returns `{ status: 'claimed' }` so the *model* decides to
48
- * retry (a legible signal beats a hidden wait when the agent might do something
49
- * better with its turn). Works regardless of conflict policy.
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
- * - `'queue'` fair-ish serialization over stateless HTTP, the SQS shape: a
52
- * client poll-acquire loop (true FIFO needs a socket) until the claim is granted
53
- * or `poll.timeoutMs` elapses. The model calls once and the tool waits its turn.
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
- // The setState of the data layer: read fresh apply CAS re-read +
67
- // re-apply with backoff on any concurrent write. Self-healing; the model
68
- // never sees a conflict. (Backoff lives in the shared reconcile loop.)
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 / queue both take a claim, write under it, and release. The only
75
- // difference is what they do when the row is already held: claim returns the
76
- // signal to the model; queue waits and retries (SQS-style poll-acquire).
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': SQS-style poll-acquire over stateless HTTP.
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
- * Coordination context middleware reads peer claims on the same
3
- * entity from the sync engine's presence stream and injects a brief
4
- * coordination note into the prompt before the LLM call.
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
- * The complement of `claim-broadcast.ts`: that one declares what
7
- * THIS agent is about to do; this one reads what OTHERS are doing
8
- * and tells the LLM about it. Together they make multiplayer-with-
9
- * AI structurally real the AI knows when a human or another
10
- * agent is mid-edit and can defer / phrase its work as
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
- * Open-source-clean: depends only on `@ai-sdk/provider` types and
15
- * the package's own `SyncAgent`. Consumers compose via the AI
16
- * SDK's `wrapLanguageModel`.
17
- *
18
- * Cost: zero extra LLM calls (read happens locally from the agent's
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
- * Build the middleware. When `agent` or `target` is null, returns a
25
- * pass-through.
20
+ * Builds the coordination-context middleware. If `agent` or `target` is null, the
21
+ * middleware passes the prompt through unchanged.
26
22
  *
27
- * Generic over the schema record see `claimBroadcastMiddleware`
28
- * for why `Ablo<S>` and `Ablo<SchemaRecord>` aren't structurally
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
- // Read peer claims on the same target. Synchronous lookup
40
- // against the engine's reactive claims.others array no I/O.
41
- const peerClaims = agent.claims.others.filter((claim) => claim.target.type === target.type &&
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
- * Format a one-paragraph coordination note for the LLM. Includes
76
- * who's editing and what (when known). Kept short the goal is
77
- * "AI knows," not "AI gets a wall of text."
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
- if (claims.length === 1) {
82
- const c = claims[0];
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}. ` +