@abloatai/ablo 0.3.1 → 0.5.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 (92) hide show
  1. package/CHANGELOG.md +54 -1
  2. package/NOTICE +2 -2
  3. package/README.md +99 -78
  4. package/dist/BaseSyncedStore.d.ts +3 -2
  5. package/dist/agent/Agent.d.ts +1 -1
  6. package/dist/agent/Agent.js +1 -1
  7. package/dist/agent/index.d.ts +4 -4
  8. package/dist/agent/index.js +6 -6
  9. package/dist/agent/types.d.ts +1 -1
  10. package/dist/ai-sdk/index.d.ts +3 -3
  11. package/dist/ai-sdk/index.js +3 -3
  12. package/dist/ai-sdk/intent-broadcast.d.ts +1 -1
  13. package/dist/ai-sdk/intent-broadcast.js +1 -1
  14. package/dist/auth/index.d.ts +1 -1
  15. package/dist/client/Ablo.d.ts +53 -27
  16. package/dist/client/Ablo.js +32 -1
  17. package/dist/client/auth.d.ts +3 -3
  18. package/dist/client/auth.js +5 -5
  19. package/dist/client/createModelProxy.d.ts +118 -32
  20. package/dist/client/createModelProxy.js +87 -44
  21. package/dist/client/index.d.ts +3 -3
  22. package/dist/client/index.js +3 -3
  23. package/dist/config/index.d.ts +1 -1
  24. package/dist/config/index.js +1 -1
  25. package/dist/core/index.d.ts +1 -1
  26. package/dist/core/index.js +2 -2
  27. package/dist/errors.d.ts +9 -7
  28. package/dist/errors.js +9 -7
  29. package/dist/index.d.ts +20 -6
  30. package/dist/index.js +41 -22
  31. package/dist/interfaces/headless.d.ts +1 -1
  32. package/dist/interfaces/headless.js +2 -2
  33. package/dist/policy/index.d.ts +2 -2
  34. package/dist/policy/index.js +2 -2
  35. package/dist/policy/types.d.ts +10 -0
  36. package/dist/principal.d.ts +3 -3
  37. package/dist/principal.js +3 -3
  38. package/dist/query/client.d.ts +7 -6
  39. package/dist/react/AbloProvider.d.ts +44 -1
  40. package/dist/react/AbloProvider.js +3 -1
  41. package/dist/react/ClientSideSuspense.d.ts +1 -1
  42. package/dist/react/SyncGroupProvider.js +1 -1
  43. package/dist/react/context.d.ts +1 -1
  44. package/dist/react/context.js +1 -1
  45. package/dist/react/index.d.ts +1 -1
  46. package/dist/react/index.js +1 -1
  47. package/dist/react/useCurrentUserId.js +1 -1
  48. package/dist/react/useErrorListener.js +1 -1
  49. package/dist/react/useMutate.d.ts +1 -1
  50. package/dist/react/useMutationFailureListener.js +1 -1
  51. package/dist/react/useReader.d.ts +1 -1
  52. package/dist/schema/field.d.ts +1 -1
  53. package/dist/schema/field.js +1 -1
  54. package/dist/schema/index.d.ts +2 -2
  55. package/dist/schema/index.js +2 -2
  56. package/dist/schema/model.d.ts +2 -2
  57. package/dist/schema/model.js +2 -2
  58. package/dist/schema/queries.d.ts +1 -1
  59. package/dist/schema/queries.js +1 -1
  60. package/dist/schema/relation.d.ts +1 -1
  61. package/dist/schema/relation.js +1 -1
  62. package/dist/schema/schema.d.ts +1 -1
  63. package/dist/schema/schema.js +1 -1
  64. package/dist/source/index.d.ts +22 -28
  65. package/dist/source/index.js +23 -20
  66. package/dist/source/pushQueue.d.ts +1 -1
  67. package/dist/source/pushQueue.js +2 -2
  68. package/dist/sync/SyncWebSocket.d.ts +20 -5
  69. package/dist/sync/createIntentStream.js +7 -0
  70. package/dist/testing/fixtures/models.d.ts +1 -1
  71. package/dist/testing/fixtures/models.js +1 -1
  72. package/dist/testing/helpers/react-wrapper.d.ts +2 -2
  73. package/dist/testing/helpers/react-wrapper.js +2 -2
  74. package/dist/testing/index.d.ts +1 -1
  75. package/dist/testing/index.js +1 -1
  76. package/dist/types/streams.d.ts +41 -1
  77. package/docs/api.md +78 -20
  78. package/docs/data-sources.md +50 -16
  79. package/docs/examples/ai-sdk-tool.md +14 -31
  80. package/docs/examples/existing-python-backend.md +6 -6
  81. package/docs/integration-guide.md +8 -7
  82. package/docs/interaction-model.md +16 -4
  83. package/docs/mcp.md +1 -1
  84. package/docs/quickstart.md +20 -18
  85. package/examples/data-source/README.md +1 -1
  86. package/examples/data-source/ablo-driver.ts +5 -5
  87. package/examples/data-source/customer-server.ts +10 -10
  88. package/examples/data-source/run.ts +9 -11
  89. package/examples/data-source/schema.ts +1 -1
  90. package/examples/quickstart.ts +2 -2
  91. package/llms.txt +1 -1
  92. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,12 +1,65 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 9154c1b: Rename intent handle methods to a clearer claim vocabulary; add `AbloProvider` `bootstrapMode`.
