fix: filter hidden internal agents from UI and updated sdk version
This commit is contained in:
@@ -72,6 +72,10 @@ pnpm run desktop:build # Build desktop app
|
|||||||
pnpm vscode:build # Build VS Code extension
|
pnpm vscode:build # Build VS Code extension
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Communication & Output Discipline (MANDATORY)
|
||||||
|
- Default to brevity. Responses must be as short as possible (until you suggesting plan) while remaining correct.
|
||||||
|
- Do not narrate internal reasoning, step-by-step thinking, or deliberation.
|
||||||
|
|
||||||
## Key Patterns
|
## Key Patterns
|
||||||
|
|
||||||
### Section-Based Navigation
|
### Section-Based Navigation
|
||||||
|
|||||||
+1
-1
@@ -59,7 +59,7 @@
|
|||||||
"@heroui/system": "^2.4.23",
|
"@heroui/system": "^2.4.23",
|
||||||
"@heroui/theme": "^2.4.23",
|
"@heroui/theme": "^2.4.23",
|
||||||
"@ibm/plex": "^6.4.1",
|
"@ibm/plex": "^6.4.1",
|
||||||
"@opencode-ai/sdk": "^1.0.150",
|
"@opencode-ai/sdk": "^1.0.167",
|
||||||
"@radix-ui/react-collapsible": "^1.1.12",
|
"@radix-ui/react-collapsible": "^1.1.12",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||||
|
|||||||
Generated
+1
-1
@@ -2847,7 +2847,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openchamber-desktop"
|
name = "openchamber-desktop"
|
||||||
version = "1.2.3"
|
version = "1.2.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"axum",
|
"axum",
|
||||||
|
|||||||
@@ -34,10 +34,11 @@ export const AgentMentionAutocomplete = React.forwardRef<AgentMentionAutocomplet
|
|||||||
const containerRef = React.useRef<HTMLDivElement | null>(null);
|
const containerRef = React.useRef<HTMLDivElement | null>(null);
|
||||||
const [selectedIndex, setSelectedIndex] = React.useState(0);
|
const [selectedIndex, setSelectedIndex] = React.useState(0);
|
||||||
const [agents, setAgents] = React.useState<AgentInfo[]>([]);
|
const [agents, setAgents] = React.useState<AgentInfo[]>([]);
|
||||||
const { agents: allAgents } = useConfigStore();
|
const { getVisibleAgents } = useConfigStore();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const filtered = allAgents
|
const visibleAgents = getVisibleAgents();
|
||||||
|
const filtered = visibleAgents
|
||||||
.filter((agent) => isMentionable(agent.mode))
|
.filter((agent) => isMentionable(agent.mode))
|
||||||
.map((agent) => ({
|
.map((agent) => ({
|
||||||
name: agent.name,
|
name: agent.name,
|
||||||
@@ -54,7 +55,7 @@ export const AgentMentionAutocomplete = React.forwardRef<AgentMentionAutocomplet
|
|||||||
|
|
||||||
setAgents(matches);
|
setAgents(matches);
|
||||||
setSelectedIndex(0);
|
setSelectedIndex(0);
|
||||||
}, [allAgents, searchQuery]);
|
}, [getVisibleAgents, searchQuery]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const handlePointerDown = (event: MouseEvent | TouchEvent) => {
|
const handlePointerDown = (event: MouseEvent | TouchEvent) => {
|
||||||
|
|||||||
@@ -72,7 +72,8 @@ export const ChatInput: React.FC<ChatInputProps> = ({ onOpenSettings, scrollToBo
|
|||||||
const clearAttachedFiles = useSessionStore((state) => state.clearAttachedFiles);
|
const clearAttachedFiles = useSessionStore((state) => state.clearAttachedFiles);
|
||||||
const saveSessionAgentSelection = useSessionStore((state) => state.saveSessionAgentSelection);
|
const saveSessionAgentSelection = useSessionStore((state) => state.saveSessionAgentSelection);
|
||||||
|
|
||||||
const { currentProviderId, currentModelId, currentAgentName, agents, setAgent } = useConfigStore();
|
const { currentProviderId, currentModelId, currentAgentName, setAgent, getVisibleAgents } = useConfigStore();
|
||||||
|
const agents = getVisibleAgents();
|
||||||
const { isMobile } = useUIStore();
|
const { isMobile } = useUIStore();
|
||||||
const { working } = useAssistantStatus();
|
const { working } = useAssistantStatus();
|
||||||
const [showAbortStatus, setShowAbortStatus] = React.useState(false);
|
const [showAbortStatus, setShowAbortStatus] = React.useState(false);
|
||||||
|
|||||||
@@ -209,7 +209,6 @@ interface ModelControlsProps {
|
|||||||
export const ModelControls: React.FC<ModelControlsProps> = ({ className }) => {
|
export const ModelControls: React.FC<ModelControlsProps> = ({ className }) => {
|
||||||
const {
|
const {
|
||||||
providers,
|
providers,
|
||||||
agents,
|
|
||||||
currentProviderId,
|
currentProviderId,
|
||||||
currentModelId,
|
currentModelId,
|
||||||
currentAgentName,
|
currentAgentName,
|
||||||
@@ -219,8 +218,12 @@ export const ModelControls: React.FC<ModelControlsProps> = ({ className }) => {
|
|||||||
getCurrentProvider,
|
getCurrentProvider,
|
||||||
getModelMetadata,
|
getModelMetadata,
|
||||||
getCurrentAgent,
|
getCurrentAgent,
|
||||||
|
getVisibleAgents,
|
||||||
} = useConfigStore();
|
} = useConfigStore();
|
||||||
|
|
||||||
|
// Use visible agents (excludes hidden internal agents)
|
||||||
|
const agents = getVisibleAgents();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
currentSessionId,
|
currentSessionId,
|
||||||
messages,
|
messages,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from '@/components/ui/dropdown-menu';
|
} from '@/components/ui/dropdown-menu';
|
||||||
import { RiAddLine, RiAiAgentFill, RiAiAgentLine, RiDeleteBinLine, RiFileCopyLine, RiMore2Line, RiRobot2Line, RiRobotLine } from '@remixicon/react';
|
import { RiAddLine, RiAiAgentFill, RiAiAgentLine, RiDeleteBinLine, RiFileCopyLine, RiMore2Line, RiRobot2Line, RiRobotLine } from '@remixicon/react';
|
||||||
import { useAgentsStore } from '@/stores/useAgentsStore';
|
import { useAgentsStore, isAgentBuiltIn, isAgentHidden } from '@/stores/useAgentsStore';
|
||||||
import { useUIStore } from '@/stores/useUIStore';
|
import { useUIStore } from '@/stores/useUIStore';
|
||||||
import { useDeviceInfo } from '@/lib/device';
|
import { useDeviceInfo } from '@/lib/device';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
@@ -66,7 +66,7 @@ export const AgentsSidebar: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteAgent = async (agent: Agent) => {
|
const handleDeleteAgent = async (agent: Agent) => {
|
||||||
if (agent.builtIn) {
|
if (isAgentBuiltIn(agent)) {
|
||||||
toast.error('Built-in agents cannot be deleted');
|
toast.error('Built-in agents cannot be deleted');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -112,8 +112,10 @@ export const AgentsSidebar: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const builtInAgents = agents.filter((agent) => agent.builtIn);
|
// Filter out hidden agents (internal agents like title, compaction, summary)
|
||||||
const customAgents = agents.filter((agent) => !agent.builtIn);
|
const visibleAgents = agents.filter((agent) => !isAgentHidden(agent));
|
||||||
|
const builtInAgents = visibleAgents.filter(isAgentBuiltIn);
|
||||||
|
const customAgents = visibleAgents.filter((agent) => !isAgentBuiltIn(agent));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col bg-sidebar">
|
<div className="flex h-full flex-col bg-sidebar">
|
||||||
@@ -122,7 +124,7 @@ export const AgentsSidebar: React.FC = () => {
|
|||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<h2 className="typography-ui-label font-semibold text-foreground">Agents</h2>
|
<h2 className="typography-ui-label font-semibold text-foreground">Agents</h2>
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<span className="typography-meta text-muted-foreground">{agents.length}</span>
|
<span className="typography-meta text-muted-foreground">{visibleAgents.length}</span>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button type="button" variant="ghost" size="icon" className="h-7 w-7 text-muted-foreground">
|
<Button type="button" variant="ghost" size="icon" className="h-7 w-7 text-muted-foreground">
|
||||||
<RiAddLine className="size-4" />
|
<RiAddLine className="size-4" />
|
||||||
@@ -133,7 +135,7 @@ export const AgentsSidebar: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ScrollableOverlay outerClassName="flex-1 min-h-0" className="space-y-1 px-3 py-2 overflow-x-hidden">
|
<ScrollableOverlay outerClassName="flex-1 min-h-0" className="space-y-1 px-3 py-2 overflow-x-hidden">
|
||||||
{agents.length === 0 ? (
|
{visibleAgents.length === 0 ? (
|
||||||
<div className="py-12 px-4 text-center text-muted-foreground">
|
<div className="py-12 px-4 text-center text-muted-foreground">
|
||||||
<RiRobot2Line className="mx-auto mb-3 h-10 w-10 opacity-50" />
|
<RiRobot2Line className="mx-auto mb-3 h-10 w-10 opacity-50" />
|
||||||
<p className="typography-ui-label font-medium">No agents configured</p>
|
<p className="typography-ui-label font-medium">No agents configured</p>
|
||||||
@@ -297,7 +299,7 @@ const AgentListItem: React.FC<AgentListItemProps> = ({
|
|||||||
Duplicate
|
Duplicate
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|
||||||
{!agent.builtIn && onDelete && (
|
{!isAgentBuiltIn(agent) && onDelete && (
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ export const AgentSelector: React.FC<AgentSelectorProps> = ({
|
|||||||
onChange,
|
onChange,
|
||||||
className
|
className
|
||||||
}) => {
|
}) => {
|
||||||
const { agents, loadAgents } = useAgentsStore();
|
const { loadAgents, getVisibleAgents } = useAgentsStore();
|
||||||
|
const agents = getVisibleAgents();
|
||||||
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;
|
||||||
|
|||||||
@@ -398,6 +398,10 @@ export const useChatScrollManager = ({
|
|||||||
|
|
||||||
spacerHeightRef.current = 0;
|
spacerHeightRef.current = 0;
|
||||||
setSpacerHeight(0);
|
setSpacerHeight(0);
|
||||||
|
|
||||||
|
setPendingAnchorId(null);
|
||||||
|
setShowScrollButton(false);
|
||||||
|
|
||||||
userScrollOverrideRef.current = false;
|
userScrollOverrideRef.current = false;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps -- only run on session change, not message changes
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- only run on session change, not message changes
|
||||||
@@ -480,6 +484,21 @@ export const useChatScrollManager = ({
|
|||||||
};
|
};
|
||||||
}, [refreshSpacer, updateScrollButtonVisibility]);
|
}, [refreshSpacer, updateScrollButtonVisibility]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
updateScrollButtonVisibility();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rafId = window.requestAnimationFrame(() => {
|
||||||
|
updateScrollButtonVisibility();
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.cancelAnimationFrame(rafId);
|
||||||
|
};
|
||||||
|
}, [currentSessionId, sessionMessages.length, updateScrollButtonVisibility]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (anchorId) {
|
if (anchorId) {
|
||||||
refreshSpacer();
|
refreshSpacer();
|
||||||
|
|||||||
@@ -30,6 +30,21 @@ export interface AgentConfig {
|
|||||||
disable?: boolean;
|
disable?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extended Agent type for API properties not in SDK types
|
||||||
|
export type AgentWithExtras = Agent & { native?: boolean; hidden?: boolean };
|
||||||
|
|
||||||
|
// Helper to check if agent is built-in (handles both SDK 'builtIn' and API 'native')
|
||||||
|
export const isAgentBuiltIn = (agent: Agent): boolean =>
|
||||||
|
agent.builtIn || (agent as AgentWithExtras).native === true;
|
||||||
|
|
||||||
|
// Helper to check if agent is hidden (internal agents like title, compaction, summary)
|
||||||
|
export const isAgentHidden = (agent: Agent): boolean =>
|
||||||
|
(agent as AgentWithExtras).hidden === true;
|
||||||
|
|
||||||
|
// Helper to filter only visible (non-hidden) agents
|
||||||
|
export const filterVisibleAgents = (agents: Agent[]): Agent[] =>
|
||||||
|
agents.filter((agent) => !isAgentHidden(agent));
|
||||||
|
|
||||||
const CONFIG_EVENT_SOURCE = "useAgentsStore";
|
const CONFIG_EVENT_SOURCE = "useAgentsStore";
|
||||||
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||||
const MAX_HEALTH_WAIT_MS = 20000;
|
const MAX_HEALTH_WAIT_MS = 20000;
|
||||||
@@ -51,6 +66,8 @@ interface AgentsStore {
|
|||||||
updateAgent: (name: string, config: Partial<AgentConfig>) => Promise<boolean>;
|
updateAgent: (name: string, config: Partial<AgentConfig>) => Promise<boolean>;
|
||||||
deleteAgent: (name: string) => Promise<boolean>;
|
deleteAgent: (name: string) => Promise<boolean>;
|
||||||
getAgentByName: (name: string) => Agent | undefined;
|
getAgentByName: (name: string) => Agent | undefined;
|
||||||
|
// Returns only visible agents (excludes hidden internal agents)
|
||||||
|
getVisibleAgents: () => Agent[];
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@@ -264,6 +281,11 @@ export const useAgentsStore = create<AgentsStore>()(
|
|||||||
const { agents } = get();
|
const { agents } = get();
|
||||||
return agents.find((a) => a.name === name);
|
return agents.find((a) => a.name === name);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getVisibleAgents: () => {
|
||||||
|
const { agents } = get();
|
||||||
|
return filterVisibleAgents(agents);
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: "agents-store",
|
name: "agents-store",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { scopeMatches, subscribeToConfigChanges } from "@/lib/configSync";
|
|||||||
import type { ModelMetadata } from "@/types";
|
import type { ModelMetadata } from "@/types";
|
||||||
import { getSafeStorage } from "./utils/safeStorage";
|
import { getSafeStorage } from "./utils/safeStorage";
|
||||||
import type { SessionStore } from "./types/sessionTypes";
|
import type { SessionStore } from "./types/sessionTypes";
|
||||||
|
import { filterVisibleAgents } from "./useAgentsStore";
|
||||||
|
|
||||||
const MODELS_DEV_API_URL = "https://models.dev/api.json";
|
const MODELS_DEV_API_URL = "https://models.dev/api.json";
|
||||||
const MODELS_DEV_PROXY_URL = "/api/openchamber/models-metadata";
|
const MODELS_DEV_PROXY_URL = "/api/openchamber/models-metadata";
|
||||||
@@ -230,6 +231,8 @@ interface ConfigStore {
|
|||||||
getCurrentModel: () => ProviderModel | undefined;
|
getCurrentModel: () => ProviderModel | undefined;
|
||||||
getCurrentAgent: () => Agent | undefined;
|
getCurrentAgent: () => Agent | undefined;
|
||||||
getModelMetadata: (providerId: string, modelId: string) => ModelMetadata | undefined;
|
getModelMetadata: (providerId: string, modelId: string) => ModelMetadata | undefined;
|
||||||
|
// Returns only visible agents (excludes hidden internal agents like title, compaction, summary)
|
||||||
|
getVisibleAgents: () => Agent[];
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@@ -522,6 +525,10 @@ export const useConfigStore = create<ConfigStore>()(
|
|||||||
const { modelsMetadata } = get();
|
const { modelsMetadata } = get();
|
||||||
return modelsMetadata.get(key);
|
return modelsMetadata.get(key);
|
||||||
},
|
},
|
||||||
|
getVisibleAgents: () => {
|
||||||
|
const { agents } = get();
|
||||||
|
return filterVisibleAgents(agents);
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: "config-store",
|
name: "config-store",
|
||||||
|
|||||||
Generated
+5
-5
@@ -27,8 +27,8 @@ importers:
|
|||||||
specifier: ^6.4.1
|
specifier: ^6.4.1
|
||||||
version: 6.4.1
|
version: 6.4.1
|
||||||
'@opencode-ai/sdk':
|
'@opencode-ai/sdk':
|
||||||
specifier: ^1.0.150
|
specifier: ^1.0.167
|
||||||
version: 1.0.150
|
version: 1.0.167
|
||||||
'@radix-ui/react-collapsible':
|
'@radix-ui/react-collapsible':
|
||||||
specifier: ^1.1.12
|
specifier: ^1.1.12
|
||||||
version: 1.1.12(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
version: 1.1.12(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||||
@@ -1363,8 +1363,8 @@ packages:
|
|||||||
'@opencode-ai/sdk@1.0.133':
|
'@opencode-ai/sdk@1.0.133':
|
||||||
resolution: {integrity: sha512-kM+VJJ09SU51aruQ78DSy+6CjNc4wMytvGBrZ1IIJ8etUIdGA59wrnIOSxBVs4u/Gb9pjjgsF8sWp59UdLWP9w==}
|
resolution: {integrity: sha512-kM+VJJ09SU51aruQ78DSy+6CjNc4wMytvGBrZ1IIJ8etUIdGA59wrnIOSxBVs4u/Gb9pjjgsF8sWp59UdLWP9w==}
|
||||||
|
|
||||||
'@opencode-ai/sdk@1.0.150':
|
'@opencode-ai/sdk@1.0.167':
|
||||||
resolution: {integrity: sha512-Nz9Di8UD/GK01w3N+jpiGNB733pYkNY8RNLbuE/HUxEGSP5apbXBY0IdhbW7859sXZZK38kF1NqOx4UxwBf4Bw==}
|
resolution: {integrity: sha512-zUeAg+s/lddSyJ4noeKxUclT35huyOK0hHRBJn3bKL6LzBTxlRXxKVsSBaqT3JaX/xL+kJeLqzV2W4IetAzlUA==}
|
||||||
|
|
||||||
'@opencode-ai/sdk@1.0.65':
|
'@opencode-ai/sdk@1.0.65':
|
||||||
resolution: {integrity: sha512-35aOmXhRHNPlx0ThhYwudfZhP1Sg8y94Wsqm+XsgGfHATllQvQjNVOVPfSp3TW3xCAoJ0/PXJlcYjPS3kZDeNA==}
|
resolution: {integrity: sha512-35aOmXhRHNPlx0ThhYwudfZhP1Sg8y94Wsqm+XsgGfHATllQvQjNVOVPfSp3TW3xCAoJ0/PXJlcYjPS3kZDeNA==}
|
||||||
@@ -6667,7 +6667,7 @@ snapshots:
|
|||||||
|
|
||||||
'@opencode-ai/sdk@1.0.133': {}
|
'@opencode-ai/sdk@1.0.133': {}
|
||||||
|
|
||||||
'@opencode-ai/sdk@1.0.150': {}
|
'@opencode-ai/sdk@1.0.167': {}
|
||||||
|
|
||||||
'@opencode-ai/sdk@1.0.65': {}
|
'@opencode-ai/sdk@1.0.65': {}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user