uira-orchestration 0.1.1

Agent definitions, SDK, tool registry, and hook implementations for Uira
Documentation
use regex::Regex;
use uira_core::HookOutput;

pub struct KeywordPattern {
    pub name: &'static str,
    regex: Regex,
    message_fn: fn(Option<&str>) -> String,
}

impl KeywordPattern {
    pub fn new(name: &'static str, pattern: &str, message_fn: fn(Option<&str>) -> String) -> Self {
        Self {
            name,
            regex: Regex::new(pattern).expect("Invalid regex pattern"),
            message_fn,
        }
    }

    pub fn matches(&self, text: &str) -> bool {
        self.regex.is_match(text)
    }

    pub fn get_message(&self, agent: Option<&str>) -> String {
        (self.message_fn)(agent)
    }
}

pub struct KeywordDetector {
    patterns: Vec<KeywordPattern>,
}

impl Default for KeywordDetector {
    fn default() -> Self {
        Self::new()
    }
}

impl KeywordDetector {
    pub fn new() -> Self {
        Self {
            patterns: vec![
                KeywordPattern::new(
                    "ralph",
                    r"(?i)\b(ralph|don't stop|must complete|until done)\b",
                    ralph_message,
                ),
                KeywordPattern::new("ultrawork", r"(?i)\b(ultrawork|ulw)\b", ultrawork_message),
                KeywordPattern::new(
                    "search",
                    r"(?i)\b(search|find|locate|lookup|explore|discover|scan|grep|query)\b|where\s+is|show\s+me|list\s+all",
                    search_message,
                ),
                KeywordPattern::new(
                    "analyze",
                    r"(?i)\b(analyze|analyse|investigate|examine|research|study|deep[\s-]?dive|inspect|audit|debug)\b|why\s+is|how\s+does|how\s+to",
                    analyze_message,
                ),
            ],
        }
    }

    pub fn with_pattern(mut self, pattern: KeywordPattern) -> Self {
        self.patterns.push(pattern);
        self
    }

    pub fn detect(&self, prompt: &str, agent: Option<&str>) -> Option<HookOutput> {
        let clean_prompt = remove_code_blocks(prompt);

        for pattern in &self.patterns {
            if pattern.matches(&clean_prompt) {
                return Some(HookOutput::with_message(&pattern.get_message(agent)));
            }
        }
        None
    }

    pub fn detect_all(&self, prompt: &str, agent: Option<&str>) -> Vec<(&'static str, String)> {
        let clean_prompt = remove_code_blocks(prompt);
        let mut results = Vec::new();

        for pattern in &self.patterns {
            if pattern.matches(&clean_prompt) {
                results.push((pattern.name, pattern.get_message(agent)));
            }
        }
        results
    }
}

fn remove_code_blocks(text: &str) -> String {
    let code_block_re = Regex::new(r"```[\s\S]*?```").unwrap();
    let inline_code_re = Regex::new(r"`[^`]+`").unwrap();

    let without_blocks = code_block_re.replace_all(text, "");
    inline_code_re.replace_all(&without_blocks, "").to_string()
}

fn is_planner_agent(agent: Option<&str>) -> bool {
    agent
        .map(|a| {
            let lower = a.to_lowercase();
            lower.contains("prometheus") || lower.contains("planner") || lower == "plan"
        })
        .unwrap_or(false)
}

fn ultrawork_message(agent: Option<&str>) -> String {
    if is_planner_agent(agent) {
        return ULTRAWORK_PLANNER_MESSAGE.to_string();
    }
    ULTRAWORK_MESSAGE.to_string()
}

fn search_message(_agent: Option<&str>) -> String {
    SEARCH_MODE_MESSAGE.to_string()
}

fn analyze_message(_agent: Option<&str>) -> String {
    ANALYZE_MODE_MESSAGE.to_string()
}

