From 57f2c8e4e312f2416006835bc9455ded82ea1af8 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Tue, 13 May 2025 19:49:55 +0200 Subject: [PATCH] Add group parameter to parser chunk for message grouping --- src/lib/components/studio/chat/chat.svelte | 5 +- src/lib/components/studio/chat/parser.ts | 9 +++- .../components/studio/chat/queue.svelte.ts | 46 +++++++++++++++++++ src/lib/components/studio/chatWrapper.svelte | 5 +- .../studio/artifact-[artifact]/+layout.svelte | 11 +---- 5 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 src/lib/components/studio/chat/queue.svelte.ts diff --git a/src/lib/components/studio/chat/chat.svelte b/src/lib/components/studio/chat/chat.svelte index 23576a817..1e68a8370 100644 --- a/src/lib/components/studio/chat/chat.svelte +++ b/src/lib/components/studio/chat/chat.svelte @@ -67,9 +67,12 @@ const reader = response.body.getReader(); const decoder = new TextDecoder(); + const group = Symbol(); let chunk = await reader.read(); while (!chunk.done) { - parser.chunk(decoder.decode(chunk.value), 'system'); + parser.chunk(decoder.decode(chunk.value), 'system', { + group + }); chunk = await reader.read(); } parser.end(); diff --git a/src/lib/components/studio/chat/parser.ts b/src/lib/components/studio/chat/parser.ts index b7ae0f0f9..69bf24a14 100644 --- a/src/lib/components/studio/chat/parser.ts +++ b/src/lib/components/studio/chat/parser.ts @@ -5,6 +5,7 @@ export type ActionType = 'file' | 'shell'; interface Base { id: symbol; from: 'user' | 'system' | 'error'; + group: string | symbol | null; content: string; complete: boolean; } @@ -25,6 +26,7 @@ export type ParsedItem = Action | TextChunk; export class StreamParser { private items: ParsedItem[] = []; private store = writable([]); + private currentGroup: Base['group'] = null; private currentFrom: Base['from'] = 'system'; private currentAction: Action | null = null; private currentTextChunk: TextChunk | null = null; @@ -45,7 +47,7 @@ export class StreamParser { private triggerCallbacks(event: keyof typeof this.callbacks, action: Action) { if (!this.callbacksEnabled) return; - this.callbacks.complete.forEach((callback) => callback(action)); + this.callbacks[event].forEach((callback) => callback(action)); } /** @@ -68,7 +70,7 @@ export class StreamParser { public chunk( text: string, from: Base['from'], - options: { silent: boolean } = { silent: false } + options: { silent?: boolean; group?: Base['group'] } = { silent: false, group: null } ): void { // If the source changes, complete the current text chunk if (this.currentFrom !== from) { @@ -79,6 +81,7 @@ export class StreamParser { } } + this.currentGroup = options.group; this.currentFrom = from; this.callbacksEnabled = !options.silent; this.buffer += text; @@ -224,6 +227,7 @@ export class StreamParser { this.currentAction = { id: Symbol(), from: this.currentFrom, + group: this.currentGroup, type, src: attributes.src, content: '', @@ -289,6 +293,7 @@ export class StreamParser { this.currentTextChunk = { id: Symbol(), from: this.currentFrom, + group: this.currentGroup, content: text, complete: false }; diff --git a/src/lib/components/studio/chat/queue.svelte.ts b/src/lib/components/studio/chat/queue.svelte.ts new file mode 100644 index 000000000..a70470768 --- /dev/null +++ b/src/lib/components/studio/chat/queue.svelte.ts @@ -0,0 +1,46 @@ +import type { Action } from './parser'; + +interface Item { + id: symbol; + status: 'waiting' | 'processing' | 'done'; + data: T; +} + +type Lists = Record[]>; + +class Queue { + public lists = $state[]>>({}); + + public enqueue(list: keyof Lists, item: T): symbol { + if (!this.lists[list]) { + this.lists[list] = []; + } + const id = Symbol(); + this.lists[list].push({ + id, + status: 'waiting', + data: item + }); + + return id; + } + + public dequeue(list: keyof Lists): Item { + const item = this.lists[list].find((item) => item.status === 'waiting'); + if (item) { + item.status = 'processing'; + } + + return item; + } + + public update(list: keyof Lists, id: symbol, status: Item['status'], data: T): void { + const item = this.lists[list].find((item) => item.id === id); + if (item) { + item.data = data; + item.status = status; + } + } +} + +export const queue = new Queue(); diff --git a/src/lib/components/studio/chatWrapper.svelte b/src/lib/components/studio/chatWrapper.svelte index bb8e01395..a5ac109ab 100644 --- a/src/lib/components/studio/chatWrapper.svelte +++ b/src/lib/components/studio/chatWrapper.svelte @@ -14,6 +14,7 @@ import { isSmallViewport } from '$lib/stores/viewport'; import { filesystem } from '$lib/components/editor/filesystem'; import { previewFrameRef } from '$routes/(console)/project-[project]/store'; + import { queue } from './chat/queue.svelte'; $effect(() => { if ($isSmallViewport || page.params.artifact) { @@ -125,13 +126,15 @@ for (const message of messages) { const from = message.role === 'assistant' ? 'system' : 'user'; parser.chunk(message.content, from, { - silent: true + silent: true, + group: message.$id }); parser.end(); } }); parser.on('complete', async (action) => { + queue.enqueue(action.group, action); switch (action.type) { case 'file': await synapse.dispatch('fs', { diff --git a/src/routes/(console)/project-[project]/studio/artifact-[artifact]/+layout.svelte b/src/routes/(console)/project-[project]/studio/artifact-[artifact]/+layout.svelte index 71ec000ce..5e28c2313 100644 --- a/src/routes/(console)/project-[project]/studio/artifact-[artifact]/+layout.svelte +++ b/src/routes/(console)/project-[project]/studio/artifact-[artifact]/+layout.svelte @@ -1,22 +1,13 @@