Skip to content

Commit e26479b

Browse files
committed
Organize Codex intelligent routing modules
1 parent d5e3f62 commit e26479b

7 files changed

Lines changed: 163 additions & 149 deletions

File tree

src/ucode/agents/codex.py

Lines changed: 7 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
import os
66
import re
7-
import shlex
8-
import subprocess
97
from pathlib import Path
108

119
from ucode.agent_updates import available_npm_package_update
@@ -22,6 +20,10 @@
2220
build_tool_base_url,
2321
get_databricks_token,
2422
)
23+
from ucode.intelligent_routing.codex_hooks import (
24+
remove_intelligent_routing_hooks,
25+
sync_intelligent_routing_hooks,
26+
)
2527
from ucode.launcher import exec_or_spawn
2628
from ucode.state import mark_tool_managed, save_state
2729
from ucode.telemetry import agent_version, ucode_version
@@ -38,7 +40,6 @@
3840
MINIMUM_ROUTING_CODEX_VERSION = (0, 145, 0)
3941
MINIMUM_ROUTING_CODEX_VERSION_TEXT = "0.145.0"
4042
INTELLIGENT_ROUTING_STATE_KEY = "codex_intelligent_routing_enabled"
41-
ROUTING_HOOK_COMMAND_MARKER = "codex-router-hook"
4243

4344