8
+
9
+ BREAKING — on the model intent handle (`ablo.<model>.intent(id)`):
10
+ `acquire`→`claim`, `acquireOrAwait`→`claimOrWait`, `settled`→`whenFree`,
11
+ `release`→`finish`, `revoke`→`cancel`. The lower-level `IntentHandle` /
12
+ `IntentLeaseHandle` (`ablo.intents.*`) are unchanged.
13
+
14
+ Also: `AbloProvider` gains a `bootstrapMode` prop (`'full' | 'none'`) to skip the
15
+ baseline pull on read-light pages; `StaleContextConflict` gains an optional
16
+ `conflictingFields`; README + JSDoc clarity pass and a new HTTP API section.
17
+
18
+ ## 0.4.0
19
+
20
+ ### Minor Changes
21
+
22
+ - Per-entity coordination intents on the model accessor.
23
+
24
+ Coordinate writes to an entity through the same accessor you read it with —
25
+ `ablo.<model>.intent(id)`, returning a `ModelIntentHandle`. Intent state is one
26
+ self-describing object (`{ object: 'intent', id, status, target, action, heldBy,
27
+ participantKind, createdAt?, expiresAt? }`) with a single lifecycle:
28
+ `status: 'active' | 'committed' | 'expired' | 'canceled'`. An `active` intent is
29
+ the lock.
30
+
31
+ ### Added
32
+ - `ablo.<model>.intent(id)` → `ModelIntentHandle<T>`, beside `create` / `update`
33
+ / `retrieve` / `load` on every model.
34
+ - Read side (any participant, synchronous + reactive): `current` (the holder's
35
+ intent, or `null`), `status` (`'idle'` when free), `settled()`.
36
+ - Write side (the holder): `acquire()`, `acquireOrAwait()`, lease-guarded
37
+ `update()`, `release()`, `revoke()`.
38
+ - `AsyncDisposable`: `await using lock = ablo.<model>.intent(id)` auto-releases
39
+ on scope exit.
40
+ - `acquireOrAwait()` — serialize-on-contention: take the lease, or wait out the
41
+ current holder, re-read the changed row, then take it. The caller never branches
42
+ on who holds the target — it just gets the target safely. Bind it to an agent's
43
+ write-tool boundary so agents never reason about coordination.
44
+ - New exports: `ModelIntentHandle`, `ModelIntentAcquireOptions`.
45
+
46
+ ### Changed
47
+ - `acquire()` is fire-and-forget over the socket — it does not throw on conflict.
48
+ Resolve contention with `acquireOrAwait()` (wait) or read `current` for a
49
+ reactive "who's editing" badge, rather than catching a rejection.
50
+
51
+ ### Deprecated
52
+ - Participant-level `intents.claim()` / `onRejected()` and the `intent_rejected`
53
+ wire frame still work but are superseded by the per-model handle. Their removal
54
+ is a future breaking change.
55
+
3
56
  ## Unreleased
