* refactor(keyword-detector): split constants into domain-specific modules * feat(shared): add requiresAnyModel and isAnyFallbackModelAvailable * feat(config): add hephaestus to agent schemas * feat(agents): add Hephaestus autonomous deep worker * feat(cli): update model-fallback for hephaestus support * feat(plugin): add hephaestus to config handler with ordering * test(delegate-task): update tests for hephaestus agent * docs: update AGENTS.md files for hephaestus * docs: add hephaestus to READMEs * chore: regenerate config schema * fix(delegate-task): bypass requiresModel check when user provides explicit config * docs(hephaestus): add 4-part context structure for explore/librarian prompts * docs: fix review comments from cubic (non-breaking changes) - Move Hephaestus from Primary Agents to Subagents (uses own fallback chain) - Fix Hephaestus fallback chain documentation (claude-opus-4-5 → gemini-3-pro) - Add settings.local.json to claude-code-hooks config sources - Fix delegate_task parameters in ultrawork prompt (agent→subagent_type, background→run_in_background, add load_skills) - Update line counts in AGENTS.md (index.ts: 788, manager.ts: 1440) * docs: fix additional documentation inconsistencies from oracle review - Fix delegate_task parameters in Background Agents example (docs/features.md) - Fix Hephaestus fallback chain in root AGENTS.md to match model-requirements.ts * docs: clarify Hephaestus has no fallback (requires gpt-5.2-codex only) Hephaestus uses requiresModel constraint - it only activates when gpt-5.2-codex is available. The fallback chain in code is unreachable, so documentation should not mention fallbacks. * fix(hephaestus): remove unreachable fallback chain entries Hephaestus has requiresModel: gpt-5.2-codex which means the agent only activates when that specific model is available. The fallback entries (claude-opus-4-5, gemini-3-pro) were unreachable and misleading. --------- Co-authored-by: justsisyphus <justsisyphus@users.noreply.github.com>
54 lines
1.7 KiB
TypeScript
54 lines
1.7 KiB
TypeScript
import {
|
|
KEYWORD_DETECTORS,
|
|
CODE_BLOCK_PATTERN,
|
|
INLINE_CODE_PATTERN,
|
|
} from "./constants"
|
|
|
|
export interface DetectedKeyword {
|
|
type: "ultrawork" | "search" | "analyze"
|
|
message: string
|
|
}
|
|
|
|
export function removeCodeBlocks(text: string): string {
|
|
return text.replace(CODE_BLOCK_PATTERN, "").replace(INLINE_CODE_PATTERN, "")
|
|
}
|
|
|
|
/**
|
|
* Resolves message to string, handling both static strings and dynamic functions.
|
|
*/
|
|
function resolveMessage(
|
|
message: string | ((agentName?: string, modelID?: string) => string),
|
|
agentName?: string,
|
|
modelID?: string
|
|
): string {
|
|
return typeof message === "function" ? message(agentName, modelID) : message
|
|
}
|
|
|
|
export function detectKeywords(text: string, agentName?: string, modelID?: string): string[] {
|
|
const textWithoutCode = removeCodeBlocks(text)
|
|
return KEYWORD_DETECTORS.filter(({ pattern }) =>
|
|
pattern.test(textWithoutCode)
|
|
).map(({ message }) => resolveMessage(message, agentName, modelID))
|
|
}
|
|
|
|
export function detectKeywordsWithType(text: string, agentName?: string, modelID?: string): DetectedKeyword[] {
|
|
const textWithoutCode = removeCodeBlocks(text)
|
|
const types: Array<"ultrawork" | "search" | "analyze"> = ["ultrawork", "search", "analyze"]
|
|
return KEYWORD_DETECTORS.map(({ pattern, message }, index) => ({
|
|
matches: pattern.test(textWithoutCode),
|
|
type: types[index],
|
|
message: resolveMessage(message, agentName, modelID),
|
|
}))
|
|
.filter((result) => result.matches)
|
|
.map(({ type, message }) => ({ type, message }))
|
|
}
|
|
|
|
export function extractPromptText(
|
|
parts: Array<{ type: string; text?: string }>
|
|
): string {
|
|
return parts
|
|
.filter((p) => p.type === "text")
|
|
.map((p) => p.text || "")
|
|
.join(" ")
|
|
}
|