-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathrouter.ts
More file actions
125 lines (110 loc) · 3.41 KB
/
router.ts
File metadata and controls
125 lines (110 loc) · 3.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/**
* Smart Router
*
* Routes commands to optimal tools based on intent and environment.
* Returns resolutions: allow, advise (use different tool), or block.
*/
import type { Intent } from './intent.js';
import type { Environment } from './environment.js';
/**
* Routing resolution types
*/
export type Resolution =
| { action: 'allow' }
| { action: 'advise'; tool: string; reason: string }
| { action: 'block'; reason: string };
/**
* Single routing rule with environment-specific resolutions.
* The router checks resolutions in priority order.
*/
export interface RoutingRule {
/** Pattern to match commands ( RegExp ) */
match: RegExp;
/** Intent type for this rule */
intent: Intent;
/** Resolution per environment/tool */
resolutions: {
/** Use RTK if available */
rtk?: Resolution;
/** Use jcodemunch if indexed */
jcodemunch?: Resolution;
/** General tool (Grep, Read, Glob, etc.) */
general?: Resolution;
/** Fallback: allow raw command */
fallback?: Resolution;
/** Wildcard: always matches if set */
_?: Resolution;
};
}
/**
* Resolve a routing rule based on environment.
* Checks resolutions in priority order: rtk → jcodemunch → general → fallback → _
*/
export function resolve(rule: RoutingRule, env: Environment): Resolution {
const { resolutions } = rule;
// Priority 1: RTK (token-optimized CLI proxy)
if (env.rtkAvailable && resolutions.rtk) {
return resolutions.rtk;
}
// Priority 2: jcodemunch (indexed code search)
if (env.jcodemunchIndexed && resolutions.jcodemunch) {
return resolutions.jcodemunch;
}
// Priority 3: General tool (dedicated Claude Code tool)
if (resolutions.general) {
return resolutions.general;
}
// Priority 4: Explicit fallback
if (resolutions.fallback) {
return resolutions.fallback;
}
// Priority 5: Wildcard (default)
if (resolutions._) {
return resolutions._;
}
// No resolution found: allow by default
return { action: 'allow' };
}
/**
* Format a resolution as a human-readable message.
*/
export function formatResolution(resolution: Resolution, command: string): string {
switch (resolution.action) {
case 'allow':
return `Allowing command: ${command}`;
case 'advise':
return `Advise: Use "${resolution.tool}" instead. Reason: ${resolution.reason}`;
case 'block':
return `BLOCKED: ${resolution.reason}`;
}
}
/**
* Check if a resolution requires the agent to change its behavior.
*/
export function requiresAction(resolution: Resolution): boolean {
return resolution.action !== 'allow';
}
/**
* Compute token savings estimate for a resolution.
* Returns percentage (0-100) or null if not applicable.
*/
export function estimateTokenSavings(resolution: Resolution): number | null {
if (resolution.action === 'allow' || resolution.action === 'block') {
return null;
}
// Estimate savings based on the tool being suggested
const tool = resolution.tool.toLowerCase();
if (tool.includes('jcodemunch') || tool.includes('search_symbols')) {
return 85; // Structured symbol search vs raw grep
}
if (tool.includes('grep') && tool.includes('rtk')) {
return 60; // Filtered grep output
}
if (tool.includes('read') && !tool.includes('cat')) {
return 75; // Clean read vs cat with artifacts
}
if (tool.includes('glob') || tool.includes('find')) {
return 77; // Targeted discovery vs recursive find
}
return null;
}