4
57
 
5
58
  Schema-driven identity sync-group composition, plus a terser capability surface.
6
59
 
7
60
  The convention for deriving a participant's allowed sync-groups from its identity is now declared on the consumer's schema as an open registration. Consumers with a `{ regionId, customerId }` identity shape declare their own roles instead of receiving any built-in prefixes from the SDK.
8
61
 
9
- Capability fields shed their redundant `allowed` prefix to match the surrounding vocabulary — capability inputs always describe what the bearer *can* touch, so the prefix was doing no disambiguation work for the consumer.
62
+ Capability fields shed their redundant `allowed` prefix to match the surrounding vocabulary — capability inputs always describe what the bearer _can_ touch, so the prefix was doing no disambiguation work for the consumer.
10
63
 
11
64
  ### Added
12
65
 
package/NOTICE CHANGED
@@ -1,4 +1,4 @@
1
- @ablo/sync-engine
1
+ @abloatai/ablo
2
2
  Copyright 2025-2026 Fablo Innovation AB
3
3
 
4
4
  This product includes software developed by Fablo Innovation AB
@@ -7,6 +7,6 @@ This product includes software developed by Fablo Innovation AB
7
7
  "Ablo" is a trademark of Fablo Innovation AB. This license does not grant
8
8
  permission to use the Ablo name, logo, or trademarks. Third parties
9
9
  may describe their use of or compatibility with Ablo factually (e.g.,
10
- "built with @ablo/sync-engine") but may not use the Ablo name in a way
10
+ "built with @abloatai/ablo") but may not use the Ablo name in a way
11
11
  that suggests endorsement, affiliation, or origin without written
12
12
  permission.
package/README.md CHANGED
@@ -1,13 +1,14 @@
1
1
  # Ablo
2
2
 
3
- Ablo Sync is a schema-first state control layer for AI agents and collaborative apps.
3
+ Ablo Sync is a typed sync engine for shared app state the kind that humans,
4
+ server code, and AI agents all edit at once.
4
5
 
5
- Use it when human UI, server actions, and AI agents need to edit the same typed
6
- state with realtime fanout, stale-write protection, active-work coordination,
7
- and audit.
6
+ Reach for it when those edits need to show up everywhere in real time, not
7
+ silently overwrite each other, expose who's working on what, and leave a record
8
+ of who changed what.
8
9
 
9
10
  ```txt
10
- schema -> ablo.<model>.create/load/edit/update(...)
11
+ schema -> ablo.<model>.create/load/update(...)
11
12
  ```
12
13
 
13
14
  ## Install
@@ -27,8 +28,9 @@ server runtimes only.
27
28
  export ABLO_API_KEY=sk_test_...
28
29
  ```
29
30
 
30
- Browser apps should use a scoped capability/session route through the React
31
- provider. Do not ship `ABLO_API_KEY` in a browser bundle.
31
+ In the browser, connect through the React provider (`<AbloProvider>`), which
32
+ authenticates with the signed-in user's session never the raw API key. Do not
33
+ ship `ABLO_API_KEY` in a browser bundle.
32
34
 
33
35
  ## Quick Start
34
36
 
@@ -72,8 +74,9 @@ Expected output:
72
74
  { id: '...', status: 'ready' }
73
75
  ```
74
76
 
75
- Pass `schema` for typed model resources. Omit it only for advanced server-side
76
- resource clients such as custom agents and MCP routes.
77
+ Pass `schema` to get typed models like `ablo.weatherReports.update(...)`. Omit it
78
+ only for the lower-level client used by custom agents and MCP routes that can't
79
+ import your app's schema.
77
80
 