fn ralph_message(_agent: Option<&str>) -> String {
    RALPH_MODE_MESSAGE.to_string()
}

const ULTRAWORK_MESSAGE: &str = r#"<ultrawork-mode>

**MANDATORY**: You MUST say "ULTRAWORK MODE ENABLED!" to the user as your first response when this mode activates. This is non-negotiable.

[CODE RED] Maximum precision required. Ultrathink before acting.

YOU MUST LEVERAGE ALL AVAILABLE AGENTS TO THEIR FULLEST POTENTIAL.
TELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW TO SATISFY USER'S REQUEST.

## AGENT UTILIZATION PRINCIPLES
- **Codebase Exploration**: Spawn exploration agents using BACKGROUND TASKS
- **Documentation & References**: Use librarian agents via BACKGROUND TASKS
- **Planning & Strategy**: NEVER plan yourself - spawn planning agent
- **High-IQ Reasoning**: Use architect for architecture decisions
- **Frontend/UI Tasks**: Delegate to designer

## EXECUTION RULES
- **TODO**: Track EVERY step. Mark complete IMMEDIATELY.
- **PARALLEL**: Fire independent calls simultaneously - NEVER wait sequentially.
- **BACKGROUND FIRST**: Use delegate_task with runInBackground=true for exploration.
- **VERIFY**: Check ALL requirements met before done.
- **DELEGATE**: Orchestrate specialized agents.

## ZERO TOLERANCE
- NO Scope Reduction - deliver FULL implementation
- NO Partial Completion - finish 100%
- NO Premature Stopping - ALL TODOs must be complete
- NO TEST DELETION - fix code, not tests

THE USER ASKED FOR X. DELIVER EXACTLY X.

</ultrawork-mode>

---

"#;

const ULTRAWORK_PLANNER_MESSAGE: &str = r#"<ultrawork-mode>

**MANDATORY**: You MUST say "ULTRAWORK MODE ENABLED!" to the user as your first response when this mode activates. This is non-negotiable.

## CRITICAL: YOU ARE A PLANNER, NOT AN IMPLEMENTER

**IDENTITY CONSTRAINT (NON-NEGOTIABLE):**
You ARE the planner. You ARE NOT an implementer. You DO NOT write code. You DO NOT execute tasks.

**TOOL RESTRICTIONS (SYSTEM-ENFORCED):**
| Tool | Allowed | Blocked |
|------|---------|---------|
| Write/Edit | `.uira/**/*.md` ONLY | Everything else |
| Read | All files | - |
| Bash | Research commands only | Implementation commands |
| Task | explore, librarian | - |

**WHEN USER ASKS YOU TO IMPLEMENT:**
REFUSE. Say: "I'm a planner. I create work plans, not implementations. The executor agents will implement after planning."

## CONTEXT GATHERING (MANDATORY BEFORE PLANNING)

**Before drafting ANY plan, gather context via explore/librarian agents.**

### Research Protocol
1. **Fire parallel background agents** for comprehensive context
2. **Wait for results** before planning - rushed plans fail
3. **Synthesize findings** into informed requirements

**NEVER plan blind. Context first, plan second.**

</ultrawork-mode>

---

"#;

const SEARCH_MODE_MESSAGE: &str = r#"<search-mode>
MAXIMIZE SEARCH EFFORT. Launch multiple background agents IN PARALLEL:
- explore agents (codebase patterns, file structures)
- librarian agents (remote repos, official docs, GitHub examples)
Plus direct tools: Grep, Glob, LSP
NEVER stop at first result - be exhaustive.
</search-mode>

---

"#;

const RALPH_MODE_MESSAGE: &str = r#"<ralph-mode>

[RALPH MODE ACTIVATED]

You are in RALPH mode - a self-referential work loop that continues until VERIFIED completion.

## CRITICAL RULES

1. **NEVER STOP** until the task is truly complete
2. **TRACK PROGRESS** using todo list - mark items complete as you go
3. **SIGNAL COMPLETION** with: <promise>TASK COMPLETE</promise>

