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
|
@@ -136,8 +136,8 @@ const forwardToAgent = consumer({
|
|
|
136
136
|
? 'mention'
|
|
137
137
|
: 'passive'
|
|
138
138
|
const message: ChatAgentMessage = {
|
|
139
|
-
//
|
|
140
|
-
//
|
|
139
|
+
// Derived from the room event's id, so a retried forward converges on
|
|
140
|
+
// the same message in the agent's session.
|
|
141
141
|
id: await idempotentId('chat.message', context.event.id),
|
|
142
142
|
role: 'user',
|
|
143
143
|
metadata: {
|
|
@@ -9,7 +9,7 @@ const postgresUrl = process.env.DATABASE_URL?.replace(
|
|
|
9
9
|
)
|
|
10
10
|
|
|
11
11
|
export const store: RedisStore | PostgresStore | undefined = redisUrl
|
|
12
|
-
? redis({ url: redisUrl })
|
|
12
|
+
? redis({ url: redisUrl, keyPrefix: 'a2-playground-tagged' })
|
|
13
13
|
: postgresUrl
|
|
14
14
|
? postgres({ connectionString: postgresUrl })
|
|
15
15
|
: undefined
|
package/package.json
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* your schema.
|
|
8
8
|
*
|
|
9
9
|
* Whatever creates them, A2 relies on the table and column names, the column
|
|
10
|
-
* types, the primary keys, and the unique index on a2_events
|
|
11
|
-
* other indexes keep its queries fast. Every name is spelled
|
|
12
|
-
* `casing` setting changes none of them.
|
|
10
|
+
* types, the primary keys, and the unique index on a2_events (session_id,
|
|
11
|
+
* event_id). The other indexes keep its queries fast. Every name is spelled
|
|
12
|
+
* out, so Drizzle's `casing` setting changes none of them.
|
|
13
13
|
*
|
|
14
14
|
* A2's tables change only when a release's changelog says so; compare your
|
|
15
15
|
* copy with that release's file. Drizzle can't declare functions or
|
|
@@ -48,7 +48,10 @@ export const a2Events = pgTable(
|
|
|
48
48
|
name: 'a2_events_pkey',
|
|
49
49
|
columns: [table.sessionId, table.idx],
|
|
50
50
|
}),
|
|
51
|
-
uniqueIndex('
|
|
51
|
+
uniqueIndex('a2_events_session_event_id').on(
|
|
52
|
+
table.sessionId,
|
|
53
|
+
table.eventId,
|
|
54
|
+
),
|
|
52
55
|
index('a2_events_types').on(table.sessionId, table.eventType, table.idx),
|
|
53
56
|
],
|
|
54
57
|
)
|
package/sql/postgres/schema.sql
CHANGED
|
@@ -254,9 +254,6 @@ end $$;
|
|
|
254
254
|
--> statement-breakpoint
|
|
255
255
|
|
|
256
256
|
do $$ begin
|
|
257
|
-
if to_regclass('a2_events_event_id') is null then
|
|
258
|
-
create unique index if not exists a2_events_event_id on a2_events (event_id);
|
|
259
|
-
end if;
|
|
260
257
|
if to_regclass('a2_events_types') is null then
|
|
261
258
|
create index if not exists a2_events_types
|
|
262
259
|
on a2_events (session_id, event_type, idx);
|
|
@@ -274,3 +271,27 @@ do $$ begin
|
|
|
274
271
|
on a2_snapshot_pins (session_id, reducer_name, up_to_index);
|
|
275
272
|
end if;
|
|
276
273
|
end $$;
|
|
274
|
+
--> statement-breakpoint
|
|
275
|
+
|
|
276
|
+
-- Event ids are unique per session, through the index on (session_id,
|
|
277
|
+
-- event_id). It replaces a2_events_event_id, on event_id alone. The swap
|
|
278
|
+
-- locks the table before it builds, so it waits for running queries instead
|
|
279
|
+
-- of deadlocking with a writer when the whole file runs as one transaction.
|
|
280
|
+
-- The old index goes only once the new one is valid, so a session's ids
|
|
281
|
+
-- always have a unique index.
|
|
282
|
+
do $$ begin
|
|
283
|
+
if to_regclass('a2_events_session_event_id') is null then
|
|
284
|
+
if to_regclass('a2_events_event_id') is not null then
|
|
285
|
+
lock table a2_events in access exclusive mode;
|
|
286
|
+
end if;
|
|
287
|
+
create unique index if not exists a2_events_session_event_id
|
|
288
|
+
on a2_events (session_id, event_id);
|
|
289
|
+
end if;
|
|
290
|
+
if to_regclass('a2_events_event_id') is not null and exists (
|
|
291
|
+
select 1 from pg_index
|
|
292
|
+
where indexrelid = to_regclass('a2_events_session_event_id')
|
|
293
|
+
and indisvalid and indisunique
|
|
294
|
+
) then
|
|
295
|
+
drop index a2_events_event_id;
|
|
296
|
+
end if;
|
|
297
|
+
end $$;
|
package/src/actor-shared.ts
CHANGED
|
@@ -131,7 +131,11 @@ export type ActorScheduleSend<E> = {
|
|
|
131
131
|
export type ActorContext<D extends ActorProtocol> = {
|
|
132
132
|
/** Mutable draft, committed atomically with the handler's completion. */
|
|
133
133
|
state: D['state']
|
|
134
|
-
/**
|
|
134
|
+
/**
|
|
135
|
+
* The message id — stable across re-runs and unique within the instance;
|
|
136
|
+
* the idempotency key for external I/O. An explicit send id that repeats
|
|
137
|
+
* in another instance repeats here too.
|
|
138
|
+
*/
|
|
135
139
|
id: string
|
|
136
140
|
/** Durable 1-based dispatch ordinal of this message. */
|
|
137
141
|
attempt: number
|
|
@@ -150,7 +154,11 @@ export type ActorContext<D extends ActorProtocol> = {
|
|
|
150
154
|
* whose serial handlers decide against fresh state.
|
|
151
155
|
*/
|
|
152
156
|
export type ActorConcurrentContext<D extends ActorProtocol> = {
|
|
153
|
-
/**
|
|
157
|
+
/**
|
|
158
|
+
* The message id — stable across re-runs and unique within the instance;
|
|
159
|
+
* the idempotency key for external I/O. An explicit send id that repeats
|
|
160
|
+
* in another instance repeats here too.
|
|
161
|
+
*/
|
|
154
162
|
id: string
|
|
155
163
|
/** Durable 1-based dispatch ordinal of this message. */
|
|
156
164
|
attempt: number
|
package/src/ai-agent.ts
CHANGED
|
@@ -75,6 +75,7 @@ import type {
|
|
|
75
75
|
import { A2Error } from './errors.ts'
|
|
76
76
|
import {
|
|
77
77
|
consumeSchedulerSendFailure,
|
|
78
|
+
drainSettledHooks,
|
|
78
79
|
failedPreviousAttempt,
|
|
79
80
|
installAmbientToolScopeStorage,
|
|
80
81
|
type AmbientToolScope,
|
|
@@ -2148,6 +2149,7 @@ export function createConsumers<
|
|
|
2148
2149
|
const source =
|
|
2149
2150
|
harness !== undefined
|
|
2150
2151
|
? await harness.step({
|
|
2152
|
+
scope: states,
|
|
2151
2153
|
agentName: options.contract.name,
|
|
2152
2154
|
sessionId: ctx.event.sessionId,
|
|
2153
2155
|
requestIndex: ctx.event.index,
|
|
@@ -2556,6 +2558,17 @@ export function agent(
|
|
|
2556
2558
|
consumers: [...builtIns, ...(serverOptions.consumers ?? [])],
|
|
2557
2559
|
})
|
|
2558
2560
|
registerHarnessStates(server, states)
|
|
2561
|
+
const driver =
|
|
2562
|
+
harness === undefined || harness.type === 'ai-sdk'
|
|
2563
|
+
? undefined
|
|
2564
|
+
: harnessDriver(harness)
|
|
2565
|
+
const release = driver?.release
|
|
2566
|
+
// What a harness kept for a session's next step goes once nothing is left
|
|
2567
|
+
// to run for the session here.
|
|
2568
|
+
if (release !== undefined)
|
|
2569
|
+
drainSettledHooks.set(server, (sessionId) =>
|
|
2570
|
+
release({ scope: states, sessionId }),
|
|
2571
|
+
)
|
|
2559
2572
|
const applicationEvents = 'contract' in rest
|
|
2560
2573
|
setServerFetchHooks(server, {
|
|
2561
2574
|
validateIngress: (context) =>
|