digital-workers 2.0.2 → 2.1.3
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/.turbo/turbo-build.log +4 -5
- package/CHANGELOG.md +31 -0
- package/LICENSE +21 -0
- package/README.md +134 -180
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +1 -0
- package/dist/actions.js.map +1 -1
- package/dist/agent-comms.d.ts +438 -0
- package/dist/agent-comms.d.ts.map +1 -0
- package/dist/agent-comms.js +666 -0
- package/dist/agent-comms.js.map +1 -0
- package/dist/capability-tiers.d.ts +230 -0
- package/dist/capability-tiers.d.ts.map +1 -0
- package/dist/capability-tiers.js +388 -0
- package/dist/capability-tiers.js.map +1 -0
- package/dist/cascade-context.d.ts +523 -0
- package/dist/cascade-context.d.ts.map +1 -0
- package/dist/cascade-context.js +494 -0
- package/dist/cascade-context.js.map +1 -0
- package/dist/error-escalation.d.ts +416 -0
- package/dist/error-escalation.d.ts.map +1 -0
- package/dist/error-escalation.js +656 -0
- package/dist/error-escalation.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -1
- package/dist/load-balancing.d.ts +395 -0
- package/dist/load-balancing.d.ts.map +1 -0
- package/dist/load-balancing.js +905 -0
- package/dist/load-balancing.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/package.json +14 -14
- package/src/actions.js +436 -0
- package/src/actions.ts +9 -8
- package/src/agent-comms.ts +1238 -0
- package/src/approve.js +234 -0
- package/src/ask.js +226 -0
- package/src/capability-tiers.ts +545 -0
- package/src/cascade-context.ts +648 -0
- package/src/decide.js +244 -0
- package/src/do.js +227 -0
- package/src/error-escalation.ts +1135 -0
- package/src/generate.js +298 -0
- package/src/goals.js +205 -0
- package/src/index.js +68 -0
- package/src/index.ts +223 -0
- package/src/is.js +317 -0
- package/src/kpis.js +270 -0
- package/src/load-balancing.ts +1381 -0
- package/src/notify.js +219 -0
- package/src/role.js +110 -0
- package/src/team.js +130 -0
- package/src/transports.js +357 -0
- package/src/types.js +71 -0
- package/src/types.ts +8 -0
- package/test/actions.test.js +401 -0
- package/test/agent-comms.test.ts +1397 -0
- package/test/capability-tiers.test.ts +631 -0
- package/test/cascade-context.test.ts +692 -0
- package/test/error-escalation.test.ts +1205 -0
- package/test/load-balancing-thread-safety.test.ts +464 -0
- package/test/load-balancing.test.ts +1145 -0
- package/test/standalone.test.js +250 -0
- package/test/types.test.js +371 -0
- package/test/types.test.ts +35 -0
|
@@ -0,0 +1,631 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability Tiers Tests
|
|
3
|
+
*
|
|
4
|
+
* TDD tests for agent capability tiers with complexity levels and toolsets.
|
|
5
|
+
* Following the cascade pattern: code < generative < agentic < human
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, expectTypeOf } from 'vitest'
|
|
9
|
+
import type {
|
|
10
|
+
CapabilityTier,
|
|
11
|
+
CapabilityProfile,
|
|
12
|
+
TierConfig,
|
|
13
|
+
TierToolset,
|
|
14
|
+
TaskComplexity,
|
|
15
|
+
TierMatchResult,
|
|
16
|
+
TierEscalation,
|
|
17
|
+
} from '../src/capability-tiers.js'
|
|
18
|
+
import {
|
|
19
|
+
CAPABILITY_TIERS,
|
|
20
|
+
TIER_ORDER,
|
|
21
|
+
createCapabilityProfile,
|
|
22
|
+
compareTiers,
|
|
23
|
+
isHigherTier,
|
|
24
|
+
isLowerTier,
|
|
25
|
+
getNextTier,
|
|
26
|
+
getPreviousTier,
|
|
27
|
+
matchTierToComplexity,
|
|
28
|
+
canExecuteAtTier,
|
|
29
|
+
getToolsForTier,
|
|
30
|
+
getTierConfig,
|
|
31
|
+
validateTierEscalation,
|
|
32
|
+
TierRegistry,
|
|
33
|
+
} from '../src/capability-tiers.js'
|
|
34
|
+
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// Capability Tier Definition Tests
|
|
37
|
+
// ============================================================================
|
|
38
|
+
|
|
39
|
+
describe('CapabilityTier', () => {
|
|
40
|
+
describe('tier values', () => {
|
|
41
|
+
it('should define the four core tiers', () => {
|
|
42
|
+
expect(CAPABILITY_TIERS).toContain('code')
|
|
43
|
+
expect(CAPABILITY_TIERS).toContain('generative')
|
|
44
|
+
expect(CAPABILITY_TIERS).toContain('agentic')
|
|
45
|
+
expect(CAPABILITY_TIERS).toContain('human')
|
|
46
|
+
expect(CAPABILITY_TIERS).toHaveLength(4)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('should have correct tier order (code < generative < agentic < human)', () => {
|
|
50
|
+
expect(TIER_ORDER.code).toBe(0)
|
|
51
|
+
expect(TIER_ORDER.generative).toBe(1)
|
|
52
|
+
expect(TIER_ORDER.agentic).toBe(2)
|
|
53
|
+
expect(TIER_ORDER.human).toBe(3)
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
describe('tier comparison', () => {
|
|
58
|
+
it('should compare tiers correctly', () => {
|
|
59
|
+
expect(compareTiers('code', 'generative')).toBeLessThan(0)
|
|
60
|
+
expect(compareTiers('generative', 'code')).toBeGreaterThan(0)
|
|
61
|
+
expect(compareTiers('code', 'code')).toBe(0)
|
|
62
|
+
expect(compareTiers('agentic', 'human')).toBeLessThan(0)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('should identify higher tiers', () => {
|
|
66
|
+
expect(isHigherTier('generative', 'code')).toBe(true)
|
|
67
|
+
expect(isHigherTier('agentic', 'generative')).toBe(true)
|
|
68
|
+
expect(isHigherTier('human', 'agentic')).toBe(true)
|
|
69
|
+
expect(isHigherTier('code', 'generative')).toBe(false)
|
|
70
|
+
expect(isHigherTier('code', 'code')).toBe(false)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('should identify lower tiers', () => {
|
|
74
|
+
expect(isLowerTier('code', 'generative')).toBe(true)
|
|
75
|
+
expect(isLowerTier('generative', 'agentic')).toBe(true)
|
|
76
|
+
expect(isLowerTier('agentic', 'human')).toBe(true)
|
|
77
|
+
expect(isLowerTier('generative', 'code')).toBe(false)
|
|
78
|
+
expect(isLowerTier('code', 'code')).toBe(false)
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('should get next tier in escalation', () => {
|
|
82
|
+
expect(getNextTier('code')).toBe('generative')
|
|
83
|
+
expect(getNextTier('generative')).toBe('agentic')
|
|
84
|
+
expect(getNextTier('agentic')).toBe('human')
|
|
85
|
+
expect(getNextTier('human')).toBeNull()
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('should get previous tier in de-escalation', () => {
|
|
89
|
+
expect(getPreviousTier('human')).toBe('agentic')
|
|
90
|
+
expect(getPreviousTier('agentic')).toBe('generative')
|
|
91
|
+
expect(getPreviousTier('generative')).toBe('code')
|
|
92
|
+
expect(getPreviousTier('code')).toBeNull()
|
|
93
|
+
})
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
// ============================================================================
|
|
98
|
+
// Capability Profile Tests
|
|
99
|
+
// ============================================================================
|
|
100
|
+
|
|
101
|
+
describe('CapabilityProfile', () => {
|
|
102
|
+
describe('profile creation', () => {
|
|
103
|
+
it('should create a valid capability profile', () => {
|
|
104
|
+
const profile = createCapabilityProfile({
|
|
105
|
+
name: 'basic-code-executor',
|
|
106
|
+
tier: 'code',
|
|
107
|
+
complexityRating: 1,
|
|
108
|
+
tools: ['calculate', 'lookup'],
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
expect(profile.name).toBe('basic-code-executor')
|
|
112
|
+
expect(profile.tier).toBe('code')
|
|
113
|
+
expect(profile.complexityRating).toBe(1)
|
|
114
|
+
expect(profile.tools).toEqual(['calculate', 'lookup'])
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('should have required fields', () => {
|
|
118
|
+
const profile = createCapabilityProfile({
|
|
119
|
+
name: 'test-profile',
|
|
120
|
+
tier: 'generative',
|
|
121
|
+
complexityRating: 3,
|
|
122
|
+
tools: [],
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
expect(profile).toHaveProperty('name')
|
|
126
|
+
expect(profile).toHaveProperty('tier')
|
|
127
|
+
expect(profile).toHaveProperty('complexityRating')
|
|
128
|
+
expect(profile).toHaveProperty('tools')
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('should support optional description', () => {
|
|
132
|
+
const profile = createCapabilityProfile({
|
|
133
|
+
name: 'described-profile',
|
|
134
|
+
tier: 'agentic',
|
|
135
|
+
complexityRating: 7,
|
|
136
|
+
tools: ['browse', 'execute'],
|
|
137
|
+
description: 'An agentic profile with web and code capabilities',
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
expect(profile.description).toBe('An agentic profile with web and code capabilities')
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('should support optional constraints', () => {
|
|
144
|
+
const profile = createCapabilityProfile({
|
|
145
|
+
name: 'constrained-profile',
|
|
146
|
+
tier: 'generative',
|
|
147
|
+
complexityRating: 4,
|
|
148
|
+
tools: ['generate'],
|
|
149
|
+
constraints: {
|
|
150
|
+
maxTokens: 4000,
|
|
151
|
+
allowedDomains: ['internal'],
|
|
152
|
+
requiresApproval: false,
|
|
153
|
+
},
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
expect(profile.constraints?.maxTokens).toBe(4000)
|
|
157
|
+
expect(profile.constraints?.allowedDomains).toEqual(['internal'])
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
describe('profile validation', () => {
|
|
162
|
+
it('should validate complexity rating is within tier bounds', () => {
|
|
163
|
+
// Code tier: complexity 1-2
|
|
164
|
+
expect(() => createCapabilityProfile({
|
|
165
|
+
name: 'invalid',
|
|
166
|
+
tier: 'code',
|
|
167
|
+
complexityRating: 5, // Too high for code tier
|
|
168
|
+
tools: [],
|
|
169
|
+
})).toThrow()
|
|
170
|
+
|
|
171
|
+
// Human tier: complexity 8-10
|
|
172
|
+
expect(() => createCapabilityProfile({
|
|
173
|
+
name: 'invalid',
|
|
174
|
+
tier: 'human',
|
|
175
|
+
complexityRating: 2, // Too low for human tier
|
|
176
|
+
tools: [],
|
|
177
|
+
})).toThrow()
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it('should validate tier-appropriate tools', () => {
|
|
181
|
+
// Code tier should not have agentic tools
|
|
182
|
+
expect(() => createCapabilityProfile({
|
|
183
|
+
name: 'invalid',
|
|
184
|
+
tier: 'code',
|
|
185
|
+
complexityRating: 1,
|
|
186
|
+
tools: ['autonomous-browse'], // Agentic tool not allowed at code tier
|
|
187
|
+
})).toThrow()
|
|
188
|
+
})
|
|
189
|
+
})
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
// ============================================================================
|
|
193
|
+
// Tier Configuration Tests
|
|
194
|
+
// ============================================================================
|
|
195
|
+
|
|
196
|
+
describe('TierConfig', () => {
|
|
197
|
+
describe('getTierConfig', () => {
|
|
198
|
+
it('should return config for code tier', () => {
|
|
199
|
+
const config = getTierConfig('code')
|
|
200
|
+
|
|
201
|
+
expect(config.tier).toBe('code')
|
|
202
|
+
expect(config.minComplexity).toBe(1)
|
|
203
|
+
expect(config.maxComplexity).toBe(2)
|
|
204
|
+
expect(config.description).toBeDefined()
|
|
205
|
+
expect(config.allowedTools).toBeDefined()
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it('should return config for generative tier', () => {
|
|
209
|
+
const config = getTierConfig('generative')
|
|
210
|
+
|
|
211
|
+
expect(config.tier).toBe('generative')
|
|
212
|
+
expect(config.minComplexity).toBe(3)
|
|
213
|
+
expect(config.maxComplexity).toBe(5)
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
it('should return config for agentic tier', () => {
|
|
217
|
+
const config = getTierConfig('agentic')
|
|
218
|
+
|
|
219
|
+
expect(config.tier).toBe('agentic')
|
|
220
|
+
expect(config.minComplexity).toBe(6)
|
|
221
|
+
expect(config.maxComplexity).toBe(8)
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
it('should return config for human tier', () => {
|
|
225
|
+
const config = getTierConfig('human')
|
|
226
|
+
|
|
227
|
+
expect(config.tier).toBe('human')
|
|
228
|
+
expect(config.minComplexity).toBe(9)
|
|
229
|
+
expect(config.maxComplexity).toBe(10)
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
it('should include timeout configuration per tier', () => {
|
|
233
|
+
const codeConfig = getTierConfig('code')
|
|
234
|
+
const agenticConfig = getTierConfig('agentic')
|
|
235
|
+
const humanConfig = getTierConfig('human')
|
|
236
|
+
|
|
237
|
+
// Code should be fastest
|
|
238
|
+
expect(codeConfig.defaultTimeout).toBeLessThan(agenticConfig.defaultTimeout)
|
|
239
|
+
// Human should have longest timeout
|
|
240
|
+
expect(humanConfig.defaultTimeout).toBeGreaterThan(agenticConfig.defaultTimeout)
|
|
241
|
+
})
|
|
242
|
+
})
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
// ============================================================================
|
|
246
|
+
// Tier Toolset Tests
|
|
247
|
+
// ============================================================================
|
|
248
|
+
|
|
249
|
+
describe('TierToolset', () => {
|
|
250
|
+
describe('getToolsForTier', () => {
|
|
251
|
+
it('should return deterministic tools for code tier', () => {
|
|
252
|
+
const tools = getToolsForTier('code')
|
|
253
|
+
|
|
254
|
+
expect(tools).toContain('calculate')
|
|
255
|
+
expect(tools).toContain('lookup')
|
|
256
|
+
expect(tools).toContain('validate')
|
|
257
|
+
expect(tools).toContain('transform')
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
it('should return LLM tools for generative tier', () => {
|
|
261
|
+
const tools = getToolsForTier('generative')
|
|
262
|
+
|
|
263
|
+
expect(tools).toContain('generate')
|
|
264
|
+
expect(tools).toContain('summarize')
|
|
265
|
+
expect(tools).toContain('analyze')
|
|
266
|
+
expect(tools).toContain('classify')
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
it('should return autonomous tools for agentic tier', () => {
|
|
270
|
+
const tools = getToolsForTier('agentic')
|
|
271
|
+
|
|
272
|
+
expect(tools).toContain('browse')
|
|
273
|
+
expect(tools).toContain('execute')
|
|
274
|
+
expect(tools).toContain('plan')
|
|
275
|
+
expect(tools).toContain('delegate')
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
it('should return HITL tools for human tier', () => {
|
|
279
|
+
const tools = getToolsForTier('human')
|
|
280
|
+
|
|
281
|
+
expect(tools).toContain('approve')
|
|
282
|
+
expect(tools).toContain('review')
|
|
283
|
+
expect(tools).toContain('decide')
|
|
284
|
+
expect(tools).toContain('escalate')
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
it('should include lower tier tools in higher tiers', () => {
|
|
288
|
+
const generativeTools = getToolsForTier('generative')
|
|
289
|
+
const agenticTools = getToolsForTier('agentic')
|
|
290
|
+
const humanTools = getToolsForTier('human')
|
|
291
|
+
|
|
292
|
+
// Generative should include code tools
|
|
293
|
+
expect(generativeTools).toContain('calculate')
|
|
294
|
+
|
|
295
|
+
// Agentic should include generative and code tools
|
|
296
|
+
expect(agenticTools).toContain('calculate')
|
|
297
|
+
expect(agenticTools).toContain('generate')
|
|
298
|
+
|
|
299
|
+
// Human should include all lower tier tools
|
|
300
|
+
expect(humanTools).toContain('calculate')
|
|
301
|
+
expect(humanTools).toContain('generate')
|
|
302
|
+
expect(humanTools).toContain('browse')
|
|
303
|
+
})
|
|
304
|
+
})
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
// ============================================================================
|
|
308
|
+
// Task Complexity Matching Tests
|
|
309
|
+
// ============================================================================
|
|
310
|
+
|
|
311
|
+
describe('Task Complexity Matching', () => {
|
|
312
|
+
describe('matchTierToComplexity', () => {
|
|
313
|
+
it('should match low complexity to code tier', () => {
|
|
314
|
+
const result = matchTierToComplexity(1)
|
|
315
|
+
expect(result.tier).toBe('code')
|
|
316
|
+
expect(result.confidence).toBeGreaterThan(0.9)
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
it('should match medium-low complexity to generative tier', () => {
|
|
320
|
+
const result = matchTierToComplexity(4)
|
|
321
|
+
expect(result.tier).toBe('generative')
|
|
322
|
+
expect(result.confidence).toBeGreaterThan(0.8)
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
it('should match medium-high complexity to agentic tier', () => {
|
|
326
|
+
const result = matchTierToComplexity(7)
|
|
327
|
+
expect(result.tier).toBe('agentic')
|
|
328
|
+
expect(result.confidence).toBeGreaterThan(0.8)
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
it('should match high complexity to human tier', () => {
|
|
332
|
+
const result = matchTierToComplexity(10)
|
|
333
|
+
expect(result.tier).toBe('human')
|
|
334
|
+
expect(result.confidence).toBeGreaterThan(0.9)
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
it('should handle boundary cases', () => {
|
|
338
|
+
// Boundary between code and generative
|
|
339
|
+
const result2_3 = matchTierToComplexity(2.5)
|
|
340
|
+
expect(['code', 'generative']).toContain(result2_3.tier)
|
|
341
|
+
|
|
342
|
+
// Boundary between generative and agentic
|
|
343
|
+
const result5_6 = matchTierToComplexity(5.5)
|
|
344
|
+
expect(['generative', 'agentic']).toContain(result5_6.tier)
|
|
345
|
+
|
|
346
|
+
// Boundary between agentic and human
|
|
347
|
+
const result8_9 = matchTierToComplexity(8.5)
|
|
348
|
+
expect(['agentic', 'human']).toContain(result8_9.tier)
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
it('should include suggested tools in result', () => {
|
|
352
|
+
const result = matchTierToComplexity(4)
|
|
353
|
+
expect(result.suggestedTools).toBeDefined()
|
|
354
|
+
expect(result.suggestedTools.length).toBeGreaterThan(0)
|
|
355
|
+
})
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
describe('canExecuteAtTier', () => {
|
|
359
|
+
it('should return true when tier matches or exceeds complexity', () => {
|
|
360
|
+
expect(canExecuteAtTier('code', 1)).toBe(true)
|
|
361
|
+
expect(canExecuteAtTier('generative', 3)).toBe(true)
|
|
362
|
+
expect(canExecuteAtTier('agentic', 6)).toBe(true)
|
|
363
|
+
expect(canExecuteAtTier('human', 10)).toBe(true)
|
|
364
|
+
})
|
|
365
|
+
|
|
366
|
+
it('should return true for higher tiers handling lower complexity', () => {
|
|
367
|
+
expect(canExecuteAtTier('generative', 1)).toBe(true) // generative can do code work
|
|
368
|
+
expect(canExecuteAtTier('agentic', 4)).toBe(true) // agentic can do generative work
|
|
369
|
+
expect(canExecuteAtTier('human', 2)).toBe(true) // human can do any work
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
it('should return false for lower tiers handling higher complexity', () => {
|
|
373
|
+
expect(canExecuteAtTier('code', 5)).toBe(false) // code cannot do generative work
|
|
374
|
+
expect(canExecuteAtTier('generative', 7)).toBe(false) // generative cannot do agentic work
|
|
375
|
+
expect(canExecuteAtTier('agentic', 10)).toBe(false) // agentic cannot do human work
|
|
376
|
+
})
|
|
377
|
+
})
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
// ============================================================================
|
|
381
|
+
// Tier Escalation Tests
|
|
382
|
+
// ============================================================================
|
|
383
|
+
|
|
384
|
+
describe('Tier Escalation', () => {
|
|
385
|
+
describe('validateTierEscalation', () => {
|
|
386
|
+
it('should allow valid escalation to next tier', () => {
|
|
387
|
+
const escalation: TierEscalation = {
|
|
388
|
+
fromTier: 'code',
|
|
389
|
+
toTier: 'generative',
|
|
390
|
+
reason: 'Task requires natural language understanding',
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const result = validateTierEscalation(escalation)
|
|
394
|
+
expect(result.valid).toBe(true)
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
it('should allow multi-level escalation with justification', () => {
|
|
398
|
+
const escalation: TierEscalation = {
|
|
399
|
+
fromTier: 'code',
|
|
400
|
+
toTier: 'agentic',
|
|
401
|
+
reason: 'Task requires autonomous decision making',
|
|
402
|
+
skipJustification: 'Generative tier insufficient for task complexity',
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const result = validateTierEscalation(escalation)
|
|
406
|
+
expect(result.valid).toBe(true)
|
|
407
|
+
})
|
|
408
|
+
|
|
409
|
+
it('should reject multi-level escalation without justification', () => {
|
|
410
|
+
const escalation: TierEscalation = {
|
|
411
|
+
fromTier: 'code',
|
|
412
|
+
toTier: 'agentic',
|
|
413
|
+
reason: 'Task requires autonomous decision making',
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const result = validateTierEscalation(escalation)
|
|
417
|
+
expect(result.valid).toBe(false)
|
|
418
|
+
expect(result.error).toContain('skipJustification')
|
|
419
|
+
})
|
|
420
|
+
|
|
421
|
+
it('should reject de-escalation without explicit flag', () => {
|
|
422
|
+
const escalation: TierEscalation = {
|
|
423
|
+
fromTier: 'agentic',
|
|
424
|
+
toTier: 'code',
|
|
425
|
+
reason: 'Simpler approach found',
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const result = validateTierEscalation(escalation)
|
|
429
|
+
expect(result.valid).toBe(false)
|
|
430
|
+
expect(result.error).toContain('de-escalation')
|
|
431
|
+
})
|
|
432
|
+
|
|
433
|
+
it('should allow de-escalation with explicit flag', () => {
|
|
434
|
+
const escalation: TierEscalation = {
|
|
435
|
+
fromTier: 'agentic',
|
|
436
|
+
toTier: 'code',
|
|
437
|
+
reason: 'Simpler approach found',
|
|
438
|
+
allowDeescalation: true,
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const result = validateTierEscalation(escalation)
|
|
442
|
+
expect(result.valid).toBe(true)
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
it('should require reason for any escalation', () => {
|
|
446
|
+
const escalation: TierEscalation = {
|
|
447
|
+
fromTier: 'code',
|
|
448
|
+
toTier: 'generative',
|
|
449
|
+
reason: '', // Empty reason
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const result = validateTierEscalation(escalation)
|
|
453
|
+
expect(result.valid).toBe(false)
|
|
454
|
+
expect(result.error).toContain('reason')
|
|
455
|
+
})
|
|
456
|
+
})
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
// ============================================================================
|
|
460
|
+
// Tier Registry Tests
|
|
461
|
+
// ============================================================================
|
|
462
|
+
|
|
463
|
+
describe('TierRegistry', () => {
|
|
464
|
+
it('should register custom capability profiles', () => {
|
|
465
|
+
const registry = new TierRegistry()
|
|
466
|
+
|
|
467
|
+
registry.register({
|
|
468
|
+
name: 'custom-analyst',
|
|
469
|
+
tier: 'generative',
|
|
470
|
+
complexityRating: 4,
|
|
471
|
+
tools: ['summarize', 'classify', 'analyze'],
|
|
472
|
+
description: 'Specialized text analysis profile',
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
const profile = registry.get('custom-analyst')
|
|
476
|
+
expect(profile).toBeDefined()
|
|
477
|
+
expect(profile?.tier).toBe('generative')
|
|
478
|
+
})
|
|
479
|
+
|
|
480
|
+
it('should list profiles by tier', () => {
|
|
481
|
+
const registry = new TierRegistry()
|
|
482
|
+
|
|
483
|
+
registry.register({
|
|
484
|
+
name: 'gen-1',
|
|
485
|
+
tier: 'generative',
|
|
486
|
+
complexityRating: 3,
|
|
487
|
+
tools: ['generate'],
|
|
488
|
+
})
|
|
489
|
+
|
|
490
|
+
registry.register({
|
|
491
|
+
name: 'gen-2',
|
|
492
|
+
tier: 'generative',
|
|
493
|
+
complexityRating: 4,
|
|
494
|
+
tools: ['summarize'],
|
|
495
|
+
})
|
|
496
|
+
|
|
497
|
+
registry.register({
|
|
498
|
+
name: 'code-1',
|
|
499
|
+
tier: 'code',
|
|
500
|
+
complexityRating: 1,
|
|
501
|
+
tools: ['calculate'],
|
|
502
|
+
})
|
|
503
|
+
|
|
504
|
+
const generativeProfiles = registry.listByTier('generative')
|
|
505
|
+
expect(generativeProfiles).toHaveLength(2)
|
|
506
|
+
expect(generativeProfiles.map(p => p.name)).toContain('gen-1')
|
|
507
|
+
expect(generativeProfiles.map(p => p.name)).toContain('gen-2')
|
|
508
|
+
})
|
|
509
|
+
|
|
510
|
+
it('should find profiles matching complexity requirements', () => {
|
|
511
|
+
const registry = new TierRegistry()
|
|
512
|
+
|
|
513
|
+
registry.register({
|
|
514
|
+
name: 'simple-code',
|
|
515
|
+
tier: 'code',
|
|
516
|
+
complexityRating: 1,
|
|
517
|
+
tools: ['calculate'],
|
|
518
|
+
})
|
|
519
|
+
|
|
520
|
+
registry.register({
|
|
521
|
+
name: 'advanced-agent',
|
|
522
|
+
tier: 'agentic',
|
|
523
|
+
complexityRating: 7,
|
|
524
|
+
tools: ['browse', 'execute'],
|
|
525
|
+
})
|
|
526
|
+
|
|
527
|
+
const matches = registry.findByComplexity(7)
|
|
528
|
+
expect(matches.length).toBeGreaterThan(0)
|
|
529
|
+
expect(matches.some(m => m.name === 'advanced-agent')).toBe(true)
|
|
530
|
+
expect(matches.some(m => m.name === 'simple-code')).toBe(false)
|
|
531
|
+
})
|
|
532
|
+
|
|
533
|
+
it('should find profiles with required tools', () => {
|
|
534
|
+
const registry = new TierRegistry()
|
|
535
|
+
|
|
536
|
+
registry.register({
|
|
537
|
+
name: 'browser-agent',
|
|
538
|
+
tier: 'agentic',
|
|
539
|
+
complexityRating: 6,
|
|
540
|
+
tools: ['browse', 'plan'],
|
|
541
|
+
})
|
|
542
|
+
|
|
543
|
+
registry.register({
|
|
544
|
+
name: 'code-agent',
|
|
545
|
+
tier: 'agentic',
|
|
546
|
+
complexityRating: 7,
|
|
547
|
+
tools: ['execute', 'delegate'],
|
|
548
|
+
})
|
|
549
|
+
|
|
550
|
+
const browserProfiles = registry.findByTools(['browse'])
|
|
551
|
+
expect(browserProfiles).toHaveLength(1)
|
|
552
|
+
expect(browserProfiles[0].name).toBe('browser-agent')
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
it('should support profile unregistration', () => {
|
|
556
|
+
const registry = new TierRegistry()
|
|
557
|
+
|
|
558
|
+
registry.register({
|
|
559
|
+
name: 'temp-profile',
|
|
560
|
+
tier: 'code',
|
|
561
|
+
complexityRating: 1,
|
|
562
|
+
tools: [],
|
|
563
|
+
})
|
|
564
|
+
|
|
565
|
+
expect(registry.get('temp-profile')).toBeDefined()
|
|
566
|
+
|
|
567
|
+
registry.unregister('temp-profile')
|
|
568
|
+
expect(registry.get('temp-profile')).toBeUndefined()
|
|
569
|
+
})
|
|
570
|
+
|
|
571
|
+
it('should prevent duplicate registrations', () => {
|
|
572
|
+
const registry = new TierRegistry()
|
|
573
|
+
|
|
574
|
+
registry.register({
|
|
575
|
+
name: 'unique-profile',
|
|
576
|
+
tier: 'code',
|
|
577
|
+
complexityRating: 1,
|
|
578
|
+
tools: [],
|
|
579
|
+
})
|
|
580
|
+
|
|
581
|
+
expect(() => registry.register({
|
|
582
|
+
name: 'unique-profile',
|
|
583
|
+
tier: 'generative',
|
|
584
|
+
complexityRating: 3,
|
|
585
|
+
tools: [],
|
|
586
|
+
})).toThrow()
|
|
587
|
+
})
|
|
588
|
+
})
|
|
589
|
+
|
|
590
|
+
// ============================================================================
|
|
591
|
+
// Type Tests
|
|
592
|
+
// ============================================================================
|
|
593
|
+
|
|
594
|
+
describe('Type Definitions', () => {
|
|
595
|
+
it('should have correct CapabilityTier type', () => {
|
|
596
|
+
const tier: CapabilityTier = 'code'
|
|
597
|
+
expectTypeOf(tier).toMatchTypeOf<'code' | 'generative' | 'agentic' | 'human'>()
|
|
598
|
+
})
|
|
599
|
+
|
|
600
|
+
it('should have correct CapabilityProfile type', () => {
|
|
601
|
+
const profile: CapabilityProfile = {
|
|
602
|
+
name: 'test',
|
|
603
|
+
tier: 'code',
|
|
604
|
+
complexityRating: 1,
|
|
605
|
+
tools: [],
|
|
606
|
+
}
|
|
607
|
+
expectTypeOf(profile).toHaveProperty('name')
|
|
608
|
+
expectTypeOf(profile).toHaveProperty('tier')
|
|
609
|
+
expectTypeOf(profile).toHaveProperty('complexityRating')
|
|
610
|
+
expectTypeOf(profile).toHaveProperty('tools')
|
|
611
|
+
})
|
|
612
|
+
|
|
613
|
+
it('should have correct TierConfig type', () => {
|
|
614
|
+
const config: TierConfig = {
|
|
615
|
+
tier: 'code',
|
|
616
|
+
minComplexity: 1,
|
|
617
|
+
maxComplexity: 2,
|
|
618
|
+
description: 'Code tier',
|
|
619
|
+
allowedTools: ['calculate'],
|
|
620
|
+
defaultTimeout: 5000,
|
|
621
|
+
}
|
|
622
|
+
expectTypeOf(config).toHaveProperty('tier')
|
|
623
|
+
expectTypeOf(config).toHaveProperty('minComplexity')
|
|
624
|
+
expectTypeOf(config).toHaveProperty('maxComplexity')
|
|
625
|
+
})
|
|
626
|
+
|
|
627
|
+
it('should have correct TaskComplexity type', () => {
|
|
628
|
+
const complexity: TaskComplexity = 5
|
|
629
|
+
expectTypeOf(complexity).toMatchTypeOf<number>()
|
|
630
|
+
})
|
|
631
|
+
})
|