refactor(core): resolve default agent info (#27125)

This commit is contained in:
Shoubhit Dash
2026-05-13 01:08:30 +05:30
committed by GitHub
parent e540daabc4
commit 45de4975de
6 changed files with 30 additions and 13 deletions
+3 -3
View File
@@ -1094,8 +1094,8 @@ export class Agent implements ACPAgent {
const currentModeId = await (async () => { const currentModeId = await (async () => {
if (!availableModes.length) return undefined if (!availableModes.length) return undefined
const defaultAgentName = await AppRuntime.runPromise(AgentModule.Service.use((svc) => svc.defaultAgent())) const defaultAgent = await AppRuntime.runPromise(AgentModule.Service.use((svc) => svc.defaultInfo()))
const resolvedModeId = availableModes.find((mode) => mode.name === defaultAgentName)?.id ?? availableModes[0].id const resolvedModeId = availableModes.find((mode) => mode.name === defaultAgent.name)?.id ?? availableModes[0].id
this.sessionManager.setMode(sessionId, resolvedModeId) this.sessionManager.setMode(sessionId, resolvedModeId)
return resolvedModeId return resolvedModeId
})() })()
@@ -1328,7 +1328,7 @@ export class Agent implements ACPAgent {
if (!current) { if (!current) {
this.sessionManager.setModel(session.id, model) this.sessionManager.setModel(session.id, model)
} }
const agent = session.modeId ?? (await AppRuntime.runPromise(AgentModule.Service.use((svc) => svc.defaultAgent()))) const agent = session.modeId ?? (await AppRuntime.runPromise(AgentModule.Service.use((svc) => svc.defaultInfo()))).name
const parts: Array< const parts: Array<
| { type: "text"; text: string; synthetic?: boolean; ignored?: boolean } | { type: "text"; text: string; synthetic?: boolean; ignored?: boolean }
+12 -3
View File
@@ -57,6 +57,7 @@ const GeneratedAgent = Schema.Struct({
export interface Interface { export interface Interface {
readonly get: (agent: string) => Effect.Effect<Info> readonly get: (agent: string) => Effect.Effect<Info>
readonly list: () => Effect.Effect<Info[]> readonly list: () => Effect.Effect<Info[]>
readonly defaultInfo: () => Effect.Effect<Info>
readonly defaultAgent: () => Effect.Effect<string> readonly defaultAgent: () => Effect.Effect<string>
readonly generate: (input: { readonly generate: (input: {
description: string description: string
@@ -333,23 +334,28 @@ export const layer = Layer.effect(
) )
}) })
const defaultAgent = Effect.fnUntraced(function* () { const defaultInfo = Effect.fnUntraced(function* () {
const c = yield* config.get() const c = yield* config.get()
if (c.default_agent) { if (c.default_agent) {
const agent = agents[c.default_agent] const agent = agents[c.default_agent]
if (!agent) throw new Error(`default agent "${c.default_agent}" not found`) if (!agent) throw new Error(`default agent "${c.default_agent}" not found`)
if (agent.mode === "subagent") throw new Error(`default agent "${c.default_agent}" is a subagent`) if (agent.mode === "subagent") throw new Error(`default agent "${c.default_agent}" is a subagent`)
if (agent.hidden === true) throw new Error(`default agent "${c.default_agent}" is hidden`) if (agent.hidden === true) throw new Error(`default agent "${c.default_agent}" is hidden`)
return agent.name return agent
} }
const visible = Object.values(agents).find((a) => a.mode !== "subagent" && a.hidden !== true) const visible = Object.values(agents).find((a) => a.mode !== "subagent" && a.hidden !== true)
if (!visible) throw new Error("no primary visible agent found") if (!visible) throw new Error("no primary visible agent found")
return visible.name return visible
})
const defaultAgent = Effect.fnUntraced(function* () {
return (yield* defaultInfo()).name
}) })
return { return {
get, get,
list, list,
defaultInfo,
defaultAgent, defaultAgent,
} satisfies State } satisfies State
}), }),
@@ -362,6 +368,9 @@ export const layer = Layer.effect(
list: Effect.fn("Agent.list")(function* () { list: Effect.fn("Agent.list")(function* () {
return yield* InstanceState.useEffect(state, (s) => s.list()) return yield* InstanceState.useEffect(state, (s) => s.list())
}), }),
defaultInfo: Effect.fn("Agent.defaultInfo")(function* () {
return yield* InstanceState.useEffect(state, (s) => s.defaultInfo())
}),
defaultAgent: Effect.fn("Agent.defaultAgent")(function* () { defaultAgent: Effect.fn("Agent.defaultAgent")(function* () {
return yield* InstanceState.useEffect(state, (s) => s.defaultAgent()) return yield* InstanceState.useEffect(state, (s) => s.defaultAgent())
}), }),
@@ -79,7 +79,7 @@ export const experimentalHandlers = HttpApiBuilder.group(InstanceHttpApi, "exper
const list = yield* registry.tools({ const list = yield* registry.tools({
providerID: ctx.query.provider, providerID: ctx.query.provider,
modelID: ctx.query.model, modelID: ctx.query.model,
agent: yield* agents.get(yield* agents.defaultAgent()), agent: yield* agents.defaultInfo(),
}) })
return list.map((item) => ({ return list.map((item) => ({
id: item.id, id: item.id,
+5 -5
View File
@@ -1083,8 +1083,8 @@ NOTE: At any point in time through this workflow you should feel free to ask the
}) })
const createUserMessage = Effect.fn("SessionPrompt.createUserMessage")(function* (input: PromptInput) { const createUserMessage = Effect.fn("SessionPrompt.createUserMessage")(function* (input: PromptInput) {
const agentName = input.agent || (yield* agents.defaultAgent()) const agentName = input.agent
const ag = yield* agents.get(agentName) const ag = agentName ? yield* agents.get(agentName) : yield* agents.defaultInfo()
if (!ag) { if (!ag) {
const available = (yield* agents.list()).filter((a) => !a.hidden).map((a) => a.name) const available = (yield* agents.list()).filter((a) => !a.hidden).map((a) => a.name)
const hint = available.length ? ` Available agents: ${available.join(", ")}` : "" const hint = available.length ? ` Available agents: ${available.join(", ")}` : ""
@@ -1875,7 +1875,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
yield* bus.publish(Session.Event.Error, { sessionID: input.sessionID, error: error.toObject() }) yield* bus.publish(Session.Event.Error, { sessionID: input.sessionID, error: error.toObject() })
throw error throw error
} }
const agentName = cmd.agent ?? input.agent ?? (yield* agents.defaultAgent()) const agentName = cmd.agent ?? input.agent
const raw = input.arguments.match(argsRegex) ?? [] const raw = input.arguments.match(argsRegex) ?? []
const args = raw.map((arg) => arg.replace(quoteTrimRegex, "")) const args = raw.map((arg) => arg.replace(quoteTrimRegex, ""))
@@ -1928,7 +1928,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
yield* getModel(taskModel.providerID, taskModel.modelID, input.sessionID) yield* getModel(taskModel.providerID, taskModel.modelID, input.sessionID)
const agent = yield* agents.get(agentName) const agent = agentName ? yield* agents.get(agentName) : yield* agents.defaultInfo()
if (!agent) { if (!agent) {
const available = (yield* agents.list()).filter((a) => !a.hidden).map((a) => a.name) const available = (yield* agents.list()).filter((a) => !a.hidden).map((a) => a.name)
const hint = available.length ? ` Available agents: ${available.join(", ")}` : "" const hint = available.length ? ` Available agents: ${available.join(", ")}` : ""
@@ -1952,7 +1952,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
] ]
: [...templateParts, ...(input.parts ?? [])] : [...templateParts, ...(input.parts ?? [])]
const userAgent = isSubtask ? (input.agent ?? (yield* agents.defaultAgent())) : agentName const userAgent = isSubtask ? (input.agent ?? (yield* agents.defaultInfo()).name) : agent.name
const userModel = isSubtask const userModel = isSubtask
? input.model ? input.model
? Provider.parseModel(input.model) ? Provider.parseModel(input.model)
@@ -638,6 +638,14 @@ it.instance("defaultAgent returns build when no default_agent config", () =>
}), }),
) )
it.instance("defaultInfo returns resolved build agent when no default_agent config", () =>
Effect.gen(function* () {
const agent = yield* load((svc) => svc.defaultInfo())
expect(agent.name).toBe("build")
expect(agent.mode).toBe("primary")
}),
)
it.instance( it.instance(
"defaultAgent respects default_agent config set to plan", "defaultAgent respects default_agent config set to plan",
() => () =>
+1 -1
View File
@@ -180,7 +180,7 @@ describe("tool.registry", () => {
const promptTools = yield* registry.tools({ const promptTools = yield* registry.tools({
providerID: ProviderID.opencode, providerID: ProviderID.opencode,
modelID: ModelID.make("test"), modelID: ModelID.make("test"),
agent: yield* agents.get(yield* agents.defaultAgent()), agent: yield* agents.defaultInfo(),
}) })
const promptTool = promptTools.find((tool) => tool.id === "sql") const promptTool = promptTools.find((tool) => tool.id === "sql")
if (!promptTool) throw new Error("custom sql tool was not returned for prompts") if (!promptTool) throw new Error("custom sql tool was not returned for prompts")