refactor: major codebase cleanup - BDD comments, file splitting, bug fixes (#1350)
* style(tests): normalize BDD comments from '// #given' to '// given'
- Replace 4,668 Python-style BDD comments across 107 test files
- Patterns changed: // #given -> // given, // #when -> // when, // #then -> // then
- Also handles no-space variants: //#given -> // given
* fix(rules-injector): prefer output.metadata.filePath over output.title
- Extract file path resolution to dedicated output-path.ts module
- Prefer metadata.filePath which contains actual file path
- Fall back to output.title only when metadata unavailable
- Fixes issue where rules weren't injected when tool output title was a label
* feat(slashcommand): add optional user_message parameter
- Add user_message optional parameter for command arguments
- Model can now call: command='publish' user_message='patch'
- Improves error messages with clearer format guidance
- Helps LLMs understand correct parameter usage
* feat(hooks): restore compaction-context-injector hook
- Restore hook deleted in cbbc7bd0 for session compaction context
- Injects 7 mandatory sections: User Requests, Final Goal, Work Completed,
Remaining Tasks, Active Working Context, MUST NOT Do, Agent Verification State
- Re-register in hooks/index.ts and main plugin entry
* refactor(background-agent): split manager.ts into focused modules
- Extract constants.ts for TTL values and internal types (52 lines)
- Extract state.ts for TaskStateManager class (204 lines)
- Extract spawner.ts for task creation logic (244 lines)
- Extract result-handler.ts for completion handling (265 lines)
- Reduce manager.ts from 1377 to 755 lines (45% reduction)
- Maintain backward compatible exports
* refactor(agents): split prometheus-prompt.ts into subdirectory
- Move 1196-line prometheus-prompt.ts to prometheus/ subdirectory
- Organize prompt sections into separate files for maintainability
- Update agents/index.ts exports
* refactor(delegate-task): split tools.ts into focused modules
- Extract categories.ts for category definitions and routing
- Extract executor.ts for task execution logic
- Extract helpers.ts for utility functions
- Extract prompt-builder.ts for prompt construction
- Reduce tools.ts complexity with cleaner separation of concerns
* refactor(builtin-skills): split skills.ts into individual skill files
- Move each skill to dedicated file in skills/ subdirectory
- Create barrel export for backward compatibility
- Improve maintainability with focused skill modules
* chore: update import paths and lockfile
- Update prometheus import path after refactor
- Update bun.lock
* fix(tests): complete BDD comment normalization
- Fix remaining #when/#then patterns missed by initial sed
- Affected: state.test.ts, events.test.ts
---------
Co-authored-by: justsisyphus <justsisyphus@users.noreply.github.com>
This commit is contained in:
+93
-93
@@ -9,53 +9,53 @@ const TEST_DEFAULT_MODEL = "anthropic/claude-opus-4-5"
|
||||
|
||||
describe("createBuiltinAgents with model overrides", () => {
|
||||
test("Sisyphus with default model has thinking config", async () => {
|
||||
// #given - no overrides, using systemDefaultModel
|
||||
// given - no overrides, using systemDefaultModel
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL)
|
||||
|
||||
// #then
|
||||
// then
|
||||
expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-5")
|
||||
expect(agents.sisyphus.thinking).toEqual({ type: "enabled", budgetTokens: 32000 })
|
||||
expect(agents.sisyphus.reasoningEffort).toBeUndefined()
|
||||
})
|
||||
|
||||
test("Sisyphus with GPT model override has reasoningEffort, no thinking", async () => {
|
||||
// #given
|
||||
// given
|
||||
const overrides = {
|
||||
sisyphus: { model: "github-copilot/gpt-5.2" },
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
|
||||
|
||||
// #then
|
||||
// then
|
||||
expect(agents.sisyphus.model).toBe("github-copilot/gpt-5.2")
|
||||
expect(agents.sisyphus.reasoningEffort).toBe("medium")
|
||||
expect(agents.sisyphus.thinking).toBeUndefined()
|
||||
})
|
||||
|
||||
test("Sisyphus uses system default when no availableModels provided", async () => {
|
||||
// #given
|
||||
// given
|
||||
const systemDefaultModel = "anthropic/claude-opus-4-5"
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], {}, undefined, systemDefaultModel)
|
||||
|
||||
// #then - falls back to system default when no availability match
|
||||
// then - falls back to system default when no availability match
|
||||
expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-5")
|
||||
expect(agents.sisyphus.thinking).toEqual({ type: "enabled", budgetTokens: 32000 })
|
||||
expect(agents.sisyphus.reasoningEffort).toBeUndefined()
|
||||
})
|
||||
|
||||
test("Oracle uses connected provider fallback when availableModels is empty and cache exists", async () => {
|
||||
// #given - connected providers cache has "openai", which matches oracle's first fallback entry
|
||||
// given - connected providers cache has "openai", which matches oracle's first fallback entry
|
||||
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["openai"])
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL)
|
||||
|
||||
// #then - oracle resolves via connected cache fallback to openai/gpt-5.2 (not system default)
|
||||
// then - oracle resolves via connected cache fallback to openai/gpt-5.2 (not system default)
|
||||
expect(agents.oracle.model).toBe("openai/gpt-5.2")
|
||||
expect(agents.oracle.reasoningEffort).toBe("medium")
|
||||
expect(agents.oracle.thinking).toBeUndefined()
|
||||
@@ -63,28 +63,28 @@ describe("createBuiltinAgents with model overrides", () => {
|
||||
})
|
||||
|
||||
test("Oracle created without model field when no cache exists (first run scenario)", async () => {
|
||||
// #given - no cache at all (first run)
|
||||
// given - no cache at all (first run)
|
||||
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null)
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL)
|
||||
|
||||
// #then - oracle should be created with system default model (fallback to systemDefaultModel)
|
||||
// then - oracle should be created with system default model (fallback to systemDefaultModel)
|
||||
expect(agents.oracle).toBeDefined()
|
||||
expect(agents.oracle.model).toBe(TEST_DEFAULT_MODEL)
|
||||
cacheSpy.mockRestore?.()
|
||||
})
|
||||
|
||||
test("Oracle with GPT model override has reasoningEffort, no thinking", async () => {
|
||||
// #given
|
||||
// given
|
||||
const overrides = {
|
||||
oracle: { model: "openai/gpt-5.2" },
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
|
||||
|
||||
// #then
|
||||
// then
|
||||
expect(agents.oracle.model).toBe("openai/gpt-5.2")
|
||||
expect(agents.oracle.reasoningEffort).toBe("medium")
|
||||
expect(agents.oracle.textVerbosity).toBe("high")
|
||||
@@ -92,15 +92,15 @@ describe("createBuiltinAgents with model overrides", () => {
|
||||
})
|
||||
|
||||
test("Oracle with Claude model override has thinking, no reasoningEffort", async () => {
|
||||
// #given
|
||||
// given
|
||||
const overrides = {
|
||||
oracle: { model: "anthropic/claude-sonnet-4" },
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
|
||||
|
||||
// #then
|
||||
// then
|
||||
expect(agents.oracle.model).toBe("anthropic/claude-sonnet-4")
|
||||
expect(agents.oracle.thinking).toEqual({ type: "enabled", budgetTokens: 32000 })
|
||||
expect(agents.oracle.reasoningEffort).toBeUndefined()
|
||||
@@ -108,15 +108,15 @@ describe("createBuiltinAgents with model overrides", () => {
|
||||
})
|
||||
|
||||
test("non-model overrides are still applied after factory rebuild", async () => {
|
||||
// #given
|
||||
// given
|
||||
const overrides = {
|
||||
sisyphus: { model: "github-copilot/gpt-5.2", temperature: 0.5 },
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
|
||||
|
||||
// #then
|
||||
// then
|
||||
expect(agents.sisyphus.model).toBe("github-copilot/gpt-5.2")
|
||||
expect(agents.sisyphus.temperature).toBe(0.5)
|
||||
})
|
||||
@@ -124,38 +124,38 @@ describe("createBuiltinAgents with model overrides", () => {
|
||||
|
||||
describe("createBuiltinAgents without systemDefaultModel", () => {
|
||||
test("agents created via connected cache fallback even without systemDefaultModel", async () => {
|
||||
// #given - connected cache has "openai", which matches oracle's fallback chain
|
||||
// given - connected cache has "openai", which matches oracle's fallback chain
|
||||
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["openai"])
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], {}, undefined, undefined)
|
||||
|
||||
// #then - connected cache enables model resolution despite no systemDefaultModel
|
||||
// then - connected cache enables model resolution despite no systemDefaultModel
|
||||
expect(agents.oracle).toBeDefined()
|
||||
expect(agents.oracle.model).toBe("openai/gpt-5.2")
|
||||
cacheSpy.mockRestore?.()
|
||||
})
|
||||
|
||||
test("agents NOT created when no cache and no systemDefaultModel (first run without defaults)", async () => {
|
||||
// #given
|
||||
// given
|
||||
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(null)
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], {}, undefined, undefined)
|
||||
|
||||
// #then
|
||||
// then
|
||||
expect(agents.oracle).toBeUndefined()
|
||||
cacheSpy.mockRestore?.()
|
||||
})
|
||||
|
||||
test("sisyphus created via connected cache fallback even without systemDefaultModel", async () => {
|
||||
// #given - connected cache has "anthropic", which matches sisyphus's first fallback entry
|
||||
// given - connected cache has "anthropic", which matches sisyphus's first fallback entry
|
||||
const cacheSpy = spyOn(connectedProvidersCache, "readConnectedProvidersCache").mockReturnValue(["anthropic"])
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], {}, undefined, undefined)
|
||||
|
||||
// #then - connected cache enables model resolution despite no systemDefaultModel
|
||||
// then - connected cache enables model resolution despite no systemDefaultModel
|
||||
expect(agents.sisyphus).toBeDefined()
|
||||
expect(agents.sisyphus.model).toBe("anthropic/claude-opus-4-5")
|
||||
cacheSpy.mockRestore?.()
|
||||
@@ -171,7 +171,7 @@ describe("buildAgent with category and skills", () => {
|
||||
})
|
||||
|
||||
test("agent with category inherits category settings", () => {
|
||||
// #given - agent factory that sets category but no model
|
||||
// given - agent factory that sets category but no model
|
||||
const source = {
|
||||
"test-agent": () =>
|
||||
({
|
||||
@@ -180,15 +180,15 @@ describe("buildAgent with category and skills", () => {
|
||||
}) as AgentConfig,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agent = buildAgent(source["test-agent"], TEST_MODEL)
|
||||
|
||||
// #then - category's built-in model is applied
|
||||
// then - category's built-in model is applied
|
||||
expect(agent.model).toBe("google/gemini-3-pro")
|
||||
})
|
||||
|
||||
test("agent with category and existing model keeps existing model", () => {
|
||||
// #given
|
||||
// given
|
||||
const source = {
|
||||
"test-agent": () =>
|
||||
({
|
||||
@@ -198,15 +198,15 @@ describe("buildAgent with category and skills", () => {
|
||||
}) as AgentConfig,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agent = buildAgent(source["test-agent"], TEST_MODEL)
|
||||
|
||||
// #then - explicit model takes precedence over category
|
||||
// then - explicit model takes precedence over category
|
||||
expect(agent.model).toBe("custom/model")
|
||||
})
|
||||
|
||||
test("agent with category inherits variant", () => {
|
||||
// #given
|
||||
// given
|
||||
const source = {
|
||||
"test-agent": () =>
|
||||
({
|
||||
@@ -222,16 +222,16 @@ describe("buildAgent with category and skills", () => {
|
||||
},
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agent = buildAgent(source["test-agent"], TEST_MODEL, categories)
|
||||
|
||||
// #then
|
||||
// then
|
||||
expect(agent.model).toBe("openai/gpt-5.2")
|
||||
expect(agent.variant).toBe("xhigh")
|
||||
})
|
||||
|
||||
test("agent with skills has content prepended to prompt", () => {
|
||||
// #given
|
||||
// given
|
||||
const source = {
|
||||
"test-agent": () =>
|
||||
({
|
||||
@@ -241,17 +241,17 @@ describe("buildAgent with category and skills", () => {
|
||||
}) as AgentConfig,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agent = buildAgent(source["test-agent"], TEST_MODEL)
|
||||
|
||||
// #then
|
||||
// then
|
||||
expect(agent.prompt).toContain("Role: Designer-Turned-Developer")
|
||||
expect(agent.prompt).toContain("Original prompt content")
|
||||
expect(agent.prompt).toMatch(/Designer-Turned-Developer[\s\S]*Original prompt content/s)
|
||||
})
|
||||
|
||||
test("agent with multiple skills has all content prepended", () => {
|
||||
// #given
|
||||
// given
|
||||
const source = {
|
||||
"test-agent": () =>
|
||||
({
|
||||
@@ -261,16 +261,16 @@ describe("buildAgent with category and skills", () => {
|
||||
}) as AgentConfig,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agent = buildAgent(source["test-agent"], TEST_MODEL)
|
||||
|
||||
// #then
|
||||
// then
|
||||
expect(agent.prompt).toContain("Role: Designer-Turned-Developer")
|
||||
expect(agent.prompt).toContain("Agent prompt")
|
||||
})
|
||||
|
||||
test("agent without category or skills works as before", () => {
|
||||
// #given
|
||||
// given
|
||||
const source = {
|
||||
"test-agent": () =>
|
||||
({
|
||||
@@ -281,17 +281,17 @@ describe("buildAgent with category and skills", () => {
|
||||
}) as AgentConfig,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agent = buildAgent(source["test-agent"], TEST_MODEL)
|
||||
|
||||
// #then
|
||||
// then
|
||||
expect(agent.model).toBe("custom/model")
|
||||
expect(agent.temperature).toBe(0.5)
|
||||
expect(agent.prompt).toBe("Base prompt")
|
||||
})
|
||||
|
||||
test("agent with category and skills applies both", () => {
|
||||
// #given
|
||||
// given
|
||||
const source = {
|
||||
"test-agent": () =>
|
||||
({
|
||||
@@ -302,10 +302,10 @@ describe("buildAgent with category and skills", () => {
|
||||
}) as AgentConfig,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agent = buildAgent(source["test-agent"], TEST_MODEL)
|
||||
|
||||
// #then - category's built-in model and skills are applied
|
||||
// then - category's built-in model and skills are applied
|
||||
expect(agent.model).toBe("openai/gpt-5.2-codex")
|
||||
expect(agent.variant).toBe("xhigh")
|
||||
expect(agent.prompt).toContain("Role: Designer-Turned-Developer")
|
||||
@@ -313,7 +313,7 @@ describe("buildAgent with category and skills", () => {
|
||||
})
|
||||
|
||||
test("agent with non-existent category has no effect", () => {
|
||||
// #given
|
||||
// given
|
||||
const source = {
|
||||
"test-agent": () =>
|
||||
({
|
||||
@@ -323,10 +323,10 @@ describe("buildAgent with category and skills", () => {
|
||||
}) as AgentConfig,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agent = buildAgent(source["test-agent"], TEST_MODEL)
|
||||
|
||||
// #then
|
||||
// then
|
||||
// Note: The factory receives model, but if category doesn't exist, it's not applied
|
||||
// The agent's model comes from the factory output (which doesn't set model)
|
||||
expect(agent.model).toBeUndefined()
|
||||
@@ -334,7 +334,7 @@ describe("buildAgent with category and skills", () => {
|
||||
})
|
||||
|
||||
test("agent with non-existent skills only prepends found ones", () => {
|
||||
// #given
|
||||
// given
|
||||
const source = {
|
||||
"test-agent": () =>
|
||||
({
|
||||
@@ -344,16 +344,16 @@ describe("buildAgent with category and skills", () => {
|
||||
}) as AgentConfig,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agent = buildAgent(source["test-agent"], TEST_MODEL)
|
||||
|
||||
// #then
|
||||
// then
|
||||
expect(agent.prompt).toContain("Role: Designer-Turned-Developer")
|
||||
expect(agent.prompt).toContain("Base prompt")
|
||||
})
|
||||
|
||||
test("agent with empty skills array keeps original prompt", () => {
|
||||
// #given
|
||||
// given
|
||||
const source = {
|
||||
"test-agent": () =>
|
||||
({
|
||||
@@ -363,15 +363,15 @@ describe("buildAgent with category and skills", () => {
|
||||
}) as AgentConfig,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agent = buildAgent(source["test-agent"], TEST_MODEL)
|
||||
|
||||
// #then
|
||||
// then
|
||||
expect(agent.prompt).toBe("Base prompt")
|
||||
})
|
||||
|
||||
test("agent with agent-browser skill resolves when browserProvider is set", () => {
|
||||
// #given
|
||||
// given
|
||||
const source = {
|
||||
"test-agent": () =>
|
||||
({
|
||||
@@ -381,16 +381,16 @@ describe("buildAgent with category and skills", () => {
|
||||
}) as AgentConfig,
|
||||
}
|
||||
|
||||
// #when - browserProvider is "agent-browser"
|
||||
// when - browserProvider is "agent-browser"
|
||||
const agent = buildAgent(source["test-agent"], TEST_MODEL, undefined, undefined, "agent-browser")
|
||||
|
||||
// #then - agent-browser skill content should be in prompt
|
||||
// then - agent-browser skill content should be in prompt
|
||||
expect(agent.prompt).toContain("agent-browser")
|
||||
expect(agent.prompt).toContain("Base prompt")
|
||||
})
|
||||
|
||||
test("agent with agent-browser skill NOT resolved when browserProvider not set", () => {
|
||||
// #given
|
||||
// given
|
||||
const source = {
|
||||
"test-agent": () =>
|
||||
({
|
||||
@@ -400,10 +400,10 @@ describe("buildAgent with category and skills", () => {
|
||||
}) as AgentConfig,
|
||||
}
|
||||
|
||||
// #when - no browserProvider (defaults to playwright)
|
||||
// when - no browserProvider (defaults to playwright)
|
||||
const agent = buildAgent(source["test-agent"], TEST_MODEL)
|
||||
|
||||
// #then - agent-browser skill not found, only base prompt remains
|
||||
// then - agent-browser skill not found, only base prompt remains
|
||||
expect(agent.prompt).toBe("Base prompt")
|
||||
expect(agent.prompt).not.toContain("agent-browser open")
|
||||
})
|
||||
@@ -411,36 +411,36 @@ describe("buildAgent with category and skills", () => {
|
||||
|
||||
describe("override.category expansion in createBuiltinAgents", () => {
|
||||
test("standard agent override with category expands category properties", async () => {
|
||||
// #given
|
||||
// given
|
||||
const overrides = {
|
||||
oracle: { category: "ultrabrain" } as any,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
|
||||
|
||||
// #then - ultrabrain category: model=openai/gpt-5.2-codex, variant=xhigh
|
||||
// then - ultrabrain category: model=openai/gpt-5.2-codex, variant=xhigh
|
||||
expect(agents.oracle).toBeDefined()
|
||||
expect(agents.oracle.model).toBe("openai/gpt-5.2-codex")
|
||||
expect(agents.oracle.variant).toBe("xhigh")
|
||||
})
|
||||
|
||||
test("standard agent override with category AND direct variant - direct wins", async () => {
|
||||
// #given - ultrabrain has variant=xhigh, but direct override says "max"
|
||||
// given - ultrabrain has variant=xhigh, but direct override says "max"
|
||||
const overrides = {
|
||||
oracle: { category: "ultrabrain", variant: "max" } as any,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
|
||||
|
||||
// #then - direct variant overrides category variant
|
||||
// then - direct variant overrides category variant
|
||||
expect(agents.oracle).toBeDefined()
|
||||
expect(agents.oracle.variant).toBe("max")
|
||||
})
|
||||
|
||||
test("standard agent override with category AND direct reasoningEffort - direct wins", async () => {
|
||||
// #given - custom category has reasoningEffort=xhigh, direct override says "low"
|
||||
// given - custom category has reasoningEffort=xhigh, direct override says "low"
|
||||
const categories = {
|
||||
"test-cat": {
|
||||
model: "openai/gpt-5.2",
|
||||
@@ -451,16 +451,16 @@ describe("override.category expansion in createBuiltinAgents", () => {
|
||||
oracle: { category: "test-cat", reasoningEffort: "low" } as any,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL, categories)
|
||||
|
||||
// #then - direct reasoningEffort wins over category
|
||||
// then - direct reasoningEffort wins over category
|
||||
expect(agents.oracle).toBeDefined()
|
||||
expect(agents.oracle.reasoningEffort).toBe("low")
|
||||
})
|
||||
|
||||
test("standard agent override with category applies reasoningEffort from category when no direct override", async () => {
|
||||
// #given - custom category has reasoningEffort, no direct reasoningEffort in override
|
||||
// given - custom category has reasoningEffort, no direct reasoningEffort in override
|
||||
const categories = {
|
||||
"reasoning-cat": {
|
||||
model: "openai/gpt-5.2",
|
||||
@@ -471,54 +471,54 @@ describe("override.category expansion in createBuiltinAgents", () => {
|
||||
oracle: { category: "reasoning-cat" } as any,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL, categories)
|
||||
|
||||
// #then - category reasoningEffort is applied
|
||||
// then - category reasoningEffort is applied
|
||||
expect(agents.oracle).toBeDefined()
|
||||
expect(agents.oracle.reasoningEffort).toBe("high")
|
||||
})
|
||||
|
||||
test("sisyphus override with category expands category properties", async () => {
|
||||
// #given
|
||||
// given
|
||||
const overrides = {
|
||||
sisyphus: { category: "ultrabrain" } as any,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
|
||||
|
||||
// #then - ultrabrain category: model=openai/gpt-5.2-codex, variant=xhigh
|
||||
// then - ultrabrain category: model=openai/gpt-5.2-codex, variant=xhigh
|
||||
expect(agents.sisyphus).toBeDefined()
|
||||
expect(agents.sisyphus.model).toBe("openai/gpt-5.2-codex")
|
||||
expect(agents.sisyphus.variant).toBe("xhigh")
|
||||
})
|
||||
|
||||
test("atlas override with category expands category properties", async () => {
|
||||
// #given
|
||||
// given
|
||||
const overrides = {
|
||||
atlas: { category: "ultrabrain" } as any,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
|
||||
|
||||
// #then - ultrabrain category: model=openai/gpt-5.2-codex, variant=xhigh
|
||||
// then - ultrabrain category: model=openai/gpt-5.2-codex, variant=xhigh
|
||||
expect(agents.atlas).toBeDefined()
|
||||
expect(agents.atlas.model).toBe("openai/gpt-5.2-codex")
|
||||
expect(agents.atlas.variant).toBe("xhigh")
|
||||
})
|
||||
|
||||
test("override with non-existent category has no effect on config", async () => {
|
||||
// #given
|
||||
// given
|
||||
const overrides = {
|
||||
oracle: { category: "non-existent-category" } as any,
|
||||
}
|
||||
|
||||
// #when
|
||||
// when
|
||||
const agents = await createBuiltinAgents([], overrides, undefined, TEST_DEFAULT_MODEL)
|
||||
|
||||
// #then - no category-specific variant/reasoningEffort applied from non-existent category
|
||||
// then - no category-specific variant/reasoningEffort applied from non-existent category
|
||||
expect(agents.oracle).toBeDefined()
|
||||
const agentsWithoutOverride = await createBuiltinAgents([], {}, undefined, TEST_DEFAULT_MODEL)
|
||||
expect(agents.oracle.model).toBe(agentsWithoutOverride.oracle.model)
|
||||
@@ -527,7 +527,7 @@ describe("override.category expansion in createBuiltinAgents", () => {
|
||||
|
||||
describe("Deadlock prevention - fetchAvailableModels must not receive client", () => {
|
||||
test("createBuiltinAgents should call fetchAvailableModels with undefined client to prevent deadlock", async () => {
|
||||
// #given - This test ensures we don't regress on issue #1301
|
||||
// given - This test ensures we don't regress on issue #1301
|
||||
// Passing client to fetchAvailableModels during createBuiltinAgents (called from config handler)
|
||||
// causes deadlock:
|
||||
// - Plugin init waits for server response (client.provider.list())
|
||||
@@ -540,7 +540,7 @@ describe("Deadlock prevention - fetchAvailableModels must not receive client", (
|
||||
model: { list: () => Promise.resolve({ data: [] }) },
|
||||
}
|
||||
|
||||
// #when - Even when client is provided, fetchAvailableModels must be called with undefined
|
||||
// when - Even when client is provided, fetchAvailableModels must be called with undefined
|
||||
await createBuiltinAgents(
|
||||
[],
|
||||
{},
|
||||
@@ -552,7 +552,7 @@ describe("Deadlock prevention - fetchAvailableModels must not receive client", (
|
||||
mockClient // client is passed but should NOT be forwarded to fetchAvailableModels
|
||||
)
|
||||
|
||||
// #then - fetchAvailableModels must be called with undefined as first argument (no client)
|
||||
// then - fetchAvailableModels must be called with undefined as first argument (no client)
|
||||
// This prevents the deadlock described in issue #1301
|
||||
expect(fetchSpy).toHaveBeenCalled()
|
||||
const firstCallArgs = fetchSpy.mock.calls[0]
|
||||
|
||||
Reference in New Issue
Block a user