## COMPLETION PROTOCOL

When you believe the task is done:
1. Verify all requirements are met
2. Ensure all tests pass (if applicable)
3. Check all todos are complete
4. Output: <promise>TASK COMPLETE</promise>

The system will verify your completion claim against configured goals.
If verification fails, you will be asked to continue.

## STATUS BLOCK (Optional)

You can output a status block to track progress:

---RALPH_STATUS---
STATUS: IN_PROGRESS | COMPLETE | BLOCKED
TASKS_COMPLETED_THIS_LOOP: <number>
FILES_MODIFIED: <number>
TESTS_STATUS: PASSING | FAILING | NOT_RUN
WORK_TYPE: IMPLEMENTATION | TESTING | DOCUMENTATION | REFACTORING | DEBUGGING
EXIT_SIGNAL: false | true
---END_RALPH_STATUS---

</ralph-mode>

---

"#;

const ANALYZE_MODE_MESSAGE: &str = r#"<analyze-mode>
ANALYSIS MODE. Gather context before diving deep:

CONTEXT GATHERING (parallel):
- 1-2 explore agents (codebase patterns, implementations)
- 1-2 librarian agents (if external library involved)
- Direct tools: Grep, Glob, LSP for targeted searches

IF COMPLEX (architecture, multi-system, debugging after 2+ failures):
- Consult architect agent for strategic guidance

SYNTHESIZE findings before proceeding.
</analyze-mode>

---

"#;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_detect_ralph() {
        let detector = KeywordDetector::new();

        let result = detector.detect("ralph: do something", None);
        assert!(result.is_some());
        let msg = result.unwrap().message.unwrap();
        assert!(msg.contains("ralph-mode"));

        let result = detector.detect("don't stop until done", None);
        assert!(result.is_some());

        let result = detector.detect("must complete this task", None);
        assert!(result.is_some());
    }

    #[test]
    fn test_detect_ultrawork() {
        let detector = KeywordDetector::new();

        let result = detector.detect("ultrawork: do something", None);
        assert!(result.is_some());
        let msg = result.unwrap().message.unwrap();
        assert!(msg.contains("ULTRAWORK MODE ENABLED"));

        let result = detector.detect("ulw do this", None);
        assert!(result.is_some());
    }

    #[test]
    fn test_detect_search() {
        let detector = KeywordDetector::new();

        let result = detector.detect("search for files", None);
        assert!(result.is_some());
        let msg = result.unwrap().message.unwrap();
        assert!(msg.contains("search-mode"));

        let result = detector.detect("find the bug", None);
        assert!(result.is_some());
    }

    #[test]
    fn test_detect_analyze() {
        let detector = KeywordDetector::new();

        let result = detector.detect("analyze this code", None);
        assert!(result.is_some());
        let msg = result.unwrap().message.unwrap();
        assert!(msg.contains("analyze-mode"));
    }

    #[test]
    fn test_no_detection_in_code_blocks() {
        let detector = KeywordDetector::new();

        let result = detector.detect("Here's an example:\n```\nultrawork\n```", None);
        assert!(result.is_none());

        let result = detector.detect("Use `ultrawork` command", None);
        assert!(result.is_none());
    }

    #[test]
    fn test_planner_agent_message() {
        let detector = KeywordDetector::new();

        let result = detector.detect("ultrawork: plan this", Some("prometheus"));
        assert!(result.is_some());
        let msg = result.unwrap().message.unwrap();
        assert!(msg.contains("YOU ARE A PLANNER"));
    }

    #[test]
    fn test_priority_order() {
        let detector = KeywordDetector::new();

        let result = detector.detect("ultrawork search for files", None);
        assert!(result.is_some());
        let msg = result.unwrap().message.unwrap();
        assert!(msg.contains("ultrawork-mode"));
    }
}