78
81
  Run the package example from this directory:
79
82
 
@@ -87,100 +90,113 @@ future agents, read [Integration Guide](./docs/integration-guide.md).
87
90
 
88
91
  ## AI Activity on Existing State
89
92
 
90
- Use `edit` when AI or background work will touch an existing row for more than a
91
- quick write. Other participants can see the activity while your code runs. The
92
- activity is cleared when `update` finishes; call `release` if the work ends
93
- without a write.
93
+ When AI or background work will spend real time on an existing row not just a
94
+ one-shot write coordinate through `ablo.<model>.intent(id)`, the coordination
95
+ accessor that sits beside `create`/`update`/`retrieve`. It takes the row's `id` (the same
96
+ id you pass to `retrieve(id)` / `update(id, …)`) and returns a handle
97
+ synchronously, so you can see who's already working on a row before you start.
94
98
 
95
99
  ```ts
96
- const edit = await ablo.weatherReports.edit('weather_stockholm', {
97
- activity: 'checking_weather',
98
- field: 'forecast',
99
- ttl: '2m',
100
- });
100
+ // `report_stockholm` is this weather report's id — set at create time, or the
101
+ // `created.id` returned above.
102
+ const report = ablo.weatherReports.intent('report_stockholm');
103
+
104
+ // Read side: is someone already on it? Wait for them to finish.
105
+ if (report.current) {
106
+ report.current.heldBy; // 'agent:forecaster'
107
+ await report.whenFree();
108
+ }
109
+
110
+ // Write side: claim so other participants yield while we work.
111
+ await report.claim({ action: 'checking_weather', field: 'forecast', ttl: '2m' });
101
112
 
102
113
  // Your existing weather tool or agent call. While this runs, other clients see
103
- // that weather_stockholm is being checked.
104
- const weather = await weatherAgent.getWeather(edit.current.location, {
105
- signal: edit.signal,
106
- });
114
+ // that report_stockholm is being checked.
115
+ const row = ablo.weatherReports.retrieve('report_stockholm');
116
+ const weather = await weatherAgent.getWeather(row.location);
107
117
 
108
- await edit.update({
118
+ await report.update({
109
119
  status: 'ready',
110
120
  forecast: weather.summary,
111
121
  });
112
122
  ```
113
123
 
114
- Ablo does not fetch the weather. It keeps the activity visible, gives the agent
115
- call an abort signal if the row changes, and clears the activity when
116
- `edit.update(...)` finishes.
124
+ Ablo does not fetch the weather. It keeps the activity visible while the work
125
+ runs, rejects `report.update(...)` with `AbloStaleContextError` if the row
126
+ changed under you, and finishes the claim automatically once the write lands.
117
127
 
118
128
  ## Multiplayer
119
129
 
120
130
  There is no separate multiplayer mode. When human UI, server actions, and agent
121
- workers use the same schema client and write through `ablo.<model>`, they are on
122
- the same shared resource stream.
131
+ workers share the same schema and write through `ablo.<model>`, they all see
132
+ each other's changes in real time — that's the default, not a feature you turn on.
123
133
 
124
134
  - `ablo.<model>.create/update/delete` fan out confirmed deltas to subscribers.
125
135
  - `useAblo(...)` gives React clients the live row plus active intents.
126
- - `ablo.<model>.edit(...)` lets humans and agents see active work before a write lands.
127
- - `ablo.intents` remains available for custom lower-level coordination.
136
+ - `ablo.<model>.intent(id)` lets humans and agents see and coordinate active work before a write lands.
128
137
 
129
- If a team writes directly to its own database outside Ablo, that write bypasses
130
- the multiplayer stream until the app reports it through Data Source events.
138
+ Always write through Ablo the SDK (`ablo.<model>.create/update/delete`) or the
139
+ HTTP API (`POST /v1/commits`). If you write straight to your own database
140
+ instead, those changes won't reach connected clients. Use Ablo's endpoints and
141
+ the fan-out is automatic.
131
142
 
