@abloatai/ablo 0.26.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 (398) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +101 -85
  3. package/dist/BaseSyncedStore.d.ts +85 -88
  4. package/dist/BaseSyncedStore.js +131 -147
  5. package/dist/Database.d.ts +54 -68
  6. package/dist/Database.js +97 -113
  7. package/dist/{ObjectPool.d.ts → InstanceCache.d.ts} +10 -13
  8. package/dist/{ObjectPool.js → InstanceCache.js} +85 -83
  9. package/dist/LazyReferenceCollection.d.ts +11 -15
  10. package/dist/LazyReferenceCollection.js +12 -16
  11. package/dist/Model.d.ts +37 -52
  12. package/dist/Model.js +46 -61
  13. package/dist/ModelRegistry.d.ts +21 -19
  14. package/dist/ModelRegistry.js +23 -27
  15. package/dist/NetworkMonitor.d.ts +5 -6
  16. package/dist/NetworkMonitor.js +5 -6
  17. package/dist/SyncClient.d.ts +112 -112
  18. package/dist/SyncClient.js +165 -172
  19. package/dist/adapters/alwaysOnline.d.ts +6 -8
  20. package/dist/adapters/alwaysOnline.js +6 -8
  21. package/dist/adapters/inMemoryStorage.d.ts +9 -9
  22. package/dist/adapters/inMemoryStorage.js +9 -9
  23. package/dist/agent/Agent.d.ts +27 -32
  24. package/dist/agent/Agent.js +18 -19
  25. package/dist/agent/index.d.ts +4 -4
  26. package/dist/agent/index.js +5 -5
  27. package/dist/agent/session.d.ts +47 -44
  28. package/dist/agent/session.js +37 -48
  29. package/dist/agent/types.d.ts +26 -31
  30. package/dist/agent/types.js +6 -7
  31. package/dist/ai-sdk/coordinatedTool.d.ts +108 -0
  32. package/dist/ai-sdk/{coordinated-tool.js → coordinatedTool.js} +44 -38
  33. package/dist/ai-sdk/coordinationContext.d.ts +46 -0
  34. package/dist/ai-sdk/{coordination-context.js → coordinationContext.js} +26 -33
  35. package/dist/ai-sdk/index.d.ts +25 -22
  36. package/dist/ai-sdk/index.js +25 -22
  37. package/dist/ai-sdk/wrap.d.ts +6 -7
  38. package/dist/ai-sdk/wrap.js +1 -1
  39. package/dist/auth/credentialPolicy.d.ts +69 -74
  40. package/dist/auth/credentialPolicy.js +51 -56
  41. package/dist/auth/credentialSource.d.ts +6 -5
  42. package/dist/auth/credentialSource.js +9 -10
  43. package/dist/auth/index.d.ts +59 -58
  44. package/dist/auth/index.js +31 -37
  45. package/dist/auth/schemas.d.ts +5 -4
  46. package/dist/auth/schemas.js +5 -4
  47. package/dist/batching/index.d.ts +19 -21
  48. package/dist/batching/index.js +14 -17
  49. package/dist/cli.cjs +167 -119
  50. package/dist/client/Ablo.d.ts +73 -73
  51. package/dist/client/Ablo.js +125 -160
  52. package/dist/client/ApiClient.d.ts +30 -19
  53. package/dist/client/ApiClient.js +133 -38
  54. package/dist/client/auth.d.ts +47 -47
  55. package/dist/client/auth.js +108 -117
  56. package/dist/client/claimHeartbeatLoop.d.ts +50 -0
  57. package/dist/client/claimHeartbeatLoop.js +88 -0
  58. package/dist/client/consoleLogger.d.ts +5 -6
  59. package/dist/client/consoleLogger.js +5 -6
  60. package/dist/client/createInternalComponents.d.ts +14 -17
  61. package/dist/client/createInternalComponents.js +25 -30
  62. package/dist/client/createModelProxy.d.ts +130 -120
  63. package/dist/client/createModelProxy.js +152 -122
  64. package/dist/client/credentialEndpoint.d.ts +40 -42
  65. package/dist/client/credentialEndpoint.js +35 -36
  66. package/dist/client/functionalUpdate.d.ts +29 -27
  67. package/dist/client/functionalUpdate.js +21 -21
  68. package/dist/client/hostedEndpoints.d.ts +9 -12
  69. package/dist/client/hostedEndpoints.js +9 -12
  70. package/dist/client/httpClient.d.ts +57 -53
  71. package/dist/client/httpClient.js +29 -31
  72. package/dist/client/identity.d.ts +15 -20
  73. package/dist/client/identity.js +47 -58
  74. package/dist/client/modelRegistration.d.ts +5 -9
  75. package/dist/client/modelRegistration.js +67 -87
  76. package/dist/client/options.d.ts +134 -157
  77. package/dist/client/options.js +3 -7
  78. package/dist/client/registerDataSource.d.ts +9 -9
  79. package/dist/client/registerDataSource.js +15 -16
  80. package/dist/client/resourceTypes.d.ts +64 -75
  81. package/dist/client/resourceTypes.js +4 -10
  82. package/dist/client/schemaConfig.d.ts +31 -43
  83. package/dist/client/schemaConfig.js +38 -50
  84. package/dist/client/sessionMint.d.ts +16 -12
  85. package/dist/client/sessionMint.js +26 -31
  86. package/dist/client/validateAbloOptions.d.ts +12 -14
  87. package/dist/client/validateAbloOptions.js +8 -9
  88. package/dist/client/writeOptionsSchema.d.ts +18 -16
  89. package/dist/client/writeOptionsSchema.js +23 -20
  90. package/dist/client/wsMutationExecutor.d.ts +15 -20
  91. package/dist/client/wsMutationExecutor.js +17 -23
  92. package/dist/context.d.ts +6 -4
  93. package/dist/context.js +6 -4
  94. package/dist/coordination/index.d.ts +10 -8
  95. package/dist/coordination/index.js +14 -12
  96. package/dist/coordination/schema.d.ts +176 -128
  97. package/dist/coordination/schema.js +197 -133
  98. package/dist/coordination/trace.d.ts +9 -10
  99. package/dist/coordination/trace.js +13 -14
  100. package/dist/core/DatabaseManager.d.ts +5 -7
  101. package/dist/core/DatabaseManager.js +15 -19
  102. package/dist/core/QueryProcessor.d.ts +7 -9
  103. package/dist/core/QueryProcessor.js +22 -28
  104. package/dist/core/QueryView.d.ts +8 -8
  105. package/dist/core/QueryView.js +2 -2
  106. package/dist/core/StoreManager.d.ts +12 -14
  107. package/dist/core/StoreManager.js +21 -24
  108. package/dist/core/ViewRegistry.d.ts +5 -5
  109. package/dist/core/ViewRegistry.js +4 -4
  110. package/dist/core/index.d.ts +17 -12
  111. package/dist/core/index.js +32 -26
  112. package/dist/core/openIDBWithTimeout.d.ts +38 -36
  113. package/dist/core/openIDBWithTimeout.js +42 -43
  114. package/dist/core/queryUtils.d.ts +45 -0
  115. package/dist/core/queryUtils.js +69 -0
  116. package/dist/core/storeContract.d.ts +63 -61
  117. package/dist/core/storeContract.js +8 -12
  118. package/dist/environment.d.ts +28 -0
  119. package/dist/environment.js +21 -0
  120. package/dist/errorCodes.d.ts +107 -99
  121. package/dist/errorCodes.js +131 -132
  122. package/dist/errors.d.ts +160 -166
  123. package/dist/errors.js +155 -158
  124. package/dist/index.d.ts +30 -27
  125. package/dist/index.js +89 -86
  126. package/dist/interfaces/index.d.ts +102 -113
  127. package/dist/interfaces/index.js +5 -4
  128. package/dist/keys/index.d.ts +27 -29
  129. package/dist/keys/index.js +41 -40
  130. package/dist/mutators/RecordingTransaction.d.ts +16 -16
  131. package/dist/mutators/RecordingTransaction.js +31 -37
  132. package/dist/mutators/Transaction.d.ts +18 -26
  133. package/dist/mutators/Transaction.js +14 -20
  134. package/dist/mutators/UndoManager.d.ts +122 -131
  135. package/dist/mutators/UndoManager.js +145 -156
  136. package/dist/mutators/defineMutators.d.ts +23 -34
  137. package/dist/mutators/defineMutators.js +14 -20
  138. package/dist/mutators/inverseOp.d.ts +12 -15
  139. package/dist/mutators/inverseOp.js +12 -15
  140. package/dist/mutators/mutateActions.d.ts +10 -9
  141. package/dist/mutators/mutateActions.js +1 -1
  142. package/dist/mutators/readerActions.d.ts +9 -8
  143. package/dist/mutators/readerActions.js +2 -2
  144. package/dist/mutators/undoApply.d.ts +31 -27
  145. package/dist/mutators/undoApply.js +26 -24
  146. package/dist/policy/index.d.ts +5 -3
  147. package/dist/policy/index.js +5 -3
  148. package/dist/policy/types.d.ts +104 -100
  149. package/dist/policy/types.js +67 -66
  150. package/dist/query/client.d.ts +28 -23
  151. package/dist/query/client.js +45 -43
  152. package/dist/query/types.d.ts +37 -60
  153. package/dist/query/types.js +13 -33
  154. package/dist/react/AbloProvider.d.ts +1 -1
  155. package/dist/react/AbloProvider.js +2 -2
  156. package/dist/react/context.d.ts +25 -28
  157. package/dist/react/context.js +9 -10
  158. package/dist/react/index.d.ts +41 -42
  159. package/dist/react/index.js +37 -38
  160. package/dist/react/internalContext.d.ts +17 -19
  161. package/dist/react/useAblo.d.ts +23 -22
  162. package/dist/react/useAblo.js +16 -14
  163. package/dist/react/useCurrentUserId.d.ts +8 -7
  164. package/dist/react/useCurrentUserId.js +8 -7
  165. package/dist/react/useErrorListener.d.ts +7 -7
  166. package/dist/react/useErrorListener.js +10 -11
  167. package/dist/react/useMutationFailureListener.d.ts +8 -8
  168. package/dist/react/useMutationFailureListener.js +8 -8
  169. package/dist/react/useMutators.d.ts +11 -11
  170. package/dist/react/useMutators.js +3 -3
  171. package/dist/react/useReactive.js +2 -2
  172. package/dist/react/useSyncStatus.d.ts +4 -6
  173. package/dist/react/useUndoScope.d.ts +7 -9
  174. package/dist/react/useUndoScope.js +1 -1
  175. package/dist/schema/coordination.d.ts +21 -25
  176. package/dist/schema/coordination.js +21 -25
  177. package/dist/schema/ddl.d.ts +43 -39
  178. package/dist/schema/ddl.js +75 -68
  179. package/dist/schema/ddlLock.d.ts +20 -24
  180. package/dist/schema/ddlLock.js +18 -23
  181. package/dist/schema/diff.d.ts +99 -61
  182. package/dist/schema/diff.js +43 -34
  183. package/dist/schema/field.d.ts +37 -42
  184. package/dist/schema/field.js +35 -48
  185. package/dist/schema/generate.d.ts +12 -12
  186. package/dist/schema/generate.js +12 -12
  187. package/dist/schema/index.d.ts +2 -2
  188. package/dist/schema/index.js +21 -23
  189. package/dist/schema/model.d.ts +118 -143
  190. package/dist/schema/model.js +22 -33
  191. package/dist/schema/openapi.d.ts +10 -9
  192. package/dist/schema/openapi.js +5 -3
  193. package/dist/schema/queries.d.ts +29 -31
  194. package/dist/schema/queries.js +23 -25
  195. package/dist/schema/relation.d.ts +89 -99
  196. package/dist/schema/relation.js +13 -13
  197. package/dist/schema/residency.d.ts +16 -13
  198. package/dist/schema/residency.js +16 -13
  199. package/dist/schema/roles.d.ts +36 -43
  200. package/dist/schema/roles.js +31 -37
  201. package/dist/schema/schema.d.ts +33 -42
  202. package/dist/schema/schema.js +31 -32
  203. package/dist/schema/select.d.ts +13 -13
  204. package/dist/schema/select.js +13 -13
  205. package/dist/schema/serialize.d.ts +28 -31
  206. package/dist/schema/serialize.js +27 -31
  207. package/dist/schema/sugar.d.ts +17 -32
  208. package/dist/schema/sugar.js +14 -29
  209. package/dist/schema/{sync-delta-row.d.ts → syncDeltaRow.d.ts} +26 -49
  210. package/dist/schema/syncDeltaRow.js +89 -0
  211. package/dist/schema/tenancy.d.ts +44 -46
  212. package/dist/schema/tenancy.js +46 -48
  213. package/dist/server/adapter.d.ts +58 -58
  214. package/dist/server/adapter.js +13 -14
  215. package/dist/server/commit.d.ts +60 -64
  216. package/dist/server/index.d.ts +9 -10
  217. package/dist/server/index.js +1 -1
  218. package/dist/server/readConfig.d.ts +70 -0
  219. package/dist/server/readConfig.js +8 -0
  220. package/dist/server/storageMode.d.ts +23 -0
  221. package/dist/server/storageMode.js +17 -0
  222. package/dist/source/adapter.d.ts +30 -25
  223. package/dist/source/adapter.js +10 -10
  224. package/dist/source/adapters/drizzle.d.ts +28 -23
  225. package/dist/source/adapters/drizzle.js +30 -25
  226. package/dist/source/adapters/kysely.d.ts +27 -25
  227. package/dist/source/adapters/kysely.js +24 -23
  228. package/dist/source/adapters/memory.d.ts +8 -7
  229. package/dist/source/adapters/memory.js +9 -8
  230. package/dist/source/adapters/prisma.d.ts +13 -12
  231. package/dist/source/adapters/prisma.js +22 -25
  232. package/dist/source/conformance.d.ts +18 -11
  233. package/dist/source/conformance.js +17 -11
  234. package/dist/source/connector.d.ts +31 -32
  235. package/dist/source/connector.js +28 -28
  236. package/dist/source/connectorProtocol.d.ts +160 -0
  237. package/dist/source/connectorProtocol.js +162 -0
  238. package/dist/source/contract.d.ts +26 -27
  239. package/dist/source/contract.js +28 -29
  240. package/dist/source/factory.d.ts +46 -58
  241. package/dist/source/factory.js +22 -27
  242. package/dist/source/index.d.ts +7 -9
  243. package/dist/source/index.js +12 -14
  244. package/dist/source/migrations.d.ts +9 -9
  245. package/dist/source/migrations.js +9 -9
  246. package/dist/source/next.d.ts +9 -10
  247. package/dist/source/next.js +6 -7
  248. package/dist/source/pushQueue.d.ts +69 -47
  249. package/dist/source/pushQueue.js +32 -28
  250. package/dist/source/signing.d.ts +46 -17
  251. package/dist/source/signing.js +28 -11
  252. package/dist/source/types.d.ts +121 -104
  253. package/dist/source/types.js +13 -14
  254. package/dist/stores/ObjectStore.d.ts +10 -11
  255. package/dist/stores/ObjectStore.js +11 -12
  256. package/dist/stores/ObjectStoreContract.d.ts +12 -15
  257. package/dist/stores/SyncActionStore.d.ts +7 -11
  258. package/dist/stores/SyncActionStore.js +13 -17
  259. package/dist/surface.d.ts +27 -20
  260. package/dist/surface.js +27 -20
  261. package/dist/sync/{BootstrapHelper.d.ts → BootstrapFetcher.d.ts} +36 -42
  262. package/dist/sync/{BootstrapHelper.js → BootstrapFetcher.js} +76 -76
  263. package/dist/sync/ConnectionManager.d.ts +39 -50
  264. package/dist/sync/ConnectionManager.js +55 -66
  265. package/dist/sync/NetworkProbe.d.ts +24 -29
  266. package/dist/sync/NetworkProbe.js +63 -69
  267. package/dist/sync/{HydrationCoordinator.d.ts → OnDemandLoader.d.ts} +42 -41
  268. package/dist/sync/{HydrationCoordinator.js → OnDemandLoader.js} +59 -54
  269. package/dist/sync/{AreaOfInterestManager.d.ts → SubscriptionManager.d.ts} +43 -57
  270. package/dist/sync/{AreaOfInterestManager.js → SubscriptionManager.js} +43 -51
  271. package/dist/sync/SyncWebSocket.d.ts +139 -165
  272. package/dist/sync/SyncWebSocket.js +191 -223
  273. package/dist/sync/awaitClaimGrant.d.ts +18 -18
  274. package/dist/sync/awaitClaimGrant.js +11 -11
  275. package/dist/sync/bootstrapApply.d.ts +34 -24
  276. package/dist/sync/bootstrapApply.js +27 -19
  277. package/dist/sync/commitFrames.d.ts +21 -20
  278. package/dist/sync/commitFrames.js +18 -18
  279. package/dist/sync/createClaimStream.d.ts +23 -22
  280. package/dist/sync/createClaimStream.js +105 -23
  281. package/dist/sync/createPresenceStream.d.ts +19 -18
  282. package/dist/sync/createPresenceStream.js +25 -26
  283. package/dist/sync/createSnapshot.d.ts +12 -14
  284. package/dist/sync/createSnapshot.js +20 -26
  285. package/dist/sync/credentialLifecycle.d.ts +104 -104
  286. package/dist/sync/credentialLifecycle.js +140 -147
  287. package/dist/sync/deltaPipeline.d.ts +36 -34
  288. package/dist/sync/deltaPipeline.js +64 -65
  289. package/dist/sync/groupChange.d.ts +63 -61
  290. package/dist/sync/groupChange.js +74 -78
  291. package/dist/sync/heartbeat.d.ts +34 -33
  292. package/dist/sync/heartbeat.js +31 -31
  293. package/dist/sync/participants.d.ts +19 -19
  294. package/dist/sync/schemas.d.ts +3 -2
  295. package/dist/sync/schemas.js +14 -10
  296. package/dist/sync/syncCursor.d.ts +17 -21
  297. package/dist/sync/syncCursor.js +17 -21
  298. package/dist/sync/syncPlan.d.ts +28 -36
  299. package/dist/sync/syncPlan.js +18 -19
  300. package/dist/sync/syncPosition.d.ts +54 -49
  301. package/dist/sync/syncPosition.js +57 -52
  302. package/dist/sync/wsFrameHandlers.d.ts +35 -36
  303. package/dist/sync/wsFrameHandlers.js +63 -67
  304. package/dist/testing/fixtures/bootstrap.d.ts +12 -6
  305. package/dist/testing/fixtures/bootstrap.js +12 -6
  306. package/dist/testing/fixtures/deltas.d.ts +30 -33
  307. package/dist/testing/fixtures/deltas.js +30 -33
  308. package/dist/testing/fixtures/models.d.ts +11 -10
  309. package/dist/testing/fixtures/models.js +11 -10
  310. package/dist/testing/helpers/{react-wrapper.d.ts → reactWrapper.d.ts} +13 -10
  311. package/dist/testing/helpers/{react-wrapper.js → reactWrapper.js} +15 -12
  312. package/dist/testing/helpers/{sync-engine-harness.d.ts → syncEngineHarness.d.ts} +17 -15
  313. package/dist/testing/helpers/{sync-engine-harness.js → syncEngineHarness.js} +12 -10
  314. package/dist/testing/helpers/wait.d.ts +13 -8
  315. package/dist/testing/helpers/wait.js +13 -8
  316. package/dist/testing/index.d.ts +3 -3
  317. package/dist/testing/index.js +2 -2
  318. package/dist/testing/mocks/MockMutationExecutor.d.ts +18 -17
  319. package/dist/testing/mocks/MockMutationExecutor.js +15 -14
  320. package/dist/testing/mocks/MockNetworkMonitor.d.ts +8 -8
  321. package/dist/testing/mocks/MockNetworkMonitor.js +8 -8
  322. package/dist/testing/mocks/MockSyncContext.d.ts +20 -17
  323. package/dist/testing/mocks/MockSyncContext.js +15 -13
  324. package/dist/testing/mocks/MockSyncStore.d.ts +10 -10
  325. package/dist/testing/mocks/MockSyncStore.js +11 -11
  326. package/dist/testing/mocks/MockWebSocket.d.ts +26 -22
  327. package/dist/testing/mocks/MockWebSocket.js +22 -21
  328. package/dist/transactions/TransactionQueue.d.ts +181 -176
  329. package/dist/transactions/TransactionQueue.js +338 -350
  330. package/dist/transactions/TransactionStore.d.ts +6 -4
  331. package/dist/transactions/TransactionStore.js +6 -4
  332. package/dist/transactions/UnconfirmedWrites.d.ts +82 -0
  333. package/dist/transactions/UnconfirmedWrites.js +104 -0
  334. package/dist/transactions/coalesceRules.d.ts +41 -17
  335. package/dist/transactions/coalesceRules.js +40 -17
  336. package/dist/transactions/commitPayload.d.ts +48 -52
  337. package/dist/transactions/commitPayload.js +48 -57
  338. package/dist/transactions/deltaConfirmation.d.ts +20 -22
  339. package/dist/transactions/deltaConfirmation.js +37 -45
  340. package/dist/transactions/optimisticApply.d.ts +49 -0
  341. package/dist/transactions/optimisticApply.js +65 -0
  342. package/dist/transactions/{persistedReplay.d.ts → replayValidation.d.ts} +28 -22
  343. package/dist/transactions/{persistedReplay.js → replayValidation.js} +33 -27
  344. package/dist/types/global.d.ts +46 -41
  345. package/dist/types/global.js +20 -19
  346. package/dist/types/index.d.ts +71 -77
  347. package/dist/types/index.js +22 -22
  348. package/dist/types/modelData.d.ts +6 -8
  349. package/dist/types/modelData.js +5 -7
  350. package/dist/types/participant.d.ts +10 -11
  351. package/dist/types/participant.js +6 -8
  352. package/dist/types/streams.d.ts +208 -195
  353. package/dist/types/streams.js +7 -7
  354. package/dist/utils/asyncIterator.d.ts +25 -32
  355. package/dist/utils/asyncIterator.js +25 -32
  356. package/dist/utils/duration.d.ts +12 -15
  357. package/dist/utils/duration.js +12 -15
  358. package/dist/utils/mobxSetup.d.ts +53 -0
  359. package/dist/utils/{mobx-setup.js → mobxSetup.js} +42 -98
  360. package/dist/webhooks/events.d.ts +21 -16
  361. package/dist/webhooks/events.js +10 -8
  362. package/dist/webhooks/index.d.ts +5 -7
  363. package/dist/webhooks/index.js +5 -7
  364. package/dist/{schema/sync-delta-wire.d.ts → wire/delta.d.ts} +58 -41
  365. package/dist/wire/delta.js +114 -0
  366. package/dist/wire/errorEnvelope.d.ts +30 -31
  367. package/dist/wire/errorEnvelope.js +34 -40
  368. package/dist/wire/frames.d.ts +79 -86
  369. package/dist/wire/frames.js +26 -33
  370. package/dist/wire/index.d.ts +14 -12
  371. package/dist/wire/index.js +30 -26
  372. package/dist/wire/listEnvelope.d.ts +16 -23
  373. package/dist/wire/listEnvelope.js +7 -6
  374. package/dist/wire/protocol.d.ts +25 -32
  375. package/dist/wire/protocol.js +25 -32
  376. package/dist/wire/protocolVersion.d.ts +44 -40
  377. package/dist/wire/protocolVersion.js +44 -40
  378. package/docs/coordination.md +59 -0
  379. package/package.json +11 -10
  380. package/dist/ai-sdk/coordinated-tool.d.ts +0 -101
  381. package/dist/ai-sdk/coordination-context.d.ts +0 -52
  382. package/dist/core/query-utils.d.ts +0 -34
  383. package/dist/core/query-utils.js +0 -59
  384. package/dist/schema/sync-delta-row.js +0 -103
  385. package/dist/schema/sync-delta-wire.js +0 -102
  386. package/dist/server/read-config.d.ts +0 -67
  387. package/dist/server/read-config.js +0 -8
  388. package/dist/server/storage-mode.d.ts +0 -8
  389. package/dist/server/storage-mode.js +0 -28
  390. package/dist/source/connector-protocol.d.ts +0 -159
  391. package/dist/source/connector-protocol.js +0 -161
  392. package/dist/transactions/OptimisticEchoTracker.d.ts +0 -82
  393. package/dist/transactions/OptimisticEchoTracker.js +0 -104
  394. package/dist/transactions/mutation-error-handler.d.ts +0 -5
  395. package/dist/transactions/mutation-error-handler.js +0 -39
  396. package/dist/transactions/optimistic.d.ts +0 -24
  397. package/dist/transactions/optimistic.js +0 -45
  398. package/dist/utils/mobx-setup.d.ts +0 -42
