Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/components/ConversationSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const ConversationSettings: FC<ConversationSettingsProps> = ({ conversati
const isLoading = isLoadingConfig || (!chatConfig && !configError && !isDemo);

return (
<div className="flex flex-col">
<div className="flex h-full flex-col">
{isLoading ? (
<div className="flex h-full items-center justify-center p-8">
<div className="flex flex-col items-center gap-4">
Expand Down Expand Up @@ -85,7 +85,7 @@ export const ConversationSettings: FC<ConversationSettingsProps> = ({ conversati
) : (
<Form {...form}>
<form onSubmit={handleSubmit(onSubmit)} className="flex h-full flex-col">
<div className="flex-1 space-y-8 overflow-y-auto p-4 pb-24">
<div className="flex-1 space-y-8 overflow-y-auto p-4 pb-12">
<h3 className="mt-4 text-lg font-medium">Chat Settings</h3>

{/* Conversation Name Field */}
Expand Down Expand Up @@ -226,7 +226,7 @@ export const ConversationSettings: FC<ConversationSettingsProps> = ({ conversati
</div>

{/* Submit Button */}
<div className="sticky bottom-0 mt-auto border-t bg-background p-4">
<div className="flex-shrink-0 border-t bg-background p-4">
<Button
type="submit"
disabled={!isDirty || isSubmitting}
Expand Down
16 changes: 10 additions & 6 deletions src/components/MainLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,18 @@ const MainLayout: FC<Props> = ({ conversationId, taskId }) => {
});

// Handle initial conversation/task selection
if (conversationId) {
if (conversationId && selectedConversation$.get() !== conversationId) {
selectedConversation$.set(conversationId);
} else if (taskId) {
} else if (taskId && selectedTask$.get() !== taskId) {
selectedTask$.set(taskId);
} else {
// Explicitly clear both selected conversation and conversation state
selectedConversation$.set('');
selectedTask$.set('');
} else if (!conversationId && !taskId) {
// Only clear if they're not already empty
if (selectedConversation$.get() !== '') {
selectedConversation$.set('');
}
if (selectedTask$.get() !== '') {
selectedTask$.set('');
}
}
}, [conversationId, taskId]);

Expand Down
2 changes: 1 addition & 1 deletion src/components/RightSidebarContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ export const RightSidebarContent: FC<Props> = ({ conversationId, activeTab }) =>
}
};

return <div className="h-full overflow-auto border-l bg-background">{renderContent()}</div>;
return <div className="h-full border-l bg-background">{renderContent()}</div>;
};
2 changes: 1 addition & 1 deletion src/components/settings/ToolsConfiguration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const ToolsConfiguration = ({ form, toolFields, isSubmitting }: ToolsConf

{/* Tools listing */}
<div className="space-y-4">
<FormDescription>List of tools that the agent can use.</FormDescription>
<FormDescription>Tools that the agent can use.</FormDescription>

{/* Current tools as badges */}
{fields.length > 0 && (
Expand Down
54 changes: 46 additions & 8 deletions src/hooks/useConversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,11 @@ export function useConversation(conversationId: string) {
}

// Check if conversation already has data (e.g., from placeholder)
const existingConversation = conversations$.get(conversationId);
const hasExistingMessages =
existingConversation && existingConversation.data.log.length > 0;

const hasExistingMessages = conversation$?.data.log.peek()?.length > 0;
console.log('[useConversation] Loading conversation', {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The newly added console.log statements (e.g., logging conversation load info) may be too verbose for production. Consider gating these behind a debug flag or using a proper logging utility.

conversationId,
hasExistingMessages,
});
if (!hasExistingMessages) {
// Only load from API if we don't already have conversation data
try {
Expand All @@ -78,6 +79,7 @@ export function useConversation(conversationId: string) {
try {
const chatConfig = await api.getChatConfig(conversationId);
updateConversation(conversationId, { data, chatConfig });
console.log(`[useConversation] Loaded conversation and config for ${conversationId}`);
} catch (error) {
console.warn(
`[useConversation] Failed to load chat config for ${conversationId}:`,
Expand Down Expand Up @@ -126,21 +128,56 @@ export function useConversation(conversationId: string) {
// Add empty message placeholder if needed
const messages$ = conversation$?.data.log;
const lastMessage$ = messages$?.[messages$.length - 1];
if (lastMessage$.role.get() !== 'assistant' || lastMessage$.content.get() !== '') {
console.log(
'[useConversation] MessageStart - messages count:',
messages$?.length,
'lastMessage role:',
lastMessage$?.role?.get(),
'content:',
JSON.stringify(lastMessage$?.content?.get())
);
if (
!lastMessage$ ||
lastMessage$.role.get() !== 'assistant' ||
lastMessage$.content.get() !== ''
) {
const streamingMessage: StreamingMessage = {
role: 'assistant',
content: '',
timestamp: new Date().toISOString(),
isComplete: false,
};
console.log('[useConversation] Adding streaming message placeholder');
addMessage(conversationId, streamingMessage);
console.log(
'[useConversation] Placeholder added, new messages count:',
conversation$?.data.log.length
);
} else {
console.log('[useConversation] Reusing existing empty assistant message');
}
},
onToken: (token) => {
console.log('[useConversation] Received token:', token);
const messages$ = conversation$?.data.log;
const lastMessage$ = messages$?.[messages$.length - 1];
if (lastMessage$?.role.get() === 'assistant') {
console.log(
'[useConversation] Token handler - lastMessage role:',
lastMessage$?.role?.get(),
'content length:',
lastMessage$?.content?.get()?.length
);
if (lastMessage$?.role?.get() === 'assistant') {
lastMessage$.content.set((prev) => prev + token);
console.log(
'[useConversation] Token appended, new content length:',
lastMessage$.content.get().length
);
} else {
console.warn(
'[useConversation] No assistant message to append token to. Last message role:',
lastMessage$?.role?.get()
);
}
},
onMessageComplete: (message) => {
Expand Down Expand Up @@ -263,9 +300,10 @@ export function useConversation(conversationId: string) {
updateConversationName(conversationId, config.chat.name);
}
},
onConnected: () => {
setConnected(conversationId, true);
},
});

setConnected(conversationId, true);
} catch (error) {
console.error('Error loading conversation:', error);
toast({
Expand Down
25 changes: 22 additions & 3 deletions src/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ export class ApiClient {
onInterrupted: () => void;
onError: (error: string) => void;
onConfigChanged?: (config: ChatConfig, changedFields: string[]) => void;
onConnected?: () => void;
}
): void {
// Close any existing event stream for this conversation
Expand Down Expand Up @@ -292,6 +293,13 @@ export class ApiClient {
*/
const url = new URL(`${this.baseUrl}/api/v2/conversations/${conversationId}/events`);

// Pass existing session_id if available to reuse the session
const existingSessionId = this.sessions$.get(conversationId).get();
if (existingSessionId) {
url.searchParams.set('session_id', existingSessionId);
console.log(`[ApiClient] Reusing existing session ID for SSE: ${existingSessionId}`);
}

if (this.authHeader) {
// Extract token from "Bearer <token>"
const token = this.authHeader.split(' ')[1];
Expand Down Expand Up @@ -394,6 +402,8 @@ export class ApiClient {
this.sessions$.set(conversationId, data.session_id);
// Clear the session ID timeout
clearTimeout(sessionIdTimeout);
// Notify that connection is established
callbacks.onConnected?.();
break;

case 'interrupted':
Expand Down Expand Up @@ -565,9 +575,18 @@ export class ApiClient {
body: JSON.stringify(request),
});

// Store the session ID
this.sessions$.set(logfile, response.session_id);
console.log(`[ApiClient] Stored session ID from createConversation: ${response.session_id}`);
// Store the session ID only if not already set by SSE
const existingSessionId = this.sessions$.get(logfile).get();
if (!existingSessionId) {
this.sessions$.set(logfile, response.session_id);
console.log(
`[ApiClient] Stored session ID from createConversation: ${response.session_id}`
);
} else {
console.log(
`[ApiClient] Session ID already exists from SSE, not overwriting: ${existingSessionId}`
);
}

return response;
} catch (error) {
Expand Down
Loading