From e6b07a056304e58eef667b50b34e1fcacc8e00f0 Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Thu, 18 Dec 2025 19:02:42 +0200 Subject: [PATCH] fix: filter hidden internal agents from UI and updated sdk version --- AGENTS.md | 4 ++++ package.json | 2 +- packages/desktop/src-tauri/Cargo.lock | 2 +- .../chat/AgentMentionAutocomplete.tsx | 7 +++--- packages/ui/src/components/chat/ChatInput.tsx | 3 ++- .../ui/src/components/chat/ModelControls.tsx | 5 ++++- .../sections/agents/AgentsSidebar.tsx | 16 ++++++++------ .../sections/commands/AgentSelector.tsx | 3 ++- packages/ui/src/hooks/useChatScrollManager.ts | 19 ++++++++++++++++ packages/ui/src/stores/useAgentsStore.ts | 22 +++++++++++++++++++ packages/ui/src/stores/useConfigStore.ts | 7 ++++++ pnpm-lock.yaml | 10 ++++----- 12 files changed, 80 insertions(+), 20 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 21c0a75f..4802deb5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -72,6 +72,10 @@ pnpm run desktop:build # Build desktop app 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 ### Section-Based Navigation diff --git a/package.json b/package.json index b31055fc..c081ad75 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "@heroui/system": "^2.4.23", "@heroui/theme": "^2.4.23", "@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-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", diff --git a/packages/desktop/src-tauri/Cargo.lock b/packages/desktop/src-tauri/Cargo.lock index f2ddcafe..6c3e5b33 100644 --- a/packages/desktop/src-tauri/Cargo.lock +++ b/packages/desktop/src-tauri/Cargo.lock @@ -2847,7 +2847,7 @@ dependencies = [ [[package]] name = "openchamber-desktop" -version = "1.2.3" +version = "1.2.4" dependencies = [ "anyhow", "axum", diff --git a/packages/ui/src/components/chat/AgentMentionAutocomplete.tsx b/packages/ui/src/components/chat/AgentMentionAutocomplete.tsx index 90a85970..28279319 100644 --- a/packages/ui/src/components/chat/AgentMentionAutocomplete.tsx +++ b/packages/ui/src/components/chat/AgentMentionAutocomplete.tsx @@ -34,10 +34,11 @@ export const AgentMentionAutocomplete = React.forwardRef(null); const [selectedIndex, setSelectedIndex] = React.useState(0); const [agents, setAgents] = React.useState([]); - const { agents: allAgents } = useConfigStore(); + const { getVisibleAgents } = useConfigStore(); React.useEffect(() => { - const filtered = allAgents + const visibleAgents = getVisibleAgents(); + const filtered = visibleAgents .filter((agent) => isMentionable(agent.mode)) .map((agent) => ({ name: agent.name, @@ -54,7 +55,7 @@ export const AgentMentionAutocomplete = React.forwardRef { const handlePointerDown = (event: MouseEvent | TouchEvent) => { diff --git a/packages/ui/src/components/chat/ChatInput.tsx b/packages/ui/src/components/chat/ChatInput.tsx index 169746a4..a0b38d3c 100644 --- a/packages/ui/src/components/chat/ChatInput.tsx +++ b/packages/ui/src/components/chat/ChatInput.tsx @@ -72,7 +72,8 @@ export const ChatInput: React.FC = ({ onOpenSettings, scrollToBo const clearAttachedFiles = useSessionStore((state) => state.clearAttachedFiles); 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 { working } = useAssistantStatus(); const [showAbortStatus, setShowAbortStatus] = React.useState(false); diff --git a/packages/ui/src/components/chat/ModelControls.tsx b/packages/ui/src/components/chat/ModelControls.tsx index 5d99af2d..d713063b 100644 --- a/packages/ui/src/components/chat/ModelControls.tsx +++ b/packages/ui/src/components/chat/ModelControls.tsx @@ -209,7 +209,6 @@ interface ModelControlsProps { export const ModelControls: React.FC = ({ className }) => { const { providers, - agents, currentProviderId, currentModelId, currentAgentName, @@ -219,8 +218,12 @@ export const ModelControls: React.FC = ({ className }) => { getCurrentProvider, getModelMetadata, getCurrentAgent, + getVisibleAgents, } = useConfigStore(); + // Use visible agents (excludes hidden internal agents) + const agents = getVisibleAgents(); + const { currentSessionId, messages, diff --git a/packages/ui/src/components/sections/agents/AgentsSidebar.tsx b/packages/ui/src/components/sections/agents/AgentsSidebar.tsx index f52b8317..b144b89e 100644 --- a/packages/ui/src/components/sections/agents/AgentsSidebar.tsx +++ b/packages/ui/src/components/sections/agents/AgentsSidebar.tsx @@ -19,7 +19,7 @@ import { DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; 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 { useDeviceInfo } from '@/lib/device'; import { cn } from '@/lib/utils'; @@ -66,7 +66,7 @@ export const AgentsSidebar: React.FC = () => { }; const handleDeleteAgent = async (agent: Agent) => { - if (agent.builtIn) { + if (isAgentBuiltIn(agent)) { toast.error('Built-in agents cannot be deleted'); return; } @@ -112,8 +112,10 @@ export const AgentsSidebar: React.FC = () => { } }; - const builtInAgents = agents.filter((agent) => agent.builtIn); - const customAgents = agents.filter((agent) => !agent.builtIn); + // Filter out hidden agents (internal agents like title, compaction, summary) + const visibleAgents = agents.filter((agent) => !isAgentHidden(agent)); + const builtInAgents = visibleAgents.filter(isAgentBuiltIn); + const customAgents = visibleAgents.filter((agent) => !isAgentBuiltIn(agent)); return (
@@ -122,7 +124,7 @@ export const AgentsSidebar: React.FC = () => {

Agents

- {agents.length} + {visibleAgents.length}
- {agents.length === 0 ? ( + {visibleAgents.length === 0 ? (

No agents configured

@@ -297,7 +299,7 @@ const AgentListItem: React.FC = ({ Duplicate - {!agent.builtIn && onDelete && ( + {!isAgentBuiltIn(agent) && onDelete && ( { e.stopPropagation(); diff --git a/packages/ui/src/components/sections/commands/AgentSelector.tsx b/packages/ui/src/components/sections/commands/AgentSelector.tsx index 238d4b7c..93f2d51c 100644 --- a/packages/ui/src/components/sections/commands/AgentSelector.tsx +++ b/packages/ui/src/components/sections/commands/AgentSelector.tsx @@ -23,7 +23,8 @@ export const AgentSelector: React.FC = ({ onChange, className }) => { - const { agents, loadAgents } = useAgentsStore(); + const { loadAgents, getVisibleAgents } = useAgentsStore(); + const agents = getVisibleAgents(); const isMobile = useUIStore(state => state.isMobile); const { isMobile: deviceIsMobile } = useDeviceInfo(); const isActuallyMobile = isMobile || deviceIsMobile; diff --git a/packages/ui/src/hooks/useChatScrollManager.ts b/packages/ui/src/hooks/useChatScrollManager.ts index cbabcdfd..64d81813 100644 --- a/packages/ui/src/hooks/useChatScrollManager.ts +++ b/packages/ui/src/hooks/useChatScrollManager.ts @@ -398,6 +398,10 @@ export const useChatScrollManager = ({ spacerHeightRef.current = 0; setSpacerHeight(0); + + setPendingAnchorId(null); + setShowScrollButton(false); + userScrollOverrideRef.current = false; } // 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]); + React.useEffect(() => { + if (typeof window === 'undefined') { + updateScrollButtonVisibility(); + return; + } + + const rafId = window.requestAnimationFrame(() => { + updateScrollButtonVisibility(); + }); + + return () => { + window.cancelAnimationFrame(rafId); + }; + }, [currentSessionId, sessionMessages.length, updateScrollButtonVisibility]); + React.useEffect(() => { if (anchorId) { refreshSpacer(); diff --git a/packages/ui/src/stores/useAgentsStore.ts b/packages/ui/src/stores/useAgentsStore.ts index 9f5b35c1..1218c32a 100644 --- a/packages/ui/src/stores/useAgentsStore.ts +++ b/packages/ui/src/stores/useAgentsStore.ts @@ -30,6 +30,21 @@ export interface AgentConfig { 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 sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const MAX_HEALTH_WAIT_MS = 20000; @@ -51,6 +66,8 @@ interface AgentsStore { updateAgent: (name: string, config: Partial) => Promise; deleteAgent: (name: string) => Promise; getAgentByName: (name: string) => Agent | undefined; + // Returns only visible agents (excludes hidden internal agents) + getVisibleAgents: () => Agent[]; } declare global { @@ -264,6 +281,11 @@ export const useAgentsStore = create()( const { agents } = get(); return agents.find((a) => a.name === name); }, + + getVisibleAgents: () => { + const { agents } = get(); + return filterVisibleAgents(agents); + }, }), { name: "agents-store", diff --git a/packages/ui/src/stores/useConfigStore.ts b/packages/ui/src/stores/useConfigStore.ts index 2fef0703..fc7b9a65 100644 --- a/packages/ui/src/stores/useConfigStore.ts +++ b/packages/ui/src/stores/useConfigStore.ts @@ -7,6 +7,7 @@ import { scopeMatches, subscribeToConfigChanges } from "@/lib/configSync"; import type { ModelMetadata } from "@/types"; import { getSafeStorage } from "./utils/safeStorage"; import type { SessionStore } from "./types/sessionTypes"; +import { filterVisibleAgents } from "./useAgentsStore"; const MODELS_DEV_API_URL = "https://models.dev/api.json"; const MODELS_DEV_PROXY_URL = "/api/openchamber/models-metadata"; @@ -230,6 +231,8 @@ interface ConfigStore { getCurrentModel: () => ProviderModel | undefined; getCurrentAgent: () => Agent | undefined; getModelMetadata: (providerId: string, modelId: string) => ModelMetadata | undefined; + // Returns only visible agents (excludes hidden internal agents like title, compaction, summary) + getVisibleAgents: () => Agent[]; } declare global { @@ -522,6 +525,10 @@ export const useConfigStore = create()( const { modelsMetadata } = get(); return modelsMetadata.get(key); }, + getVisibleAgents: () => { + const { agents } = get(); + return filterVisibleAgents(agents); + }, }), { name: "config-store", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index faf3afce..bf46504d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,8 +27,8 @@ importers: specifier: ^6.4.1 version: 6.4.1 '@opencode-ai/sdk': - specifier: ^1.0.150 - version: 1.0.150 + specifier: ^1.0.167 + version: 1.0.167 '@radix-ui/react-collapsible': 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) @@ -1363,8 +1363,8 @@ packages: '@opencode-ai/sdk@1.0.133': resolution: {integrity: sha512-kM+VJJ09SU51aruQ78DSy+6CjNc4wMytvGBrZ1IIJ8etUIdGA59wrnIOSxBVs4u/Gb9pjjgsF8sWp59UdLWP9w==} - '@opencode-ai/sdk@1.0.150': - resolution: {integrity: sha512-Nz9Di8UD/GK01w3N+jpiGNB733pYkNY8RNLbuE/HUxEGSP5apbXBY0IdhbW7859sXZZK38kF1NqOx4UxwBf4Bw==} + '@opencode-ai/sdk@1.0.167': + resolution: {integrity: sha512-zUeAg+s/lddSyJ4noeKxUclT35huyOK0hHRBJn3bKL6LzBTxlRXxKVsSBaqT3JaX/xL+kJeLqzV2W4IetAzlUA==} '@opencode-ai/sdk@1.0.65': resolution: {integrity: sha512-35aOmXhRHNPlx0ThhYwudfZhP1Sg8y94Wsqm+XsgGfHATllQvQjNVOVPfSp3TW3xCAoJ0/PXJlcYjPS3kZDeNA==} @@ -6667,7 +6667,7 @@ snapshots: '@opencode-ai/sdk@1.0.133': {} - '@opencode-ai/sdk@1.0.150': {} + '@opencode-ai/sdk@1.0.167': {} '@opencode-ai/sdk@1.0.65': {}