@@ -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,13 +32,10 @@ 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
- // Type compares case-insensitively: observed claims carry the WIRE
42
- // dialect (lowercased typename, `slidedeck`), while callers naturally
43
- // write the schema typename (`SlideDeck`) — the same normalization the
44
- // commit plane applies (`modelMap` lookups lowercase, and
45
- // `targetsOverlap` below already lowercases field/path).
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`).
46
39
  const wantedType = target.type.toLowerCase();
47
40
  const peerClaims = agent.claims.others.filter((claim) => claim.target.type.toLowerCase() === wantedType &&
48
41
  claim.target.id === target.id &&
@@ -78,9 +71,9 @@ function targetsOverlap(claimTarget, target) {
78
71
  return fieldOverlaps && rangeOverlaps;
79
72
  }
80
73
  /**
81
- * Format a one-paragraph coordination note for the LLM. Includes
82
- * who's editing and what (when known). Kept short the goal is
83
- * "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.
84
77
  */
85
78
  function formatCoordinationNote(claims, target) {
86
79
  const entityLabel = target.type.toLowerCase();
@@ -72,22 +72,24 @@
72
72
  * to one entity before any tool is chosen; tool implementations stay exactly
73
73
  * the same.
74
74
  *
75
- * ## Multi-agent coordination — the canonical way
76
- *
77
- * When several agents (or agents + humans) write the SAME row concurrently, the
78
- * outcome is decided by **(write path) × (the model's conflict policy)**, NOT by
79
- * how smart the model is. The same model silently loses 3 of 4 concurrent
80
- * contributions through a blind whole-row write, and lands all 4 through a
81
- * coordinated one because the coordinated write returns a *signal* the model
82
- * (or the runtime) acts on. Two empirical laws fall out:
83
- *
84
- * 1. **Surface the signal.** A write that swallows the conflict and reports
85
- * success is the footgun. Every robust path returns a legible result
86
- * (`reject` re-read & retry; `claimed` → the model tries again) instead of
87
- * clobbering. Reaching for a bigger model does not fix a silent write.
88
- * 2. **Back off.** Under N-way contention, writers that retry in lock-step just
89
- * re-collide. The shared reconcile loop already jitters its backoff; any
90
- * hand-rolled retry must too, or it exhausts its budget and drops a writer.
75
+ * ## Multi-agent coordination
76
+ *
77
+ * When several agents, or agents and people, write the same row at once, the
78
+ * outcome depends on the write path and the model's conflict policy, not on how
79
+ * capable the model is. The same model silently loses three of four concurrent
80
+ * contributions through a blind whole-row write, yet lands all four through a
81
+ * coordinated one, because a coordinated write returns a signal the model or the
82
+ * runtime can act on. Two rules follow:
83
+ *
84
+ * 1. Surface the signal. A write that swallows the conflict and reports success
85
+ * is the trap. Every reliable path returns a legible result instead of
86
+ * overwriting a rejection leads to a re-read and retry, and a `'claimed'`
87
+ * result leads the model to try again. A larger model does not fix a silent
88
+ * write.
89
+ * 2. Back off. Under heavy contention, writers that retry in lock-step simply
90
+ * collide again. The shared reconcile loop already jitters its backoff, and
91
+ * any retry you write by hand should too, or it exhausts its budget and drops
92
+ * a writer.
91
93
  *
92
94
  * `coordinatedTool` (below) encodes both. Prefer it over a hand-written tool for
93
95
  * "save the agent's contribution into the shared row":
@@ -107,12 +109,13 @@
107
109
  * |----------|-------------------|---------------|------------------------|
108
110
  * | `merge` | accumulate (CAS) | re-read + re-apply (silent, backed off) | must be `reject` (default) |
109
111
  * | `claim` | mutual exclusion | returns `{status:'claimed'}` → model retries | any |
110
- * | `queue` | FIFO-ish (SQS) | poll-acquire until granted / timeout | any |
112
+ * | `queue` | FIFO-ish (poll) | poll-acquire until granted / timeout | any |
111
113
  *
112
- * Note: a model declaring `agentsNotify()` HOLDS a losing write instead of
113
- * rejecting it, which defeats `merge`'s reconcile (the loser is dropped, not
114
- * retried). Use `agentsReject()` for accumulate semantics, or `claim`/`queue`.
114
+ * Note: a model that declares `agentsNotify()` holds a losing write rather than
115
+ * rejecting it, which defeats `'merge'`'s reconcile loop — the loser is dropped
116
+ * instead of retried. Use `agentsReject()` for accumulate semantics, or the
117
+ * `'claim'` or `'queue'` strategy.
115
118
  */
116
- export { coordinationContextMiddleware, type CoordinationContextMiddlewareOptions, type ClaimTarget, } from './coordination-context.js';
119
+ export { coordinationContextMiddleware, type CoordinationContextMiddlewareOptions, type ClaimTarget, } from './coordinationContext.js';
117
120
  export { wrapWithMultiplayer, type WrapWithMultiplayerOptions } from './wrap.js';
118
- export { coordinatedTool, type CoordinationStrategy, type CoordinatedToolOptions, type CoordinatedWriteResult, } from './coordinated-tool.js';
121
+ export { coordinatedTool, type CoordinationStrategy, type CoordinatedToolOptions, type CoordinatedWriteResult, } from './coordinatedTool.js';
@@ -72,22 +72,24 @@
72
72
  * to one entity before any tool is chosen; tool implementations stay exactly
73
73
  * the same.
74
74
  *
75
- * ## Multi-agent coordination — the canonical way
76
- *
77
- * When several agents (or agents + humans) write the SAME row concurrently, the
78
- * outcome is decided by **(write path) × (the model's conflict policy)**, NOT by
79
- * how smart the model is. The same model silently loses 3 of 4 concurrent
80
- * contributions through a blind whole-row write, and lands all 4 through a
81
- * coordinated one because the coordinated write returns a *signal* the model
82
- * (or the runtime) acts on. Two empirical laws fall out:
83
- *
84
- * 1. **Surface the signal.** A write that swallows the conflict and reports
85
- * success is the footgun. Every robust path returns a legible result
86
- * (`reject` re-read & retry; `claimed` → the model tries again) instead of
87
- * clobbering. Reaching for a bigger model does not fix a silent write.
88
- * 2. **Back off.** Under N-way contention, writers that retry in lock-step just
89
- * re-collide. The shared reconcile loop already jitters its backoff; any
90
- * hand-rolled retry must too, or it exhausts its budget and drops a writer.
75
+ * ## Multi-agent coordination
76
+ *
77
+ * When several agents, or agents and people, write the same row at once, the
78
+ * outcome depends on the write path and the model's conflict policy, not on how
79
+ * capable the model is. The same model silently loses three of four concurrent
80
+ * contributions through a blind whole-row write, yet lands all four through a
81
+ * coordinated one, because a coordinated write returns a signal the model or the
82
+ * runtime can act on. Two rules follow:
83
+ *
84
+ * 1. Surface the signal. A write that swallows the conflict and reports success
85
+ * is the trap. Every reliable path returns a legible result instead of
86
+ * overwriting a rejection leads to a re-read and retry, and a `'claimed'`
87
+ * result leads the model to try again. A larger model does not fix a silent
88
+ * write.
89
+ * 2. Back off. Under heavy contention, writers that retry in lock-step simply
90
+ * collide again. The shared reconcile loop already jitters its backoff, and
91
+ * any retry you write by hand should too, or it exhausts its budget and drops
92
+ * a writer.
91
93
  *
92
94
  * `coordinatedTool` (below) encodes both. Prefer it over a hand-written tool for
93
95
  * "save the agent's contribution into the shared row":
@@ -107,12 +109,13 @@
107
109
  * |----------|-------------------|---------------|------------------------|
108
110
  * | `merge` | accumulate (CAS) | re-read + re-apply (silent, backed off) | must be `reject` (default) |
109
111
  * | `claim` | mutual exclusion | returns `{status:'claimed'}` → model retries | any |
110
- * | `queue` | FIFO-ish (SQS) | poll-acquire until granted / timeout | any |
112
+ * | `queue` | FIFO-ish (poll) | poll-acquire until granted / timeout | any |
111
113
  *
112
- * Note: a model declaring `agentsNotify()` HOLDS a losing write instead of
113
- * rejecting it, which defeats `merge`'s reconcile (the loser is dropped, not
114
- * retried). Use `agentsReject()` for accumulate semantics, or `claim`/`queue`.
114
+ * Note: a model that declares `agentsNotify()` holds a losing write rather than
115
+ * rejecting it, which defeats `'merge'`'s reconcile loop — the loser is dropped
116
+ * instead of retried. Use `agentsReject()` for accumulate semantics, or the
117
+ * `'claim'` or `'queue'` strategy.
115
118
  */
116
- export { coordinationContextMiddleware, } from './coordination-context.js';
119
+ export { coordinationContextMiddleware, } from './coordinationContext.js';
117
120
  export { wrapWithMultiplayer } from './wrap.js';
118
- export { coordinatedTool, } from './coordinated-tool.js';
121
+ export { coordinatedTool, } from './coordinatedTool.js';
@@ -29,7 +29,7 @@ import { wrapLanguageModel } from 'ai';
29
29
  import type { LanguageModelV3, LanguageModelV3Middleware } from '@ai-sdk/provider';
30
30
  import type { Ablo } from '../client/Ablo.js';
31
31
  import type { SchemaRecord } from '../schema/schema.js';
32
- import { type ClaimTarget } from './coordination-context.js';
32
+ import { type ClaimTarget } from './coordinationContext.js';
33
33
  export interface WrapWithMultiplayerOptions<R extends SchemaRecord = SchemaRecord> {
34
34
  /** The base language model to wrap. Consumer brings their own. */
35
35
  readonly model: LanguageModelV3;
@@ -52,14 +52,13 @@ export interface WrapWithMultiplayerOptions<R extends SchemaRecord = SchemaRecor
52
52
  */
53
53
  readonly excludeClaimIds?: readonly string[];
54
54
  /**
55
- * Optional extra middleware to compose. Runs in the order given,
56
- * INSIDE the multiplayer middlewares (so the multiplayer wrap is
57
- * the outer-most). Useful for caching, observability, custom
58
- * transforms that should not affect the multiplayer signal.
55
+ * Extra middleware to compose. It runs in the order given, nested inside the
56
+ * multiplayer middleware, so the multiplayer wrap stays the outermost layer.
57
+ * Use it for caching, observability, or custom transforms that should not
58
+ * affect the multiplayer signal.
59
59
  *
60
60
  * For full control over ordering, skip this helper and call
61
- * `wrapLanguageModel` directly with all middleware in the order
62
- * you want.
61
+ * `wrapLanguageModel` directly with all the middleware in the order you want.
63
62
  */
64
63
  readonly extraMiddleware?: readonly LanguageModelV3Middleware[];
65
64
  }