Add group parameter to parser chunk for message grouping

This commit is contained in:
Torsten Dittmann
2025-05-13 19:49:55 +02:00
parent 6637f87821
commit 57f2c8e4e3
5 changed files with 62 additions and 14 deletions
+4 -1
View File
@@ -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();
+7 -2
View File
@@ -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<ParsedItem[]>([]);
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
};
@@ -0,0 +1,46 @@
import type { Action } from './parser';
interface Item<T> {
id: symbol;
status: 'waiting' | 'processing' | 'done';
data: T;
}
type Lists<T> = Record<symbol | string, Item<T>[]>;
class Queue<T> {
public lists = $state<Record<symbol | string, Item<T>[]>>({});
public enqueue(list: keyof Lists<T>, 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<T>): Item<T> {
const item = this.lists[list].find((item) => item.status === 'waiting');
if (item) {
item.status = 'processing';
}
return item;
}
public update(list: keyof Lists<T>, id: symbol, status: Item<T>['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<Action>();
+4 -1
View File
@@ -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', {
@@ -1,22 +1,13 @@
<script lang="ts">
import {
Layout,
Typography,
Divider,
Icon,
Button,
ActionMenu
} from '@appwrite.io/pink-svelte';
import { Layout, Typography, Divider, Icon, Button } from '@appwrite.io/pink-svelte';
import { isTabSelected } from '$lib/helpers/load';
import { page } from '$app/state';
import { ActionDropdown, Tab, Tabs, Terminal } from '$lib/components';
import { base } from '$app/paths';
import { isSmallViewport } from '$lib/stores/viewport';
import {
IconAppwrite,
IconChevronDoubleDown,
IconChevronDoubleUp,
IconChevronDown,
IconPlusSm,
IconTerminal,
IconPlus