fix(agent-selector): read agents from active-directory config store
AgentSelector used useAgentsStore which is only warm after a chat session loads, so the todo send dialog opened from the project context panel showed an empty agent list. Prefer useConfigStore.agents (the same source ModelControls uses in chat) with useAgentsStore as fallback, and load both on mount when neither is populated. Also set the primary-mode filter on the scheduled task editor agent selector to keep its options consistent with the other flows.
This commit is contained in:
@@ -1,11 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import type { Agent } from '@opencode-ai/sdk/v2';
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from '@/components/ui/dropdown-menu';
|
} from '@/components/ui/dropdown-menu';
|
||||||
import { useAgentsStore } from '@/stores/useAgentsStore';
|
import { useAgentsStore, filterVisibleAgents } from '@/stores/useAgentsStore';
|
||||||
|
import { useConfigStore } from '@/stores/useConfigStore';
|
||||||
import { useUIStore } from '@/stores/useUIStore';
|
import { useUIStore } from '@/stores/useUIStore';
|
||||||
import { useDeviceInfo } from '@/lib/device';
|
import { useDeviceInfo } from '@/lib/device';
|
||||||
import { RiArrowDownSLine, RiRobot2Line } from '@remixicon/react';
|
import { RiArrowDownSLine, RiRobot2Line } from '@remixicon/react';
|
||||||
@@ -16,15 +18,27 @@ interface AgentSelectorProps {
|
|||||||
agentName: string;
|
agentName: string;
|
||||||
onChange: (agentName: string) => void;
|
onChange: (agentName: string) => void;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
filter?: (agent: Agent) => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AgentSelector: React.FC<AgentSelectorProps> = ({
|
export const AgentSelector: React.FC<AgentSelectorProps> = ({
|
||||||
agentName,
|
agentName,
|
||||||
onChange,
|
onChange,
|
||||||
className
|
className,
|
||||||
|
filter,
|
||||||
}) => {
|
}) => {
|
||||||
const { loadAgents, getVisibleAgents } = useAgentsStore();
|
const configAgents = useConfigStore((state) => state.agents);
|
||||||
const agents = getVisibleAgents();
|
const agentsStoreAgents = useAgentsStore((state) => state.agents);
|
||||||
|
const loadAgentsStore = useAgentsStore((state) => state.loadAgents);
|
||||||
|
const loadConfigAgents = useConfigStore((state) => state.loadAgents);
|
||||||
|
const rawAgents = React.useMemo(() => {
|
||||||
|
if (Array.isArray(configAgents) && configAgents.length > 0) return configAgents;
|
||||||
|
return Array.isArray(agentsStoreAgents) ? agentsStoreAgents : [];
|
||||||
|
}, [configAgents, agentsStoreAgents]);
|
||||||
|
const agents = React.useMemo(() => {
|
||||||
|
const visible = filterVisibleAgents(rawAgents);
|
||||||
|
return filter ? visible.filter(filter) : visible;
|
||||||
|
}, [rawAgents, filter]);
|
||||||
const isMobile = useUIStore(state => state.isMobile);
|
const isMobile = useUIStore(state => state.isMobile);
|
||||||
const { isMobile: deviceIsMobile } = useDeviceInfo();
|
const { isMobile: deviceIsMobile } = useDeviceInfo();
|
||||||
const isActuallyMobile = isMobile || deviceIsMobile;
|
const isActuallyMobile = isMobile || deviceIsMobile;
|
||||||
@@ -32,8 +46,10 @@ export const AgentSelector: React.FC<AgentSelectorProps> = ({
|
|||||||
const [isMobilePanelOpen, setIsMobilePanelOpen] = React.useState(false);
|
const [isMobilePanelOpen, setIsMobilePanelOpen] = React.useState(false);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
loadAgents();
|
if (rawAgents.length > 0) return;
|
||||||
}, [loadAgents]);
|
void loadConfigAgents();
|
||||||
|
void loadAgentsStore();
|
||||||
|
}, [rawAgents.length, loadConfigAgents, loadAgentsStore]);
|
||||||
|
|
||||||
const closeMobilePanel = () => setIsMobilePanelOpen(false);
|
const closeMobilePanel = () => setIsMobilePanelOpen(false);
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { toast } from '@/components/ui';
|
|||||||
import { RiAddLine, RiCloseLine, RiCalendarLine, RiArrowLeftSLine, RiArrowRightSLine, RiArrowDownSLine } from '@remixicon/react';
|
import { RiAddLine, RiCloseLine, RiCalendarLine, RiArrowLeftSLine, RiArrowRightSLine, RiArrowDownSLine } from '@remixicon/react';
|
||||||
import { ModelSelector } from '@/components/sections/agents/ModelSelector';
|
import { ModelSelector } from '@/components/sections/agents/ModelSelector';
|
||||||
import { AgentSelector } from '@/components/sections/commands/AgentSelector';
|
import { AgentSelector } from '@/components/sections/commands/AgentSelector';
|
||||||
|
import { isPrimaryMode } from '@/components/chat/mobileControlsUtils';
|
||||||
import { CommandAutocomplete, type CommandAutocompleteHandle } from '@/components/chat/CommandAutocomplete';
|
import { CommandAutocomplete, type CommandAutocompleteHandle } from '@/components/chat/CommandAutocomplete';
|
||||||
import { FileMentionAutocomplete, type FileMentionHandle } from '@/components/chat/FileMentionAutocomplete';
|
import { FileMentionAutocomplete, type FileMentionHandle } from '@/components/chat/FileMentionAutocomplete';
|
||||||
import { useConfigStore } from '@/stores/useConfigStore';
|
import { useConfigStore } from '@/stores/useConfigStore';
|
||||||
@@ -1308,6 +1309,7 @@ export function ScheduledTaskEditorDialog(props: {
|
|||||||
<FieldLabel>Agent</FieldLabel>
|
<FieldLabel>Agent</FieldLabel>
|
||||||
<AgentSelector
|
<AgentSelector
|
||||||
agentName={draft.execution.agent}
|
agentName={draft.execution.agent}
|
||||||
|
filter={(agent) => isPrimaryMode(agent.mode)}
|
||||||
onChange={(agent) => setDraft((prev) => ({
|
onChange={(agent) => setDraft((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
execution: {
|
execution: {
|
||||||
|
|||||||
Reference in New Issue
Block a user