fix(app): show selector for custom agents (#37198)
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
parent
888c4cb504
commit
4a760b5743
@@ -0,0 +1,29 @@
|
|||||||
|
import { describe, expect, test } from "bun:test"
|
||||||
|
import { hasCustomAgent, resolveAgent } from "./local-agent"
|
||||||
|
|
||||||
|
describe("hasCustomAgent", () => {
|
||||||
|
test("detects explicitly custom agents", () => {
|
||||||
|
expect(hasCustomAgent([{ native: true }, { native: false }])).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("ignores built-in and unclassified agents", () => {
|
||||||
|
expect(hasCustomAgent([{ native: true }, {}])).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("resolveAgent", () => {
|
||||||
|
const agents = [{ name: "plan" }, { name: "build" }, { name: "custom" }]
|
||||||
|
|
||||||
|
test("uses the requested available agent", () => {
|
||||||
|
expect(resolveAgent(agents, "custom")?.name).toBe("custom")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("defaults to build", () => {
|
||||||
|
expect(resolveAgent(agents)?.name).toBe("build")
|
||||||
|
expect(resolveAgent(agents, "missing")?.name).toBe("build")
|
||||||
|
})
|
||||||
|
|
||||||
|
test("uses the first agent when build is unavailable", () => {
|
||||||
|
expect(resolveAgent([{ name: "custom" }], "missing")?.name).toBe("custom")
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export function hasCustomAgent(items: Array<{ native?: boolean }>) {
|
||||||
|
return items.some((item) => item.native === false)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveAgent<T extends { name: string }>(items: T[], name?: string) {
|
||||||
|
return items.find((item) => item.name === name) ?? items.find((item) => item.name === "build") ?? items[0]
|
||||||
|
}
|
||||||
@@ -4,8 +4,10 @@ import { useParams } from "@solidjs/router"
|
|||||||
import { batch, createEffect, createMemo, startTransition } from "solid-js"
|
import { batch, createEffect, createMemo, startTransition } from "solid-js"
|
||||||
import { createStore } from "solid-js/store"
|
import { createStore } from "solid-js/store"
|
||||||
import { useModels } from "@/context/models"
|
import { useModels } from "@/context/models"
|
||||||
|
import { useSettings } from "@/context/settings"
|
||||||
import { useProviders } from "@/hooks/use-providers"
|
import { useProviders } from "@/hooks/use-providers"
|
||||||
import { Persist, persisted } from "@/utils/persist"
|
import { Persist, persisted } from "@/utils/persist"
|
||||||
|
import { hasCustomAgent, resolveAgent } from "./local-agent"
|
||||||
import { cycleModelVariant, getConfiguredAgentVariant, resolveModelVariant } from "./model-variant"
|
import { cycleModelVariant, getConfiguredAgentVariant, resolveModelVariant } from "./model-variant"
|
||||||
import { useSDK } from "./sdk"
|
import { useSDK } from "./sdk"
|
||||||
import { useSync } from "./sync"
|
import { useSync } from "./sync"
|
||||||
@@ -62,9 +64,11 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
|||||||
const serverSDK = useServerSDK()
|
const serverSDK = useServerSDK()
|
||||||
const providers = useProviders(() => sdk().directory)
|
const providers = useProviders(() => sdk().directory)
|
||||||
const models = useModels()
|
const models = useModels()
|
||||||
|
const settings = useSettings()
|
||||||
|
|
||||||
const id = createMemo(() => params.id || undefined)
|
const id = createMemo(() => params.id || undefined)
|
||||||
const list = createMemo(() => sync().data.agent.filter((item) => item.mode !== "subagent" && !item.hidden))
|
const list = createMemo(() => sync().data.agent.filter((item) => item.mode !== "subagent" && !item.hidden))
|
||||||
|
const agentsVisible = createMemo(() => settings.visibility.customAgents() || hasCustomAgent(list()))
|
||||||
const connected = createMemo(() => new Set(providers.connected().map((item) => item.id)))
|
const connected = createMemo(() => new Set(providers.connected().map((item) => item.id)))
|
||||||
|
|
||||||
const [saved, setSaved, , savedReady] = persisted(
|
const [saved, setSaved, , savedReady] = persisted(
|
||||||
@@ -107,9 +111,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pickAgent = (name: string | undefined) => {
|
const pickAgent = (name: string | undefined) => {
|
||||||
const items = list()
|
return resolveAgent(list(), name)
|
||||||
if (items.length === 0) return
|
|
||||||
return items.find((item) => item.name === name) ?? items[0]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
@@ -180,8 +182,9 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
|||||||
|
|
||||||
const agent = {
|
const agent = {
|
||||||
list,
|
list,
|
||||||
|
visible: agentsVisible,
|
||||||
current() {
|
current() {
|
||||||
return pickAgent(scope()?.agent ?? store.current)
|
return pickAgent(agentsVisible() ? (scope()?.agent ?? store.current) : "build")
|
||||||
},
|
},
|
||||||
set(name: string | undefined) {
|
set(name: string | undefined) {
|
||||||
const item = pickAgent(name)
|
const item = pickAgent(name)
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export function createPromptInputController(input: {
|
|||||||
options: local.agent.list().map((agent) => agent.name),
|
options: local.agent.list().map((agent) => agent.name),
|
||||||
current: local.agent.current()?.name ?? "",
|
current: local.agent.current()?.name ?? "",
|
||||||
loading: agentsQuery.isLoading,
|
loading: agentsQuery.isLoading,
|
||||||
visible: settings.visibility.customAgents(),
|
visible: local.agent.visible(),
|
||||||
select: local.agent.set,
|
select: local.agent.set,
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { useCommand, type CommandOption } from "@/context/command"
|
import { useCommand, type CommandOption } from "@/context/command"
|
||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
import { useLocal, type ModelSelection } from "@/context/local"
|
import { useLocal, type ModelSelection } from "@/context/local"
|
||||||
import { useSettings } from "@/context/settings"
|
|
||||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||||
import { getCursorPosition, setCursorPosition } from "@/components/prompt-input/editor-dom"
|
import { getCursorPosition, setCursorPosition } from "@/components/prompt-input/editor-dom"
|
||||||
import { useSessionLayout } from "./session-layout"
|
import { useSessionLayout } from "./session-layout"
|
||||||
@@ -19,7 +18,6 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
|
|||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
const local = useLocal()
|
const local = useLocal()
|
||||||
const settings = useSettings()
|
|
||||||
const { sessionKey } = useSessionLayout()
|
const { sessionKey } = useSessionLayout()
|
||||||
const sessionOwnership = createSessionOwnership(sessionKey)
|
const sessionOwnership = createSessionOwnership(sessionKey)
|
||||||
const model = input.model ?? local.model
|
const model = input.model ?? local.model
|
||||||
@@ -70,7 +68,7 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
|
|||||||
description: language.t("command.agent.cycle.description"),
|
description: language.t("command.agent.cycle.description"),
|
||||||
keybind: "mod+.",
|
keybind: "mod+.",
|
||||||
slash: "agent",
|
slash: "agent",
|
||||||
disabled: !settings.visibility.customAgents(),
|
disabled: !local.agent.visible(),
|
||||||
onSelect: () => local.agent.move(1),
|
onSelect: () => local.agent.move(1),
|
||||||
}),
|
}),
|
||||||
agentCommand({
|
agentCommand({
|
||||||
@@ -78,7 +76,7 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
|
|||||||
title: language.t("command.agent.cycle.reverse"),
|
title: language.t("command.agent.cycle.reverse"),
|
||||||
description: language.t("command.agent.cycle.reverse.description"),
|
description: language.t("command.agent.cycle.reverse.description"),
|
||||||
keybind: "shift+mod+.",
|
keybind: "shift+mod+.",
|
||||||
disabled: !settings.visibility.customAgents(),
|
disabled: !local.agent.visible(),
|
||||||
onSelect: () => local.agent.move(-1),
|
onSelect: () => local.agent.move(-1),
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
|||||||
Reference in New Issue
Block a user