mirror of
https://github.com/davidkaya/aryx.git
synced 2026-08-07 04:08:45 +02:00
fix: stream session updates live
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
pruneSessionActivities,
|
||||
type SessionActivityMap,
|
||||
} from '@renderer/lib/sessionActivity';
|
||||
import { applySessionEventWorkspace } from '@renderer/lib/sessionWorkspace';
|
||||
import { WelcomePane } from '@renderer/components/WelcomePane';
|
||||
import { getElectronApi } from '@renderer/lib/electronApi';
|
||||
import type { PatternDefinition } from '@shared/domain/pattern';
|
||||
@@ -70,6 +71,7 @@ export default function App() {
|
||||
});
|
||||
|
||||
const offSessionEvent = api.onSessionEvent((event) => {
|
||||
setWorkspace((current) => applySessionEventWorkspace(current, event));
|
||||
setSessionActivities((current) => applySessionEventActivity(current, event));
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
import type { SessionEventRecord } from '@shared/domain/event';
|
||||
import type { ChatMessageRecord, SessionRecord } from '@shared/domain/session';
|
||||
import type { WorkspaceState } from '@shared/domain/workspace';
|
||||
|
||||
export function applySessionEventWorkspace(
|
||||
current: WorkspaceState | undefined,
|
||||
event: SessionEventRecord,
|
||||
): WorkspaceState | undefined {
|
||||
if (!current) {
|
||||
return current;
|
||||
}
|
||||
|
||||
const sessionIndex = current.sessions.findIndex((session) => session.id === event.sessionId);
|
||||
if (sessionIndex < 0) {
|
||||
return current;
|
||||
}
|
||||
|
||||
const session = current.sessions[sessionIndex];
|
||||
const nextSession = applySessionEvent(session, event);
|
||||
if (nextSession === session) {
|
||||
return current;
|
||||
}
|
||||
|
||||
const nextSessions = current.sessions.slice();
|
||||
nextSessions[sessionIndex] = nextSession;
|
||||
return {
|
||||
...current,
|
||||
sessions: nextSessions,
|
||||
};
|
||||
}
|
||||
|
||||
function applySessionEvent(session: SessionRecord, event: SessionEventRecord): SessionRecord {
|
||||
switch (event.kind) {
|
||||
case 'status':
|
||||
return applyStatusEvent(session, event);
|
||||
case 'error':
|
||||
return applyErrorEvent(session, event);
|
||||
case 'message-delta':
|
||||
return applyMessageDeltaEvent(session, event);
|
||||
case 'message-complete':
|
||||
return applyMessageCompleteEvent(session, event);
|
||||
default:
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
function applyStatusEvent(session: SessionRecord, event: SessionEventRecord): SessionRecord {
|
||||
if (!event.status) {
|
||||
return session;
|
||||
}
|
||||
|
||||
if (session.status === event.status && (event.status === 'error' || !session.lastError)) {
|
||||
return session;
|
||||
}
|
||||
|
||||
return {
|
||||
...session,
|
||||
status: event.status,
|
||||
lastError: event.status === 'error' ? session.lastError : undefined,
|
||||
updatedAt: event.occurredAt,
|
||||
};
|
||||
}
|
||||
|
||||
function applyErrorEvent(session: SessionRecord, event: SessionEventRecord): SessionRecord {
|
||||
const error = event.error?.trim();
|
||||
if (session.status === 'error' && session.lastError === error) {
|
||||
return session;
|
||||
}
|
||||
|
||||
return {
|
||||
...session,
|
||||
status: 'error',
|
||||
lastError: error,
|
||||
updatedAt: event.occurredAt,
|
||||
};
|
||||
}
|
||||
|
||||
function applyMessageDeltaEvent(session: SessionRecord, event: SessionEventRecord): SessionRecord {
|
||||
if (!event.messageId || event.contentDelta === undefined) {
|
||||
return session;
|
||||
}
|
||||
|
||||
const messageIndex = session.messages.findIndex((message) => message.id === event.messageId);
|
||||
if (messageIndex >= 0) {
|
||||
const existing = session.messages[messageIndex];
|
||||
const nextMessage: ChatMessageRecord = {
|
||||
...existing,
|
||||
authorName: event.authorName ?? existing.authorName,
|
||||
content: `${existing.content}${event.contentDelta}`,
|
||||
pending: true,
|
||||
};
|
||||
|
||||
if (
|
||||
nextMessage.authorName === existing.authorName
|
||||
&& nextMessage.content === existing.content
|
||||
&& existing.pending
|
||||
) {
|
||||
return session;
|
||||
}
|
||||
|
||||
const nextMessages = session.messages.slice();
|
||||
nextMessages[messageIndex] = nextMessage;
|
||||
return {
|
||||
...session,
|
||||
messages: nextMessages,
|
||||
updatedAt: event.occurredAt,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...session,
|
||||
messages: [
|
||||
...session.messages,
|
||||
{
|
||||
id: event.messageId,
|
||||
role: 'assistant',
|
||||
authorName: event.authorName ?? 'assistant',
|
||||
content: event.contentDelta,
|
||||
createdAt: event.occurredAt,
|
||||
pending: true,
|
||||
},
|
||||
],
|
||||
updatedAt: event.occurredAt,
|
||||
};
|
||||
}
|
||||
|
||||
function applyMessageCompleteEvent(session: SessionRecord, event: SessionEventRecord): SessionRecord {
|
||||
if (!event.messageId) {
|
||||
return session;
|
||||
}
|
||||
|
||||
const messageIndex = session.messages.findIndex((message) => message.id === event.messageId);
|
||||
if (messageIndex < 0) {
|
||||
return session;
|
||||
}
|
||||
|
||||
const existing = session.messages[messageIndex];
|
||||
const nextMessage: ChatMessageRecord = {
|
||||
...existing,
|
||||
authorName: event.authorName ?? existing.authorName,
|
||||
pending: false,
|
||||
};
|
||||
|
||||
if (nextMessage.authorName === existing.authorName && !existing.pending) {
|
||||
return session;
|
||||
}
|
||||
|
||||
const nextMessages = session.messages.slice();
|
||||
nextMessages[messageIndex] = nextMessage;
|
||||
return {
|
||||
...session,
|
||||
messages: nextMessages,
|
||||
updatedAt: event.occurredAt,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user