@abloatai/ablo 0.22.1 → 0.24.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.
@@ -71,6 +71,48 @@
71
71
  * `wrapWithMultiplayer` is optional. Use it when the whole model call is scoped
72
72
  * to one entity before any tool is chosen; tool implementations stay exactly
73
73
  * the same.
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.
91
+ *
92
+ * `coordinatedTool` (below) encodes both. Prefer it over a hand-written tool for
93
+ * "save the agent's contribution into the shared row":
94
+ *
95
+ * ```ts
96
+ * import { coordinatedTool } from '@abloatai/ablo/ai-sdk';
97
+ * const saveSection = coordinatedTool(ablo.documents, {
98
+ * description: 'Save your section into the shared document.',
99
+ * inputSchema: z.object({ text: z.string() }),
100
+ * id: () => DOC_ID,
101
+ * apply: (current, { text }) => ({ content: appendBlock(current.content, text) }),
102
+ * strategy: 'merge', // 'merge' (default, self-healing) | 'claim' | 'queue'
103
+ * });
104
+ * ```
105
+ *
106
+ * | strategy | writers relate by | on contention | model conflict policy |
107
+ * |----------|-------------------|---------------|------------------------|
108
+ * | `merge` | accumulate (CAS) | re-read + re-apply (silent, backed off) | must be `reject` (default) |
109
+ * | `claim` | mutual exclusion | returns `{status:'claimed'}` → model retries | any |
110
+ * | `queue` | FIFO-ish (SQS) | poll-acquire until granted / timeout | any |
111
+ *
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`.
74
115
  */
75
116
  export { coordinationContextMiddleware, } from './coordination-context.js';
76
117
  export { wrapWithMultiplayer } from './wrap.js';
118
+ export { coordinatedTool, } from './coordinated-tool.js';