132
143
  Under the hood, capabilities, tasks, leases, intents, commits, and receipts are
133
144
  real protocol primitives. They exist so agent work is scoped, coordinated,
134
- attributable, and cleaned up if a runtime disappears. They should not be
135
- ceremony in the first integration.
136
-
137
- ## Load vs Retrieve
138
-
139
- For schema clients, `load` and `retrieve` are intentionally different:
140
-
141
- - `ablo.weatherReports.load({ where })` is async. It hydrates matching rows from the
142
- local store and server, then returns them.
143
- - `ablo.weatherReports.retrieve(id)` is sync. It reads one already-loaded row from the
144
- local pool and returns `undefined` if it is not loaded yet.
145
- - `ablo.resource('weatherReports').retrieve(id)` is the lower-level resource API. It
146
- returns `{ data, stamp, intents }` for custom runtimes that need raw read
147
- stamps and receipts.
148
-
149
- ## Activity and Busy State
150
-
151
- Model edit activity is the live coordination signal. If another participant is
152
- reading, editing, or updating an entity, Ablo can return that state, wait for it
153
- to clear, or fail fast with `AbloBusyError`.
154
-
155
- ```ts
156
- const busy = ablo.intents.list({
157
- resource: 'weatherReports',
158
- id: 'weather_stockholm',
159
- });
160
-
161
- if (busy.length > 0) {
162
- console.log(`${busy[0].actor} is ${busy[0].action}`);
145
+ attributable, and cleaned up if a runtime disappears but you don't touch them
146
+ in a first integration. The default path above is enough.
147
+
148
+ ## HTTP API
149
+
150
+ The SDK is a typed wrapper over a signed HTTP API, the same way `stripe-node`
151
+ wraps Stripe's REST API. Everything you do through `ablo.<model>` is reachable
152
+ over HTTP, so backends in other languages and server-to-server callers work
153
+ without the SDK.
154
+
155
+ Writes create, update, and delete all go through one endpoint as a batch of
156
+ operations:
157
+
158
+ ```http
159
+ POST /v1/commits
160
+ Authorization: Bearer sk_live_...
161
+ Idempotency-Key: <your-unique-id>
162
+
163
+ {
164
+ "operations": [
165
+ {
166
+ "type": "UPDATE",
167
+ "model": "weatherReports",
168
+ "id": "report_stockholm",
169
+ "input": { "status": "ready" },
170
+ "readAt": 1042,
171
+ "onStale": "reject"
172
+ }
173
+ ]
163
174
  }
164
-
165
- await ablo.intents.waitFor(
166
- { resource: 'weatherReports', id: 'weather_stockholm' },
167
- );
168
175
  ```
169
176
 
170
- Policy names are literal:
177
+ Each operation is one `CREATE` / `UPDATE` / `DELETE` (plus `ARCHIVE` /
178
+ `UNARCHIVE`). Reads fetch a single row with `GET /v1/resources/{model}/{id}`.
179
+ The same API key, scope, idempotency, and stale-write rules apply as in the SDK
180
+ — the SDK just removes the boilerplate.
171
181
 
172
- - `ifBusy: 'return'` returns immediately with `intents`.
173
- - `ifBusy: 'wait'` waits on the live intent stream. Plain HTTP callers must
174
- provide their own explicit polling policy instead of getting hidden SDK polling.
175
- - `ifBusy: 'fail'` throws `AbloBusyError` with the active intents attached.
182
+ ## Load vs Retrieve
183
+
184
+ Most reads are `retrieve` it's the everyday path, especially inside `useAblo(...)`:
185
+
186
+ - `ablo.weatherReports.retrieve(id)` is sync. It returns the already-loaded row from
187
+ the local pool (or `undefined` if it isn't loaded yet). In React,
188
+ `useAblo((ablo) => ablo.weatherReports.retrieve(id))` keeps that read live.
189
+ - `ablo.weatherReports.load({ where })` is async. Reach for it when you need to
190
+ guarantee a row is hydrated before you read it — initial fetch, SSR, scripts, or
191
+ any non-reactive runtime.
176
192
 
177
193
  ## Persistence
178
194
 
179
- Ablo defaults to volatile local persistence. That keeps the SDK focused on shared
180
- state coordination instead of silently adding an IndexedDB storage product to
181
- every browser app.
195
+ Ablo keeps local state in memory by default. That keeps the SDK focused on
196
+ coordinating shared state, rather than silently turning every browser app into
197
+ an offline database it didn't ask for.
182
198
 
183
- Opt into browser durable local cache and offline queueing when you need it:
199
+ Opt into a durable browser cache and offline write queue when you want it:
184
200
 
185
201
  ```ts
