@trigger.dev/sdk 0.0.0-prerelease-streamfix-20260909094302 → 0.0.0-prerelease-20260911094758
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/dist/commonjs/imports/ai-runtime-cjs.cjs.map +1 -1
- package/dist/commonjs/imports/ai-runtime.js +2 -0
- package/dist/commonjs/v3/ai-shared.d.ts +15 -0
- package/dist/commonjs/v3/ai-shared.js +35 -1
- package/dist/commonjs/v3/ai-shared.js.map +1 -1
- package/dist/commonjs/v3/ai.d.ts +275 -25
- package/dist/commonjs/v3/ai.js +1373 -354
- package/dist/commonjs/v3/ai.js.map +1 -1
- package/dist/commonjs/v3/chat-client.d.ts +11 -2
- package/dist/commonjs/v3/chat-client.js +227 -111
- package/dist/commonjs/v3/chat-client.js.map +1 -1
- package/dist/commonjs/v3/chat-react.d.ts +88 -0
- package/dist/commonjs/v3/chat-react.js +130 -1
- package/dist/commonjs/v3/chat-react.js.map +1 -1
- package/dist/commonjs/v3/chat-server.d.ts +42 -6
- package/dist/commonjs/v3/chat-server.js +52 -7
- package/dist/commonjs/v3/chat-server.js.map +1 -1
- package/dist/commonjs/v3/chat.d.ts +92 -10
- package/dist/commonjs/v3/chat.js +328 -73
- package/dist/commonjs/v3/chat.js.map +1 -1
- package/dist/commonjs/v3/chatSnapshotIo.d.ts +2 -0
- package/dist/commonjs/v3/chatSnapshotIo.js +173 -0
- package/dist/commonjs/v3/chatSnapshotIo.js.map +1 -0
- package/dist/commonjs/v3/chatVersionSkew.d.ts +12 -0
- package/dist/commonjs/v3/chatVersionSkew.js +30 -0
- package/dist/commonjs/v3/chatVersionSkew.js.map +1 -0
- package/dist/commonjs/v3/externalDeploymentId.d.ts +23 -0
- package/dist/commonjs/v3/externalDeploymentId.js +43 -0
- package/dist/commonjs/v3/externalDeploymentId.js.map +1 -0
- package/dist/commonjs/v3/retry.d.ts +4 -0
- package/dist/commonjs/v3/retry.js +22 -13
- package/dist/commonjs/v3/retry.js.map +1 -1
- package/dist/commonjs/v3/sessions.d.ts +15 -2
- package/dist/commonjs/v3/sessions.js +12 -1
- package/dist/commonjs/v3/sessions.js.map +1 -1
- package/dist/commonjs/v3/shared.js +30 -36
- package/dist/commonjs/v3/shared.js.map +1 -1
- package/dist/commonjs/v3/test/index.d.ts +1 -0
- package/dist/commonjs/v3/test/index.js +3 -1
- package/dist/commonjs/v3/test/index.js.map +1 -1
- package/dist/commonjs/v3/test/mock-chat-agent.d.ts +47 -4
- package/dist/commonjs/v3/test/mock-chat-agent.js +116 -10
- package/dist/commonjs/v3/test/mock-chat-agent.js.map +1 -1
- package/dist/commonjs/v3/test/test-session-handle.js +6 -0
- package/dist/commonjs/v3/test/test-session-handle.js.map +1 -1
- package/dist/commonjs/v3/test/transcript-storage-tests.d.ts +40 -0
- package/dist/commonjs/v3/test/transcript-storage-tests.js +258 -0
- package/dist/commonjs/v3/test/transcript-storage-tests.js.map +1 -0
- package/dist/commonjs/v3/transcriptStorage.d.ts +261 -0
- package/dist/commonjs/v3/transcriptStorage.js +370 -0
- package/dist/commonjs/v3/transcriptStorage.js.map +1 -0
- package/dist/commonjs/version.js +1 -1
- package/dist/esm/imports/ai-runtime.d.ts +2 -2
- package/dist/esm/imports/ai-runtime.js +2 -2
- package/dist/esm/imports/ai-runtime.js.map +1 -1
- package/dist/esm/v3/ai-shared.d.ts +15 -0
- package/dist/esm/v3/ai-shared.js +33 -0
- package/dist/esm/v3/ai-shared.js.map +1 -1
- package/dist/esm/v3/ai.d.ts +275 -25
- package/dist/esm/v3/ai.js +1365 -351
- package/dist/esm/v3/ai.js.map +1 -1
- package/dist/esm/v3/chat-client.d.ts +11 -2
- package/dist/esm/v3/chat-client.js +228 -112
- package/dist/esm/v3/chat-client.js.map +1 -1
- package/dist/esm/v3/chat-react.d.ts +88 -0
- package/dist/esm/v3/chat-react.js +127 -1
- package/dist/esm/v3/chat-react.js.map +1 -1
- package/dist/esm/v3/chat-server.d.ts +42 -6
- package/dist/esm/v3/chat-server.js +53 -8
- package/dist/esm/v3/chat-server.js.map +1 -1
- package/dist/esm/v3/chat.d.ts +92 -10
- package/dist/esm/v3/chat.js +329 -74
- package/dist/esm/v3/chat.js.map +1 -1
- package/dist/esm/v3/chatSnapshotIo.d.ts +2 -0
- package/dist/esm/v3/chatSnapshotIo.js +165 -0
- package/dist/esm/v3/chatSnapshotIo.js.map +1 -0
- package/dist/esm/v3/chatVersionSkew.d.ts +12 -0
- package/dist/esm/v3/chatVersionSkew.js +27 -0
- package/dist/esm/v3/chatVersionSkew.js.map +1 -0
- package/dist/esm/v3/externalDeploymentId.d.ts +23 -0
- package/dist/esm/v3/externalDeploymentId.js +38 -0
- package/dist/esm/v3/externalDeploymentId.js.map +1 -0
- package/dist/esm/v3/retry.d.ts +4 -0
- package/dist/esm/v3/retry.js +14 -8
- package/dist/esm/v3/retry.js.map +1 -1
- package/dist/esm/v3/sessions.d.ts +15 -2
- package/dist/esm/v3/sessions.js +11 -1
- package/dist/esm/v3/sessions.js.map +1 -1
- package/dist/esm/v3/shared.js +17 -23
- package/dist/esm/v3/shared.js.map +1 -1
- package/dist/esm/v3/test/index.d.ts +1 -0
- package/dist/esm/v3/test/index.js +1 -0
- package/dist/esm/v3/test/index.js.map +1 -1
- package/dist/esm/v3/test/mock-chat-agent.d.ts +47 -4
- package/dist/esm/v3/test/mock-chat-agent.js +118 -12
- package/dist/esm/v3/test/mock-chat-agent.js.map +1 -1
- package/dist/esm/v3/test/test-session-handle.js +6 -0
- package/dist/esm/v3/test/test-session-handle.js.map +1 -1
- package/dist/esm/v3/test/transcript-storage-tests.d.ts +40 -0
- package/dist/esm/v3/test/transcript-storage-tests.js +255 -0
- package/dist/esm/v3/test/transcript-storage-tests.js.map +1 -0
- package/dist/esm/v3/transcriptStorage.d.ts +261 -0
- package/dist/esm/v3/transcriptStorage.js +357 -0
- package/dist/esm/v3/transcriptStorage.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/docs/ai-chat/actions.mdx +55 -23
- package/docs/ai-chat/anatomy.mdx +3 -3
- package/docs/ai-chat/backend.mdx +125 -48
- package/docs/ai-chat/background-injection.mdx +69 -19
- package/docs/ai-chat/client-protocol.mdx +5 -4
- package/docs/ai-chat/compaction.mdx +13 -7
- package/docs/ai-chat/custom-agents.mdx +23 -0
- package/docs/ai-chat/fast-starts.mdx +27 -20
- package/docs/ai-chat/frontend.mdx +19 -14
- package/docs/ai-chat/how-it-works.mdx +1 -1
- package/docs/ai-chat/lifecycle-hooks.mdx +6 -2
- package/docs/ai-chat/migrating-from-a-route-handler.mdx +16 -14
- package/docs/ai-chat/patterns/database-persistence.mdx +6 -2
- package/docs/ai-chat/patterns/native-compaction.mdx +310 -0
- package/docs/ai-chat/patterns/persistence-and-replay.mdx +34 -23
- package/docs/ai-chat/patterns/skills.mdx +7 -10
- package/docs/ai-chat/patterns/version-upgrades.mdx +79 -6
- package/docs/ai-chat/pending-messages.mdx +3 -3
- package/docs/ai-chat/prompt-caching.mdx +23 -25
- package/docs/ai-chat/quick-start.mdx +11 -11
- package/docs/ai-chat/reference.mdx +67 -9
- package/docs/ai-chat/sessions.mdx +6 -1
- package/docs/ai-chat/testing.mdx +2 -1
- package/docs/ai-chat/tools.mdx +18 -13
- package/docs/ai-chat/transcript-storage.mdx +239 -0
- package/docs/ai-chat/upgrade-guide.mdx +2 -2
- package/docs/apikeys.mdx +27 -45
- package/docs/config/extensions/syncEnvVars.mdx +6 -0
- package/docs/deploy-environment-variables.mdx +23 -2
- package/docs/deployment/overview.mdx +4 -8
- package/docs/deployment/preview-branches.mdx +4 -4
- package/docs/deployment/version-skew-protection.mdx +62 -0
- package/docs/manual-setup.mdx +7 -7
- package/docs/mcp-tools.mdx +9 -0
- package/docs/quick-start.mdx +3 -3
- package/docs/realtime/auth.mdx +1 -1
- package/docs/reports.mdx +157 -0
- package/docs/self-hosting/security.mdx +17 -0
- package/docs/tasks/scheduled.mdx +24 -0
- package/docs/triggering.mdx +1 -1
- package/docs/troubleshooting-zod.mdx +158 -0
- package/package.json +4 -4
- package/skills/trigger-authoring-chat-agent/SKILL.md +41 -29
- package/skills/trigger-chat-agent-advanced/SKILL.md +54 -19
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import { apiClientManager, pageTranscriptEntries, } from "@trigger.dev/core/v3";
|
|
2
|
+
import { readChatSnapshot, writeChatSnapshot } from "./chatSnapshotIo.js";
|
|
3
|
+
export function emptyTranscriptState() {
|
|
4
|
+
return { entries: [], state: null };
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Apply changes to a transcript, in order. Pure: returns a new state and
|
|
8
|
+
* never mutates the input. Replaying the same changes converges, which is
|
|
9
|
+
* what lets a storage retry a failed write without checking what landed.
|
|
10
|
+
*/
|
|
11
|
+
export function reduceTranscriptChanges(prev, changes) {
|
|
12
|
+
let entries = prev.entries.slice();
|
|
13
|
+
let state = prev.state;
|
|
14
|
+
for (const change of changes) {
|
|
15
|
+
switch (change.op) {
|
|
16
|
+
case "put": {
|
|
17
|
+
const message = change.message;
|
|
18
|
+
const entry = { id: message.id, final: change.final ?? true, message };
|
|
19
|
+
const idx = entries.findIndex((e) => e.id === message.id);
|
|
20
|
+
if (idx === -1)
|
|
21
|
+
entries.push(entry);
|
|
22
|
+
else
|
|
23
|
+
entries[idx] = entry;
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
case "remove": {
|
|
27
|
+
entries = entries.filter((e) => e.id !== change.id);
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
case "truncateAfter": {
|
|
31
|
+
const idx = entries.findIndex((e) => e.id === change.afterId);
|
|
32
|
+
if (idx !== -1)
|
|
33
|
+
entries = entries.slice(0, idx + 1);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
case "state": {
|
|
37
|
+
state = change.value ?? null;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return { entries, state };
|
|
43
|
+
}
|
|
44
|
+
function fingerprintMessage(message) {
|
|
45
|
+
return JSON.stringify(message);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build the shadow for `messages`. An id is non-final when this save says so
|
|
49
|
+
* (`nonFinalIds`) or when it was non-final before and its content has not
|
|
50
|
+
* changed: a partial answer stays partial until the message itself changes.
|
|
51
|
+
*/
|
|
52
|
+
export function createTranscriptShadow(messages, nonFinalIds, previous) {
|
|
53
|
+
const ids = [];
|
|
54
|
+
const fingerprints = new Map();
|
|
55
|
+
const nonFinal = new Set();
|
|
56
|
+
for (const message of messages) {
|
|
57
|
+
const fingerprint = fingerprintMessage(message);
|
|
58
|
+
ids.push(message.id);
|
|
59
|
+
fingerprints.set(message.id, fingerprint);
|
|
60
|
+
if (nonFinalIds?.has(message.id) ||
|
|
61
|
+
(previous?.nonFinal.has(message.id) && previous.fingerprints.get(message.id) === fingerprint)) {
|
|
62
|
+
nonFinal.add(message.id);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return { ids, fingerprints, nonFinal };
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Derive the changes that take `shadow` to `next`.
|
|
69
|
+
*
|
|
70
|
+
* The common prefix (by id) is compared message by message and a changed
|
|
71
|
+
* message becomes an in-place `put`. Past the prefix, everything the shadow
|
|
72
|
+
* still had is dropped with one `truncateAfter` on the last common id (or
|
|
73
|
+
* one `remove` per message when there is no common prefix) and everything
|
|
74
|
+
* `next` has is appended with `put`, in order. Applying the result with
|
|
75
|
+
* {@link reduceTranscriptChanges} reproduces `next` exactly, including
|
|
76
|
+
* order, for any two lists.
|
|
77
|
+
*/
|
|
78
|
+
export function diffTranscript(shadow, next, options = {}) {
|
|
79
|
+
const nextShadow = createTranscriptShadow(next, options.nonFinalIds, shadow);
|
|
80
|
+
const changes = [];
|
|
81
|
+
const put = (message) => {
|
|
82
|
+
const final = nextShadow.nonFinal.has(message.id) ? false : undefined;
|
|
83
|
+
changes.push(final === undefined ? { op: "put", message } : { op: "put", message, final });
|
|
84
|
+
};
|
|
85
|
+
let lcp = 0;
|
|
86
|
+
while (lcp < shadow.ids.length && lcp < next.length && shadow.ids[lcp] === next[lcp].id) {
|
|
87
|
+
lcp++;
|
|
88
|
+
}
|
|
89
|
+
for (let i = 0; i < lcp; i++) {
|
|
90
|
+
const message = next[i];
|
|
91
|
+
if (shadow.fingerprints.get(message.id) !== nextShadow.fingerprints.get(message.id) ||
|
|
92
|
+
shadow.nonFinal.has(message.id) !== nextShadow.nonFinal.has(message.id)) {
|
|
93
|
+
put(message);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (shadow.ids.length > lcp) {
|
|
97
|
+
if (lcp > 0) {
|
|
98
|
+
changes.push({ op: "truncateAfter", afterId: shadow.ids[lcp - 1] });
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
for (const id of shadow.ids)
|
|
102
|
+
changes.push({ op: "remove", id });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
for (let i = lcp; i < next.length; i++) {
|
|
106
|
+
put(next[i]);
|
|
107
|
+
}
|
|
108
|
+
return { changes, shadow: nextShadow };
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Roughly how many messages the snapshot keeps once a conversation has
|
|
112
|
+
* compacted. Raising it costs bytes on every save; lowering it shortens how far
|
|
113
|
+
* back a conversation can be rendered from the platform's own store.
|
|
114
|
+
*/
|
|
115
|
+
const SNAPSHOT_KEEP_MESSAGES = 100;
|
|
116
|
+
/**
|
|
117
|
+
* The built-in storage: the transcript in the platform's object store, read by
|
|
118
|
+
* the Sessions dashboard and the transcript API.
|
|
119
|
+
*
|
|
120
|
+
* One object per conversation, rewritten each turn, holding the transcript plus
|
|
121
|
+
* the runtime state. Once a conversation has been compacted, it keeps roughly
|
|
122
|
+
* the last hundred messages rather than all of them, so the object stops
|
|
123
|
+
* growing with the conversation. An app that needs the full history keeps its
|
|
124
|
+
* own transcript storage.
|
|
125
|
+
*/
|
|
126
|
+
export function snapshotTranscriptStorage() {
|
|
127
|
+
return {
|
|
128
|
+
async load(scope, opts) {
|
|
129
|
+
if (opts?.limit !== undefined || opts?.before !== undefined) {
|
|
130
|
+
const page = await readTranscriptPage(scope.chatId, opts);
|
|
131
|
+
if (page)
|
|
132
|
+
return page;
|
|
133
|
+
}
|
|
134
|
+
const snapshot = await readChatSnapshot(scope.chatId);
|
|
135
|
+
const full = snapshot
|
|
136
|
+
? { entries: snapshot.messages, state: snapshot.state }
|
|
137
|
+
: emptyTranscriptState();
|
|
138
|
+
return {
|
|
139
|
+
...pageEntries(full.entries, opts),
|
|
140
|
+
state: full.state,
|
|
141
|
+
cursors: snapshot
|
|
142
|
+
? { lastOutEventId: snapshot.lastOutEventId, lastInEventId: snapshot.lastInEventId }
|
|
143
|
+
: undefined,
|
|
144
|
+
};
|
|
145
|
+
},
|
|
146
|
+
async save(ctx, changeset) {
|
|
147
|
+
const entries = trimTranscriptForSnapshot(changeset.transcript.entries, changeset.transcript.state, { keep: SNAPSHOT_KEEP_MESSAGES });
|
|
148
|
+
await writeChatSnapshot(ctx.chatId, {
|
|
149
|
+
version: 2,
|
|
150
|
+
savedAt: Date.now(),
|
|
151
|
+
messages: entries,
|
|
152
|
+
state: normalizeRuntimeStateForWindow(changeset.transcript.state, entries.map((entry) => entry.id)),
|
|
153
|
+
lastOutEventId: changeset.cursors?.lastOutEventId,
|
|
154
|
+
lastInEventId: changeset.cursors?.lastInEventId,
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* A page of the platform transcript read server-side, for a render read with
|
|
161
|
+
* `limit`/`before` from an app server holding a secret key. `undefined` when
|
|
162
|
+
* the call is not possible from here (a run's public token cannot use the
|
|
163
|
+
* endpoint), so the caller falls back to reading the whole blob.
|
|
164
|
+
*
|
|
165
|
+
* Carries no runtime `state`: the endpoint serves the transcript only, so a
|
|
166
|
+
* paged result always reports `state: null`. The model lane is restored from
|
|
167
|
+
* the whole-blob read instead, which is reachable only with private auth.
|
|
168
|
+
*/
|
|
169
|
+
async function readTranscriptPage(chatId, opts) {
|
|
170
|
+
try {
|
|
171
|
+
const page = await apiClientManager.clientOrThrow().getSessionTranscript(chatId, opts);
|
|
172
|
+
return {
|
|
173
|
+
messages: page.messages,
|
|
174
|
+
state: null,
|
|
175
|
+
cursors: page.cursors,
|
|
176
|
+
nextCursor: page.nextCursor,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/** The storage `chat.agent` uses when none is configured: {@link snapshotTranscriptStorage}. */
|
|
184
|
+
export const defaultStorage = snapshotTranscriptStorage();
|
|
185
|
+
function pageEntries(all, opts) {
|
|
186
|
+
const page = pageTranscriptEntries(all, opts);
|
|
187
|
+
return {
|
|
188
|
+
messages: page.entries.map((e) => e.message),
|
|
189
|
+
nextCursor: page.nextCursor,
|
|
190
|
+
nonFinalIds: page.entries.filter((e) => !e.final).map((e) => e.id),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* A storage that keeps every transcript in process memory. The reference
|
|
195
|
+
* implementation for the conformance tests, and a way to inspect exactly
|
|
196
|
+
* what the runtime hands a storage.
|
|
197
|
+
*/
|
|
198
|
+
export function memoryTranscriptStorage() {
|
|
199
|
+
const transcripts = new Map();
|
|
200
|
+
const changesets = [];
|
|
201
|
+
return {
|
|
202
|
+
changesets,
|
|
203
|
+
transcript(chatId) {
|
|
204
|
+
return transcripts.get(chatId);
|
|
205
|
+
},
|
|
206
|
+
async load(scope, opts) {
|
|
207
|
+
const stored = transcripts.get(scope.chatId);
|
|
208
|
+
if (!stored)
|
|
209
|
+
return { messages: [], state: null, cursors: undefined, nextCursor: undefined };
|
|
210
|
+
return {
|
|
211
|
+
...pageEntries(stored.entries, opts),
|
|
212
|
+
state: stored.state,
|
|
213
|
+
cursors: stored.cursors,
|
|
214
|
+
};
|
|
215
|
+
},
|
|
216
|
+
async save(ctx, changeset) {
|
|
217
|
+
changesets.push({ ctx, changeset });
|
|
218
|
+
const prev = transcripts.get(ctx.chatId);
|
|
219
|
+
const next = reduceTranscriptChanges(prev ?? emptyTranscriptState(), changeset.changes);
|
|
220
|
+
transcripts.set(ctx.chatId, { ...next, cursors: changeset.cursors ?? prev?.cursors });
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* The slice of a transcript worth storing, which is the last `keep` messages
|
|
226
|
+
* once a conversation has compacted, and all of it before that.
|
|
227
|
+
*
|
|
228
|
+
* Expressed relative to the compaction watermark rather than as a plain tail,
|
|
229
|
+
* because everything after the watermark is live context that the next boot
|
|
230
|
+
* converts and must never be dropped. The runtime stamps the watermark at the
|
|
231
|
+
* newest message on each compacted save, so in practice the two coincide and
|
|
232
|
+
* this keeps the last `keep`; the watermark-relative form is what keeps it
|
|
233
|
+
* correct if a watermark ever lands earlier in the transcript.
|
|
234
|
+
*
|
|
235
|
+
* Without a watermark nothing is dropped: every entry is still context.
|
|
236
|
+
*
|
|
237
|
+
* This is what stops the object rewritten each turn from growing with the
|
|
238
|
+
* conversation. An app that needs the whole history keeps its own transcript
|
|
239
|
+
* storage.
|
|
240
|
+
*/
|
|
241
|
+
export function trimTranscriptForSnapshot(entries, state, opts) {
|
|
242
|
+
const throughId = parseTranscriptRuntimeState(state)?.compaction?.throughId;
|
|
243
|
+
if (throughId === undefined || throughId === "")
|
|
244
|
+
return entries;
|
|
245
|
+
const idx = entries.findIndex((entry) => entry.id === throughId);
|
|
246
|
+
if (idx === -1)
|
|
247
|
+
return entries;
|
|
248
|
+
// Keep the watermark entry itself, so a restored lane can still find it.
|
|
249
|
+
const start = Math.max(0, idx + 1 - Math.max(1, opts.keep));
|
|
250
|
+
return start === 0 ? entries : entries.slice(start);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Rewrite runtime state so it still describes the transcript window being
|
|
254
|
+
* persisted.
|
|
255
|
+
*
|
|
256
|
+
* A compaction watermark that has moved out of the window becomes `""`, which
|
|
257
|
+
* is how a restored lane says "the compacted messages cover everything before
|
|
258
|
+
* this window". Left as-is, the watermark would name an entry the window does
|
|
259
|
+
* not contain, and restoring the lane would discard the compacted messages and
|
|
260
|
+
* re-convert the window from scratch — an agent that has silently forgotten the
|
|
261
|
+
* conversation. Injections anchored outside the window go too: the span they
|
|
262
|
+
* belonged to is already inside the compacted lane.
|
|
263
|
+
*/
|
|
264
|
+
export function normalizeRuntimeStateForWindow(state, windowIds) {
|
|
265
|
+
const runtimeState = parseTranscriptRuntimeState(state);
|
|
266
|
+
if (!runtimeState)
|
|
267
|
+
return state;
|
|
268
|
+
const ids = new Set(windowIds);
|
|
269
|
+
const compaction = runtimeState.compaction;
|
|
270
|
+
const watermarkOutside = compaction !== undefined && compaction.throughId !== "" && !ids.has(compaction.throughId);
|
|
271
|
+
const injections = runtimeState.injections?.filter((injection) => injection.afterId === "" || ids.has(injection.afterId));
|
|
272
|
+
if (!watermarkOutside && injections?.length === runtimeState.injections?.length) {
|
|
273
|
+
return state;
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
...runtimeState,
|
|
277
|
+
...(compaction
|
|
278
|
+
? {
|
|
279
|
+
compaction: {
|
|
280
|
+
modelMessages: compaction.modelMessages,
|
|
281
|
+
throughId: watermarkOutside ? "" : compaction.throughId,
|
|
282
|
+
},
|
|
283
|
+
}
|
|
284
|
+
: {}),
|
|
285
|
+
...(injections ? { injections } : {}),
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
export function parseTranscriptRuntimeState(value) {
|
|
289
|
+
if (!value || typeof value !== "object")
|
|
290
|
+
return undefined;
|
|
291
|
+
const record = value;
|
|
292
|
+
if (record.v !== 1)
|
|
293
|
+
return undefined;
|
|
294
|
+
const out = { v: 1 };
|
|
295
|
+
const compaction = record.compaction;
|
|
296
|
+
if (compaction &&
|
|
297
|
+
typeof compaction === "object" &&
|
|
298
|
+
Array.isArray(compaction.modelMessages) &&
|
|
299
|
+
typeof compaction.throughId === "string") {
|
|
300
|
+
out.compaction = {
|
|
301
|
+
modelMessages: compaction.modelMessages,
|
|
302
|
+
throughId: compaction.throughId,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
if (Array.isArray(record.injections)) {
|
|
306
|
+
out.injections = record.injections.flatMap((entry) => {
|
|
307
|
+
const inj = entry;
|
|
308
|
+
return inj && typeof inj.afterId === "string" && Array.isArray(inj.messages)
|
|
309
|
+
? [{ afterId: inj.afterId, messages: inj.messages }]
|
|
310
|
+
: [];
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
if (Array.isArray(record.queued) && record.queued.length > 0) {
|
|
314
|
+
out.queued = record.queued;
|
|
315
|
+
}
|
|
316
|
+
return out;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Rebuild the model lane for a transcript at boot. Uses the persisted
|
|
320
|
+
* compacted lane while the transcript still contains its `throughId`
|
|
321
|
+
* boundary, then converts the rest of the transcript, re-inserting persisted
|
|
322
|
+
* injections after the messages they followed.
|
|
323
|
+
*/
|
|
324
|
+
export async function restoreModelLane(messages, state, convert) {
|
|
325
|
+
const lane = [];
|
|
326
|
+
let start = 0;
|
|
327
|
+
let compacted = false;
|
|
328
|
+
if (state?.compaction) {
|
|
329
|
+
const throughId = state.compaction.throughId;
|
|
330
|
+
const idx = throughId === "" ? -1 : messages.findIndex((m) => m.id === throughId);
|
|
331
|
+
if (idx !== -1 || throughId === "") {
|
|
332
|
+
lane.push(...state.compaction.modelMessages);
|
|
333
|
+
start = idx + 1;
|
|
334
|
+
compacted = true;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const anchored = (state?.injections ?? [])
|
|
338
|
+
.map((inj) => ({
|
|
339
|
+
inj,
|
|
340
|
+
idx: inj.afterId === "" ? -1 : messages.findIndex((m) => m.id === inj.afterId),
|
|
341
|
+
}))
|
|
342
|
+
.filter(({ inj, idx }) => (inj.afterId === "" ? start === 0 : idx >= start))
|
|
343
|
+
.sort((a, b) => a.idx - b.idx);
|
|
344
|
+
let cursor = start;
|
|
345
|
+
for (const { inj, idx } of anchored) {
|
|
346
|
+
if (idx + 1 > cursor) {
|
|
347
|
+
lane.push(...(await convert(messages.slice(cursor, idx + 1))));
|
|
348
|
+
cursor = idx + 1;
|
|
349
|
+
}
|
|
350
|
+
lane.push(...inj.messages);
|
|
351
|
+
}
|
|
352
|
+
if (cursor < messages.length) {
|
|
353
|
+
lane.push(...(await convert(messages.slice(cursor))));
|
|
354
|
+
}
|
|
355
|
+
return { messages: lane, compacted, injections: anchored.map(({ inj }) => inj) };
|
|
356
|
+
}
|
|
357
|
+
//# sourceMappingURL=transcriptStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transcriptStorage.js","sourceRoot":"","sources":["../../../src/v3/transcriptStorage.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const VERSION = "0.0.0-prerelease-
|
|
1
|
+
export const VERSION = "0.0.0-prerelease-20260911094758";
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
package/docs/ai-chat/actions.mdx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Actions"
|
|
3
3
|
sidebarTitle: "Actions"
|
|
4
|
-
description: "Custom commands sent from the frontend that mutate chat state without consuming a turn
|
|
4
|
+
description: "Custom commands sent from the frontend that mutate chat state without consuming a turn: undo, rollback, edit, regenerate."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## Overview
|
|
@@ -44,7 +44,7 @@ export const myChat = chat.agent({
|
|
|
44
44
|
// returning void → side-effect-only, no model call
|
|
45
45
|
},
|
|
46
46
|
|
|
47
|
-
run: async ({ messages, signal }) => {
|
|
47
|
+
run: async ({ messages, signal, streamText }) => {
|
|
48
48
|
return streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal });
|
|
49
49
|
},
|
|
50
50
|
});
|
|
@@ -52,36 +52,68 @@ export const myChat = chat.agent({
|
|
|
52
52
|
|
|
53
53
|
**Lifecycle flow:** Wake → parse action against `actionSchema` → `hydrateMessages` (if set) → **`onAction`** → apply `chat.history` mutations → emit `trigger:turn-complete` → wait for next message.
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
When `onAction` returns `chat.turn()`, the flow continues instead of emitting `trigger:turn-complete`: the edit is snapshotted, then a turn runs on the edited history with `trigger: "action-turn"`, so `onTurnStart`, `run()`, `onBeforeTurnComplete` and `onTurnComplete` all fire and the answer is persisted like any turn's. See [Answering after an action](#answering-after-an-action).
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
## Answering after an action
|
|
58
|
+
|
|
59
|
+
An action is a state edit. To answer after the edit, return `chat.turn()`: the edit is applied and snapshotted, then a turn runs on the edited history exactly as a message turn does. `onTurnStart`, `run()`, `onBeforeTurnComplete` and `onTurnComplete` fire, the turn counter advances, and the answer gets everything a turn has: the agent's system prompt and tools, steering, compaction, injected instructions and persistence.
|
|
58
60
|
|
|
59
61
|
```ts
|
|
60
|
-
onAction: async ({ action
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
onAction: async ({ action }) => {
|
|
63
|
+
switch (action.type) {
|
|
64
|
+
case "undo":
|
|
65
|
+
chat.history.slice(0, -2);
|
|
66
|
+
return; // edit only, no turn
|
|
67
|
+
|
|
68
|
+
case "regenerate":
|
|
69
|
+
chat.history.slice(0, -1);
|
|
70
|
+
return chat.turn(); // answer the edited history
|
|
71
|
+
|
|
72
|
+
case "retry-formal":
|
|
73
|
+
chat.history.slice(0, -1);
|
|
74
|
+
chat.inject([{ role: "system", content: "Answer formally this time." }]);
|
|
75
|
+
return chat.turn(); // with a one-shot instruction
|
|
68
76
|
}
|
|
69
|
-
// other actions return void → side-effect only
|
|
70
77
|
}
|
|
71
78
|
```
|
|
72
79
|
|
|
73
|
-
|
|
80
|
+
`run()` receives the edited history with no incoming user message, the same shape as a `regenerate-message` turn, and its `trigger` is `"action-turn"`, so a `run()` that returns early on `"action"` (the pre-May behaviour, when actions invoked `run()` directly) still answers. Returning anything other than `chat.turn()` or nothing is an error; a response can no longer be returned from `onAction` directly.
|
|
81
|
+
|
|
82
|
+
### Actions and persistence
|
|
83
|
+
|
|
84
|
+
An action that returns nothing does not fire `onTurnComplete`, and that is where an app that owns its own transcript normally writes. What that means depends on which persistence model you use.
|
|
85
|
+
|
|
86
|
+
**Transcript storage** (the default, or your own `storage`): nothing to do. After an action that changed the conversation, the runtime hands the storage a changeset with `reason: "action"`. An undo is one `truncateAfter`; a regenerate is a `truncateAfter` followed by the new answer's `put` when the turn completes; an edit is a `put` for the edited id. The changeset carries the same resume cursors as the last turn. See [Transcript storage](/ai-chat/transcript-storage#what-the-runtime-saves). An action that returns `chat.turn()` is followed by a turn, which persists its answer the way every turn does.
|
|
87
|
+
|
|
88
|
+
**Your own store through the deprecated `hydrateMessages`**: the runtime deliberately does not write, because your store is the source of truth. A history edit lives only in the running worker until you persist it, and a continuation rehydrates from your store, not from what the worker had in memory. Mirror each edit in your store, not only additions: a regenerate is a delete *and* an insert. The answer that follows `chat.turn()` reaches your store through `onTurnComplete`, like any turn's answer.
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
onAction: async ({ action, chatId }) => {
|
|
92
|
+
if (action.type === "undo") {
|
|
93
|
+
chat.history.slice(0, -2);
|
|
94
|
+
await db.deleteLastExchange(chatId); // the rollback is yours to persist
|
|
95
|
+
}
|
|
96
|
+
if (action.type === "regenerate") {
|
|
97
|
+
chat.history.slice(0, -1);
|
|
98
|
+
await db.deleteLastAssistant(chatId); // the delete half
|
|
99
|
+
return chat.turn(); // the insert half arrives in onTurnComplete
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
onTurnComplete: async ({ chatId, newUIMessages }) => {
|
|
103
|
+
await db.saveMessages(chatId, newUIMessages);
|
|
104
|
+
},
|
|
105
|
+
```
|
|
74
106
|
|
|
75
107
|
## Gating actions on HITL state
|
|
76
108
|
|
|
77
109
|
If you have a [human-in-the-loop](/ai-chat/patterns/human-in-the-loop) tool waiting on `addToolOutput`, you usually want to refuse competing actions like `regenerate` until the answer arrives. [`chat.history.getPendingToolCalls()`](/ai-chat/backend#chat-history) gives you exactly that signal:
|
|
78
110
|
|
|
79
111
|
```ts
|
|
80
|
-
onAction: async ({ action
|
|
112
|
+
onAction: async ({ action }) => {
|
|
81
113
|
if (action.type === "regenerate") {
|
|
82
114
|
if (chat.history.getPendingToolCalls().length > 0) return; // gated
|
|
83
115
|
chat.history.slice(0, -1);
|
|
84
|
-
return
|
|
116
|
+
return chat.turn();
|
|
85
117
|
}
|
|
86
118
|
},
|
|
87
119
|
```
|
|
@@ -89,10 +121,10 @@ onAction: async ({ action, messages, signal }) => {
|
|
|
89
121
|
## Sending actions from the frontend
|
|
90
122
|
|
|
91
123
|
```ts
|
|
92
|
-
// Browser
|
|
124
|
+
// Browser: TriggerChatTransport
|
|
93
125
|
const stream = await transport.sendAction(chatId, { type: "undo" });
|
|
94
126
|
|
|
95
|
-
// Server
|
|
127
|
+
// Server: AgentChat
|
|
96
128
|
const stream = await agentChat.sendAction({ type: "rollback", targetMessageId: "msg-3" });
|
|
97
129
|
```
|
|
98
130
|
|
|
@@ -104,8 +136,8 @@ The action payload is validated against `actionSchema` on the backend; invalid a
|
|
|
104
136
|
|
|
105
137
|
## See also
|
|
106
138
|
|
|
107
|
-
- [`chat.history`](/ai-chat/backend#chat-history)
|
|
108
|
-
- [Sending actions from the frontend](/ai-chat/frontend#sending-actions)
|
|
109
|
-
- [`hydrateMessages`](/ai-chat/lifecycle-hooks#hydratemessages)
|
|
110
|
-
- [Branching conversations](/ai-chat/patterns/branching-conversations)
|
|
111
|
-
- [Human-in-the-loop](/ai-chat/patterns/human-in-the-loop)
|
|
139
|
+
- [`chat.history`](/ai-chat/backend#chat-history): the imperative API actions use to mutate state
|
|
140
|
+
- [Sending actions from the frontend](/ai-chat/frontend#sending-actions): sending actions through `useChat` so a turn that follows one renders like any turn
|
|
141
|
+
- [`hydrateMessages`](/ai-chat/lifecycle-hooks#hydratemessages): fires before `onAction` when set
|
|
142
|
+
- [Branching conversations](/ai-chat/patterns/branching-conversations): pairs action handlers with backend-controlled history
|
|
143
|
+
- [Human-in-the-loop](/ai-chat/patterns/human-in-the-loop): gating fresh actions while a tool is waiting
|
package/docs/ai-chat/anatomy.mdx
CHANGED
|
@@ -18,7 +18,7 @@ Everything below maps onto one annotated agent:
|
|
|
18
18
|
|
|
19
19
|
```ts trigger/my-agent.ts
|
|
20
20
|
import { chat } from "@trigger.dev/sdk/ai";
|
|
21
|
-
import {
|
|
21
|
+
import { stepCountIs } from "ai";
|
|
22
22
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
23
23
|
|
|
24
24
|
export const myAgent = chat.agent({
|
|
@@ -36,9 +36,9 @@ export const myAgent = chat.agent({
|
|
|
36
36
|
|
|
37
37
|
// The turn loop. Messages arrive accumulated; you stream back.
|
|
38
38
|
// Options, levels, and alternatives — see Backend.
|
|
39
|
-
run: async ({ messages, tools, signal }) =>
|
|
39
|
+
run: async ({ messages, tools, signal, streamText }) =>
|
|
40
40
|
streamText({
|
|
41
|
-
|
|
41
|
+
tools,
|
|
42
42
|
model: anthropic("claude-sonnet-4-5"),
|
|
43
43
|
messages,
|
|
44
44
|
abortSignal: signal,
|