diff --git a/packages/kilo-vscode/eslint.config.mjs b/packages/kilo-vscode/eslint.config.mjs index f82b5a9d931..5b01bdb44a9 100644 --- a/packages/kilo-vscode/eslint.config.mjs +++ b/packages/kilo-vscode/eslint.config.mjs @@ -34,7 +34,7 @@ export default [ { files: ["src/KiloProvider.ts"], rules: { - "max-lines": ["error", 3200], + "max-lines": ["error", 3300], }, }, eslintConfigPrettier, diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index 6888caf5d19..c6803658093 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -90,12 +90,26 @@ import { saveCustomProvider as saveCustomProviderAction, } from "./provider-actions" import { fetchOpenAIModels, FetchModelsError } from "./shared/fetch-models" +import type { Agent } from "@kilocode/sdk/v2/client" type KiloProviderOptions = { projectDirectory?: string | null slimEditMetadata?: boolean } +// Helper to map agent data to the subset of fields sent to the webview +const mapAgent = (a: Agent) => ({ + name: a.name, + displayName: a.displayName, + description: a.description, + mode: a.mode, + native: a.native, + hidden: a.hidden, + color: a.color, + deprecated: a.deprecated, + permission: a.permission, +}) + export class KiloProvider implements vscode.WebviewViewProvider, TelemetryPropertiesProvider { public static readonly viewType = "kilo-code.SidebarProvider" @@ -1625,15 +1639,8 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper const message = { type: "agentsLoaded", - agents: visible.map((a) => ({ - name: a.name, - displayName: a.displayName, - description: a.description, - mode: a.mode, - native: a.native, - color: a.color, - deprecated: a.deprecated, - })), + agents: visible.map(mapAgent), + allAgents: agents.map(mapAgent), defaultAgent, } this.cachedAgentsMessage = message diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx index 5349789bae3..ed5583a9e3c 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/AgentBehaviourTab.tsx @@ -82,7 +82,12 @@ const AgentBehaviourTab: Component = () => { }) const agentNames = createMemo(() => { - const names = session.agents().map((a) => a.name) + // Exclude server-side hidden internal modes (compaction, title, summary) + // from the list. Config-only agents are still added below. + const names = session + .allAgents() + .filter((a) => !a.hidden) + .map((a) => a.name) // Also include any agents from config that might not be in the agent list const agents = Object.keys(config().agent ?? {}) for (const name of agents) { @@ -93,10 +98,15 @@ const AgentBehaviourTab: Component = () => { return names.sort() }) - const defaultAgentOptions = createMemo(() => [ - { value: "", label: language.t("common.default") }, - ...agentNames().map((name) => ({ value: name, label: name })), - ]) + // Default-agent picker must only show visible primary agents (not subagents + // or hidden modes) since the CLI rejects those as default_agent values. + const defaultAgentOptions = createMemo(() => { + const visible = session.agents().map((a) => a.name) + return [ + { value: "", label: language.t("common.default") }, + ...visible.map((name) => ({ value: name, label: name })), + ] + }) const instructions = () => config().instructions ?? [] @@ -185,7 +195,7 @@ const AgentBehaviourTab: Component = () => { )) } - const removableModes = createMemo(() => session.agents().filter((a) => !a.native)) + const removableModes = createMemo(() => session.allAgents().filter((a) => !a.native)) const confirmRemoveMode = (agent: AgentInfo) => { dialog.show(() => ( @@ -354,7 +364,7 @@ const AgentBehaviourTab: Component = () => { {(name, index) => { - const agent = () => session.agents().find((a) => a.name === name) + const agent = () => session.allAgents().find((a) => a.name === name) const isCustom = () => !agent()?.native const agentCfg = () => config().agent?.[name] ?? {} const disabled = () => agentCfg().disable ?? false @@ -396,6 +406,19 @@ const AgentBehaviourTab: Component = () => { custom + + + {language.t("settings.agentBehaviour.badge.subagent")} + + = (props) => { // agent() may be undefined for modes that only exist in the config draft (just // created, not yet saved). This is fine — native defaults to false (correct for // custom modes) and all fields read from cfg() which comes from config context. - const agent = () => session.agents().find((a) => a.name === props.name) + const agent = () => session.allAgents().find((a) => a.name === props.name) const native = () => agent()?.native ?? false + const [expanded, setExpanded] = createSignal(false) const cfg = createMemo(() => config().agent?.[props.name] ?? {}) @@ -230,6 +231,18 @@ const ModeEditView: Component = (props) => { + {/* Calculated permissions (read-only, collapsible) */} + + {(rules) => ( + setExpanded((v) => !v)} + /> + )} + +