fix: numeric skill names, ultrawork missing run_in_background, ZWSP agent lookups

- #3354: Coerce data.name to String in loadSkillFromPath/loadSkillFromPathAsync
  to prevent crash when YAML parses numeric skill names (e.g., name: 12306)

- #3416: Add required run_in_background parameter to all task() examples in
  ultrawork prompts (default, gpt, gemini, planner) to match tool schema

- #3379/#3417/#3418/#3337/#3335: Strip ZWSP (U+200B) before agent name
  comparisons in agent-tool-restrictions, sync-prompt-sender, tool-execute-after,
  tool-execute-before, oracle-verification-detector, call-omo-agent,
  recovery-prompt-config, and agent-variant to prevent ZWSP-prefixed display
  names from breaking exact-match lookups
This commit is contained in:
YeonGyu-Kim
2026-04-15 10:46:41 +09:00
parent 54a94d4169
commit 62c60ae9d8
14 changed files with 61 additions and 48 deletions
@@ -1,3 +1,4 @@
import { stripInvisibleAgentCharacters } from "../../shared/agent-display-names"
import type { CompactionAgentConfigCheckpoint } from "../../shared/compaction-agent-config-checkpoint"
export type RecoveryPromptConfig = CompactionAgentConfigCheckpoint & {
@@ -66,7 +67,7 @@ export function isPromptConfigRecovered(
const agentMatches =
typeof actualAgent === "string" &&
!isCompactionAgent(actualAgent) &&
actualAgent.toLowerCase() === expectedPromptConfig.agent.toLowerCase()
stripInvisibleAgentCharacters(actualAgent).toLowerCase() === stripInvisibleAgentCharacters(expectedPromptConfig.agent).toLowerCase()
return (
agentMatches &&
+13 -13
View File
@@ -104,7 +104,7 @@ TELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW TO SATISFY USER'S REQUEST.
| Architecture decision needed | MUST call plan agent |
\`\`\`
task(subagent_type="plan", load_skills=[], prompt="<gathered context + user request>")
task(subagent_type="plan", load_skills=[], run_in_background=false, prompt="<gathered context + user request>")
\`\`\`
**WHY PLAN AGENT IS MANDATORY:**
@@ -119,9 +119,9 @@ task(subagent_type="plan", load_skills=[], prompt="<gathered context + user requ
| Scenario | Action |
|----------|--------|
| Plan agent asks clarifying questions | \`task(session_id="{returned_session_id}", load_skills=[], prompt="<your answer>")\` |
| Need to refine the plan | \`task(session_id="{returned_session_id}", load_skills=[], prompt="Please adjust: <feedback>")\` |
| Plan needs more detail | \`task(session_id="{returned_session_id}", load_skills=[], prompt="Add more detail to Task N")\` |
| Plan agent asks clarifying questions | \`task(session_id="{returned_session_id}", load_skills=[], run_in_background=false, prompt="<your answer>")\` |
| Need to refine the plan | \`task(session_id="{returned_session_id}", load_skills=[], run_in_background=false, prompt="Please adjust: <feedback>")\` |
| Plan needs more detail | \`task(session_id="{returned_session_id}", load_skills=[], run_in_background=false, prompt="Add more detail to Task N")\` |
**WHY SESSION_ID IS CRITICAL:**
- Plan agent retains FULL conversation context
@@ -131,10 +131,10 @@ task(subagent_type="plan", load_skills=[], prompt="<gathered context + user requ
\`\`\`
// WRONG: Starting fresh loses all context
task(subagent_type="plan", load_skills=[], prompt="Here's more info...")
task(subagent_type="plan", load_skills=[], run_in_background=false, prompt="Here's more info...")
// CORRECT: Resume preserves everything
task(session_id="ses_abc123", load_skills=[], prompt="Here's my answer to your question: ...")
task(session_id="ses_abc123", load_skills=[], run_in_background=false, prompt="Here's my answer to your question: ...")
\`\`\`
**FAILURE TO CALL PLAN AGENT = INCOMPLETE WORK.**
@@ -149,21 +149,21 @@ task(session_id="ses_abc123", load_skills=[], prompt="Here's my answer to your q
|-----------|--------|-----|
| Codebase exploration | task(subagent_type="explore", load_skills=[], run_in_background=true) | Parallel, context-efficient |
| Documentation lookup | task(subagent_type="librarian", load_skills=[], run_in_background=true) | Specialized knowledge |
| Planning | task(subagent_type="plan", load_skills=[]) | Parallel task graph + structured TODO list |
| Hard problem (conventional) | task(subagent_type="oracle", load_skills=[]) | Architecture, debugging, complex logic |
| Hard problem (non-conventional) | task(category="artistry", load_skills=[...]) | Different approach needed |
| Implementation | task(category="...", load_skills=[...]) | Domain-optimized models |
| Planning | task(subagent_type="plan", load_skills=[], run_in_background=false) | Parallel task graph + structured TODO list |
| Hard problem (conventional) | task(subagent_type="oracle", load_skills=[], run_in_background=false) | Architecture, debugging, complex logic |
| Hard problem (non-conventional) | task(category="artistry", load_skills=[...], run_in_background=true) | Different approach needed |
| Implementation | task(category="...", load_skills=[...], run_in_background=true) | Domain-optimized models |
**CATEGORY + SKILL DELEGATION:**
\`\`\`
// Frontend work
task(category="visual-engineering", load_skills=["frontend-ui-ux"])
task(category="visual-engineering", load_skills=["frontend-ui-ux"], run_in_background=true)
// Complex logic
task(category="ultrabrain", load_skills=["typescript-programmer"])
task(category="ultrabrain", load_skills=["typescript-programmer"], run_in_background=true)
// Quick fixes
task(category="quick", load_skills=["git-master"])
task(category="quick", load_skills=["git-master"], run_in_background=true)
\`\`\`
**YOU SHOULD ONLY DO IT YOURSELF WHEN:**
@@ -156,7 +156,7 @@ TELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW TO SATISFY USER'S REQUEST.
| Architecture decision needed | MUST call plan agent |
\`\`\`
task(subagent_type="plan", load_skills=[], prompt="<gathered context + user request>")
task(subagent_type="plan", load_skills=[], run_in_background=false, prompt="<gathered context + user request>")
\`\`\`
### SESSION CONTINUITY WITH PLAN AGENT (CRITICAL)
@@ -165,9 +165,9 @@ task(subagent_type="plan", load_skills=[], prompt="<gathered context + user requ
| Scenario | Action |
|----------|--------|
| Plan agent asks clarifying questions | \`task(session_id="{returned_session_id}", load_skills=[], prompt="<your answer>")\` |
| Need to refine the plan | \`task(session_id="{returned_session_id}", load_skills=[], prompt="Please adjust: <feedback>")\` |
| Plan needs more detail | \`task(session_id="{returned_session_id}", load_skills=[], prompt="Add more detail to Task N")\` |
| Plan agent asks clarifying questions | \`task(session_id="{returned_session_id}", load_skills=[], run_in_background=false, prompt="<your answer>")\` |
| Need to refine the plan | \`task(session_id="{returned_session_id}", load_skills=[], run_in_background=false, prompt="Please adjust: <feedback>")\` |
| Plan needs more detail | \`task(session_id="{returned_session_id}", load_skills=[], run_in_background=false, prompt="Add more detail to Task N")\` |
**FAILURE TO CALL PLAN AGENT = INCOMPLETE WORK.**
@@ -183,10 +183,10 @@ task(subagent_type="plan", load_skills=[], prompt="<gathered context + user requ
|-----------|--------|-----|
| Codebase exploration | task(subagent_type="explore", load_skills=[], run_in_background=true) | Parallel, context-efficient |
| Documentation lookup | task(subagent_type="librarian", load_skills=[], run_in_background=true) | Specialized knowledge |
| Planning | task(subagent_type="plan", load_skills=[]) | Parallel task graph + structured TODO list |
| Hard problem (conventional) | task(subagent_type="oracle", load_skills=[]) | Architecture, debugging, complex logic |
| Hard problem (non-conventional) | task(category="artistry", load_skills=[...]) | Different approach needed |
| Implementation | task(category="...", load_skills=[...]) | Domain-optimized models |
| Planning | task(subagent_type="plan", load_skills=[], run_in_background=false) | Parallel task graph + structured TODO list |
| Hard problem (conventional) | task(subagent_type="oracle", load_skills=[], run_in_background=false) | Architecture, debugging, complex logic |
| Hard problem (non-conventional) | task(category="artistry", load_skills=[...], run_in_background=true) | Different approach needed |
| Implementation | task(category="...", load_skills=[...], run_in_background=true) | Domain-optimized models |
**YOU SHOULD ONLY DO IT YOURSELF WHEN:**
- Task is trivially simple (1-2 lines, obvious change)
+3 -3
View File
@@ -71,9 +71,9 @@ Use these when they provide clear value based on the decision framework above:
|----------|-------------|------------|
| explore agent | Need codebase patterns you don't have | \`task(subagent_type="explore", load_skills=[], run_in_background=true, ...)\` |
| librarian agent | External library docs, OSS examples | \`task(subagent_type="librarian", load_skills=[], run_in_background=true, ...)\` |
| oracle agent | Stuck on architecture/debugging after 2+ attempts | \`task(subagent_type="oracle", load_skills=[], ...)\` |
| plan agent | Complex multi-step with dependencies (5+ steps) | \`task(subagent_type="plan", load_skills=[], ...)\` |
| task category | Specialized work matching a category | \`task(category="...", load_skills=[...])\` |
| oracle agent | Stuck on architecture/debugging after 2+ attempts | \`task(subagent_type="oracle", load_skills=[], run_in_background=false, ...)\` |
| plan agent | Complex multi-step with dependencies (5+ steps) | \`task(subagent_type="plan", load_skills=[], run_in_background=false, ...)\` |
| task category | Specialized work matching a category | \`task(category="...", load_skills=[...], run_in_background=true)\` |
<tool_usage_rules>
- Prefer tools over internal knowledge for fresh or user-specific data
@@ -117,7 +117,7 @@ Each TODO item MUST include:
| Wave | Tasks | Dispatch Command |
|------|-------|------------------|
| 1 | 1, 4 | \`task(category="...", load_skills=[...], run_in_background=false)\` × 2 |
| 1 | 1, 4 | \`task(category="...", load_skills=[...], run_in_background=true)\` × 2 |
| 2 | 2, 3, 5 | \`task(...)\` × 3 after Wave 1 completes |
| 3 | 6 | \`task(...)\` final integration |
@@ -1,3 +1,4 @@
import { stripInvisibleAgentCharacters } from "../../shared/agent-display-names"
import { ULTRAWORK_VERIFICATION_PROMISE } from "./constants"
export interface OracleVerificationEvidence {
@@ -54,7 +55,7 @@ export function isOracleVerified(text: string): boolean {
return false
}
const isOracleAgent = evidence.agent.toLowerCase() === "oracle"
const isOracleAgent = stripInvisibleAgentCharacters(evidence.agent).toLowerCase() === "oracle"
const isVerifiedPromise = evidence.promise === ULTRAWORK_VERIFICATION_PROMISE
return isOracleAgent && isVerifiedPromise
@@ -62,7 +63,7 @@ export function isOracleVerified(text: string): boolean {
export function extractOracleSessionID(text: string): string | undefined {
const evidence = parseOracleVerificationEvidence(text)
if (!evidence || evidence.agent.toLowerCase() !== "oracle") {
if (!evidence || stripInvisibleAgentCharacters(evidence.agent).toLowerCase() !== "oracle") {
return undefined
}