experimental-a2 0.21.1 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/{actor-HnGmrOZZ.d.ts → actor-CqibLgjQ.d.ts} +13 -5
- package/dist/actor-CqibLgjQ.d.ts.map +1 -0
- package/dist/actor-client.d.ts +1 -1
- package/dist/actor-react.d.ts +1 -1
- package/dist/actor-react.js +1 -1
- package/dist/actor-shared-DFET5q16.js.map +1 -1
- package/dist/actor.d.ts +1 -1
- package/dist/actor.js +3 -3
- package/dist/{ai-CvEnqVfo.d.ts → ai-DAu77CDr.d.ts} +2 -2
- package/dist/{ai-CvEnqVfo.d.ts.map → ai-DAu77CDr.d.ts.map} +1 -1
- package/dist/{ai-CzE672Q3.js → ai-EEfKyc-z.js} +2 -2
- package/dist/{ai-CzE672Q3.js.map → ai-EEfKyc-z.js.map} +1 -1
- package/dist/ai-client.d.ts +1 -1
- package/dist/ai-client.js +2 -2
- package/dist/ai-fx.d.ts +4 -2
- package/dist/ai-fx.d.ts.map +1 -1
- package/dist/ai-fx.js +211 -61
- package/dist/ai-fx.js.map +1 -1
- package/dist/{ai-harness-Bfk-Lycn.d.ts → ai-harness-DTjkAr2T.d.ts} +2 -2
- package/dist/{ai-harness-Bfk-Lycn.d.ts.map → ai-harness-DTjkAr2T.d.ts.map} +1 -1
- package/dist/ai-harness-dQeJaR1t.js.map +1 -1
- package/dist/ai-pi.d.ts +1 -1
- package/dist/ai-pi.js +1 -1
- package/dist/ai-react.d.ts +1 -1
- package/dist/ai-react.js +2 -2
- package/dist/ai-server.d.ts +3 -3
- package/dist/ai-server.d.ts.map +1 -1
- package/dist/ai-server.js +10 -4
- package/dist/ai-server.js.map +1 -1
- package/dist/ai.d.ts +1 -1
- package/dist/ai.js +1 -1
- package/dist/{client-9IeTsiAs.js → client-BQS4i_V9.js} +27 -4
- package/dist/client-BQS4i_V9.js.map +1 -0
- package/dist/client-CUMbS_38.d.ts.map +1 -1
- package/dist/client.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/{internal-Bc4PvfHk.js → internal-CvsrprnU.js} +32 -15
- package/dist/{internal-Bc4PvfHk.js.map → internal-CvsrprnU.js.map} +1 -1
- package/dist/react.js +1 -1
- package/dist/{runtime-consumer-BWmht60z.js → runtime-consumer-CIeL33wj.js} +2 -2
- package/dist/{runtime-consumer-BWmht60z.js.map → runtime-consumer-CIeL33wj.js.map} +1 -1
- package/dist/scheduler-qstash.d.ts +2 -2
- package/dist/scheduler-qstash.js +2 -2
- package/dist/scheduler-vercel.d.ts +2 -2
- package/dist/scheduler-vercel.js +2 -2
- package/dist/{server-DvIB8kj5.js → server-DtFrWxi3.js} +30 -8
- package/dist/server-DtFrWxi3.js.map +1 -0
- package/dist/{server-BshFZ0eL.d.ts → server-qgez0Xny.d.ts} +3 -3
- package/dist/{server-BshFZ0eL.d.ts.map → server-qgez0Xny.d.ts.map} +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +1 -1
- package/dist/{session-clear-Bk_29eEw.d.ts → session-clear-D1PFe7xl.d.ts} +2 -2
- package/dist/session-clear-D1PFe7xl.d.ts.map +1 -0
- package/dist/{store-Z2qjw50n.d.ts → store-D0MhBvg6.d.ts} +15 -6
- package/dist/store-D0MhBvg6.d.ts.map +1 -0
- package/dist/store-N8PXxDAS.js.map +1 -1
- package/dist/store-memory.d.ts +1 -1
- package/dist/store-memory.d.ts.map +1 -1
- package/dist/store-memory.js +15 -17
- package/dist/store-memory.js.map +1 -1
- package/dist/{store-polling-DYNyxCev.js → store-polling-BZt2Rf3D.js} +2 -2
- package/dist/{store-polling-DYNyxCev.js.map → store-polling-BZt2Rf3D.js.map} +1 -1
- package/dist/store-postgres.d.ts +1 -1
- package/dist/store-postgres.d.ts.map +1 -1
- package/dist/store-postgres.js +31 -40
- package/dist/store-postgres.js.map +1 -1
- package/dist/store-presence-polling-JuAy2Ck2.js +111 -0
- package/dist/store-presence-polling-JuAy2Ck2.js.map +1 -0
- package/dist/store-redis-http.d.ts +1 -1
- package/dist/store-redis-http.js +3 -3
- package/dist/{store-redis-notify-IiVdlYHc.js → store-redis-notify-CsJw_hfD.js} +538 -397
- package/dist/store-redis-notify-CsJw_hfD.js.map +1 -0
- package/dist/store-redis.d.ts +1 -1
- package/dist/store-redis.d.ts.map +1 -1
- package/dist/store-redis.js +3 -4
- package/dist/store-redis.js.map +1 -1
- package/dist/store-sqlite.d.ts +1 -1
- package/dist/store-sqlite.d.ts.map +1 -1
- package/dist/store-sqlite.js +16 -18
- package/dist/store-sqlite.js.map +1 -1
- package/dist/stream-buffer-DrTyiIuo.js +57 -0
- package/dist/stream-buffer-DrTyiIuo.js.map +1 -0
- package/dist/{wire-CZGqNZRx.js → wire-CV-Z7wz-.js} +3 -3
- package/dist/{wire-CZGqNZRx.js.map → wire-CV-Z7wz-.js.map} +1 -1
- package/docs/actors/01-introduction.mdx +5 -2
- package/docs/agents/03-conversations.mdx +9 -8
- package/docs/agents/04-harnesses.mdx +7 -4
- package/docs/reference/01-core.mdx +3 -2
- package/docs/reference/02-server.mdx +5 -1
- package/docs/reference/04-ai.mdx +13 -4
- package/docs/reference/06-errors.mdx +1 -1
- package/docs/server/01-consumers.mdx +4 -1
- package/docs/server/06-guarantees.mdx +7 -4
- package/docs/stores/02-redis.mdx +16 -10
- package/docs/stores/03-redis-http.mdx +6 -4
- package/docs/stores/04-postgres.mdx +2 -2
- package/docs/upgrades/01-overview.mdx +1 -0
- package/docs/upgrades/78-0-22.mdx +115 -0
- package/examples/playground/app/a0/sandbox.ts +58 -13
- package/examples/playground/app/a2slack/db/a2.ts +7 -4
- package/examples/playground/app/a2slack/db/migrations/0004_a2_session_event_ids.sql +2 -0
- package/examples/playground/app/a2slack/db/migrations/meta/0004_snapshot.json +1165 -0
- package/examples/playground/app/a2slack/db/migrations/meta/_journal.json +8 -1
- package/examples/playground/app/chat/server.ts +2 -2
- package/examples/playground/lib/store.ts +1 -1
- package/examples/playground/package.json +1 -1
- package/package.json +1 -1
- package/sql/postgres/drizzle-schema.ts +7 -4
- package/sql/postgres/schema.sql +24 -3
- package/src/actor-shared.ts +10 -2
- package/src/ai-agent.ts +13 -0
- package/src/ai-fx.ts +321 -77
- package/src/ai-harness.ts +7 -0
- package/src/client.ts +19 -2
- package/src/deterministic-id.ts +1 -1
- package/src/internal.ts +42 -11
- package/src/presence-recovery.ts +18 -11
- package/src/presence-tombstones.ts +52 -0
- package/src/push-envelope.ts +2 -2
- package/src/server.ts +49 -15
- package/src/store-memory.ts +24 -32
- package/src/store-postgres.ts +43 -53
- package/src/store-presence-polling.ts +59 -34
- package/src/store-redis-core.ts +595 -439
- package/src/store-redis-notify.ts +74 -26
- package/src/store-redis.ts +2 -3
- package/src/store-sqlite.ts +34 -40
- package/src/store.ts +14 -5
- package/dist/actor-HnGmrOZZ.d.ts.map +0 -1
- package/dist/client-9IeTsiAs.js.map +0 -1
- package/dist/server-DvIB8kj5.js.map +0 -1
- package/dist/session-clear-Bk_29eEw.d.ts.map +0 -1
- package/dist/store-Z2qjw50n.d.ts.map +0 -1
- package/dist/store-presence-polling-CzQ0wdtM.js +0 -94
- package/dist/store-presence-polling-CzQ0wdtM.js.map +0 -1
- package/dist/store-redis-notify-IiVdlYHc.js.map +0 -1
- package/dist/stream-buffer-Cx7AAPGq.js +0 -23
- package/dist/stream-buffer-Cx7AAPGq.js.map +0 -1
|
@@ -19,6 +19,11 @@ export function pollPresence({
|
|
|
19
19
|
sleep?: (ms: number) => Sleeper
|
|
20
20
|
}): {
|
|
21
21
|
ready: Promise<void>
|
|
22
|
+
/**
|
|
23
|
+
* Runs a foreground snapshot read and counts it as a poll, so a stamp a
|
|
24
|
+
* viewer paints from it is one later deletes carry.
|
|
25
|
+
*/
|
|
26
|
+
snapshot(read: () => Promise<PresenceRow[]>): Promise<PresenceRow[]>
|
|
22
27
|
update(patch: PresencePatch): void
|
|
23
28
|
wake(): void
|
|
24
29
|
stop(): void
|
|
@@ -45,6 +50,46 @@ export function pollPresence({
|
|
|
45
50
|
// Seeding is best effort; foreground snapshots still report read errors.
|
|
46
51
|
.catch(() => undefined)
|
|
47
52
|
|
|
53
|
+
/** Delivers how `rows` differ from what was seen; true when they do. */
|
|
54
|
+
const reconcile = (rows: PresenceRow[]): boolean => {
|
|
55
|
+
const live = new Set<string>()
|
|
56
|
+
let changed = false
|
|
57
|
+
for (const row of rows) {
|
|
58
|
+
const id = key(row)
|
|
59
|
+
live.add(id)
|
|
60
|
+
const prior = seen.get(id)
|
|
61
|
+
seen.set(id, row)
|
|
62
|
+
if (
|
|
63
|
+
prior?.seen === row.seen &&
|
|
64
|
+
prior.at.getTime() === row.at.getTime() &&
|
|
65
|
+
JSON.stringify(prior.value) === JSON.stringify(row.value)
|
|
66
|
+
)
|
|
67
|
+
continue
|
|
68
|
+
changed = true
|
|
69
|
+
deliver({
|
|
70
|
+
participant: row.participant,
|
|
71
|
+
values: { [row.field]: row.value },
|
|
72
|
+
seen: row.seen,
|
|
73
|
+
at: row.at,
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
for (const [id, row] of seen) {
|
|
77
|
+
if (live.has(id)) continue
|
|
78
|
+
seen.delete(id)
|
|
79
|
+
changed = true
|
|
80
|
+
deliver({
|
|
81
|
+
participant: row.participant,
|
|
82
|
+
values: { [row.field]: null },
|
|
83
|
+
seen: row.seen,
|
|
84
|
+
// The last seen stamp, never this poller's clock: only
|
|
85
|
+
// senders' clocks order the plane, and an observer-stamped
|
|
86
|
+
// delete could outrank the sender's next set.
|
|
87
|
+
at: row.at,
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
return changed
|
|
91
|
+
}
|
|
92
|
+
|
|
48
93
|
const run = async (): Promise<void> => {
|
|
49
94
|
await ready
|
|
50
95
|
for (;;) {
|
|
@@ -60,39 +105,7 @@ export function pollPresence({
|
|
|
60
105
|
const rows = await read()
|
|
61
106
|
if (stopped) return
|
|
62
107
|
if (version !== reading) continue
|
|
63
|
-
|
|
64
|
-
let changed = false
|
|
65
|
-
for (const row of rows) {
|
|
66
|
-
const id = key(row)
|
|
67
|
-
live.add(id)
|
|
68
|
-
const prior = seen.get(id)
|
|
69
|
-
seen.set(id, row)
|
|
70
|
-
if (
|
|
71
|
-
prior?.seen === row.seen &&
|
|
72
|
-
prior.at.getTime() === row.at.getTime() &&
|
|
73
|
-
JSON.stringify(prior.value) === JSON.stringify(row.value)
|
|
74
|
-
)
|
|
75
|
-
continue
|
|
76
|
-
changed = true
|
|
77
|
-
deliver({
|
|
78
|
-
participant: row.participant,
|
|
79
|
-
values: { [row.field]: row.value },
|
|
80
|
-
seen: row.seen,
|
|
81
|
-
at: row.at,
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
for (const [id, row] of seen) {
|
|
85
|
-
if (live.has(id)) continue
|
|
86
|
-
seen.delete(id)
|
|
87
|
-
changed = true
|
|
88
|
-
deliver({
|
|
89
|
-
participant: row.participant,
|
|
90
|
-
values: { [row.field]: null },
|
|
91
|
-
seen: row.seen,
|
|
92
|
-
at: new Date(),
|
|
93
|
-
})
|
|
94
|
-
}
|
|
95
|
-
if (changed) activate()
|
|
108
|
+
if (reconcile(rows)) activate()
|
|
96
109
|
else if (version === before)
|
|
97
110
|
interval = Math.min(interval * 2, POLL_TIMINGS.idleCeilingMs)
|
|
98
111
|
} catch {
|
|
@@ -103,10 +116,22 @@ export function pollPresence({
|
|
|
103
116
|
void run()
|
|
104
117
|
return {
|
|
105
118
|
ready,
|
|
119
|
+
async snapshot(readSnapshot) {
|
|
120
|
+
const reading = version
|
|
121
|
+
const rows = await readSnapshot()
|
|
122
|
+
if (!stopped && version === reading && reconcile(rows)) activate()
|
|
123
|
+
return rows
|
|
124
|
+
},
|
|
106
125
|
wake: activate,
|
|
107
126
|
update(patch) {
|
|
108
127
|
for (const [field, value] of Object.entries(patch.values)) {
|
|
109
|
-
|
|
128
|
+
const id = key({ participant: patch.participant, field })
|
|
129
|
+
// A deleted field is one the next read should not find.
|
|
130
|
+
if (value === null) {
|
|
131
|
+
seen.delete(id)
|
|
132
|
+
continue
|
|
133
|
+
}
|
|
134
|
+
seen.set(id, {
|
|
110
135
|
participant: patch.participant,
|
|
111
136
|
field,
|
|
112
137
|
value,
|