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:
@@ -35,7 +35,7 @@ describe("keyword-detector message transform", () => {
|
||||
}
|
||||
|
||||
test("should prepend ultrawork message to text part", async () => {
|
||||
// #given - a fresh ContextCollector and keyword-detector hook
|
||||
// given - a fresh ContextCollector and keyword-detector hook
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
const sessionID = "test-session-123"
|
||||
@@ -44,10 +44,10 @@ describe("keyword-detector message transform", () => {
|
||||
parts: [{ type: "text", text: "ultrawork do something" }],
|
||||
}
|
||||
|
||||
// #when - keyword detection runs
|
||||
// when - keyword detection runs
|
||||
await hook["chat.message"]({ sessionID }, output)
|
||||
|
||||
// #then - message should be prepended to text part with separator and original text
|
||||
// then - message should be prepended to text part with separator and original text
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).toContain("---")
|
||||
@@ -56,7 +56,7 @@ describe("keyword-detector message transform", () => {
|
||||
})
|
||||
|
||||
test("should prepend search message to text part", async () => {
|
||||
// #given - mock getMainSessionID to return our session (isolate from global state)
|
||||
// given - mock getMainSessionID to return our session (isolate from global state)
|
||||
const collector = new ContextCollector()
|
||||
const sessionID = "search-test-session"
|
||||
getMainSessionSpy = spyOn(sessionState, "getMainSessionID").mockReturnValue(sessionID)
|
||||
@@ -66,10 +66,10 @@ describe("keyword-detector message transform", () => {
|
||||
parts: [{ type: "text", text: "search for the bug" }],
|
||||
}
|
||||
|
||||
// #when - keyword detection runs
|
||||
// when - keyword detection runs
|
||||
await hook["chat.message"]({ sessionID }, output)
|
||||
|
||||
// #then - search message should be prepended to text part
|
||||
// then - search message should be prepended to text part
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).toContain("---")
|
||||
@@ -78,7 +78,7 @@ describe("keyword-detector message transform", () => {
|
||||
})
|
||||
|
||||
test("should NOT transform when no keywords detected", async () => {
|
||||
// #given - no keywords in message
|
||||
// given - no keywords in message
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
const sessionID = "test-session"
|
||||
@@ -87,10 +87,10 @@ describe("keyword-detector message transform", () => {
|
||||
parts: [{ type: "text", text: "just a normal message" }],
|
||||
}
|
||||
|
||||
// #when - keyword detection runs
|
||||
// when - keyword detection runs
|
||||
await hook["chat.message"]({ sessionID }, output)
|
||||
|
||||
// #then - text should remain unchanged
|
||||
// then - text should remain unchanged
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).toBe("just a normal message")
|
||||
@@ -128,7 +128,7 @@ describe("keyword-detector session filtering", () => {
|
||||
}
|
||||
|
||||
test("should skip non-ultrawork keywords in non-main session (using mainSessionID check)", async () => {
|
||||
// #given - main session is set, different session submits search keyword
|
||||
// given - main session is set, different session submits search keyword
|
||||
const mainSessionID = "main-123"
|
||||
const subagentSessionID = "subagent-456"
|
||||
setMainSession(mainSessionID)
|
||||
@@ -139,19 +139,19 @@ describe("keyword-detector session filtering", () => {
|
||||
parts: [{ type: "text", text: "search mode 찾아줘" }],
|
||||
}
|
||||
|
||||
// #when - non-main session triggers keyword detection
|
||||
// when - non-main session triggers keyword detection
|
||||
await hook["chat.message"](
|
||||
{ sessionID: subagentSessionID },
|
||||
output
|
||||
)
|
||||
|
||||
// #then - search keyword should be filtered out based on mainSessionID comparison
|
||||
// then - search keyword should be filtered out based on mainSessionID comparison
|
||||
const skipLog = logCalls.find(c => c.msg.includes("Skipping non-ultrawork keywords in non-main session"))
|
||||
expect(skipLog).toBeDefined()
|
||||
})
|
||||
|
||||
test("should allow ultrawork keywords in non-main session", async () => {
|
||||
// #given - main session is set, different session submits ultrawork keyword
|
||||
// given - main session is set, different session submits ultrawork keyword
|
||||
const mainSessionID = "main-123"
|
||||
const subagentSessionID = "subagent-456"
|
||||
setMainSession(mainSessionID)
|
||||
@@ -163,19 +163,19 @@ describe("keyword-detector session filtering", () => {
|
||||
parts: [{ type: "text", text: "ultrawork mode" }],
|
||||
}
|
||||
|
||||
// #when - non-main session triggers ultrawork keyword
|
||||
// when - non-main session triggers ultrawork keyword
|
||||
await hook["chat.message"](
|
||||
{ sessionID: subagentSessionID },
|
||||
output
|
||||
)
|
||||
|
||||
// #then - ultrawork should still work (variant set to max)
|
||||
// then - ultrawork should still work (variant set to max)
|
||||
expect(output.message.variant).toBe("max")
|
||||
expect(toastCalls).toContain("Ultrawork Mode Activated")
|
||||
})
|
||||
|
||||
test("should allow all keywords in main session", async () => {
|
||||
// #given - main session submits search keyword
|
||||
// given - main session submits search keyword
|
||||
const mainSessionID = "main-123"
|
||||
setMainSession(mainSessionID)
|
||||
|
||||
@@ -185,20 +185,20 @@ describe("keyword-detector session filtering", () => {
|
||||
parts: [{ type: "text", text: "search mode 찾아줘" }],
|
||||
}
|
||||
|
||||
// #when - main session triggers keyword detection
|
||||
// when - main session triggers keyword detection
|
||||
await hook["chat.message"](
|
||||
{ sessionID: mainSessionID },
|
||||
output
|
||||
)
|
||||
|
||||
// #then - search keyword should be detected (output unchanged but detection happens)
|
||||
// then - search keyword should be detected (output unchanged but detection happens)
|
||||
// Note: search keywords don't set variant, they inject messages via context-injector
|
||||
// This test verifies the detection logic runs without filtering
|
||||
expect(output.message.variant).toBeUndefined() // search doesn't set variant
|
||||
})
|
||||
|
||||
test("should allow all keywords when mainSessionID is not set", async () => {
|
||||
// #given - no main session set (early startup or standalone mode)
|
||||
// given - no main session set (early startup or standalone mode)
|
||||
setMainSession(undefined)
|
||||
|
||||
const toastCalls: string[] = []
|
||||
@@ -208,19 +208,19 @@ describe("keyword-detector session filtering", () => {
|
||||
parts: [{ type: "text", text: "ultrawork search" }],
|
||||
}
|
||||
|
||||
// #when - any session triggers keyword detection
|
||||
// when - any session triggers keyword detection
|
||||
await hook["chat.message"](
|
||||
{ sessionID: "any-session" },
|
||||
output
|
||||
)
|
||||
|
||||
// #then - all keywords should work
|
||||
// then - all keywords should work
|
||||
expect(output.message.variant).toBe("max")
|
||||
expect(toastCalls).toContain("Ultrawork Mode Activated")
|
||||
})
|
||||
|
||||
test("should not override existing variant", async () => {
|
||||
// #given - main session set with pre-existing variant
|
||||
// given - main session set with pre-existing variant
|
||||
setMainSession("main-123")
|
||||
|
||||
const toastCalls: string[] = []
|
||||
@@ -230,13 +230,13 @@ describe("keyword-detector session filtering", () => {
|
||||
parts: [{ type: "text", text: "ultrawork mode" }],
|
||||
}
|
||||
|
||||
// #when - ultrawork keyword triggers
|
||||
// when - ultrawork keyword triggers
|
||||
await hook["chat.message"](
|
||||
{ sessionID: "main-123" },
|
||||
output
|
||||
)
|
||||
|
||||
// #then - existing variant should remain
|
||||
// then - existing variant should remain
|
||||
expect(output.message.variant).toBe("low")
|
||||
expect(toastCalls).toContain("Ultrawork Mode Activated")
|
||||
})
|
||||
@@ -273,7 +273,7 @@ describe("keyword-detector word boundary", () => {
|
||||
}
|
||||
|
||||
test("should NOT trigger ultrawork on partial matches like 'StatefulWidget' containing 'ulw'", async () => {
|
||||
// #given - text contains 'ulw' as part of another word (StatefulWidget)
|
||||
// given - text contains 'ulw' as part of another word (StatefulWidget)
|
||||
setMainSession(undefined)
|
||||
|
||||
const toastCalls: string[] = []
|
||||
@@ -283,19 +283,19 @@ describe("keyword-detector word boundary", () => {
|
||||
parts: [{ type: "text", text: "refactor the StatefulWidget component" }],
|
||||
}
|
||||
|
||||
// #when - message with partial 'ulw' match is processed
|
||||
// when - message with partial 'ulw' match is processed
|
||||
await hook["chat.message"](
|
||||
{ sessionID: "any-session" },
|
||||
output
|
||||
)
|
||||
|
||||
// #then - ultrawork should NOT be triggered
|
||||
// then - ultrawork should NOT be triggered
|
||||
expect(output.message.variant).toBeUndefined()
|
||||
expect(toastCalls).not.toContain("Ultrawork Mode Activated")
|
||||
})
|
||||
|
||||
test("should trigger ultrawork on standalone 'ulw' keyword", async () => {
|
||||
// #given - text contains standalone 'ulw'
|
||||
// given - text contains standalone 'ulw'
|
||||
setMainSession(undefined)
|
||||
|
||||
const toastCalls: string[] = []
|
||||
@@ -305,19 +305,19 @@ describe("keyword-detector word boundary", () => {
|
||||
parts: [{ type: "text", text: "ulw do this task" }],
|
||||
}
|
||||
|
||||
// #when - message with standalone 'ulw' is processed
|
||||
// when - message with standalone 'ulw' is processed
|
||||
await hook["chat.message"](
|
||||
{ sessionID: "any-session" },
|
||||
output
|
||||
)
|
||||
|
||||
// #then - ultrawork should be triggered
|
||||
// then - ultrawork should be triggered
|
||||
expect(output.message.variant).toBe("max")
|
||||
expect(toastCalls).toContain("Ultrawork Mode Activated")
|
||||
})
|
||||
|
||||
test("should NOT trigger ultrawork on file references containing 'ulw' substring", async () => {
|
||||
// #given - file reference contains 'ulw' as substring
|
||||
// given - file reference contains 'ulw' as substring
|
||||
setMainSession(undefined)
|
||||
|
||||
const toastCalls: string[] = []
|
||||
@@ -327,13 +327,13 @@ describe("keyword-detector word boundary", () => {
|
||||
parts: [{ type: "text", text: "@StatefulWidget.tsx please review this file" }],
|
||||
}
|
||||
|
||||
// #when - message referencing file with 'ulw' substring is processed
|
||||
// when - message referencing file with 'ulw' substring is processed
|
||||
await hook["chat.message"](
|
||||
{ sessionID: "any-session" },
|
||||
output
|
||||
)
|
||||
|
||||
// #then - ultrawork should NOT be triggered
|
||||
// then - ultrawork should NOT be triggered
|
||||
expect(output.message.variant).toBeUndefined()
|
||||
expect(toastCalls).not.toContain("Ultrawork Mode Activated")
|
||||
})
|
||||
@@ -367,7 +367,7 @@ describe("keyword-detector system-reminder filtering", () => {
|
||||
}
|
||||
|
||||
test("should NOT trigger search mode from keywords inside <system-reminder> tags", async () => {
|
||||
// #given - message contains search keywords only inside system-reminder tags
|
||||
// given - message contains search keywords only inside system-reminder tags
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
const sessionID = "test-session"
|
||||
@@ -382,10 +382,10 @@ Please locate and scan the directory.
|
||||
}],
|
||||
}
|
||||
|
||||
// #when - keyword detection runs on system-reminder content
|
||||
// when - keyword detection runs on system-reminder content
|
||||
await hook["chat.message"]({ sessionID }, output)
|
||||
|
||||
// #then - should NOT trigger search mode (text should remain unchanged)
|
||||
// then - should NOT trigger search mode (text should remain unchanged)
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).not.toContain("[search-mode]")
|
||||
@@ -393,7 +393,7 @@ Please locate and scan the directory.
|
||||
})
|
||||
|
||||
test("should NOT trigger analyze mode from keywords inside <system-reminder> tags", async () => {
|
||||
// #given - message contains analyze keywords only inside system-reminder tags
|
||||
// given - message contains analyze keywords only inside system-reminder tags
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
const sessionID = "test-session"
|
||||
@@ -408,10 +408,10 @@ Research the implementation details.
|
||||
}],
|
||||
}
|
||||
|
||||
// #when - keyword detection runs on system-reminder content
|
||||
// when - keyword detection runs on system-reminder content
|
||||
await hook["chat.message"]({ sessionID }, output)
|
||||
|
||||
// #then - should NOT trigger analyze mode
|
||||
// then - should NOT trigger analyze mode
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).not.toContain("[analyze-mode]")
|
||||
@@ -419,7 +419,7 @@ Research the implementation details.
|
||||
})
|
||||
|
||||
test("should detect keywords in user text even when system-reminder is present", async () => {
|
||||
// #given - message contains both system-reminder and user search keyword
|
||||
// given - message contains both system-reminder and user search keyword
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
const sessionID = "test-session"
|
||||
@@ -435,10 +435,10 @@ Please search for the bug in the code.`
|
||||
}],
|
||||
}
|
||||
|
||||
// #when - keyword detection runs on mixed content
|
||||
// when - keyword detection runs on mixed content
|
||||
await hook["chat.message"]({ sessionID }, output)
|
||||
|
||||
// #then - should trigger search mode from user text only
|
||||
// then - should trigger search mode from user text only
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).toContain("[search-mode]")
|
||||
@@ -446,7 +446,7 @@ Please search for the bug in the code.`
|
||||
})
|
||||
|
||||
test("should handle multiple system-reminder tags in message", async () => {
|
||||
// #given - message contains multiple system-reminder blocks with keywords
|
||||
// given - message contains multiple system-reminder blocks with keywords
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
const sessionID = "test-session"
|
||||
@@ -466,10 +466,10 @@ Second reminder with investigate and examine keywords.
|
||||
}],
|
||||
}
|
||||
|
||||
// #when - keyword detection runs on message with multiple system-reminders
|
||||
// when - keyword detection runs on message with multiple system-reminders
|
||||
await hook["chat.message"]({ sessionID }, output)
|
||||
|
||||
// #then - should NOT trigger any mode (only user text exists, no keywords)
|
||||
// then - should NOT trigger any mode (only user text exists, no keywords)
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).not.toContain("[search-mode]")
|
||||
@@ -477,7 +477,7 @@ Second reminder with investigate and examine keywords.
|
||||
})
|
||||
|
||||
test("should handle case-insensitive system-reminder tags", async () => {
|
||||
// #given - message contains system-reminder with different casing
|
||||
// given - message contains system-reminder with different casing
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
const sessionID = "test-session"
|
||||
@@ -491,17 +491,17 @@ System will search and find files.
|
||||
}],
|
||||
}
|
||||
|
||||
// #when - keyword detection runs on uppercase system-reminder
|
||||
// when - keyword detection runs on uppercase system-reminder
|
||||
await hook["chat.message"]({ sessionID }, output)
|
||||
|
||||
// #then - should NOT trigger search mode
|
||||
// then - should NOT trigger search mode
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).not.toContain("[search-mode]")
|
||||
})
|
||||
|
||||
test("should handle multiline system-reminder content with search keywords", async () => {
|
||||
// #given - system-reminder with multiline content containing various search keywords
|
||||
// given - system-reminder with multiline content containing various search keywords
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
const sessionID = "test-session"
|
||||
@@ -520,10 +520,10 @@ Please explore the codebase and discover patterns.
|
||||
}],
|
||||
}
|
||||
|
||||
// #when - keyword detection runs on multiline system-reminder
|
||||
// when - keyword detection runs on multiline system-reminder
|
||||
await hook["chat.message"]({ sessionID }, output)
|
||||
|
||||
// #then - should NOT trigger search mode
|
||||
// then - should NOT trigger search mode
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).not.toContain("[search-mode]")
|
||||
@@ -558,7 +558,7 @@ describe("keyword-detector agent-specific ultrawork messages", () => {
|
||||
}
|
||||
|
||||
test("should skip ultrawork injection when agent is prometheus", async () => {
|
||||
// #given - collector and prometheus agent
|
||||
// given - collector and prometheus agent
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
const sessionID = "prometheus-session"
|
||||
@@ -567,10 +567,10 @@ describe("keyword-detector agent-specific ultrawork messages", () => {
|
||||
parts: [{ type: "text", text: "ultrawork plan this feature" }],
|
||||
}
|
||||
|
||||
// #when - ultrawork keyword detected with prometheus agent
|
||||
// when - ultrawork keyword detected with prometheus agent
|
||||
await hook["chat.message"]({ sessionID, agent: "prometheus" }, output)
|
||||
|
||||
// #then - ultrawork should be skipped for planner agents, text unchanged
|
||||
// then - ultrawork should be skipped for planner agents, text unchanged
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).toBe("ultrawork plan this feature")
|
||||
@@ -579,7 +579,7 @@ describe("keyword-detector agent-specific ultrawork messages", () => {
|
||||
})
|
||||
|
||||
test("should skip ultrawork injection when agent name contains 'planner'", async () => {
|
||||
// #given - collector and agent with 'planner' in name
|
||||
// given - collector and agent with 'planner' in name
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
const sessionID = "planner-session"
|
||||
@@ -588,10 +588,10 @@ describe("keyword-detector agent-specific ultrawork messages", () => {
|
||||
parts: [{ type: "text", text: "ulw create a work plan" }],
|
||||
}
|
||||
|
||||
// #when - ultrawork keyword detected with planner agent
|
||||
// when - ultrawork keyword detected with planner agent
|
||||
await hook["chat.message"]({ sessionID, agent: "Prometheus (Planner)" }, output)
|
||||
|
||||
// #then - ultrawork should be skipped, text unchanged
|
||||
// then - ultrawork should be skipped, text unchanged
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).toBe("ulw create a work plan")
|
||||
@@ -599,7 +599,7 @@ describe("keyword-detector agent-specific ultrawork messages", () => {
|
||||
})
|
||||
|
||||
test("should use normal ultrawork message when agent is Sisyphus", async () => {
|
||||
// #given - collector and Sisyphus agent
|
||||
// given - collector and Sisyphus agent
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
const sessionID = "sisyphus-session"
|
||||
@@ -608,10 +608,10 @@ describe("keyword-detector agent-specific ultrawork messages", () => {
|
||||
parts: [{ type: "text", text: "ultrawork implement this feature" }],
|
||||
}
|
||||
|
||||
// #when - ultrawork keyword detected with Sisyphus agent
|
||||
// when - ultrawork keyword detected with Sisyphus agent
|
||||
await hook["chat.message"]({ sessionID, agent: "sisyphus" }, output)
|
||||
|
||||
// #then - should use normal ultrawork message with agent utilization instructions
|
||||
// then - should use normal ultrawork message with agent utilization instructions
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).toContain("YOU MUST LEVERAGE ALL AVAILABLE AGENTS")
|
||||
@@ -621,7 +621,7 @@ describe("keyword-detector agent-specific ultrawork messages", () => {
|
||||
})
|
||||
|
||||
test("should use normal ultrawork message when agent is undefined", async () => {
|
||||
// #given - collector with no agent specified
|
||||
// given - collector with no agent specified
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
const sessionID = "no-agent-session"
|
||||
@@ -630,10 +630,10 @@ describe("keyword-detector agent-specific ultrawork messages", () => {
|
||||
parts: [{ type: "text", text: "ultrawork do something" }],
|
||||
}
|
||||
|
||||
// #when - ultrawork keyword detected without agent
|
||||
// when - ultrawork keyword detected without agent
|
||||
await hook["chat.message"]({ sessionID }, output)
|
||||
|
||||
// #then - should use normal ultrawork message (default behavior)
|
||||
// then - should use normal ultrawork message (default behavior)
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).toContain("YOU MUST LEVERAGE ALL AVAILABLE AGENTS")
|
||||
@@ -643,7 +643,7 @@ describe("keyword-detector agent-specific ultrawork messages", () => {
|
||||
})
|
||||
|
||||
test("should skip ultrawork for prometheus but inject for sisyphus", async () => {
|
||||
// #given - two sessions, one with prometheus, one with sisyphus
|
||||
// given - two sessions, one with prometheus, one with sisyphus
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
|
||||
@@ -663,7 +663,7 @@ describe("keyword-detector agent-specific ultrawork messages", () => {
|
||||
}
|
||||
await hook["chat.message"]({ sessionID: sisyphusSessionID, agent: "sisyphus" }, sisyphusOutput)
|
||||
|
||||
// #then - prometheus should have no injection, sisyphus should have normal ultrawork
|
||||
// then - prometheus should have no injection, sisyphus should have normal ultrawork
|
||||
const prometheusTextPart = prometheusOutput.parts.find(p => p.type === "text")
|
||||
expect(prometheusTextPart!.text).toBe("ultrawork plan")
|
||||
|
||||
@@ -674,7 +674,7 @@ describe("keyword-detector agent-specific ultrawork messages", () => {
|
||||
})
|
||||
|
||||
test("should use session state agent over stale input.agent (bug fix)", async () => {
|
||||
// #given - same session, agent switched from prometheus to sisyphus in session state
|
||||
// given - same session, agent switched from prometheus to sisyphus in session state
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
const sessionID = "same-session-agent-switch"
|
||||
@@ -687,10 +687,10 @@ describe("keyword-detector agent-specific ultrawork messages", () => {
|
||||
parts: [{ type: "text", text: "ultrawork implement this" }],
|
||||
}
|
||||
|
||||
// #when - hook receives stale input.agent="prometheus" but session state says "Sisyphus"
|
||||
// when - hook receives stale input.agent="prometheus" but session state says "Sisyphus"
|
||||
await hook["chat.message"]({ sessionID, agent: "prometheus" }, output)
|
||||
|
||||
// #then - should use Sisyphus from session state, NOT prometheus from stale input
|
||||
// then - should use Sisyphus from session state, NOT prometheus from stale input
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).toContain("YOU MUST LEVERAGE ALL AVAILABLE AGENTS")
|
||||
@@ -703,7 +703,7 @@ describe("keyword-detector agent-specific ultrawork messages", () => {
|
||||
})
|
||||
|
||||
test("should fall back to input.agent when session state is empty and skip ultrawork for prometheus", async () => {
|
||||
// #given - no session state, only input.agent available
|
||||
// given - no session state, only input.agent available
|
||||
const collector = new ContextCollector()
|
||||
const hook = createKeywordDetectorHook(createMockPluginInput(), collector)
|
||||
const sessionID = "no-session-state"
|
||||
@@ -716,10 +716,10 @@ describe("keyword-detector agent-specific ultrawork messages", () => {
|
||||
parts: [{ type: "text", text: "ultrawork plan this" }],
|
||||
}
|
||||
|
||||
// #when - hook receives input.agent="prometheus" with no session state
|
||||
// when - hook receives input.agent="prometheus" with no session state
|
||||
await hook["chat.message"]({ sessionID, agent: "prometheus" }, output)
|
||||
|
||||
// #then - prometheus fallback from input.agent, ultrawork skipped
|
||||
// then - prometheus fallback from input.agent, ultrawork skipped
|
||||
const textPart = output.parts.find(p => p.type === "text")
|
||||
expect(textPart).toBeDefined()
|
||||
expect(textPart!.text).toBe("ultrawork plan this")
|
||||
|
||||
Reference in New Issue
Block a user