diff --git a/src/components/chat/AgentComposer.tsx b/src/components/chat/AgentComposer.tsx index f9cad22..5400c7a 100644 --- a/src/components/chat/AgentComposer.tsx +++ b/src/components/chat/AgentComposer.tsx @@ -26,7 +26,9 @@ import KeyboardArrowUpRounded from "@mui/icons-material/KeyboardArrowUpRounded"; import AttachFileRounded from "@mui/icons-material/AttachFileRounded"; import BoltRounded from "@mui/icons-material/BoltRounded"; import AutoAwesomeRounded from "@mui/icons-material/AutoAwesomeRounded"; -import type { AgentModel } from "@/lib/chatStream"; +import VerifiedUserRounded from "@mui/icons-material/VerifiedUserRounded"; +import AdminPanelSettingsRounded from "@mui/icons-material/AdminPanelSettingsRounded"; +import type { AgentApprovalMode, AgentModel } from "@/lib/chatStream"; export type AgentComposerHandle = { focus: () => void; @@ -48,6 +50,8 @@ type AgentComposerProps = { onStopListening: () => void; selectedModel: AgentModel; onModelChange: (model: AgentModel) => void; + approvalMode: AgentApprovalMode; + onApprovalModeChange: (mode: AgentApprovalMode) => void; }; export const AgentComposer = React.forwardRef(function AgentComposer({ @@ -62,6 +66,8 @@ export const AgentComposer = React.forwardRef(null); @@ -245,6 +251,96 @@ export const AgentComposer = React.forwardRef ) ) : null} + + + diff --git a/src/components/chat/GlobalChatbox.tsx b/src/components/chat/GlobalChatbox.tsx index a020a5f..a9d674c 100644 --- a/src/components/chat/GlobalChatbox.tsx +++ b/src/components/chat/GlobalChatbox.tsx @@ -10,7 +10,7 @@ import { Box, Drawer, alpha, useTheme } from "@mui/material"; import { useNotification } from "@refinedev/core"; import { getAccessToken } from "@/lib/authToken"; -import type { AgentModel } from "@/lib/chatStream"; +import type { AgentApprovalMode, AgentModel } from "@/lib/chatStream"; import { useProjectStore } from "@/store/projectStore"; import { AgentComposer, type AgentComposerHandle } from "./AgentComposer"; import { AgentHeader } from "./AgentHeader"; @@ -31,6 +31,8 @@ export const GlobalChatbox: React.FC = ({ open, onClose }) => { const [selectedModel, setSelectedModel] = useState( "deepseek/deepseek-v4-pro", ); + const [approvalMode, setApprovalMode] = + useState("request"); const bottomRef = useRef(null); const composerRef = useRef(null); @@ -85,6 +87,7 @@ export const GlobalChatbox: React.FC = ({ open, onClose }) => { onToolCall: handleToolCall, onBeforeSend: stopListening, getModel: () => selectedModel, + getApprovalMode: () => approvalMode, }); const scrollToBottom = useCallback((behavior: ScrollBehavior = "smooth") => { @@ -371,6 +374,8 @@ export const GlobalChatbox: React.FC = ({ open, onClose }) => { onStopListening={stopListening} selectedModel={selectedModel} onModelChange={setSelectedModel} + approvalMode={approvalMode} + onApprovalModeChange={setApprovalMode} /> diff --git a/src/components/chat/hooks/useAgentChatSession.ts b/src/components/chat/hooks/useAgentChatSession.ts index 31e814a..8ea558a 100644 --- a/src/components/chat/hooks/useAgentChatSession.ts +++ b/src/components/chat/hooks/useAgentChatSession.ts @@ -9,7 +9,12 @@ import { resumeAgentChatStream, streamAgentChat, } from "@/lib/chatStream"; -import type { AgentModel, PermissionReply, StreamEvent } from "@/lib/chatStream"; +import type { + AgentApprovalMode, + AgentModel, + PermissionReply, + StreamEvent, +} from "@/lib/chatStream"; import type { AgentArtifact, AgentPermissionRequest, @@ -45,6 +50,7 @@ type UseAgentChatSessionOptions = { ) => void; onBeforeSend?: () => void; getModel?: () => AgentModel; + getApprovalMode?: () => AgentApprovalMode; }; type PromptRunOptions = { @@ -210,6 +216,7 @@ export const useAgentChatSession = ({ onToolCall, onBeforeSend, getModel, + getApprovalMode, }: UseAgentChatSessionOptions) => { const hydrationCompletedRef = useRef(false); const hydrationNonceRef = useRef(0); @@ -636,6 +643,7 @@ export const useAgentChatSession = ({ message: prompt, sessionId: sessionIdOverride ?? sessionIdRef.current, model: getModel?.(), + approvalMode: getApprovalMode?.(), signal: controller.signal, onEvent: (event) => applyStreamEvent(event, { @@ -686,7 +694,15 @@ export const useAgentChatSession = ({ setIsStreaming(false); } }, - [applyStreamEvent, getModel, isHydrating, isStreaming, messages, onBeforeSend], + [ + applyStreamEvent, + getApprovalMode, + getModel, + isHydrating, + isStreaming, + messages, + onBeforeSend, + ], ); const abort = useCallback(() => { diff --git a/src/lib/chatStream.test.ts b/src/lib/chatStream.test.ts index 6be9065..bda5744 100644 --- a/src/lib/chatStream.test.ts +++ b/src/lib/chatStream.test.ts @@ -72,6 +72,7 @@ describe("streamAgentChat", () => { message: "hi", session_id: undefined, model: "deepseek/deepseek-v4-pro", + approval_mode: undefined, }), }), ); diff --git a/src/lib/chatStream.ts b/src/lib/chatStream.ts index 5bbdc35..7b4a2e9 100644 --- a/src/lib/chatStream.ts +++ b/src/lib/chatStream.ts @@ -6,6 +6,7 @@ export type AgentModel = | "deepseek/deepseek-v4-pro"; export type PermissionReply = "once" | "always" | "reject"; +export type AgentApprovalMode = "request" | "always"; export type StreamEvent = | { @@ -69,6 +70,7 @@ type StreamOptions = { message: string; sessionId?: string; model?: AgentModel; + approvalMode?: AgentApprovalMode; signal?: AbortSignal; onEvent: (event: StreamEvent) => void; }; @@ -283,6 +285,7 @@ export const streamAgentChat = async ({ message, sessionId, model, + approvalMode, signal, onEvent, }: StreamOptions) => { @@ -301,6 +304,7 @@ export const streamAgentChat = async ({ message, session_id: sessionId, model, + approval_mode: approvalMode, }), projectHeaderMode: "include", userHeaderMode: "include",