Skip to content

Commit 4d13453

Browse files
authored
Merge pull request #113 from MLAI-AUS-Inc/codex/domain-scan-routing-fix
Codex/domain scan routing fix
2 parents 1030213 + ecfa1dd commit 4d13453

File tree

15 files changed

+2124
-1122
lines changed

15 files changed

+2124
-1122
lines changed

roo-standalone/roo/agent.py

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from pathlib import Path
1111

1212
from .config import get_settings
13+
from .content_intent import extract_domain, normalize_slack_text, parse_routing_intent
1314
from .llm import chat
1415
from .skills.loader import Skill, load_skills
1516
from .skills.executor import SkillExecutor
@@ -70,6 +71,8 @@ async def handle_mention(
7071
"""
7172
# Clean the message
7273
clean_text = self._clean_mention(text)
74+
thread_context = self._get_thread_context(channel_id, thread_ts)
75+
routing_intent = self._get_routing_intent(clean_text, thread_context)
7376

7477
print(f"🔍 Processing: {clean_text[:100]}...")
7578

@@ -93,19 +96,30 @@ async def handle_mention(
9396
return fast_result
9497

9598
# 2. Select appropriate skill (LLM Routing)
96-
skill = await self._select_skill(clean_text, thread_history, channel_id, thread_ts)
99+
skill = routing_intent["skill"] if routing_intent else await self._select_skill(
100+
clean_text,
101+
thread_history,
102+
channel_id,
103+
thread_ts,
104+
)
97105

98106
if skill:
99107
print(f"🎯 Selected skill: {skill.name}")
100108
self._remember_selected_skill(skill.name, channel_id, thread_ts, clean_text)
109+
effective_param_overrides = dict(param_overrides or {})
110+
if routing_intent and skill.name == routing_intent["skill"].name:
111+
effective_param_overrides = {
112+
**routing_intent.get("params", {}),
113+
**effective_param_overrides,
114+
}
101115
result = await self.skill_executor.execute(
102116
skill=skill,
103117
text=clean_text,
104118
user_id=user_id,
105119
channel_id=channel_id,
106120
thread_ts=thread_ts,
107121
thread_history=thread_history,
108-
param_overrides=param_overrides,
122+
param_overrides=effective_param_overrides or None,
109123
**kwargs
110124
)
111125
return {
@@ -202,8 +216,29 @@ def _get_skill_by_name(self, skill_name: str) -> Optional[Skill]:
202216
return next((skill for skill in self.skills if skill.name == skill_name), None)
203217

204218
def _extract_domain(self, text: str) -> Optional[str]:
205-
match = re.search(r'\b(?:https?://)?([a-z0-9][a-z0-9.-]+\.[a-z]{2,})\b', text.lower())
206-
return match.group(1) if match else None
219+
return extract_domain(text)
220+
221+
def _get_routing_intent(
222+
self,
223+
text: str,
224+
thread_context: Optional[Dict[str, Any]] = None,
225+
) -> Optional[Dict[str, Any]]:
226+
route = parse_routing_intent(
227+
text,
228+
thread_skill_name=(thread_context or {}).get("skill_name"),
229+
thread_domain=(thread_context or {}).get("domain"),
230+
)
231+
if not route:
232+
return None
233+
234+
skill = self._get_skill_by_name(route["skill_name"])
235+
if not skill:
236+
return None
237+
238+
return {
239+
"skill": skill,
240+
"params": dict(route.get("params") or {}),
241+
}
207242

208243
def _looks_like_content_request(self, text: str) -> bool:
209244
patterns = (
@@ -259,6 +294,10 @@ def _select_skill_from_triggers(
259294
text: str,
260295
thread_context: Optional[Dict[str, Any]] = None,
261296
) -> Optional[Skill]:
297+
routing_intent = self._get_routing_intent(text, thread_context)
298+
if routing_intent:
299+
return routing_intent["skill"]
300+
262301
text_lower = text.lower().strip()
263302
content_skill = self._get_skill_by_name("content-factory")
264303

@@ -451,6 +490,7 @@ def _clean_mention(self, text: str) -> str:
451490
# Fallback: remove first mention if we can't get bot ID
452491
cleaned = re.sub(r'<@[A-Z0-9]+>', '', text, count=1)
453492

493+
cleaned = normalize_slack_text(cleaned)
454494
# Remove extra whitespace
455495
cleaned = ' '.join(cleaned.split())
456496
return cleaned.strip()
@@ -467,6 +507,10 @@ async def _select_skill(
467507
return None
468508

469509
thread_context = self._get_thread_context(channel_id, thread_ts)
510+
routing_intent = self._get_routing_intent(text, thread_context)
511+
if routing_intent:
512+
return routing_intent["skill"]
513+
470514
trigger_skill = self._select_skill_from_triggers(text, thread_context)
471515
if trigger_skill:
472516
return trigger_skill
@@ -496,7 +540,8 @@ async def _select_skill(
496540
# Format history for context
497541
history_context = ""
498542
if history:
499-
history_str = "\n".join([f"{msg.get('user')}: {msg.get('text')}" for msg in history[:-1]]) # Skip last as it's the current request usually
543+
trimmed_history = history[:-1][-4:]
544+
history_str = "\n".join([f"{msg.get('user')}: {msg.get('text')}" for msg in trimmed_history]) # Skip last as it's the current request usually
500545
history_context = f"Conversation History:\n{history_str}\n"
501546

502547
thread_context_hint = ""
@@ -508,7 +553,7 @@ async def _select_skill(
508553
f"- workflow: {thread_context.get('workflow') or 'unknown'}\n"
509554
)
510555

511-
prompt = f"""You are a skill router. Given the user's message and conversation context, decide which skill to use.
556+
prompt = f"""Choose the best skill for the user's message.
512557
513558
Available skills:
514559
{skill_descriptions}
@@ -518,10 +563,16 @@ async def _select_skill(
518563
{thread_context_hint}
519564
User message: "{text}"
520565
521-
Prefer content-factory for requests about writing, researching, or planning articles, blog posts, SEO topics, keywords, or content for a domain.
566+
Routing rules:
567+
- Prefer content-factory for domain-backed repo scans, article/blog writing, SEO research, content planning, scaffolding blog/article pages, and requests like "scan the domain mlai.au" or "scan the repo for the domain mlai.au".
568+
- Prefer github-integration for GitHub auth, reconnecting GitHub, or account/integration management.
569+
- Prefer mlai-points for points, rewards, coworking, and task management.
522570
523571
Examples:
524572
- "please research the best article for me to write" -> content-factory
573+
- "scan the repo for the domain woofya.com.au" -> content-factory
574+
- "scan the domain woofya.com.au" -> content-factory
575+
- "reconnect github for woofya.com.au" -> github-integration
525576
- "write me an article about how to build an ai agent harness for long-running specific tasks" -> content-factory
526577
- "create a task called fix docs worth 5 points" -> mlai-points
527578
@@ -532,7 +583,7 @@ async def _select_skill(
532583
response = await chat([
533584
{"role": "system", "content": "You are a skill router. Respond with only the skill name."},
534585
{"role": "user", "content": prompt}
535-
], model=settings.ROUTER_MODEL, max_tokens=32, reasoning_effort="low")
586+
], model=settings.ROUTER_MODEL, max_tokens=96, reasoning_effort="low")
536587

537588
skill_name = response.content.strip().lower()
538589
# Normalize: both underscores and hyphens should match

0 commit comments

Comments
 (0)