Skip to content

Commit 0a1688e

Browse files
committed
docs(ai-chat): atomic onTurnComplete writes + Anthropic prose
Three fixes for issues caught after the docs PR merged: - Both onTurnComplete examples (Database persistence "Complete example" and Lifecycle hooks reference) now use db.$transaction([...]) instead of two separate awaits. The non-atomic form contradicted the warning earlier on the persistence page and reintroduced the exact race condition that warning calls out: a refresh between the two writes reads a stale lastEventId and duplicates the assistant message on resume. - Background injection self-review prose said "gpt-4o-mini" but the code in the same example uses claude-haiku-4-5. Aligned the prose.
1 parent 80bb600 commit 0a1688e

3 files changed

Lines changed: 26 additions & 20 deletions

File tree

docs/ai-chat/background-injection.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ export const myChat = chat.agent({
154154
});
155155
```
156156

157-
The self-review runs on `gpt-4o-mini` (fast, cheap) in the background. If the user sends another message before it completes, the coaching is still injected — `chat.inject()` persists across the idle wait.
157+
The self-review runs on `claude-haiku-4-5` (fast, cheap) in the background. If the user sends another message before it completes, the coaching is still injected — `chat.inject()` persists across the idle wait.
158158

159159
## Other use cases
160160

docs/ai-chat/lifecycle-hooks.mdx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -412,15 +412,18 @@ Fires after each turn completes, after the response is captured and the stream i
412412
export const myChat = chat.agent({
413413
id: "my-chat",
414414
onTurnComplete: async ({ chatId, uiMessages, runId, chatAccessToken, lastEventId }) => {
415-
await db.chat.update({
416-
where: { id: chatId },
417-
data: { messages: uiMessages },
418-
});
419-
await db.chatSession.upsert({
420-
where: { id: chatId },
421-
create: { id: chatId, runId, publicAccessToken: chatAccessToken, lastEventId },
422-
update: { runId, publicAccessToken: chatAccessToken, lastEventId },
423-
});
415+
// Atomic write — see Database persistence for the race-condition rationale
416+
await db.$transaction([
417+
db.chat.update({
418+
where: { id: chatId },
419+
data: { messages: uiMessages },
420+
}),
421+
db.chatSession.upsert({
422+
where: { id: chatId },
423+
create: { id: chatId, runId, publicAccessToken: chatAccessToken, lastEventId },
424+
update: { runId, publicAccessToken: chatAccessToken, lastEventId },
425+
}),
426+
]);
424427
},
425428
run: async ({ messages, signal }) => {
426429
return streamText({ model: anthropic("claude-sonnet-4-5"), messages, abortSignal: signal });

docs/ai-chat/patterns/database-persistence.mdx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -258,16 +258,19 @@ export const myChat = chat.agent({
258258
});
259259
},
260260
onTurnComplete: async ({ chatId, uiMessages, runId, chatAccessToken, lastEventId }) => {
261-
// Persist assistant response + stream position
262-
await db.chat.update({
263-
where: { id: chatId },
264-
data: { messages: uiMessages },
265-
});
266-
await db.chatSession.upsert({
267-
where: { id: chatId },
268-
create: { id: chatId, runId, publicAccessToken: chatAccessToken, lastEventId },
269-
update: { runId, publicAccessToken: chatAccessToken, lastEventId },
270-
});
261+
// Persist assistant response + stream position atomically — see the
262+
// race-condition warning earlier on this page.
263+
await db.$transaction([
264+
db.chat.update({
265+
where: { id: chatId },
266+
data: { messages: uiMessages },
267+
}),
268+
db.chatSession.upsert({
269+
where: { id: chatId },
270+
create: { id: chatId, runId, publicAccessToken: chatAccessToken, lastEventId },
271+
update: { runId, publicAccessToken: chatAccessToken, lastEventId },
272+
}),
273+
]);
271274
},
272275
run: async ({ messages, signal }) => {
273276
return streamText({

0 commit comments

Comments
 (0)