@haoyiyin/workflow 0.2.11 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/agents/contracts/implementer.d.ts +29 -0
- package/dist/src/agents/contracts/implementer.d.ts.map +1 -0
- package/dist/src/agents/contracts/implementer.js +94 -0
- package/dist/src/agents/contracts/implementer.js.map +1 -0
- package/dist/src/agents/contracts/index.d.ts +11 -0
- package/dist/src/agents/contracts/index.d.ts.map +1 -0
- package/dist/src/agents/contracts/index.js +11 -0
- package/dist/src/agents/contracts/index.js.map +1 -0
- package/dist/src/agents/contracts/planner.d.ts +25 -0
- package/dist/src/agents/contracts/planner.d.ts.map +1 -0
- package/dist/src/agents/contracts/planner.js +107 -0
- package/dist/src/agents/contracts/planner.js.map +1 -0
- package/dist/src/agents/contracts/router.d.ts +24 -0
- package/dist/src/agents/contracts/router.d.ts.map +1 -0
- package/dist/src/agents/contracts/router.js +137 -0
- package/dist/src/agents/contracts/router.js.map +1 -0
- package/dist/src/agents/contracts/verifier.d.ts +27 -0
- package/dist/src/agents/contracts/verifier.d.ts.map +1 -0
- package/dist/src/agents/contracts/verifier.js +115 -0
- package/dist/src/agents/contracts/verifier.js.map +1 -0
- package/dist/src/agents/dispatcher.d.ts +94 -51
- package/dist/src/agents/dispatcher.d.ts.map +1 -1
- package/dist/src/agents/dispatcher.js +207 -164
- package/dist/src/agents/dispatcher.js.map +1 -1
- package/dist/src/persistence/index.d.ts +4 -2
- package/dist/src/persistence/index.d.ts.map +1 -1
- package/dist/src/persistence/index.js +4 -1
- package/dist/src/persistence/index.js.map +1 -1
- package/dist/src/persistence/plan-md.d.ts +3 -2
- package/dist/src/persistence/plan-md.d.ts.map +1 -1
- package/dist/src/persistence/plan-md.js +47 -15
- package/dist/src/persistence/plan-md.js.map +1 -1
- package/dist/src/persistence/state-md.d.ts +2 -0
- package/dist/src/persistence/state-md.d.ts.map +1 -1
- package/dist/src/persistence/state-md.js +40 -22
- package/dist/src/persistence/state-md.js.map +1 -1
- package/dist/src/persistence/types.d.ts +35 -39
- package/dist/src/persistence/types.d.ts.map +1 -1
- package/dist/src/router/namespace/core/intent-router.d.ts +24 -0
- package/dist/src/router/namespace/core/intent-router.d.ts.map +1 -0
- package/dist/src/router/namespace/core/intent-router.js +190 -0
- package/dist/src/router/namespace/core/intent-router.js.map +1 -0
- package/dist/src/router/namespace/core/lifecycle-router.d.ts +28 -0
- package/dist/src/router/namespace/core/lifecycle-router.d.ts.map +1 -0
- package/dist/src/router/namespace/core/lifecycle-router.js +132 -0
- package/dist/src/router/namespace/core/lifecycle-router.js.map +1 -0
- package/dist/src/router/namespace/core/state-router.d.ts +32 -0
- package/dist/src/router/namespace/core/state-router.d.ts.map +1 -0
- package/dist/src/router/namespace/core/state-router.js +157 -0
- package/dist/src/router/namespace/core/state-router.js.map +1 -0
- package/dist/src/router/namespace/domain/code-router.d.ts +26 -0
- package/dist/src/router/namespace/domain/code-router.d.ts.map +1 -0
- package/dist/src/router/namespace/domain/code-router.js +171 -0
- package/dist/src/router/namespace/domain/code-router.js.map +1 -0
- package/dist/src/router/namespace/domain/debug-router.d.ts +25 -0
- package/dist/src/router/namespace/domain/debug-router.d.ts.map +1 -0
- package/dist/src/router/namespace/domain/debug-router.js +139 -0
- package/dist/src/router/namespace/domain/debug-router.js.map +1 -0
- package/dist/src/router/namespace/domain/plan-router.d.ts +29 -0
- package/dist/src/router/namespace/domain/plan-router.d.ts.map +1 -0
- package/dist/src/router/namespace/domain/plan-router.js +160 -0
- package/dist/src/router/namespace/domain/plan-router.js.map +1 -0
- package/dist/src/router/namespace/domain/review-router.d.ts +24 -0
- package/dist/src/router/namespace/domain/review-router.d.ts.map +1 -0
- package/dist/src/router/namespace/domain/review-router.js +116 -0
- package/dist/src/router/namespace/domain/review-router.js.map +1 -0
- package/dist/src/router/namespace/index.d.ts +19 -0
- package/dist/src/router/namespace/index.d.ts.map +1 -0
- package/dist/src/router/namespace/index.js +22 -0
- package/dist/src/router/namespace/index.js.map +1 -0
- package/dist/src/router/namespace/registry.d.ts +67 -0
- package/dist/src/router/namespace/registry.d.ts.map +1 -0
- package/dist/src/router/namespace/registry.js +197 -0
- package/dist/src/router/namespace/registry.js.map +1 -0
- package/dist/src/router/namespace/types.d.ts +124 -0
- package/dist/src/router/namespace/types.d.ts.map +1 -0
- package/dist/src/router/namespace/types.js +20 -0
- package/dist/src/router/namespace/types.js.map +1 -0
- package/dist/src/router/namespace/utility/fallback-router.d.ts +28 -0
- package/dist/src/router/namespace/utility/fallback-router.d.ts.map +1 -0
- package/dist/src/router/namespace/utility/fallback-router.js +88 -0
- package/dist/src/router/namespace/utility/fallback-router.js.map +1 -0
- package/dist/src/router/namespace/utility/quick-task-router.d.ts +28 -0
- package/dist/src/router/namespace/utility/quick-task-router.d.ts.map +1 -0
- package/dist/src/router/namespace/utility/quick-task-router.js +99 -0
- package/dist/src/router/namespace/utility/quick-task-router.js.map +1 -0
- package/dist/src/router/namespace/utility/research-router.d.ts +24 -0
- package/dist/src/router/namespace/utility/research-router.d.ts.map +1 -0
- package/dist/src/router/namespace/utility/research-router.js +84 -0
- package/dist/src/router/namespace/utility/research-router.js.map +1 -0
- package/dist/src/skills/agents-md/index.js +2 -2
- package/dist/src/skills/agents-md/index.js.map +1 -1
- package/dist/src/skills/execute-plan/index.d.ts +45 -65
- package/dist/src/skills/execute-plan/index.d.ts.map +1 -1
- package/dist/src/skills/execute-plan/index.js +325 -551
- package/dist/src/skills/execute-plan/index.js.map +1 -1
- package/dist/src/skills/index.d.ts +1 -0
- package/dist/src/skills/index.d.ts.map +1 -1
- package/dist/src/skills/index.js +1 -0
- package/dist/src/skills/index.js.map +1 -1
- package/dist/src/skills/quick-task/index.d.ts +4 -4
- package/dist/src/skills/quick-task/index.js +1 -1
- package/dist/src/skills/quick-task/index.js.map +1 -1
- package/dist/src/skills/review-diff/index.d.ts +6 -6
- package/dist/src/skills/review-diff/index.js +1 -1
- package/dist/src/skills/review-diff/index.js.map +1 -1
- package/dist/src/skills/router/index.d.ts +101 -0
- package/dist/src/skills/router/index.d.ts.map +1 -0
- package/dist/src/skills/router/index.js +450 -0
- package/dist/src/skills/router/index.js.map +1 -0
- package/dist/src/skills/router/types.d.ts +79 -0
- package/dist/src/skills/router/types.d.ts.map +1 -0
- package/dist/src/skills/router/types.js +8 -0
- package/dist/src/skills/router/types.js.map +1 -0
- package/dist/src/skills/systematic-debugging/index.js +1 -1
- package/dist/src/skills/systematic-debugging/index.js.map +1 -1
- package/dist/src/skills/tdd/index.d.ts +14 -14
- package/dist/src/skills/tdd/index.js +1 -1
- package/dist/src/skills/tdd/index.js.map +1 -1
- package/dist/src/skills/to-plan/index-enhanced.d.ts +4 -4
- package/dist/src/skills/to-plan/index-enhanced.d.ts.map +1 -1
- package/dist/src/skills/to-plan/index-enhanced.js +3 -5
- package/dist/src/skills/to-plan/index-enhanced.js.map +1 -1
- package/dist/src/skills/to-plan/index.d.ts +24 -91
- package/dist/src/skills/to-plan/index.d.ts.map +1 -1
- package/dist/src/skills/to-plan/index.js +214 -409
- package/dist/src/skills/to-plan/index.js.map +1 -1
- package/package.json +3 -5
- package/src/agents/contracts/implementer.ts +122 -0
- package/src/agents/contracts/index.ts +27 -0
- package/src/agents/contracts/planner.ts +129 -0
- package/src/agents/contracts/router.ts +168 -0
- package/src/agents/contracts/verifier.ts +137 -0
- package/src/agents/dispatcher.ts +387 -362
- package/src/persistence/index.ts +10 -4
- package/src/persistence/plan-md.ts +52 -18
- package/src/persistence/state-md.ts +45 -23
- package/src/persistence/types.ts +37 -40
- package/src/router/namespace/README.md +127 -0
- package/src/router/namespace/core/intent-router.ts +221 -0
- package/src/router/namespace/core/lifecycle-router.ts +156 -0
- package/src/router/namespace/core/state-router.ts +192 -0
- package/src/router/namespace/domain/code-router.ts +202 -0
- package/src/router/namespace/domain/debug-router.ts +167 -0
- package/src/router/namespace/domain/plan-router.ts +196 -0
- package/src/router/namespace/domain/review-router.ts +142 -0
- package/src/router/namespace/index.ts +84 -0
- package/src/router/namespace/registry.ts +242 -0
- package/src/router/namespace/types.ts +182 -0
- package/src/router/namespace/utility/fallback-router.ts +107 -0
- package/src/router/namespace/utility/quick-task-router.ts +121 -0
- package/src/router/namespace/utility/research-router.ts +105 -0
- package/src/skills/agents-md/index.ts +2 -2
- package/src/skills/execute-plan/index.ts +419 -673
- package/src/skills/index.ts +1 -0
- package/src/skills/quick-task/index.ts +1 -1
- package/src/skills/review-diff/index.ts +1 -1
- package/src/skills/router/SKILL.md +181 -0
- package/src/skills/router/index.ts +577 -0
- package/src/skills/router/types.ts +90 -0
- package/src/skills/systematic-debugging/index.ts +1 -1
- package/src/skills/tdd/index.ts +1 -1
- package/src/skills/to-plan/index-enhanced.ts +3 -5
- package/src/skills/to-plan/index.ts +231 -502
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent Router - Core Layer
|
|
3
|
+
*
|
|
4
|
+
* 基于用户意图的分类进行路由决策
|
|
5
|
+
* 使用关键词和模式匹配提取意图
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
NamespaceRouter,
|
|
10
|
+
RoutingContext,
|
|
11
|
+
RouteDecision,
|
|
12
|
+
NamespaceHealth,
|
|
13
|
+
AlternativeRoute,
|
|
14
|
+
} from '../types.js'
|
|
15
|
+
|
|
16
|
+
// 意图定义
|
|
17
|
+
interface IntentPattern {
|
|
18
|
+
name: string
|
|
19
|
+
patterns: RegExp[]
|
|
20
|
+
targetSkill: string
|
|
21
|
+
confidence: number
|
|
22
|
+
complexity: 'low' | 'medium' | 'high'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const INTENTS: IntentPattern[] = [
|
|
26
|
+
{
|
|
27
|
+
name: 'plan',
|
|
28
|
+
patterns: [
|
|
29
|
+
/plan|设计|架构|方案/i,
|
|
30
|
+
/how to implement|如何实现/i,
|
|
31
|
+
/architecture|结构/i,
|
|
32
|
+
/strategy|策略/i,
|
|
33
|
+
],
|
|
34
|
+
targetSkill: 'to-plan',
|
|
35
|
+
confidence: 0.85,
|
|
36
|
+
complexity: 'high',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'execute',
|
|
40
|
+
patterns: [
|
|
41
|
+
/implement|实现|完成/i,
|
|
42
|
+
/build|创建|建立/i,
|
|
43
|
+
/develop|开发/i,
|
|
44
|
+
/execute|执行/i,
|
|
45
|
+
],
|
|
46
|
+
targetSkill: 'execute-plan',
|
|
47
|
+
confidence: 0.8,
|
|
48
|
+
complexity: 'high',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'fix',
|
|
52
|
+
patterns: [
|
|
53
|
+
/fix|修复|解决/i,
|
|
54
|
+
/correct|修正/i,
|
|
55
|
+
/update|更新.*(typo|typo|错误)/i,
|
|
56
|
+
],
|
|
57
|
+
targetSkill: 'quick-task',
|
|
58
|
+
confidence: 0.75,
|
|
59
|
+
complexity: 'low',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'debug',
|
|
63
|
+
patterns: [
|
|
64
|
+
/debug|调试/i,
|
|
65
|
+
/bug|错误|故障/i,
|
|
66
|
+
/error|异常/i,
|
|
67
|
+
/not working|不工作|失效/i,
|
|
68
|
+
/investigate|调查/i,
|
|
69
|
+
],
|
|
70
|
+
targetSkill: 'systematic-debugging',
|
|
71
|
+
confidence: 0.85,
|
|
72
|
+
complexity: 'medium',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'review',
|
|
76
|
+
patterns: [
|
|
77
|
+
/review|审查|检查/i,
|
|
78
|
+
/audit|审核/i,
|
|
79
|
+
/check.*quality|检查.*质量/i,
|
|
80
|
+
/code review|代码审查/i,
|
|
81
|
+
],
|
|
82
|
+
targetSkill: 'review-diff',
|
|
83
|
+
confidence: 0.8,
|
|
84
|
+
complexity: 'medium',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'test',
|
|
88
|
+
patterns: [
|
|
89
|
+
/test|测试/i,
|
|
90
|
+
/tdd|test.*driven/i,
|
|
91
|
+
/unit test|单元测试/i,
|
|
92
|
+
/coverage|覆盖率/i,
|
|
93
|
+
],
|
|
94
|
+
targetSkill: 'tdd',
|
|
95
|
+
confidence: 0.85,
|
|
96
|
+
complexity: 'medium',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'research',
|
|
100
|
+
patterns: [
|
|
101
|
+
/research|研究/i,
|
|
102
|
+
/explore|探索/i,
|
|
103
|
+
/find out|查找/i,
|
|
104
|
+
/learn about|了解/i,
|
|
105
|
+
/what is|什么是/i,
|
|
106
|
+
/how does|如何.*工作/i,
|
|
107
|
+
],
|
|
108
|
+
targetSkill: 'research',
|
|
109
|
+
confidence: 0.7,
|
|
110
|
+
complexity: 'low',
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: 'docs',
|
|
114
|
+
patterns: [
|
|
115
|
+
/document|文档/i,
|
|
116
|
+
/claude\.md|agents\.md/i,
|
|
117
|
+
/readme|说明/i,
|
|
118
|
+
/update.*doc|更新.*文档/i,
|
|
119
|
+
],
|
|
120
|
+
targetSkill: 'agents-md',
|
|
121
|
+
confidence: 0.75,
|
|
122
|
+
complexity: 'low',
|
|
123
|
+
},
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
export class IntentRouter implements NamespaceRouter {
|
|
127
|
+
readonly name = 'intent'
|
|
128
|
+
readonly layer = 'core' as const
|
|
129
|
+
readonly priority = 80
|
|
130
|
+
readonly patterns = INTENTS.flatMap((i) => i.patterns)
|
|
131
|
+
|
|
132
|
+
private routeCount = 0
|
|
133
|
+
private successCount = 0
|
|
134
|
+
private totalLatency = 0
|
|
135
|
+
|
|
136
|
+
async canRoute(context: RoutingContext): Promise<boolean> {
|
|
137
|
+
// 检查是否能匹配到任何意图
|
|
138
|
+
const request = context.request.text.toLowerCase()
|
|
139
|
+
return INTENTS.some((intent) => intent.patterns.some((p) => p.test(request)))
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async route(context: RoutingContext): Promise<RouteDecision> {
|
|
143
|
+
const startTime = Date.now()
|
|
144
|
+
const requestText = context.request.text.toLowerCase()
|
|
145
|
+
|
|
146
|
+
// 计算每个意图的匹配分数
|
|
147
|
+
const scored = INTENTS.map((intent) => {
|
|
148
|
+
let score = 0
|
|
149
|
+
for (const pattern of intent.patterns) {
|
|
150
|
+
if (pattern.test(requestText)) {
|
|
151
|
+
score += intent.confidence / intent.patterns.length
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return { intent, score }
|
|
155
|
+
}).filter((s) => s.score > 0)
|
|
156
|
+
|
|
157
|
+
// 按分数排序
|
|
158
|
+
scored.sort((a, b) => b.score - a.score)
|
|
159
|
+
|
|
160
|
+
const best = scored[0]
|
|
161
|
+
const alternatives: AlternativeRoute[] = scored.slice(1, 4).map((s) => ({
|
|
162
|
+
skill: s.intent.targetSkill,
|
|
163
|
+
confidence: s.score,
|
|
164
|
+
reasoning: `Intent: ${s.intent.name}`,
|
|
165
|
+
}))
|
|
166
|
+
|
|
167
|
+
this.routeCount++
|
|
168
|
+
this.totalLatency += Date.now() - startTime
|
|
169
|
+
|
|
170
|
+
if (best) {
|
|
171
|
+
this.successCount++
|
|
172
|
+
return {
|
|
173
|
+
skill: best.intent.targetSkill,
|
|
174
|
+
confidence: Math.min(best.score, 1.0),
|
|
175
|
+
reasoning: `Intent matched: ${best.intent.name} (${best.intent.complexity} complexity)`,
|
|
176
|
+
namespace: this.name,
|
|
177
|
+
alternatives,
|
|
178
|
+
metadata: {
|
|
179
|
+
layer: this.layer,
|
|
180
|
+
processingTime: Date.now() - startTime,
|
|
181
|
+
hops: 1,
|
|
182
|
+
},
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// 无匹配
|
|
187
|
+
return {
|
|
188
|
+
skill: 'quick-task',
|
|
189
|
+
confidence: 0.3,
|
|
190
|
+
reasoning: 'No clear intent matched',
|
|
191
|
+
namespace: this.name,
|
|
192
|
+
alternatives: [],
|
|
193
|
+
metadata: {
|
|
194
|
+
layer: this.layer,
|
|
195
|
+
processingTime: Date.now() - startTime,
|
|
196
|
+
hops: 1,
|
|
197
|
+
},
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
getSupportedSkills(): string[] {
|
|
202
|
+
return INTENTS.map((i) => i.targetSkill)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
getHealth(): NamespaceHealth {
|
|
206
|
+
return {
|
|
207
|
+
name: this.name,
|
|
208
|
+
status: this.successRate() > 0.7 ? 'healthy' : 'degraded',
|
|
209
|
+
totalRoutes: this.routeCount,
|
|
210
|
+
successRate: this.successRate(),
|
|
211
|
+
avgLatency: this.routeCount > 0 ? this.totalLatency / this.routeCount : 0,
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
private successRate(): number {
|
|
216
|
+
return this.routeCount > 0 ? this.successCount / this.routeCount : 1.0
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export const intentRouter = new IntentRouter()
|
|
221
|
+
export default intentRouter
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lifecycle Router - Core Layer
|
|
3
|
+
*
|
|
4
|
+
* 基于项目生命周期阶段进行路由决策
|
|
5
|
+
* 生命周期: idle → planning → executing → verifying → completed
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
NamespaceRouter,
|
|
10
|
+
RoutingContext,
|
|
11
|
+
RouteDecision,
|
|
12
|
+
NamespaceHealth,
|
|
13
|
+
AlternativeRoute,
|
|
14
|
+
} from '../types.js'
|
|
15
|
+
|
|
16
|
+
// 各阶段可用的技能
|
|
17
|
+
const SKILLS_BY_PHASE: Record<string, string[]> = {
|
|
18
|
+
idle: ['to-plan', 'research', 'quick-task', 'agents-md'],
|
|
19
|
+
planning: ['to-plan', 'research', 'review-diff', 'agents-md'],
|
|
20
|
+
executing: ['execute-plan', 'quick-task', 'tdd', 'systematic-debugging'],
|
|
21
|
+
verifying: ['review-diff', 'systematic-debugging', 'execute-plan'],
|
|
22
|
+
completed: ['review-diff', 'agents-md', 'research'],
|
|
23
|
+
failed: ['systematic-debugging', 'to-plan', 'review-diff'],
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class LifecycleRouter implements NamespaceRouter {
|
|
27
|
+
readonly name = 'lifecycle'
|
|
28
|
+
readonly layer = 'core' as const
|
|
29
|
+
readonly priority = 90
|
|
30
|
+
readonly patterns = [
|
|
31
|
+
/plan|规划|设计/i,
|
|
32
|
+
/execute|执行|实现/i,
|
|
33
|
+
/debug|调试|fix/i,
|
|
34
|
+
/review|审查|review/i,
|
|
35
|
+
/complete|完成|结束/i,
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
private routeCount = 0
|
|
39
|
+
private successCount = 0
|
|
40
|
+
private totalLatency = 0
|
|
41
|
+
|
|
42
|
+
async canRoute(context: RoutingContext): Promise<boolean> {
|
|
43
|
+
// 总是可以检查生命周期
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async route(context: RoutingContext): Promise<RouteDecision> {
|
|
48
|
+
const startTime = Date.now()
|
|
49
|
+
const phase = context.state.phase
|
|
50
|
+
const availableSkills = SKILLS_BY_PHASE[phase] || SKILLS_BY_PHASE.idle
|
|
51
|
+
|
|
52
|
+
// 基于请求内容匹配最佳技能
|
|
53
|
+
const requestText = context.request.text.toLowerCase()
|
|
54
|
+
let bestSkill: string | null = null
|
|
55
|
+
let bestScore = 0
|
|
56
|
+
const alternatives: AlternativeRoute[] = []
|
|
57
|
+
|
|
58
|
+
for (const skill of availableSkills) {
|
|
59
|
+
const score = this.calculateSkillScore(skill, requestText, phase)
|
|
60
|
+
if (score > bestScore) {
|
|
61
|
+
// 当前最佳变为备选
|
|
62
|
+
if (bestSkill) {
|
|
63
|
+
alternatives.push({
|
|
64
|
+
skill: bestSkill,
|
|
65
|
+
confidence: bestScore,
|
|
66
|
+
reasoning: `Matched lifecycle phase ${phase}`,
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
bestSkill = skill
|
|
70
|
+
bestScore = score
|
|
71
|
+
} else if (score > 0.3) {
|
|
72
|
+
alternatives.push({
|
|
73
|
+
skill,
|
|
74
|
+
confidence: score,
|
|
75
|
+
reasoning: `Alternative for ${phase} phase`,
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
this.routeCount++
|
|
81
|
+
this.totalLatency += Date.now() - startTime
|
|
82
|
+
if (bestSkill) this.successCount++
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
skill: bestSkill || 'quick-task',
|
|
86
|
+
confidence: bestScore || 0.5,
|
|
87
|
+
reasoning: `Lifecycle phase: ${phase}. Available: ${availableSkills.join(', ')}`,
|
|
88
|
+
namespace: this.name,
|
|
89
|
+
alternatives: alternatives.slice(0, 3),
|
|
90
|
+
metadata: {
|
|
91
|
+
layer: this.layer,
|
|
92
|
+
processingTime: Date.now() - startTime,
|
|
93
|
+
hops: 1,
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 计算技能匹配分数
|
|
100
|
+
*/
|
|
101
|
+
private calculateSkillScore(skill: string, request: string, phase: string): number {
|
|
102
|
+
const keywordMap: Record<string, string[]> = {
|
|
103
|
+
'to-plan': ['plan', 'design', 'architecture', '规划', '设计'],
|
|
104
|
+
'execute-plan': ['implement', 'build', 'execute', '实现', '执行'],
|
|
105
|
+
'quick-task': ['fix', 'typo', 'rename', 'small', '快速', '修复'],
|
|
106
|
+
'review-diff': ['review', 'audit', 'check', '审查', '检查'],
|
|
107
|
+
'systematic-debugging': ['debug', 'bug', 'error', '调试', '错误'],
|
|
108
|
+
'tdd': ['test', 'tdd', '测试'],
|
|
109
|
+
'research': ['research', 'explore', 'learn', '研究', '探索'],
|
|
110
|
+
'agents-md': ['agent', 'claude.md', 'agents.md', '文档'],
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const keywords = keywordMap[skill] || []
|
|
114
|
+
let score = 0
|
|
115
|
+
|
|
116
|
+
for (const keyword of keywords) {
|
|
117
|
+
if (request.includes(keyword.toLowerCase())) {
|
|
118
|
+
score += 0.2
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 根据生命周期阶段调整分数
|
|
123
|
+
const phaseBoost: Record<string, Record<string, number>> = {
|
|
124
|
+
planning: { 'to-plan': 0.3, 'research': 0.2 },
|
|
125
|
+
executing: { 'execute-plan': 0.3, 'tdd': 0.2, 'quick-task': 0.1 },
|
|
126
|
+
verifying: { 'review-diff': 0.3, 'systematic-debugging': 0.2 },
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (phaseBoost[phase]?.[skill]) {
|
|
130
|
+
score += phaseBoost[phase][skill]
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return Math.min(score, 1.0)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
getSupportedSkills(): string[] {
|
|
137
|
+
return Object.values(SKILLS_BY_PHASE).flat()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
getHealth(): NamespaceHealth {
|
|
141
|
+
return {
|
|
142
|
+
name: this.name,
|
|
143
|
+
status: this.successRate() > 0.8 ? 'healthy' : 'degraded',
|
|
144
|
+
totalRoutes: this.routeCount,
|
|
145
|
+
successRate: this.successRate(),
|
|
146
|
+
avgLatency: this.routeCount > 0 ? this.totalLatency / this.routeCount : 0,
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private successRate(): number {
|
|
151
|
+
return this.routeCount > 0 ? this.successCount / this.routeCount : 1.0
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export const lifecycleRouter = new LifecycleRouter()
|
|
156
|
+
export default lifecycleRouter
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State Router - Core Layer
|
|
3
|
+
*
|
|
4
|
+
* 基于 STATE.md 和 PLAN.md 的状态进行路由决策
|
|
5
|
+
* 优先使用状态信号而非关键词匹配
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
NamespaceRouter,
|
|
10
|
+
RoutingContext,
|
|
11
|
+
RouteDecision,
|
|
12
|
+
NamespaceHealth,
|
|
13
|
+
AlternativeRoute,
|
|
14
|
+
} from '../types.js'
|
|
15
|
+
|
|
16
|
+
export class StateRouter implements NamespaceRouter {
|
|
17
|
+
readonly name = 'state'
|
|
18
|
+
readonly layer = 'core' as const
|
|
19
|
+
readonly priority = 95 // 高于 lifecycle
|
|
20
|
+
readonly patterns = [
|
|
21
|
+
/state|状态/i,
|
|
22
|
+
/plan|计划/i,
|
|
23
|
+
/continue|继续/i,
|
|
24
|
+
/resume|恢复/i,
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
private routeCount = 0
|
|
28
|
+
private successCount = 0
|
|
29
|
+
private totalLatency = 0
|
|
30
|
+
|
|
31
|
+
async canRoute(context: RoutingContext): Promise<boolean> {
|
|
32
|
+
// 如果有 plan 或 state 信息,可以路由
|
|
33
|
+
return context.plan !== null || context.state.phase !== 'idle'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async route(context: RoutingContext): Promise<RouteDecision> {
|
|
37
|
+
const startTime = Date.now()
|
|
38
|
+
const { state, plan, request } = context
|
|
39
|
+
|
|
40
|
+
// 基于状态的路由决策
|
|
41
|
+
const decision = this.makeStateBasedDecision(state, plan, request.text)
|
|
42
|
+
|
|
43
|
+
this.routeCount++
|
|
44
|
+
this.totalLatency += Date.now() - startTime
|
|
45
|
+
this.successCount++
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
...decision,
|
|
49
|
+
namespace: this.name,
|
|
50
|
+
metadata: {
|
|
51
|
+
layer: this.layer,
|
|
52
|
+
processingTime: Date.now() - startTime,
|
|
53
|
+
hops: 1,
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 基于状态的路由决策
|
|
60
|
+
*/
|
|
61
|
+
private makeStateBasedDecision(
|
|
62
|
+
state: RoutingContext['state'],
|
|
63
|
+
plan: RoutingContext['plan'],
|
|
64
|
+
requestText: string
|
|
65
|
+
): Omit<RouteDecision, 'namespace' | 'metadata'> {
|
|
66
|
+
const alternatives: AlternativeRoute[] = []
|
|
67
|
+
|
|
68
|
+
// 规则1: 如果有 plan 且未完成,默认路由到 execute-plan
|
|
69
|
+
if (plan && state.phase === 'executing') {
|
|
70
|
+
const completedCount = state.completedTasks?.length || 0
|
|
71
|
+
const totalCount = plan.tasks?.length || 0
|
|
72
|
+
const progress = totalCount > 0 ? completedCount / totalCount : 0
|
|
73
|
+
|
|
74
|
+
// 检查是否继续执行
|
|
75
|
+
if (progress < 1.0) {
|
|
76
|
+
return {
|
|
77
|
+
skill: 'execute-plan',
|
|
78
|
+
confidence: 0.9,
|
|
79
|
+
reasoning: `Plan exists with ${completedCount}/${totalCount} tasks complete. Phase: ${state.phase}`,
|
|
80
|
+
alternatives: [
|
|
81
|
+
{ skill: 'quick-task', confidence: 0.3, reasoning: 'Small task bypass' },
|
|
82
|
+
],
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 规则2: 如果正在 verifying,路由到 review-diff
|
|
88
|
+
if (state.phase === 'verifying') {
|
|
89
|
+
return {
|
|
90
|
+
skill: 'review-diff',
|
|
91
|
+
confidence: 0.85,
|
|
92
|
+
reasoning: `Phase is ${state.phase}, need verification`,
|
|
93
|
+
alternatives: [
|
|
94
|
+
{ skill: 'systematic-debugging', confidence: 0.4, reasoning: 'If verification fails' },
|
|
95
|
+
],
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 规则3: 如果有 plan 但还没开始执行
|
|
100
|
+
if (plan && state.phase === 'planning') {
|
|
101
|
+
return {
|
|
102
|
+
skill: 'execute-plan',
|
|
103
|
+
confidence: 0.8,
|
|
104
|
+
reasoning: `Plan ready (${plan.tasks?.length || 0} tasks), waiting to execute`,
|
|
105
|
+
alternatives: [
|
|
106
|
+
{ skill: 'to-plan', confidence: 0.3, reasoning: 'Revise plan' },
|
|
107
|
+
],
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 规则4: 如果用户说 "continue" 或 "继续"
|
|
112
|
+
if (/^\s*(continue|resume|proceed|继续|恢复)/i.test(requestText)) {
|
|
113
|
+
if (plan) {
|
|
114
|
+
return {
|
|
115
|
+
skill: 'execute-plan',
|
|
116
|
+
confidence: 0.95,
|
|
117
|
+
reasoning: 'User requested to continue with existing plan',
|
|
118
|
+
alternatives: [],
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 规则5: 默认情况 - 检查是否需要创建 plan
|
|
124
|
+
if (!plan && state.phase === 'idle') {
|
|
125
|
+
// 请求复杂度检测
|
|
126
|
+
const isComplex = this.isComplexRequest(requestText)
|
|
127
|
+
if (isComplex) {
|
|
128
|
+
return {
|
|
129
|
+
skill: 'to-plan',
|
|
130
|
+
confidence: 0.75,
|
|
131
|
+
reasoning: 'No plan exists and request appears complex',
|
|
132
|
+
alternatives: [
|
|
133
|
+
{ skill: 'quick-task', confidence: 0.4, reasoning: 'Simple approach' },
|
|
134
|
+
{ skill: 'research', confidence: 0.3, reasoning: 'Need more info' },
|
|
135
|
+
],
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 默认返回 low confidence
|
|
141
|
+
return {
|
|
142
|
+
skill: 'quick-task',
|
|
143
|
+
confidence: 0.3,
|
|
144
|
+
reasoning: `State-based routing default: ${state.phase}, no plan`,
|
|
145
|
+
alternatives: [],
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 判断请求是否复杂(需要创建 plan)
|
|
151
|
+
*/
|
|
152
|
+
private isComplexRequest(request: string): boolean {
|
|
153
|
+
const complexityIndicators = [
|
|
154
|
+
/implement|实现/i,
|
|
155
|
+
/feature|功能/i,
|
|
156
|
+
/refactor|重构/i,
|
|
157
|
+
/architecture|架构/i,
|
|
158
|
+
/design|设计/i,
|
|
159
|
+
/multiple|多个/i,
|
|
160
|
+
/steps?|步骤/i,
|
|
161
|
+
/phase|阶段/i,
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
const indicatorCount = complexityIndicators.filter((pattern) =>
|
|
165
|
+
pattern.test(request)
|
|
166
|
+
).length
|
|
167
|
+
|
|
168
|
+
// 如果匹配多个复杂度指标,认为是复杂请求
|
|
169
|
+
return indicatorCount >= 2 || request.length > 100
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
getSupportedSkills(): string[] {
|
|
173
|
+
return ['to-plan', 'execute-plan', 'quick-task', 'review-diff', 'systematic-debugging', 'research']
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
getHealth(): NamespaceHealth {
|
|
177
|
+
return {
|
|
178
|
+
name: this.name,
|
|
179
|
+
status: this.successRate() > 0.8 ? 'healthy' : 'degraded',
|
|
180
|
+
totalRoutes: this.routeCount,
|
|
181
|
+
successRate: this.successRate(),
|
|
182
|
+
avgLatency: this.routeCount > 0 ? this.totalLatency / this.routeCount : 0,
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private successRate(): number {
|
|
187
|
+
return this.routeCount > 0 ? this.successCount / this.routeCount : 1.0
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export const stateRouter = new StateRouter()
|
|
192
|
+
export default stateRouter
|