summaryrefslogtreecommitdiffhomepage
path: root/src/features
diff options
context:
space:
mode:
Diffstat (limited to 'src/features')
-rw-r--r--src/features/chat/store.svelte.ts2
-rw-r--r--src/features/chat/store.test.ts58
2 files changed, 60 insertions, 0 deletions
diff --git a/src/features/chat/store.svelte.ts b/src/features/chat/store.svelte.ts
index e997f49..1d8ab17 100644
--- a/src/features/chat/store.svelte.ts
+++ b/src/features/chat/store.svelte.ts
@@ -6,6 +6,7 @@ import type {
import type { ChatMessage } from "@dispatch/wire";
import type { RenderedChunk, TranscriptState } from "../../core/chunks";
import {
+ appendUserMessage,
applyHistory,
foldEvent,
initialState,
@@ -94,6 +95,7 @@ export function createChatStore(deps: ChatStoreDependencies): ChatStore {
},
send(text: string): void {
+ transcript = appendUserMessage(transcript, text);
const msg: ChatSendMessage = {
type: "chat.send",
conversationId: deps.conversationId,
diff --git a/src/features/chat/store.test.ts b/src/features/chat/store.test.ts
index 4ec40a9..de60b14 100644
--- a/src/features/chat/store.test.ts
+++ b/src/features/chat/store.test.ts
@@ -436,4 +436,62 @@ describe("createChatStore", () => {
store.dispose();
});
+
+ it("send optimistically shows the user message immediately", () => {
+ const transport = createFakeTransport();
+ const historySync = createFakeHistorySync();
+ const cache = createFakeCache();
+ const store = createChatStore({
+ conversationId: CONV_ID,
+ transport: transport.impl,
+ historySync: historySync.impl,
+ cache: cache.impl,
+ });
+
+ store.send("hi");
+
+ expect(store.messages).toHaveLength(1);
+ expect(store.messages[0]?.role).toBe("user");
+ expect(store.messages[0]?.chunks).toHaveLength(1);
+ expect(store.messages[0]?.chunks[0]?.type).toBe("text");
+ expect((store.messages[0]?.chunks[0] as { type: "text"; text: string }).text).toBe("hi");
+
+ store.dispose();
+ });
+
+ it("the optimistic user message is replaced after turn-sealed + history sync", async () => {
+ const transport = createFakeTransport();
+ const historySync = createFakeHistorySync();
+ const cache = createFakeCache();
+ const store = createChatStore({
+ conversationId: CONV_ID,
+ transport: transport.impl,
+ historySync: historySync.impl,
+ cache: cache.impl,
+ });
+
+ historySync.returnChunks = [
+ { seq: 1, role: "user", chunk: { type: "text", text: "hi" } },
+ { seq: 2, role: "assistant", chunk: { type: "text", text: "hello!" } },
+ ];
+
+ store.send("hi");
+ expect(store.messages).toHaveLength(1);
+ expect(store.messages[0]?.role).toBe("user");
+
+ store.handleDelta(deltaEvent({ type: "turn-start", conversationId: CONV_ID, turnId: "t1" }));
+ store.handleDelta(
+ deltaEvent({ type: "text-delta", conversationId: CONV_ID, turnId: "t1", delta: "hello!" }),
+ );
+ store.handleDelta(deltaEvent({ type: "turn-sealed", conversationId: CONV_ID, turnId: "t1" }));
+
+ await vi.waitFor(() => {
+ expect(store.messages.length).toBe(2);
+ });
+
+ expect(store.messages[0]?.role).toBe("user");
+ expect(store.messages[1]?.role).toBe("assistant");
+
+ store.dispose();
+ });
});