186
202
  const ablo = Ablo({
@@ -198,12 +214,17 @@ Every schema model has a backing store. By default, Ablo stores rows for the
198
214
  models you declare, so `ablo.weatherReports.create(...)` and `ablo.weatherReports.update(...)`
199
215
  write to Ablo-managed state.
200
216
 
201
- If your existing database remains the source of truth, connect it with a signed
202
- Data Source endpoint. Your app keeps the database credentials; Ablo sends signed
203
- commit requests to your route.
217
+ If your existing database stays the source of truth, connect it as a Data
218
+ Source: Ablo sends signed commit requests to an endpoint you host, and your app
219
+ writes its own database. Ablo never sees your database credentials — only the
220
+ API key:
204
221
 
205
222
  ```bash
206
- ABLO_DATA_SOURCE_SIGNING_SECRET=whsec_...
223
+ # stays in your app — Ablo never receives this
224
+ DATABASE_URL=postgres://...
225
+
226
+ # the only Ablo credential your app needs
227
+ ABLO_API_KEY=sk_live_...
207
228
  ```
208
229
 
209
230
  See [Connect Your Database](./docs/data-sources.md) for the route and commit shape.
@@ -123,8 +123,9 @@ export interface UserContext {
123
123
  * store routes this to SyncWebSocket so the WS URL carries
124
124
  * `kind=agent` and the server applies capability-token auth. */
125
125
  kind?: 'user' | 'agent' | 'system';
126
- /** Biscuit capability token for `kind: 'agent'`. Sent as
127
- * `?authorization=Bearer <token>` on the WS upgrade. */
126
+ /** Restricted (`rk_`) API key for `kind: 'agent'` the agent's
127
+ * bearer credential. Sent as `?authorization=Bearer <token>` on the
128
+ * WS upgrade. (Field name predates the Biscuit→opaque-key migration.) */
128
129
  capabilityToken?: string;
129
130
  /** Server-authoritative sync groups, supplied by auth/capability
130
131
  * exchange. The SDK does not invent org/user/default groups; app
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * ```ts
11
11
  * import { generateText, tool, stepCountIs } from 'ai';
12
- * import { Agent } from '@ablo/sync-engine-internal/agent';
12
+ * import { Agent } from '@abloatai/ablo/agent';
13
13
  *
14
14
  * const perception = new Agent({
15
15
  * syncServerUrl: 'http://localhost:8080',
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * ```ts
11
11
  * import { generateText, tool, stepCountIs } from 'ai';
12
- * import { Agent } from '@ablo/sync-engine-internal/agent';
12
+ * import { Agent } from '@abloatai/ablo/agent';
13
13
  *
14
14
  * const perception = new Agent({
15
15
  * syncServerUrl: 'http://localhost:8080',
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @ablo/sync-engine-internal/agent — Agent SDK helpers
2
+ * @abloatai/ablo/agent — Agent SDK helpers
3
3
  *
4
4
  * Two entry points depending on agent lifetime:
5
5
  *
@@ -12,7 +12,7 @@
12
12
  * server-issued capability token instead of session cookies.
13
13
  *
14
14
  * ```ts
15
- * import Ablo from '@ablo/sync-engine';
15
+ * import Ablo from '@abloatai/ablo';
16
16
  *
17
17
  * const ablo = Ablo({
18
18
  * schema,
@@ -44,7 +44,7 @@
44
44
  *
45
45
  * ```ts
46
46
  * import { generateText, tool, stepCountIs } from 'ai';
47
- * import { Agent } from '@ablo/sync-engine-internal/agent';
47
+ * import { Agent } from '@abloatai/ablo/agent';
48
48
  *
49
49
  * const perception = new Agent({
50
50
  * syncServerUrl: 'http://localhost:8080',
@@ -78,7 +78,7 @@
78
78
  * ```ts
79
79
  * import { tool } from 'ai';
80
80
  * import { z } from 'zod';
81
- * import { Agent, type AgentContext } from '@ablo/sync-engine-internal/agent';
81
+ * import { Agent, type AgentContext } from '@abloatai/ablo/agent';
82
82
  *
83
83
  * export const updateSlideTool = () => tool({
84
84
  * description: 'Update a slide title',
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @ablo/sync-engine-internal/agent — Agent SDK helpers
2
+ * @abloatai/ablo/agent — Agent SDK helpers
3
3
  *
4
4
  * Two entry points depending on agent lifetime:
5
5
  *
@@ -12,7 +12,7 @@
12
12
  * server-issued capability token instead of session cookies.
13
13
  *
14
14
  * ```ts
15
- * import Ablo from '@ablo/sync-engine';
15
+ * import Ablo from '@abloatai/ablo';
16
16
  *
17
17
  * const ablo = Ablo({
18
18
  * schema,
@@ -44,7 +44,7 @@
44
44
  *
45
45
  * ```ts
46
46
  * import { generateText, tool, stepCountIs } from 'ai';
47
- * import { Agent } from '@ablo/sync-engine-internal/agent';
47
+ * import { Agent } from '@abloatai/ablo/agent';
48
48
  *
49
49
  * const perception = new Agent({
50
50
  * syncServerUrl: 'http://localhost:8080',
@@ -78,7 +78,7 @@
78
78
  * ```ts
79
79
  * import { tool } from 'ai';
80
80
  * import { z } from 'zod';
81
- * import { Agent, type AgentContext } from '@ablo/sync-engine-internal/agent';
81
+ * import { Agent, type AgentContext } from '@abloatai/ablo/agent';
82
82
  *
83
83
  * export const updateSlideTool = () => tool({
84
84
  * description: 'Update a slide title',
@@ -117,12 +117,12 @@
117
117
  // `Agent` is the class AND the namespace for its types. Reach for
118
118
  // options, context, and session options via dot access:
119
119
  //
120
- // import { Agent } from '@ablo/sync-engine-internal/agent';
120
+ // import { Agent } from '@abloatai/ablo/agent';
121
121
  // const opts: Agent.Options = { ... };
122
122
  // const ctx: Agent.Context = { perception };
123
123
  // const s: Agent.SessionOptions = { ... };
124
124
  //
125
125
  // Everything else (Activity, Claim, Turn, Peer, ActiveIntent, ...)
126
126
  // lives on the `Ablo.*` namespace via
127
- // `import type { Ablo } from '@ablo/sync-engine'`.
127
+ // `import type { Ablo } from '@abloatai/ablo'`.
128
128
  export { Agent } from './Agent.js';
@@ -35,7 +35,7 @@ export interface PresenceAnnouncer {
35
35
  *
36
36
  * ```ts
37
37
  * import { generateText, tool } from 'ai';
38
- * import { Agent, type AgentContext } from '@ablo/sync-engine-internal/agent';
38
+ * import { Agent, type AgentContext } from '@abloatai/ablo/agent';
39
39
  *
40
40
  * const updateSlideTool = () => tool({
41
41
  * inputSchema: z.object({ id: z.string(), title: z.string() }),
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `@ablo/sync-engine-internal/ai-sdk` — multiplayer-with-AI as language model
2
+ * `@abloatai/ablo/ai-sdk` — multiplayer-with-AI as language model
3
3
  * middleware.
4
4
  *
5
5
  * Two cross-cutting middlewares for any AI SDK consumer using
@@ -24,7 +24,7 @@
24
24
  * import {
25
25
  * intentBroadcastMiddleware,
26
26
  * coordinationContextMiddleware,
27
- * } from '@ablo/sync-engine-internal/ai-sdk';
27
+ * } from '@abloatai/ablo/ai-sdk';
28
28
  *
29
29
  * const target = { entityType: 'SlideDeck', entityId: 'deck-abc' };
30
30
  *
@@ -48,7 +48,7 @@
48
48
  * Or use the convenience composition for the common case:
49
49
  *
50
50
  * ```ts
51
- * import { wrapWithMultiplayer } from '@ablo/sync-engine-internal/ai-sdk';
51
+ * import { wrapWithMultiplayer } from '@abloatai/ablo/ai-sdk';
52
52
  *
53
53
  * const wrappedModel = wrapWithMultiplayer({
54
54
  * model: anthropic('claude-opus-4-7'),
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `@ablo/sync-engine-internal/ai-sdk` — multiplayer-with-AI as language model
2
+ * `@abloatai/ablo/ai-sdk` — multiplayer-with-AI as language model
3
3
  * middleware.
4
4
  *
5
5
  * Two cross-cutting middlewares for any AI SDK consumer using
@@ -24,7 +24,7 @@
24
24
  * import {
25
25
  * intentBroadcastMiddleware,
26
26
  * coordinationContextMiddleware,
27
- * } from '@ablo/sync-engine-internal/ai-sdk';
27
+ * } from '@abloatai/ablo/ai-sdk';
28
28
  *
29
29
  * const target = { entityType: 'SlideDeck', entityId: 'deck-abc' };
30
30
  *
@@ -48,7 +48,7 @@
48
48
  * Or use the convenience composition for the common case:
49
49
  *
50
50
  * ```ts
51
- * import { wrapWithMultiplayer } from '@ablo/sync-engine-internal/ai-sdk';
51
+ * import { wrapWithMultiplayer } from '@abloatai/ablo/ai-sdk';
52
52
  *
53
53
  * const wrappedModel = wrapWithMultiplayer({
54
54
  * model: anthropic('claude-opus-4-7'),
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * Open-source-clean: depends only on `@ai-sdk/provider` types and
13
13
  * the package's own `SyncAgent`. No app-specific assumptions —
14
- * Ablo's web app uses this, but so can any consumer of `@ablo/sync-engine`.
14
+ * Ablo's web app uses this, but so can any consumer of `@abloatai/ablo`.
15
15
  *
16
16
  * Cost: one WS frame at stream start (`intent_begin`), one at end
17
17
  * (`intent_abandon`). No DB I/O, no extra LLM tokens.
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * Open-source-clean: depends only on `@ai-sdk/provider` types and
13
13
  * the package's own `SyncAgent`. No app-specific assumptions —
14
- * Ablo's web app uses this, but so can any consumer of `@ablo/sync-engine`.
14
+ * Ablo's web app uses this, but so can any consumer of `@abloatai/ablo`.
15
15
  *
16
16
  * Cost: one WS frame at stream start (`intent_begin`), one at end
17
17
  * (`intent_abandon`). No DB I/O, no extra LLM tokens.
@@ -63,7 +63,7 @@ export declare function resolveIdentity(options: ResolveIdentityRequest): Promis
63
63
  /**
64
64
  * Capability-token refresh scheduler.
65
65
  *
66
- * Long-lived `@ablo/sync-engine` clients hold a server-issued capability
66
+ * Long-lived `@abloatai/ablo` clients hold a server-issued capability
67
67
  * token whose TTL (1h default) is shorter than typical browser sessions.
68
68
  * Without proactive refresh, the WebSocket would either be force-closed
69
69
  * by the server at expiry (code 1008) or fail its next reconnect with