Skip to content

Commit 4a760b5

Browse files
fix(app): show selector for custom agents (anomalyco#37198)
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
1 parent 888c4cb commit 4a760b5

5 files changed

Lines changed: 46 additions & 9 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { describe, expect, test } from "bun:test"
2+
import { hasCustomAgent, resolveAgent } from "./local-agent"
3+
4+
describe("hasCustomAgent", () => {
5+
test("detects explicitly custom agents", () => {
6+
expect(hasCustomAgent([{ native: true }, { native: false }])).toBe(true)
7+
})
8+
9+
test("ignores built-in and unclassified agents", () => {
10+
expect(hasCustomAgent([{ native: true }, {}])).toBe(false)
11+
})
12+
})
13+
14+
describe("resolveAgent", () => {
15+
const agents = [{ name: "plan" }, { name: "build" }, { name: "custom" }]
16+
17+
test("uses the requested available agent", () => {
18+
expect(resolveAgent(agents, "custom")?.name).toBe("custom")
19+
})
20+
21+
test("defaults to build", () => {
22+
expect(resolveAgent(agents)?.name).toBe("build")
23+
expect(resolveAgent(agents, "missing")?.name).toBe("build")
24+
})
25+
26+
test("uses the first agent when build is unavailable", () => {
27+
expect(resolveAgent([{ name: "custom" }], "missing")?.name).toBe("custom")
28+
})
29+
})
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function hasCustomAgent(items: Array<{ native?: boolean }>) {
2+
return items.some((item) => item.native === false)
3+
}
4+
5+
export function resolveAgent<T extends { name: string }>(items: T[], name?: string) {
6+
return items.find((item) => item.name === name) ?? items.find((item) => item.name === "build") ?? items[0]
7+
}

packages/app/src/context/local.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import { useParams } from "@solidjs/router"
44
import { batch, createEffect, createMemo, startTransition } from "solid-js"
55
import { createStore } from "solid-js/store"
66
import { useModels } from "@/context/models"
7+
import { useSettings } from "@/context/settings"
78
import { useProviders } from "@/hooks/use-providers"
89
import { Persist, persisted } from "@/utils/persist"
10+
import { hasCustomAgent, resolveAgent } from "./local-agent"
911
import { cycleModelVariant, getConfiguredAgentVariant, resolveModelVariant } from "./model-variant"
1012
import { useSDK } from "./sdk"
1113
import { useSync } from "./sync"
@@ -62,9 +64,11 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
6264
const serverSDK = useServerSDK()
6365
const providers = useProviders(() => sdk().directory)
6466
const models = useModels()
67+
const settings = useSettings()
6568

6669
const id = createMemo(() => params.id || undefined)
6770
const list = createMemo(() => sync().data.agent.filter((item) => item.mode !== "subagent" && !item.hidden))
71+
const agentsVisible = createMemo(() => settings.visibility.customAgents() || hasCustomAgent(list()))
6872
const connected = createMemo(() => new Set(providers.connected().map((item) => item.id)))
6973

7074
const [saved, setSaved, , savedReady] = persisted(
@@ -107,9 +111,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
107111
}
108112

109113
const pickAgent = (name: string | undefined) => {
110-
const items = list()
111-
if (items.length === 0) return
112-
return items.find((item) => item.name === name) ?? items[0]
114+
return resolveAgent(list(), name)
113115
}
114116

115117
createEffect(() => {
@@ -180,8 +182,9 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
180182

181183
const agent = {
182184
list,
185+
visible: agentsVisible,
183186
current() {
184-
return pickAgent(scope()?.agent ?? store.current)
187+
return pickAgent(agentsVisible() ? (scope()?.agent ?? store.current) : "build")
185188
},
186189
set(name: string | undefined) {
187190
const item = pickAgent(name)

packages/app/src/pages/session/composer/session-composer-controls.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export function createPromptInputController(input: {
4141
options: local.agent.list().map((agent) => agent.name),
4242
current: local.agent.current()?.name ?? "",
4343
loading: agentsQuery.isLoading,
44-
visible: settings.visibility.customAgents(),
44+
visible: local.agent.visible(),
4545
select: local.agent.set,
4646
},
4747
model: {

packages/app/src/pages/session/use-composer-commands.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { useCommand, type CommandOption } from "@/context/command"
22
import { useLanguage } from "@/context/language"
33
import { useLocal, type ModelSelection } from "@/context/local"
4-
import { useSettings } from "@/context/settings"
54
import { useDialog } from "@opencode-ai/ui/context/dialog"
65
import { getCursorPosition, setCursorPosition } from "@/components/prompt-input/editor-dom"
76
import { useSessionLayout } from "./session-layout"
@@ -19,7 +18,6 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
1918
const dialog = useDialog()
2019
const language = useLanguage()
2120
const local = useLocal()
22-
const settings = useSettings()
2321
const { sessionKey } = useSessionLayout()
2422
const sessionOwnership = createSessionOwnership(sessionKey)
2523
const model = input.model ?? local.model
@@ -70,15 +68,15 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
7068
description: language.t("command.agent.cycle.description"),
7169
keybind: "mod+.",
7270
slash: "agent",
73-
disabled: !settings.visibility.customAgents(),
71+
disabled: !local.agent.visible(),
7472
onSelect: () => local.agent.move(1),
7573
}),
7674
agentCommand({
7775
id: "agent.cycle.reverse",
7876
title: language.t("command.agent.cycle.reverse"),
7977
description: language.t("command.agent.cycle.reverse.description"),
8078
keybind: "shift+mod+.",
81-
disabled: !settings.visibility.customAgents(),
79+
disabled: !local.agent.visible(),
8280
onSelect: () => local.agent.move(-1),
8381
}),
8482
])

0 commit comments

Comments
 (0)