mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-07-10 00:14:27 +00:00
fix(ui): scope primary agent selector to selectable agents (#528)
## Summary - rescope the UI portion of #385 to the remaining main-session selector issue from #384 - keep main-session primary selectors limited to selectable primary agents - preserve child/subagent behavior by keeping the current hidden agent available for steering - add focused tests for selector eligibility behavior This intentionally excludes the OMO/config-directory merge and plugin retry scope from #385, since that part was determined to belong outside CodeNomad. Credit to @jollyxenon for the original #385 investigation and UI direction. ## Validation - ode --test packages/ui/src/types/session.test.ts ✅ - pm run typecheck --workspace @codenomad/ui ⚠️ fails on existing SDK/type drift outside this diff Fixes #384 Based on #385
This commit is contained in:
parent
df7c507aa9
commit
8bcf365fc3
3 changed files with 64 additions and 7 deletions
|
|
@ -2,7 +2,7 @@ import { Select } from "@kobalte/core/select"
|
|||
import { Show, createEffect, createMemo } from "solid-js"
|
||||
import { agents, fetchAgents, sessions } from "../stores/sessions"
|
||||
import { ChevronDown } from "lucide-solid"
|
||||
import { isSelectablePrimaryAgent, type Agent } from "../types/session"
|
||||
import { getSelectableAgentsForSession, type Agent } from "../types/session"
|
||||
import { useI18n } from "../lib/i18n"
|
||||
import { getLogger } from "../lib/logger"
|
||||
const log = getLogger("session")
|
||||
|
|
@ -29,12 +29,7 @@ export default function AgentSelector(props: AgentSelectorProps) {
|
|||
})
|
||||
|
||||
const availableAgents = createMemo(() => {
|
||||
const allAgents = instanceAgents()
|
||||
if (isChildSession()) {
|
||||
return allAgents.filter((agent) => !agent.hidden)
|
||||
}
|
||||
|
||||
return allAgents.filter(isSelectablePrimaryAgent)
|
||||
return getSelectableAgentsForSession(instanceAgents(), props.currentAgent, isChildSession())
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
|
|
|
|||
45
packages/ui/src/types/session.test.ts
Normal file
45
packages/ui/src/types/session.test.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import assert from "node:assert/strict"
|
||||
import { describe, it } from "node:test"
|
||||
|
||||
import { getSelectableAgentsForSession, isSelectablePrimaryAgent, type Agent } from "./session.ts"
|
||||
|
||||
const visiblePrimary: Agent = { name: "plan", description: "", mode: "primary" }
|
||||
const visibleSubagent: Agent = { name: "review", description: "", mode: "subagent" }
|
||||
const hiddenPrimary: Agent = { name: "build", description: "", mode: "primary", hidden: true }
|
||||
const hiddenSubagent: Agent = { name: "debug", description: "", mode: "subagent", hidden: true }
|
||||
|
||||
describe("agent selectability", () => {
|
||||
it("matches primary-session selector rules", () => {
|
||||
assert.equal(isSelectablePrimaryAgent(visiblePrimary), true)
|
||||
assert.equal(isSelectablePrimaryAgent(visibleSubagent), false)
|
||||
assert.equal(isSelectablePrimaryAgent(hiddenPrimary), false)
|
||||
assert.equal(isSelectablePrimaryAgent(hiddenSubagent), false)
|
||||
})
|
||||
|
||||
it("excludes hidden and subagent entries from main-session selectors", () => {
|
||||
const agents = [hiddenPrimary, visibleSubagent, visiblePrimary]
|
||||
|
||||
assert.deepEqual(
|
||||
getSelectableAgentsForSession(agents, "build", false).map((agent) => agent.name),
|
||||
["plan"],
|
||||
)
|
||||
})
|
||||
|
||||
it("preserves a child session's current hidden agent for steering", () => {
|
||||
const agents = [hiddenPrimary, visibleSubagent, visiblePrimary]
|
||||
|
||||
assert.deepEqual(
|
||||
getSelectableAgentsForSession(agents, "build", true).map((agent) => agent.name),
|
||||
["review", "plan", "build"],
|
||||
)
|
||||
})
|
||||
|
||||
it("does not add unrelated hidden agents to child-session selectors", () => {
|
||||
const agents = [hiddenPrimary, visibleSubagent, visiblePrimary]
|
||||
|
||||
assert.deepEqual(
|
||||
getSelectableAgentsForSession(agents, "review", true).map((agent) => agent.name),
|
||||
["review", "plan"],
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
@ -120,6 +120,23 @@ export function isSelectablePrimaryAgent(agent: Agent): boolean {
|
|||
return !agent.hidden && agent.mode !== "subagent"
|
||||
}
|
||||
|
||||
export function getSelectableAgentsForSession(
|
||||
agentList: Agent[],
|
||||
currentAgentName: string,
|
||||
isChildSession: boolean,
|
||||
): Agent[] {
|
||||
if (!isChildSession) {
|
||||
return agentList.filter(isSelectablePrimaryAgent)
|
||||
}
|
||||
|
||||
const visibleAgents = agentList.filter((agent) => !agent.hidden)
|
||||
const currentHiddenAgent = agentList.find((agent) => agent.hidden && agent.name === currentAgentName)
|
||||
|
||||
return currentHiddenAgent && !visibleAgents.some((agent) => agent.name === currentHiddenAgent.name)
|
||||
? [...visibleAgents, currentHiddenAgent]
|
||||
: visibleAgents
|
||||
}
|
||||
|
||||
// Our client-specific Provider interface (simplified version of SDK Provider)
|
||||
export interface Provider {
|
||||
id: string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue