fix(agent): sanitize backslash/quote from agent name in launch() and background-executor
Agent names like \hephaestus\ cause 'Agent not found' errors because sanitizeSubagentType() was only called in subagent-resolver.ts but not in the direct manager.launch() path or background-executor.ts. - manager.ts: strip leading/trailing backslash/quote chars from input.agent before validation so \hephaestus\ → hephaestus - background-executor.ts: call sanitizeSubagentType(args.subagent_type) instead of passing raw value to manager.launch() - agent-display-names.ts: reuse sanitizeSubagentType in stripAgentListSortPrefix - Add unit tests for all three fix points Fixes: sessions dying with 'Agent not found: \hephaestus\'
This commit is contained in:
@@ -23,6 +23,12 @@ mock.module("../../shared/connected-providers-cache", () => ({
|
||||
writeProviderModelsCache: () => {},
|
||||
updateConnectedProvidersCache: () => {},
|
||||
}))
|
||||
mock.module("../../shared/frontmatter", () => ({
|
||||
parseFrontmatter: () => ({ frontmatter: {}, content: "" }),
|
||||
}))
|
||||
mock.module("js-yaml", () => ({
|
||||
load: () => ({}),
|
||||
}))
|
||||
mock.restore()
|
||||
|
||||
|
||||
@@ -2447,6 +2453,63 @@ describe("BackgroundManager - Non-blocking Queue Integration", () => {
|
||||
expect(task.sessionId).toBeUndefined()
|
||||
})
|
||||
|
||||
test("should sanitize wrapped agent names before task creation and queueing", async () => {
|
||||
// given
|
||||
const input = {
|
||||
description: "Test task",
|
||||
prompt: "Do something",
|
||||
agent: "\\hephaestus\\",
|
||||
parentSessionId: "parent-session",
|
||||
parentMessageId: "parent-message",
|
||||
}
|
||||
|
||||
// when
|
||||
const task = await manager.launch(input)
|
||||
const queueItem = getQueuesByKey(manager).values().next().value?.[0]
|
||||
|
||||
// then
|
||||
expect(task.agent).toBe("hephaestus")
|
||||
expect(getTaskMap(manager).get(task.id)?.agent).toBe("hephaestus")
|
||||
expect(queueItem?.input.agent).toBe("hephaestus")
|
||||
})
|
||||
|
||||
test("should sanitize slash and quote wrapped agent names before task creation and queueing", async () => {
|
||||
// given
|
||||
const input = {
|
||||
description: "Test task",
|
||||
prompt: "Do something",
|
||||
agent: "\"/hephaestus/\"",
|
||||
parentSessionId: "parent-session",
|
||||
parentMessageId: "parent-message",
|
||||
}
|
||||
|
||||
// when
|
||||
const task = await manager.launch(input)
|
||||
const queueItem = getQueuesByKey(manager).values().next().value?.[0]
|
||||
|
||||
// then
|
||||
expect(task.agent).toBe("hephaestus")
|
||||
expect(getTaskMap(manager).get(task.id)?.agent).toBe("hephaestus")
|
||||
expect(queueItem?.input.agent).toBe("hephaestus")
|
||||
})
|
||||
|
||||
test("should reject wrapper-only agent names after sanitization", async () => {
|
||||
// given
|
||||
const input = {
|
||||
description: "Test task",
|
||||
prompt: "Do something",
|
||||
agent: "\\\"/'\\\"/",
|
||||
parentSessionId: "parent-session",
|
||||
parentMessageId: "parent-message",
|
||||
}
|
||||
|
||||
// when
|
||||
const result = manager.launch(input)
|
||||
|
||||
// then
|
||||
await expect(result).rejects.toThrow("Agent parameter is required after sanitization")
|
||||
})
|
||||
|
||||
test("should initialize attempt state for a newly launched task", async () => {
|
||||
// given
|
||||
const input = {
|
||||
|
||||
@@ -383,6 +383,12 @@ export class BackgroundManager {
|
||||
throw new Error("Agent parameter is required")
|
||||
}
|
||||
|
||||
input = { ...input, agent: input.agent.trim().replace(/^[\\/"']+|[\\/"']+$/g, "").trim() }
|
||||
|
||||
if (!input.agent) {
|
||||
throw new Error("Agent parameter is required after sanitization")
|
||||
}
|
||||
|
||||
const spawnReservation = await this.reserveSubagentSpawn(input.parentSessionId)
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user