From c014d22c9f748588f042dd58f7a2272a00a839bf Mon Sep 17 00:00:00 2001 From: amosblomqvist Date: Sat, 5 Sep 2026 21:36:04 +0300 Subject: [PATCH] Wire the 409 merge-retry transport into the chat (the one-line seam) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit chat.tsx now uses createChatTransport(chatId): a send racing the wake pipeline waits for the in-flight turn, merges onto the fresh server record, and re-POSTs instead of surfacing the 409 banner. Also fixes the transport's import to the core barrel (shell import law). The optional "server-ahead heal" line in the jobs poller was considered and skipped: the racing turn IS the wake turn, whose completion flips the job to done within a poll tick or two — the existing settle-triggered syncFromServer already heals the post-merge gap within ~1-2s. The extra record fetch on every poll tick would double poll traffic for a path the settle sync already covers. --- components/chat-transport.ts | 2 +- components/chat.tsx | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/components/chat-transport.ts b/components/chat-transport.ts index 1a5d7a3..9b9243c 100644 --- a/components/chat-transport.ts +++ b/components/chat-transport.ts @@ -21,7 +21,7 @@ * a future "server-ahead" heal in the poller). Rare path; self-heals. */ import { DefaultChatTransport } from "ai"; -import type { TeacherUIMessage } from "@/src/core/ui-message"; +import type { TeacherUIMessage } from "@/src/core"; /** How often to poll turnInFlight while the racing turn runs. */ const TURN_POLL_MS = 500; diff --git a/components/chat.tsx b/components/chat.tsx index 73779cb..6f089b8 100644 --- a/components/chat.tsx +++ b/components/chat.tsx @@ -2,7 +2,8 @@ import { createContext, Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; import { useChat } from "@ai-sdk/react"; -import { DefaultChatTransport, isToolUIPart, lastAssistantMessageIsCompleteWithToolCalls } from "ai"; +import { isToolUIPart, lastAssistantMessageIsCompleteWithToolCalls } from "ai"; +import { createChatTransport } from "@/components/chat-transport"; import { useStickToBottomContext } from "use-stick-to-bottom"; import { Conversation, @@ -81,7 +82,7 @@ export function Chat({ useChat({ id: chatId, messages: initialMessages, - transport: new DefaultChatTransport({ api: "/api/chat", body: { chatId } }), + transport: createChatTransport(chatId), // After the learner answers (addToolOutput), automatically send the // continuation request so the teacher reacts to the answer. sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,