From 639a000f88a0c00ce49487f65a570338cbe20635 Mon Sep 17 00:00:00 2001 From: Muhammad B Date: Mon, 20 Apr 2026 19:23:53 +0200 Subject: [PATCH 1/2] fix: Resolve trace payload aggregation and historical normalization --- packages/gateway/src/routes/chat-history.ts | 21 ++++++++++++++++--- .../src/services/conversation-service.ts | 5 +++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/gateway/src/routes/chat-history.ts b/packages/gateway/src/routes/chat-history.ts index 52fbfe6d..5f5b7c3c 100644 --- a/packages/gateway/src/routes/chat-history.ts +++ b/packages/gateway/src/routes/chat-history.ts @@ -44,6 +44,21 @@ import type { ChannelIncomingMessage } from '@ownpilot/core'; const log = getLog('ChatHistory'); +function normalizeTrace(trace: any): any { + if (!trace) return trace; + return { + ...trace, + modelCalls: trace.modelCalls || [], + autonomyChecks: trace.autonomyChecks || [], + dbOperations: trace.dbOperations || { reads: 0, writes: 0 }, + memoryOps: trace.memoryOps || { adds: 0, recalls: 0 }, + triggersFired: trace.triggersFired || [], + errors: trace.errors || [], + events: trace.events || [], + toolCalls: trace.toolCalls || [], + }; +} + export const chatHistoryRoutes = new Hono(); // ===================================================== @@ -254,7 +269,7 @@ chatHistoryRoutes.get('/history/:id', async (c) => { provider: msg.provider, model: msg.model, toolCalls: msg.toolCalls, - trace: msg.trace, + trace: normalizeTrace(msg.trace), isError: msg.isError, createdAt: msg.createdAt.toISOString(), })), @@ -315,7 +330,7 @@ chatHistoryRoutes.get('/history/:id/unified', async (c) => { provider: msg.provider, model: msg.model, toolCalls: msg.toolCalls, - trace: msg.trace, + trace: normalizeTrace(msg.trace), isError: msg.isError, createdAt: msg.createdAt.toISOString(), source: 'web' as const, @@ -400,7 +415,7 @@ chatHistoryRoutes.get('/history/:id/unified', async (c) => { provider: msg.provider, model: msg.model, toolCalls: msg.toolCalls, - trace: msg.trace, + trace: normalizeTrace(msg.trace), isError: msg.isError, createdAt: msg.createdAt.toISOString(), source: 'ai', diff --git a/packages/gateway/src/services/conversation-service.ts b/packages/gateway/src/services/conversation-service.ts index d4f97dae..2d4580b4 100644 --- a/packages/gateway/src/services/conversation-service.ts +++ b/packages/gateway/src/services/conversation-service.ts @@ -235,6 +235,11 @@ export class ConversationService { }, ] : [], + autonomyChecks: [], + dbOperations: { reads: 0, writes: 0 }, + memoryOps: { adds: 0, recalls: 0 }, + triggersFired: [], + errors: [], mcpToolEvents, events: mcpToolEvents.map((event) => ({ type: event.type, From 0c6255d0a062779b2eed7a4f055996432ea90398 Mon Sep 17 00:00:00 2001 From: Muhammad B Date: Mon, 20 Apr 2026 19:26:42 +0200 Subject: [PATCH 2/2] style: Modernize main sidebar typography and nest alignments --- packages/ui/src/components/Sidebar.tsx | 252 +++++++++--------- .../components/sidebar/SidebarDataSection.tsx | 8 +- 2 files changed, 128 insertions(+), 132 deletions(-) diff --git a/packages/ui/src/components/Sidebar.tsx b/packages/ui/src/components/Sidebar.tsx index 6beae986..8591b5f0 100644 --- a/packages/ui/src/components/Sidebar.tsx +++ b/packages/ui/src/components/Sidebar.tsx @@ -19,7 +19,7 @@ import { SidebarFooter } from './sidebar/SidebarFooter'; import { SidebarDataSection } from './sidebar/SidebarDataSection'; import { useToast } from './ToastProvider'; import { useDialog } from './ConfirmDialog'; -import { X, ChevronRight, Search, Calendar, Edit2, Trash2, Globe, MessageSquare, Telegram, WhatsApp } from './icons'; +import { X, ChevronRight, Search, Calendar, Edit2, Trash2, Globe, MessageSquare, Telegram, WhatsApp, Settings2 } from './icons'; import type { NavItem } from '../constants/nav-items'; import type { Conversation } from '../api/types'; import { chatApi } from '../api/endpoints/chat'; @@ -56,7 +56,7 @@ function PinnedNavLink({ item, badge, onCloseCustomize, isCustomizeOpen }: { ite clearMessages(); navigate('/', { replace: true }); // Reset backend context (best-effort) - chatApi.resetContext(provider, model).catch(() => {}); + chatApi.resetContext(provider, model).catch(() => { }); } }; @@ -72,10 +72,9 @@ function PinnedNavLink({ item, badge, onCloseCustomize, isCustomizeOpen }: { ite end={item.to === '/'} onClick={handleClick} className={({ isActive }) => - `flex items-center gap-2 px-3 py-2.5 md:py-1.5 rounded-md transition-all text-base ${ - isActive && !isCustomizeOpen && !hasActiveConversation - ? 'bg-primary/10 text-primary border-l-[3px] border-primary' - : 'text-text-secondary dark:text-dark-text-secondary hover:bg-bg-tertiary dark:hover:bg-dark-bg-tertiary hover:translate-x-0.5' + `flex items-center gap-2.5 px-3 py-2 rounded-md transition-colors text-sm font-medium ${isActive && !isCustomizeOpen && !hasActiveConversation + ? 'bg-primary/10 text-primary dark:bg-primary/20' + : 'text-text-secondary dark:text-dark-text-secondary hover:bg-bg-tertiary dark:hover:bg-dark-bg-tertiary hover:text-text-primary dark:hover:text-dark-text-primary' }` } > @@ -203,9 +202,8 @@ export function Sidebar({ isMobile, isOpen, onClose, onSearchOpen, onCustomizeTo data-testid="sidebar" className={ isMobile - ? `fixed inset-y-0 left-0 z-40 w-64 bg-bg-secondary dark:bg-dark-bg-secondary flex flex-col transform transition-transform duration-200 ease-out ${ - isOpen ? 'translate-x-0' : '-translate-x-full' - }` + ? `fixed inset-y-0 left-0 z-40 w-64 bg-bg-secondary dark:bg-dark-bg-secondary flex flex-col transform transition-transform duration-200 ease-out ${isOpen ? 'translate-x-0' : '-translate-x-full' + }` : `${desktopWidthClass} border-r border-border dark:border-dark-border bg-bg-secondary dark:bg-dark-bg-secondary flex flex-col` } > @@ -277,7 +275,7 @@ export function Sidebar({ isMobile, isOpen, onClose, onSearchOpen, onCustomizeTo key="search" onClick={onSearchOpen} data-testid="sidebar-search-btn" - className="w-full flex items-center gap-2 px-3 py-2.5 md:py-1.5 rounded-md transition-all text-base text-text-secondary dark:text-dark-text-secondary hover:bg-bg-tertiary dark:hover:bg-dark-bg-tertiary hover:translate-x-0.5 text-left" + className="w-full flex items-center gap-2.5 px-3 py-2 rounded-md transition-colors text-sm font-medium text-text-secondary dark:text-dark-text-secondary hover:bg-bg-tertiary dark:hover:bg-dark-bg-tertiary hover:text-text-primary dark:hover:text-dark-text-primary text-left" > Search @@ -293,10 +291,9 @@ export function Sidebar({ isMobile, isOpen, onClose, onSearchOpen, onCustomizeTo onClick={onCloseCustomize} data-testid="sidebar-scheduled-link" className={({ isActive }) => - `flex items-center gap-2 px-3 py-2.5 md:py-1.5 rounded-md transition-all text-base ${ - isActive && !isCustomizeOpen - ? 'bg-primary/10 text-primary border-l-[3px] border-primary' - : 'text-text-secondary dark:text-dark-text-secondary hover:bg-bg-tertiary dark:hover:bg-dark-bg-tertiary hover:translate-x-0.5' + `flex items-center gap-2.5 px-3 py-2 rounded-md transition-colors text-sm font-medium ${isActive && !isCustomizeOpen + ? 'bg-primary/10 text-primary dark:bg-primary/20' + : 'text-text-secondary dark:text-dark-text-secondary hover:bg-bg-tertiary dark:hover:bg-dark-bg-tertiary hover:text-text-primary dark:hover:text-dark-text-primary' }` } > @@ -310,13 +307,12 @@ export function Sidebar({ isMobile, isOpen, onClose, onSearchOpen, onCustomizeTo
@@ -330,7 +326,7 @@ export function Sidebar({ isMobile, isOpen, onClose, onSearchOpen, onCustomizeTo - {!collapsed.recents && <>
- recents.setSearch(e.target.value)} - placeholder="Search\u2026" - data-testid="sidebar-recents-search" - className="w-full px-2 py-1 text-xs rounded border border-border dark:border-dark-border bg-bg-primary dark:bg-dark-bg-primary text-text-primary dark:text-dark-text-primary placeholder:text-text-muted focus:outline-none focus:border-primary" - /> -
- {recents.availablePlatforms.size > 0 && ( -
- {(['all', 'web', ...(recents.availablePlatforms.has('whatsapp') ? ['whatsapp'] : []), ...(recents.availablePlatforms.has('telegram') ? ['telegram'] : [])] as SourceFilter[]).map((tab) => ( - - ))} -
- )} - {recents.isLoading && recents.conversations.length === 0 ? ( -
- {[...Array(4)].map((_, i) => ( -
- ))} + {!collapsed.recents && <>
+
+ + recents.setSearch(e.target.value)} + placeholder="Search..." + data-testid="sidebar-recents-search" + className="w-full pl-8 pr-3 py-1.5 text-[13px] rounded-md bg-black/5 dark:bg-white/5 border border-transparent text-text-primary dark:text-dark-text-primary placeholder:text-text-muted focus:outline-none focus:border-primary/50 focus:bg-transparent dark:focus:bg-transparent focus:ring-1 focus:ring-primary/50 transition-all" + />
- ) : recents.conversations.length === 0 ? ( -
- {recents.search ? 'No results' : 'No conversations yet'} -
- ) : ( - <> - {/* Optimistic entries: one per active session, shows immediately +
+ {recents.availablePlatforms.size > 0 && ( +
+ {(['all', 'web', ...(recents.availablePlatforms.has('whatsapp') ? ['whatsapp'] : []), ...(recents.availablePlatforms.has('telegram') ? ['telegram'] : [])] as SourceFilter[]).map((tab) => ( + + ))} +
+ )} + {recents.isLoading && recents.conversations.length === 0 ? ( +
+ {[...Array(4)].map((_, i) => ( +
+ ))} +
+ ) : recents.conversations.length === 0 ? ( +
+ {recents.search ? 'No results' : 'No conversations yet'} +
+ ) : ( + <> + {/* Optimistic entries: one per active session, shows immediately when user sends a message. Each persists in sidebar until the DB row arrives via WS chat:history:updated. */} - {optimisticEntries.map((entry) => { - const isActive = activeConversationId === entry.id; - return ( -
-
handleRecentClick(entry.id)} - className={`group relative flex items-center gap-1.5 px-2 py-1.5 mx-1 my-0.5 rounded-md cursor-pointer transition-colors ${ - isActive ? 'bg-primary/10 text-primary' : 'hover:bg-bg-tertiary dark:hover:bg-dark-bg-tertiary text-text-secondary dark:text-dark-text-secondary' - }`} - > - - {entry.title} -
-
- ); - })} - {recents.groups.map((group) => ( -
-

{group.label}

- {group.items.map((conv) => { - const isActiveConv = activeConversationId === conv.id; - const isEditing = recents.editingId === conv.id; - const title = getConvTitle(conv); - const isChannel = conv.source === 'channel'; - const isTelegram = conv.channelPlatform === 'telegram'; + {optimisticEntries.map((entry) => { + const isActive = activeConversationId === entry.id; return ( -
handleRecentClick(conv.id)} - className={`group relative flex items-center gap-1.5 px-2 py-1.5 mx-1 my-0.5 rounded-md cursor-pointer transition-colors ${ - isActiveConv ? 'bg-primary/10 text-primary' : 'hover:bg-bg-tertiary dark:hover:bg-dark-bg-tertiary text-text-secondary dark:text-dark-text-secondary' - }`} - > - {isChannel && isTelegram ? : isChannel && conv.channelPlatform === 'whatsapp' ? : isChannel ? : } - {isEditing ? ( - recents.setEditTitle(e.target.value)} - onBlur={() => handleCommitEdit(conv.id)} - onKeyDown={(e) => { if (e.key === 'Enter') handleCommitEdit(conv.id); if (e.key === 'Escape') recents.cancelEdit(); }} - onClick={(e) => e.stopPropagation()} - className="flex-1 min-w-0 text-xs bg-bg-primary dark:bg-dark-bg-primary border border-primary rounded px-1 py-0.5 outline-none" - autoFocus - /> - ) : ( - {title} - )} - {!isEditing && ( -
- - -
- )} +
+
handleRecentClick(entry.id)} + className={`group relative flex items-center gap-2 pl-7 pr-2 py-1.5 mx-2 my-0.5 rounded-md cursor-pointer transition-colors ${isActive ? 'bg-primary/10 text-primary dark:bg-primary/20 font-medium' : 'hover:bg-bg-tertiary dark:hover:bg-dark-bg-tertiary text-text-secondary dark:text-dark-text-secondary hover:text-text-primary dark:hover:text-dark-text-primary text-[13px]' + }`} + > + + {entry.title} +
); })} -
- ))} - - )} - {recents.total > recents.conversations.length && ( -

+{recents.total - recents.conversations.length} older

- )} - - All conversations → - + {recents.groups.map((group) => ( +
+

{group.label}

+ {group.items.map((conv) => { + const isActiveConv = activeConversationId === conv.id; + const isEditing = recents.editingId === conv.id; + const title = getConvTitle(conv); + const isChannel = conv.source === 'channel'; + const isTelegram = conv.channelPlatform === 'telegram'; + return ( +
handleRecentClick(conv.id)} + className={`group relative flex items-center gap-2 pl-7 pr-2 py-1.5 mx-2 my-0.5 rounded-md cursor-pointer transition-colors ${isActiveConv ? 'bg-primary/10 text-primary dark:bg-primary/20 font-medium' : 'hover:bg-bg-tertiary dark:hover:bg-dark-bg-tertiary text-text-secondary dark:text-dark-text-secondary hover:text-text-primary dark:hover:text-dark-text-primary text-[13px]' + }`} + > + {isChannel && isTelegram ? : isChannel && conv.channelPlatform === 'whatsapp' ? : isChannel ? : } + {isEditing ? ( + recents.setEditTitle(e.target.value)} + onBlur={() => handleCommitEdit(conv.id)} + onKeyDown={(e) => { if (e.key === 'Enter') handleCommitEdit(conv.id); if (e.key === 'Escape') recents.cancelEdit(); }} + onClick={(e) => e.stopPropagation()} + className="flex-1 min-w-0 text-xs bg-bg-primary dark:bg-dark-bg-primary border border-primary rounded px-1 py-0.5 outline-none" + autoFocus + /> + ) : ( + {title} + )} + {!isEditing && ( +
+ + +
+ )} +
+ ); + })} +
+ ))} + + )} + {recents.total > recents.conversations.length && ( +

+{recents.total - recents.conversations.length} older

+ )} + + All conversations → + }
diff --git a/packages/ui/src/components/sidebar/SidebarDataSection.tsx b/packages/ui/src/components/sidebar/SidebarDataSection.tsx index 304eb04e..c98fc1e2 100644 --- a/packages/ui/src/components/sidebar/SidebarDataSection.tsx +++ b/packages/ui/src/components/sidebar/SidebarDataSection.tsx @@ -43,7 +43,7 @@ export function SidebarDataSection({ @@ -84,12 +84,12 @@ export function SidebarDataSection({ ) : items.length === 0 ? (
No {label.toLowerCase()}
) : ( -
+
{items.map((item) => (