diff --git a/src/features/ai/components/chat/ai-chat.tsx b/src/features/ai/components/chat/ai-chat.tsx index d1d3be702..fa9b6f416 100644 --- a/src/features/ai/components/chat/ai-chat.tsx +++ b/src/features/ai/components/chat/ai-chat.tsx @@ -1,7 +1,7 @@ import { listen } from "@tauri-apps/api/event"; import { Key as KeyRound } from "@phosphor-icons/react"; import type React from "react"; -import { memo, useCallback, useEffect, useRef, useState } from "react"; +import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react"; import { ProviderApiKeyCommand } from "@/features/ai/components/provider-api-key-command"; import { appendChatAcpEvent, @@ -218,8 +218,13 @@ const AIChat = memo(function AIChat({ }> >([]); const [acpEvents, setAcpEvents] = useState([]); - const effectiveChatId = - chatId ?? (activeBuffer?.type === "agent" ? activeBuffer.sessionId : chatState.currentChatId); + const activeAgentChatId = useMemo(() => { + if (activeBuffer?.type !== "agent") return null; + return chatState.chats.some((chat) => chat.id === activeBuffer.sessionId) + ? activeBuffer.sessionId + : null; + }, [activeBuffer, chatState.chats]); + const effectiveChatId = chatId ?? activeAgentChatId ?? chatState.currentChatId; useEffect(() => { if (isActiveSurface && activeBuffer) { @@ -495,6 +500,13 @@ const AIChat = memo(function AIChat({ if (!chatId) { chatId = chatActions.createNewChat(currentAgentId); } + if (activeBuffer?.type === "agent" && activeBuffer.sessionId !== chatId) { + useBufferStore.getState().actions.updateBuffer({ + ...activeBuffer, + path: `agent://${chatId}`, + sessionId: chatId, + }); + } const { processedMessage, mentionedFiles } = await parseMentionsAndLoadFiles( messageContent.trim(), diff --git a/src/features/ai/components/chat/chat-message.tsx b/src/features/ai/components/chat/chat-message.tsx index 5b1611b01..55115fc9c 100644 --- a/src/features/ai/components/chat/chat-message.tsx +++ b/src/features/ai/components/chat/chat-message.tsx @@ -1,4 +1,5 @@ import { memo, useCallback } from "react"; +import { ProviderIcon } from "@/features/ai/components/icons/provider-icons"; import type { PlanStep } from "@/features/ai/lib/plan-parser"; import { hasPlanBlock, parsePlan } from "@/features/ai/lib/plan-parser"; import type { Message } from "@/features/ai/types/ai-chat"; @@ -12,10 +13,15 @@ import { ChatLoadingIndicator } from "./chat-loading-indicator"; interface ChatMessageProps { message: Message; isLastMessage: boolean; + agentIconId?: string; onApplyCode?: (code: string, language?: string) => void; } -export const ChatMessage = memo(function ChatMessage({ message, onApplyCode }: ChatMessageProps) { +export const ChatMessage = memo(function ChatMessage({ + message, + agentIconId, + onApplyCode, +}: ChatMessageProps) { const isToolOnlyMessage = message.role === "assistant" && message.toolCalls && @@ -44,21 +50,23 @@ export const ChatMessage = memo(function ChatMessage({ message, onApplyCode }: C if (isToolOnlyMessage) { return ( -
- {message.toolCalls!.map((toolCall, toolIndex) => ( - - ))} -
+ +
+ {message.toolCalls!.map((toolCall, toolIndex) => ( + + ))} +
+
); } @@ -68,11 +76,15 @@ export const ChatMessage = memo(function ChatMessage({ message, onApplyCode }: C (!message.content || message.content.trim().length === 0) && (!message.toolCalls || message.toolCalls.length === 0) ) { - return ; + return ( + + + + ); } return ( -
+ {message.images && message.images.length > 0 && (
{message.images.map((image, index) => ( @@ -143,6 +155,23 @@ export const ChatMessage = memo(function ChatMessage({ message, onApplyCode }: C ))}
)} -
+ ); }); + +function AssistantMessageFrame({ + agentIconId, + children, +}: { + agentIconId?: string; + children: React.ReactNode; +}) { + return ( +
+
+ +
+
{children}
+
+ ); +} diff --git a/src/features/ai/components/chat/chat-messages.tsx b/src/features/ai/components/chat/chat-messages.tsx index 1a42f7866..778295ea7 100644 --- a/src/features/ai/components/chat/chat-messages.tsx +++ b/src/features/ai/components/chat/chat-messages.tsx @@ -36,6 +36,7 @@ export const ChatMessages = memo( })), ); const skills = useSettingsStore((state) => state.settings.aiSkills); + const aiProviderId = useSettingsStore((state) => state.settings.aiProviderId); const [isSkillsOpen, setIsSkillsOpen] = useState(false); const [skillsInitialView, setSkillsInitialView] = useState<"list" | "editor">("list"); @@ -44,6 +45,7 @@ export const ChatMessages = memo( [chatId, chats, currentChatId], ); const messages = currentChat?.messages || []; + const agentIconId = currentChat?.agentId === "custom" ? aiProviderId : currentChat?.agentId; const timelineItems = useMemo( () => [ @@ -165,6 +167,7 @@ export const ChatMessages = memo( diff --git a/src/features/ai/components/selectors/agent-selector.tsx b/src/features/ai/components/selectors/agent-selector.tsx index 69a55efce..37977edfc 100644 --- a/src/features/ai/components/selectors/agent-selector.tsx +++ b/src/features/ai/components/selectors/agent-selector.tsx @@ -12,6 +12,7 @@ import { AcpStreamHandler } from "@/features/ai/services/acp-stream-handler"; import { useAIChatStore } from "@/features/ai/store/store"; import type { AgentConfig } from "@/features/ai/types/acp"; import type { AgentType } from "@/features/ai/types/ai-chat"; +import { useBufferStore } from "@/features/editor/stores/buffer-store"; import { Button } from "@/ui/button"; import { Dropdown } from "@/ui/dropdown"; import Input from "@/ui/input"; @@ -182,6 +183,17 @@ export function AgentSelector({ if (variant === "header") { const newChatId = createNewChat(agentId); + const bufferStore = useBufferStore.getState(); + const activeBuffer = bufferStore.buffers.find( + (buffer) => buffer.id === bufferStore.activeBufferId, + ); + if (activeBuffer?.type === "agent") { + bufferStore.actions.updateBuffer({ + ...activeBuffer, + path: `agent://${newChatId}`, + sessionId: newChatId, + }); + } if (agentId !== "custom") { void AcpStreamHandler.warmup(agentId, newChatId).catch((error) => { console.error(`Failed to prepare ${agentId} session:`, error);