4445
SPEC: ToolSpec = {
@@ -369,7 +370,7 @@ def write_tool_config(state: dict, model: str | None = None, provider: str | Non
369370
# deep_merge can't drop keys, so clear a `model` pinned by an earlier
370371
# non-provider run that the provider overlay omits.
371372
doc.pop("model", None)
372-
_sync_intelligent_routing_hooks(
373+
sync_intelligent_routing_hooks(
373374
doc,
374375
state,
375376
enabled=intelligent_routing_enabled(state) and provider is None,
@@ -443,153 +444,15 @@ def disable_intelligent_routing(state: dict) -> bool:
443444
if not path.exists():
444445
continue
445446
doc = read_toml_safe(path)
446-
if _remove_intelligent_routing_hooks(doc):
447+
if remove_intelligent_routing_hooks(doc):
447448
write_toml_file(path, doc)
448449
changed = True
449-
from ucode.codex_routing import clear_routing_artifacts
450+
from ucode.intelligent_routing.codex_routing import clear_routing_artifacts
450451

451452
clear_routing_artifacts()
452453
return changed
453454

454455

455-
def route_launch_model(state: dict, tool_args: list[str]):
456-
"""Route a root Codex launch before the Codex process starts."""
457-
from ucode.codex_routing import request_routing_decision
458-
459-
workspace = state.get("workspace")
460-
models = state.get("codex_models")
461-
if not isinstance(workspace, str) or not isinstance(models, list):
462-
return None, "workspace model metadata is unavailable"
463-
try:
464-
token = get_databricks_token(workspace, state.get("profile"))
465-
except RuntimeError as exc:
466-
return None, f"could not authenticate the routing request: {exc}"
467-
task = _launch_routing_task(tool_args)
468-
return request_routing_decision(workspace, token, task, models)
469-
470-
471-
def _launch_routing_task(tool_args: list[str]) -> str:
472-
if "exec" in tool_args:
473-
prompt_parts = tool_args[tool_args.index("exec") + 1 :]
474-
if prompt_parts:
475-
return " ".join(prompt_parts)
476-
if tool_args:
477-
return "Start a Codex session with options: " + " ".join(tool_args)
478-
return f"Start an interactive Codex coding session in {Path.cwd().name}."
479-
480-
481-
def _sync_intelligent_routing_hooks(doc: dict, state: dict, *, enabled: bool) -> None:
482-
_remove_intelligent_routing_hooks(doc)
483-
if not enabled:
484-
return
485-
hooks = doc.setdefault("hooks", {})
486-
for event, groups in _routing_hook_groups(state).items():
487-
existing = hooks.get(event)
488-
if not isinstance(existing, list):
489-
existing = []
490-
hooks[event] = [*existing, *groups]
491-
492-
493-
def _routing_hook_groups(state: dict) -> dict[str, list[dict]]:
494-
route_argv = _routing_hook_argv(state, "route-subagent")
495-
session_argv = _routing_hook_argv(state, "session-start")
496-
subagent_argv = _routing_hook_argv(state, "record-subagent")
497-
return {
498-
"PreToolUse": [
499-
{
500-
"matcher": "Agent|.*spawn_agent$",
501-
"hooks": [_routing_command_hook(route_argv, status="Routing subagent model")],
502-
}
503-
],
504-
"SessionStart": [
505-
{
506-
"matcher": "startup|resume|clear",
507-
"hooks": [_routing_command_hook(session_argv)],
508-
}
509-
],
510-
"SubagentStart": [
511-
{
512-
"hooks": [_routing_command_hook(subagent_argv)],
513-
}
514-
],
515-
}
516-
517-
518-
def _routing_hook_argv(state: dict, event: str) -> list[str]:
519-
workspace = str(state.get("workspace") or "")
520-
argv = [
521-
build_auth_token_argv(workspace, state.get("profile"), use_pat=bool(state.get("use_pat")))[
522-
0
523-
],
524-
ROUTING_HOOK_COMMAND_MARKER,
525-
event,
526-
]
527-
if event != "route-subagent":
528-
return argv
529-
argv += ["--host", workspace]
530-
profile = state.get("profile")
531-
if isinstance(profile, str) and profile:
532-
argv += ["--profile", profile]
533-
if state.get("use_pat"):
534-
argv.append("--use-pat")
535-
for model in state.get("codex_models") or []:
536-
if isinstance(model, str) and model:
537-
argv += ["--model", model]
538-
return argv
539-
540-
541-
def _routing_command_hook(argv: list[str], *, status: str | None = None) -> dict:
542-
hook = {
543-
"type": "command",
544-
"command": shlex.join(argv),
545-
"command_windows": subprocess.list2cmdline(argv),
546-
"timeout": 35,
547-
}
548-
if status:
549-
hook["statusMessage"] = status
550-
return hook
551-
552-
553-
def _remove_intelligent_routing_hooks(doc: dict) -> bool:
554-
hooks = doc.get("hooks")
555-
if not isinstance(hooks, dict):
556-
return False
557-
changed = False
558-
for event in list(hooks):
559-
groups = hooks.get(event)
560-
if not isinstance(groups, list):
561-
continue
562-
kept_groups = []
563-
for group in groups:
564-
if not isinstance(group, dict):
565-
kept_groups.append(group)
566-
continue
567-
handlers = group.get("hooks")
568-
if not isinstance(handlers, list):
569-
kept_groups.append(group)
570-
continue
571-
kept_handlers = [
572-
handler
573-
for handler in handlers
574-
if not (
575-
isinstance(handler, dict)
576-
and ROUTING_HOOK_COMMAND_MARKER in str(handler.get("command") or "")
577-
)
578-
]
579-
if len(kept_handlers) != len(handlers):
580-
changed = True
581-
if kept_handlers:
582-
group["hooks"] = kept_handlers
583-
kept_groups.append(group)
584-
if kept_groups:
585-
hooks[event] = kept_groups
586-
else:
587-
hooks.pop(event, None)
588-
if not hooks:
589-
doc.pop("hooks", None)
590-
return changed
591-
592-
593456
def validate_cmd(binary: str) -> list[str]:
594457
return [
595458
binary,

src/ucode/cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
enable_intelligent_routing,
3535
intelligent_routing_enabled,
3636
revert_legacy_shared_config,
37-
route_launch_model,
3837
)
3938
from ucode.agents.pi import PI_SETTINGS_BACKUP_PATH, PI_SETTINGS_PATH
4039
from ucode.config_io import restore_file, set_dry_run
@@ -59,6 +58,7 @@
5958
resolve_pat_token,
6059
run_databricks_login,
6160
)
61+
from ucode.intelligent_routing.codex_routing import route_launch_model
6262
from ucode.mcp import (
6363
MCP_CLIENTS,
6464
SKILLS_MCP_KIND,
@@ -971,7 +971,7 @@ def codex_router_hook_cmd(
971971
import json
972972
import sys
973973

974-
from ucode.codex_routing import (
974+
from ucode.intelligent_routing.codex_routing import (
975975
record_session_start,
976976
record_subagent_start,
977977
route_pre_tool_use,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Intelligent-routing integrations for supported coding agents."""
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
"""Codex hook configuration for intelligent subagent routing."""
2+
3+
from __future__ import annotations
4+
5+
import shlex
6+
import subprocess
7+
8+
from ucode.databricks import build_auth_token_argv
9+
10+
ROUTING_HOOK_COMMAND_MARKER = "codex-router-hook"
11+
12+
13+
def sync_intelligent_routing_hooks(doc: dict, state: dict, *, enabled: bool) -> None:
14+
"""Synchronize ucode-managed routing hooks in a Codex config document."""
15+
remove_intelligent_routing_hooks(doc)
16+
if not enabled:
17+
return
18+
hooks = doc.setdefault("hooks", {})
19+
for event, groups in _routing_hook_groups(state).items():
20+
existing = hooks.get(event)
21+
if not isinstance(existing, list):
22+
existing = []
23+
hooks[event] = [*existing, *groups]
24+
25+
26+
def remove_intelligent_routing_hooks(doc: dict) -> bool:
27+
"""Remove only ucode-managed intelligent-routing hooks."""
28+
hooks = doc.get("hooks")
29+
if not isinstance(hooks, dict):
30+
return False
31+
changed = False
32+
for event in list(hooks):
33+
groups = hooks.get(event)
34+
if not isinstance(groups, list):
35+
continue
36+
kept_groups = []
37+
for group in groups:
38+
if not isinstance(group, dict):
39+
kept_groups.append(group)
40+
continue
41+
handlers = group.get("hooks")
42+
if not isinstance(handlers, list):
43+
kept_groups.append(group)
44+
continue
45+
kept_handlers = [
46+
handler
47+
for handler in handlers
48+
if not (
49+
isinstance(handler, dict)
50+
and ROUTING_HOOK_COMMAND_MARKER in str(handler.get("command") or "")
51+
)
52+
]
53+
if len(kept_handlers) != len(handlers):
54+
changed = True
55+
if kept_handlers:
56+
group["hooks"] = kept_handlers
57+
kept_groups.append(group)
58+
if kept_groups:
59+
hooks[event] = kept_groups
60+
else:
61+
hooks.pop(event, None)
62+
if not hooks:
63+
doc.pop("hooks", None)
64+
return changed
65+
66+
67+
def _routing_hook_groups(state: dict) -> dict[str, list[dict]]:
68+
route_argv = _routing_hook_argv(state, "route-subagent")
69+
session_argv = _routing_hook_argv(state, "session-start")
70+
subagent_argv = _routing_hook_argv(state, "record-subagent")
71+
return {
72+
"PreToolUse": [
73+
{
74+
"matcher": "Agent|.*spawn_agent$",
75+
"hooks": [_routing_command_hook(route_argv, status="Routing subagent model")],
76+
}
77+
],
78+
"SessionStart": [
79+
{
80+
"matcher": "startup|resume|clear",
81+
"hooks": [_routing_command_hook(session_argv)],
82+
}
83+
],
84+
"SubagentStart": [
85+
{
86+
"hooks": [_routing_command_hook(subagent_argv)],
87+
}
88+
],
89+
}
90+
91+
92+
def _routing_hook_argv(state: dict, event: str) -> list[str]:
93+
workspace = str(state.get("workspace") or "")
94+
argv = [
95+
build_auth_token_argv(workspace, state.get("profile"), use_pat=bool(state.get("use_pat")))[
96+
0
97+
],
98+
ROUTING_HOOK_COMMAND_MARKER,
99+
event,
100+
]
101+
if event != "route-subagent":
102+
return argv
103+
argv += ["--host", workspace]
104+
profile = state.get("profile")
105+
if isinstance(profile, str) and profile:
106+
argv += ["--profile", profile]
107+
if state.get("use_pat"):
108+
argv.append("--use-pat")
109+
for model in state.get("codex_models") or []:
110+
if isinstance(model, str) and model:
111+
argv += ["--model", model]
112+
return argv
113+
114+
115+
def _routing_command_hook(argv: list[str], *, status: str | None = None) -> dict:
116+
hook = {
117+
"type": "command",
118+
"command": shlex.join(argv),
119+
"command_windows": subprocess.list2cmdline(argv),
120+
"timeout": 35,
121+
}
122+
if status:
123+
hook["statusMessage"] = status
124+
return hook

src/ucode/codex_routing.py renamed to src/ucode/intelligent_routing/codex_routing.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from typing import Any
1414

1515
from ucode.config_io import APP_DIR
16+
from ucode.databricks import get_databricks_token
1617

1718
ROUTER_NAME = "task_v1"
1819
ROUTING_PATH = "/ai-gateway/routing/v1/routes:select"
@@ -37,6 +38,30 @@ class RoutingDecision:
3738
rationale: str = ""
3839

3940

41+
def route_launch_model(state: dict, tool_args: list[str]):
42+
"""Route a root Codex launch before the Codex process starts."""
43+
workspace = state.get("workspace")
44+
models = state.get("codex_models")
45+
if not isinstance(workspace, str) or not isinstance(models, list):
46+
return None, "workspace model metadata is unavailable"
47+
try:
48+
token = get_databricks_token(workspace, state.get("profile"))
49+
except RuntimeError as exc:
50+
return None, f"could not authenticate the routing request: {exc}"
51+
task = _launch_routing_task(tool_args)
52+
return request_routing_decision(workspace, token, task, models)
53+
54+
55+
def _launch_routing_task(tool_args: list[str]) -> str:
56+
if "exec" in tool_args:
57+
prompt_parts = tool_args[tool_args.index("exec") + 1 :]
58+
if prompt_parts:
59+
return " ".join(prompt_parts)
60+
if tool_args:
61+
return "Start a Codex session with options: " + " ".join(tool_args)
62+
return f"Start an interactive Codex coding session in {Path.cwd().name}."
63+
64+
4065
def request_routing_decision(
4166
workspace: str,
4267
token: str,

0 commit comments

Comments
 (0)