cognitive-modules-cli 2.2.0 → 2.2.1
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/cli.js +65 -12
- package/dist/commands/compose.d.ts +31 -0
- package/dist/commands/compose.js +148 -0
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.js +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -1
- package/dist/modules/composition.d.ts +251 -0
- package/dist/modules/composition.js +1265 -0
- package/dist/modules/composition.test.d.ts +11 -0
- package/dist/modules/composition.test.js +450 -0
- package/dist/modules/index.d.ts +2 -0
- package/dist/modules/index.js +2 -0
- package/dist/modules/loader.d.ts +22 -2
- package/dist/modules/loader.js +167 -4
- package/dist/modules/policy.test.d.ts +10 -0
- package/dist/modules/policy.test.js +369 -0
- package/dist/modules/runner.d.ts +357 -1
- package/dist/modules/runner.js +1221 -64
- package/dist/modules/subagent.js +2 -0
- package/dist/modules/validator.d.ts +28 -0
- package/dist/modules/validator.js +629 -0
- package/dist/types.d.ts +92 -8
- package/package.json +2 -1
- package/src/cli.ts +73 -12
- package/src/commands/compose.ts +185 -0
- package/src/commands/index.ts +1 -0
- package/src/index.ts +35 -0
- package/src/modules/composition.test.ts +558 -0
- package/src/modules/composition.ts +1674 -0
- package/src/modules/index.ts +2 -0
- package/src/modules/loader.ts +196 -6
- package/src/modules/policy.test.ts +455 -0
- package/src/modules/runner.ts +1562 -74
- package/src/modules/subagent.ts +2 -0
- package/src/modules/validator.ts +700 -0
- package/src/types.ts +112 -8
- package/tsconfig.json +1 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Composition Engine
|
|
3
|
+
*
|
|
4
|
+
* Tests all COMPOSITION.md specified functionality:
|
|
5
|
+
* - JSONPath-like expression evaluation
|
|
6
|
+
* - Condition expression evaluation
|
|
7
|
+
* - Aggregation strategies
|
|
8
|
+
* - Version matching
|
|
9
|
+
* - Sequential, Parallel, Conditional, Iterative patterns
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Composition Engine
|
|
3
|
+
*
|
|
4
|
+
* Tests all COMPOSITION.md specified functionality:
|
|
5
|
+
* - JSONPath-like expression evaluation
|
|
6
|
+
* - Condition expression evaluation
|
|
7
|
+
* - Aggregation strategies
|
|
8
|
+
* - Version matching
|
|
9
|
+
* - Sequential, Parallel, Conditional, Iterative patterns
|
|
10
|
+
*/
|
|
11
|
+
import { describe, it, expect } from 'vitest';
|
|
12
|
+
import { evaluateJsonPath, evaluateCondition, applyMapping, aggregateResults, versionMatches, validateCompositionConfig, } from './composition.js';
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// JSONPath Expression Tests
|
|
15
|
+
// =============================================================================
|
|
16
|
+
describe('evaluateJsonPath', () => {
|
|
17
|
+
const testData = {
|
|
18
|
+
name: 'test',
|
|
19
|
+
nested: {
|
|
20
|
+
value: 42,
|
|
21
|
+
deep: {
|
|
22
|
+
array: [1, 2, 3]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
items: [
|
|
26
|
+
{ id: 1, name: 'a' },
|
|
27
|
+
{ id: 2, name: 'b' },
|
|
28
|
+
{ id: 3, name: 'c' }
|
|
29
|
+
],
|
|
30
|
+
meta: {
|
|
31
|
+
confidence: 0.95,
|
|
32
|
+
risk: 'low'
|
|
33
|
+
},
|
|
34
|
+
// Test hyphenated field names (Bug fix)
|
|
35
|
+
'quick-check': {
|
|
36
|
+
meta: {
|
|
37
|
+
confidence: 0.85
|
|
38
|
+
},
|
|
39
|
+
data: {
|
|
40
|
+
result: 'success'
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
it('should return entire object for $', () => {
|
|
45
|
+
expect(evaluateJsonPath('$', testData)).toEqual(testData);
|
|
46
|
+
});
|
|
47
|
+
it('should access root field with $.field', () => {
|
|
48
|
+
expect(evaluateJsonPath('$.name', testData)).toBe('test');
|
|
49
|
+
});
|
|
50
|
+
it('should access nested field with $.nested.field', () => {
|
|
51
|
+
expect(evaluateJsonPath('$.nested.value', testData)).toBe(42);
|
|
52
|
+
expect(evaluateJsonPath('$.nested.deep.array', testData)).toEqual([1, 2, 3]);
|
|
53
|
+
});
|
|
54
|
+
it('should access array index with $.array[0]', () => {
|
|
55
|
+
expect(evaluateJsonPath('$.items[0]', testData)).toEqual({ id: 1, name: 'a' });
|
|
56
|
+
expect(evaluateJsonPath('$.items[1].name', testData)).toBe('b');
|
|
57
|
+
expect(evaluateJsonPath('$.nested.deep.array[2]', testData)).toBe(3);
|
|
58
|
+
});
|
|
59
|
+
it('should map over array with $.array[*].field', () => {
|
|
60
|
+
expect(evaluateJsonPath('$.items[*].name', testData)).toEqual(['a', 'b', 'c']);
|
|
61
|
+
expect(evaluateJsonPath('$.items[*].id', testData)).toEqual([1, 2, 3]);
|
|
62
|
+
});
|
|
63
|
+
it('should return undefined for non-existent paths', () => {
|
|
64
|
+
expect(evaluateJsonPath('$.nonexistent', testData)).toBeUndefined();
|
|
65
|
+
expect(evaluateJsonPath('$.nested.nonexistent', testData)).toBeUndefined();
|
|
66
|
+
expect(evaluateJsonPath('$.items[99]', testData)).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
it('should return literal values for non-JSONPath strings', () => {
|
|
69
|
+
expect(evaluateJsonPath('literal', testData)).toBe('literal');
|
|
70
|
+
expect(evaluateJsonPath('123', testData)).toBe('123');
|
|
71
|
+
});
|
|
72
|
+
it('should handle hyphenated field names', () => {
|
|
73
|
+
expect(evaluateJsonPath('$.quick-check.meta.confidence', testData)).toBe(0.85);
|
|
74
|
+
expect(evaluateJsonPath('$.quick-check.data.result', testData)).toBe('success');
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
// =============================================================================
|
|
78
|
+
// Condition Expression Tests
|
|
79
|
+
// =============================================================================
|
|
80
|
+
describe('evaluateCondition', () => {
|
|
81
|
+
const testData = {
|
|
82
|
+
meta: {
|
|
83
|
+
confidence: 0.85,
|
|
84
|
+
risk: 'low'
|
|
85
|
+
},
|
|
86
|
+
data: {
|
|
87
|
+
count: 5,
|
|
88
|
+
items: [1, 2, 3],
|
|
89
|
+
name: 'test module'
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
describe('comparison operators', () => {
|
|
93
|
+
it('should evaluate > operator', () => {
|
|
94
|
+
expect(evaluateCondition('$.meta.confidence > 0.7', testData)).toBe(true);
|
|
95
|
+
expect(evaluateCondition('$.meta.confidence > 0.9', testData)).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
it('should evaluate < operator', () => {
|
|
98
|
+
expect(evaluateCondition('$.meta.confidence < 0.9', testData)).toBe(true);
|
|
99
|
+
expect(evaluateCondition('$.meta.confidence < 0.5', testData)).toBe(false);
|
|
100
|
+
});
|
|
101
|
+
it('should evaluate >= operator', () => {
|
|
102
|
+
expect(evaluateCondition('$.meta.confidence >= 0.85', testData)).toBe(true);
|
|
103
|
+
expect(evaluateCondition('$.meta.confidence >= 0.9', testData)).toBe(false);
|
|
104
|
+
});
|
|
105
|
+
it('should evaluate <= operator', () => {
|
|
106
|
+
expect(evaluateCondition('$.meta.confidence <= 0.85', testData)).toBe(true);
|
|
107
|
+
expect(evaluateCondition('$.meta.confidence <= 0.5', testData)).toBe(false);
|
|
108
|
+
});
|
|
109
|
+
it('should evaluate == operator', () => {
|
|
110
|
+
expect(evaluateCondition('$.meta.risk == "low"', testData)).toBe(true);
|
|
111
|
+
expect(evaluateCondition('$.meta.risk == "high"', testData)).toBe(false);
|
|
112
|
+
expect(evaluateCondition('$.data.count == 5', testData)).toBe(true);
|
|
113
|
+
});
|
|
114
|
+
it('should evaluate != operator', () => {
|
|
115
|
+
expect(evaluateCondition('$.meta.risk != "high"', testData)).toBe(true);
|
|
116
|
+
expect(evaluateCondition('$.meta.risk != "low"', testData)).toBe(false);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('logical operators', () => {
|
|
120
|
+
it('should evaluate && operator', () => {
|
|
121
|
+
expect(evaluateCondition('$.meta.confidence > 0.7 && $.meta.risk == "low"', testData)).toBe(true);
|
|
122
|
+
expect(evaluateCondition('$.meta.confidence > 0.9 && $.meta.risk == "low"', testData)).toBe(false);
|
|
123
|
+
});
|
|
124
|
+
it('should evaluate || operator', () => {
|
|
125
|
+
expect(evaluateCondition('$.meta.confidence > 0.9 || $.meta.risk == "low"', testData)).toBe(true);
|
|
126
|
+
expect(evaluateCondition('$.meta.confidence > 0.9 || $.meta.risk == "high"', testData)).toBe(false);
|
|
127
|
+
});
|
|
128
|
+
it('should evaluate ! operator', () => {
|
|
129
|
+
expect(evaluateCondition('!false', {})).toBe(true);
|
|
130
|
+
expect(evaluateCondition('!true', {})).toBe(false);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
describe('special functions', () => {
|
|
134
|
+
it('should evaluate exists() function', () => {
|
|
135
|
+
expect(evaluateCondition('exists($.meta.confidence)', testData)).toBe(true);
|
|
136
|
+
expect(evaluateCondition('exists($.meta.nonexistent)', testData)).toBe(false);
|
|
137
|
+
});
|
|
138
|
+
it('should evaluate .length property', () => {
|
|
139
|
+
expect(evaluateCondition('$.data.items.length > 0', testData)).toBe(true);
|
|
140
|
+
expect(evaluateCondition('$.data.items.length == 3', testData)).toBe(true);
|
|
141
|
+
});
|
|
142
|
+
it('should evaluate contains() for strings', () => {
|
|
143
|
+
expect(evaluateCondition('contains($.data.name, "test")', testData)).toBe(true);
|
|
144
|
+
expect(evaluateCondition('contains($.data.name, "xyz")', testData)).toBe(false);
|
|
145
|
+
});
|
|
146
|
+
it('should evaluate contains() for arrays', () => {
|
|
147
|
+
const dataWithArray = {
|
|
148
|
+
tags: ['javascript', 'typescript', 'node']
|
|
149
|
+
};
|
|
150
|
+
expect(evaluateCondition('contains($.tags, "typescript")', dataWithArray)).toBe(true);
|
|
151
|
+
expect(evaluateCondition('contains($.tags, "python")', dataWithArray)).toBe(false);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
describe('hyphenated field names', () => {
|
|
155
|
+
const hyphenData = {
|
|
156
|
+
'quick-check': {
|
|
157
|
+
meta: { confidence: 0.85 },
|
|
158
|
+
data: { result: 'success' }
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
it('should handle hyphenated field names in conditions', () => {
|
|
162
|
+
expect(evaluateCondition('$.quick-check.meta.confidence > 0.8', hyphenData)).toBe(true);
|
|
163
|
+
expect(evaluateCondition('$.quick-check.meta.confidence > 0.9', hyphenData)).toBe(false);
|
|
164
|
+
});
|
|
165
|
+
it('should handle hyphenated fields with string comparison', () => {
|
|
166
|
+
expect(evaluateCondition('$.quick-check.data.result == "success"', hyphenData)).toBe(true);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
// =============================================================================
|
|
171
|
+
// Dataflow Mapping Tests
|
|
172
|
+
// =============================================================================
|
|
173
|
+
describe('applyMapping', () => {
|
|
174
|
+
const sourceData = {
|
|
175
|
+
code: 'function test() {}',
|
|
176
|
+
language: 'javascript',
|
|
177
|
+
nested: {
|
|
178
|
+
value: 42
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
it('should map simple fields', () => {
|
|
182
|
+
const mapping = {
|
|
183
|
+
source_code: '$.code',
|
|
184
|
+
lang: '$.language'
|
|
185
|
+
};
|
|
186
|
+
const result = applyMapping(mapping, sourceData);
|
|
187
|
+
expect(result.source_code).toBe('function test() {}');
|
|
188
|
+
expect(result.lang).toBe('javascript');
|
|
189
|
+
});
|
|
190
|
+
it('should map nested fields', () => {
|
|
191
|
+
const mapping = {
|
|
192
|
+
extracted_value: '$.nested.value'
|
|
193
|
+
};
|
|
194
|
+
const result = applyMapping(mapping, sourceData);
|
|
195
|
+
expect(result.extracted_value).toBe(42);
|
|
196
|
+
});
|
|
197
|
+
it('should handle missing fields', () => {
|
|
198
|
+
const mapping = {
|
|
199
|
+
missing: '$.nonexistent'
|
|
200
|
+
};
|
|
201
|
+
const result = applyMapping(mapping, sourceData);
|
|
202
|
+
expect(result.missing).toBeUndefined();
|
|
203
|
+
});
|
|
204
|
+
it('should pass through entire object with $', () => {
|
|
205
|
+
const mapping = {
|
|
206
|
+
all: '$'
|
|
207
|
+
};
|
|
208
|
+
const result = applyMapping(mapping, sourceData);
|
|
209
|
+
expect(result.all).toEqual(sourceData);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
// =============================================================================
|
|
213
|
+
// Aggregation Strategy Tests
|
|
214
|
+
// =============================================================================
|
|
215
|
+
describe('aggregateResults', () => {
|
|
216
|
+
const createResult = (data, confidence, risk) => ({
|
|
217
|
+
ok: true,
|
|
218
|
+
meta: {
|
|
219
|
+
confidence,
|
|
220
|
+
risk: risk,
|
|
221
|
+
explain: 'Test result'
|
|
222
|
+
},
|
|
223
|
+
data: {
|
|
224
|
+
...data,
|
|
225
|
+
rationale: 'Test rationale'
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
const results = [
|
|
229
|
+
createResult({ field1: 'value1', common: 'first' }, 0.8, 'low'),
|
|
230
|
+
createResult({ field2: 'value2', common: 'second' }, 0.9, 'medium'),
|
|
231
|
+
createResult({ field3: 'value3', common: 'third' }, 0.7, 'none')
|
|
232
|
+
];
|
|
233
|
+
describe('merge strategy', () => {
|
|
234
|
+
it('should deep merge all results (later wins)', () => {
|
|
235
|
+
const merged = aggregateResults(results, 'merge');
|
|
236
|
+
expect(merged.ok).toBe(true);
|
|
237
|
+
expect(merged.data.field1).toBe('value1');
|
|
238
|
+
expect(merged.data.field2).toBe('value2');
|
|
239
|
+
expect(merged.data.field3).toBe('value3');
|
|
240
|
+
expect(merged.data.common).toBe('third'); // Last wins
|
|
241
|
+
});
|
|
242
|
+
it('should aggregate meta values', () => {
|
|
243
|
+
const merged = aggregateResults(results, 'merge');
|
|
244
|
+
// Average confidence
|
|
245
|
+
expect(merged.meta.confidence).toBeCloseTo(0.8, 1);
|
|
246
|
+
// Max risk
|
|
247
|
+
expect(merged.meta.risk).toBe('medium');
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
describe('array strategy', () => {
|
|
251
|
+
it('should collect all results into array', () => {
|
|
252
|
+
const collected = aggregateResults(results, 'array');
|
|
253
|
+
expect(collected.ok).toBe(true);
|
|
254
|
+
const data = collected.data;
|
|
255
|
+
expect(data.results).toHaveLength(3);
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
describe('first strategy', () => {
|
|
259
|
+
it('should return first successful result', () => {
|
|
260
|
+
const first = aggregateResults(results, 'first');
|
|
261
|
+
expect(first.ok).toBe(true);
|
|
262
|
+
expect(first.data.field1).toBe('value1');
|
|
263
|
+
});
|
|
264
|
+
it('should skip failed results', () => {
|
|
265
|
+
const mixedResults = [
|
|
266
|
+
{
|
|
267
|
+
ok: false,
|
|
268
|
+
meta: { confidence: 0, risk: 'high', explain: 'Failed' },
|
|
269
|
+
error: { code: 'E1000', message: 'Error' }
|
|
270
|
+
},
|
|
271
|
+
createResult({ success: true }, 0.9, 'low')
|
|
272
|
+
];
|
|
273
|
+
const first = aggregateResults(mixedResults, 'first');
|
|
274
|
+
expect(first.ok).toBe(true);
|
|
275
|
+
expect(first.data.success).toBe(true);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
describe('edge cases', () => {
|
|
279
|
+
it('should return error for empty results', () => {
|
|
280
|
+
const empty = aggregateResults([], 'merge');
|
|
281
|
+
expect(empty.ok).toBe(false);
|
|
282
|
+
});
|
|
283
|
+
it('should return single result unchanged', () => {
|
|
284
|
+
const single = aggregateResults([results[0]], 'merge');
|
|
285
|
+
expect(single).toEqual(results[0]);
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
// =============================================================================
|
|
290
|
+
// Version Matching Tests
|
|
291
|
+
// =============================================================================
|
|
292
|
+
describe('versionMatches', () => {
|
|
293
|
+
describe('exact version', () => {
|
|
294
|
+
it('should match exact version', () => {
|
|
295
|
+
expect(versionMatches('1.0.0', '1.0.0')).toBe(true);
|
|
296
|
+
expect(versionMatches('1.0.0', '1.0.1')).toBe(false);
|
|
297
|
+
expect(versionMatches('2.0.0', '1.0.0')).toBe(false);
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
describe('wildcard (*)', () => {
|
|
301
|
+
it('should match any version with *', () => {
|
|
302
|
+
expect(versionMatches('1.0.0', '*')).toBe(true);
|
|
303
|
+
expect(versionMatches('99.99.99', '*')).toBe(true);
|
|
304
|
+
});
|
|
305
|
+
it('should match any version with empty pattern', () => {
|
|
306
|
+
expect(versionMatches('1.0.0', '')).toBe(true);
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
describe('>= operator', () => {
|
|
310
|
+
it('should match versions greater than or equal', () => {
|
|
311
|
+
expect(versionMatches('1.0.0', '>=1.0.0')).toBe(true);
|
|
312
|
+
expect(versionMatches('1.1.0', '>=1.0.0')).toBe(true);
|
|
313
|
+
expect(versionMatches('2.0.0', '>=1.0.0')).toBe(true);
|
|
314
|
+
expect(versionMatches('0.9.0', '>=1.0.0')).toBe(false);
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
describe('> operator', () => {
|
|
318
|
+
it('should match versions strictly greater', () => {
|
|
319
|
+
expect(versionMatches('1.0.1', '>1.0.0')).toBe(true);
|
|
320
|
+
expect(versionMatches('1.1.0', '>1.0.0')).toBe(true);
|
|
321
|
+
expect(versionMatches('1.0.0', '>1.0.0')).toBe(false);
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
describe('^ (caret) operator', () => {
|
|
325
|
+
it('should match same major version', () => {
|
|
326
|
+
expect(versionMatches('1.2.3', '^1.0.0')).toBe(true);
|
|
327
|
+
expect(versionMatches('1.0.0', '^1.0.0')).toBe(true);
|
|
328
|
+
expect(versionMatches('2.0.0', '^1.0.0')).toBe(false);
|
|
329
|
+
expect(versionMatches('0.9.0', '^1.0.0')).toBe(false);
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
describe('~ (tilde) operator', () => {
|
|
333
|
+
it('should match same major.minor version', () => {
|
|
334
|
+
expect(versionMatches('1.0.5', '~1.0.0')).toBe(true);
|
|
335
|
+
expect(versionMatches('1.0.0', '~1.0.0')).toBe(true);
|
|
336
|
+
expect(versionMatches('1.1.0', '~1.0.0')).toBe(false);
|
|
337
|
+
expect(versionMatches('2.0.0', '~1.0.0')).toBe(false);
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
// =============================================================================
|
|
342
|
+
// Composition Config Validation Tests
|
|
343
|
+
// =============================================================================
|
|
344
|
+
describe('validateCompositionConfig', () => {
|
|
345
|
+
it('should validate correct sequential config', () => {
|
|
346
|
+
const config = {
|
|
347
|
+
pattern: 'sequential',
|
|
348
|
+
requires: [{ name: 'module-a' }],
|
|
349
|
+
dataflow: [
|
|
350
|
+
{ from: 'input', to: 'module-a' },
|
|
351
|
+
{ from: 'module-a.output', to: 'output' }
|
|
352
|
+
]
|
|
353
|
+
};
|
|
354
|
+
const result = validateCompositionConfig(config);
|
|
355
|
+
expect(result.valid).toBe(true);
|
|
356
|
+
expect(result.errors).toHaveLength(0);
|
|
357
|
+
});
|
|
358
|
+
it('should validate correct parallel config', () => {
|
|
359
|
+
const config = {
|
|
360
|
+
pattern: 'parallel',
|
|
361
|
+
requires: [
|
|
362
|
+
{ name: 'module-a' },
|
|
363
|
+
{ name: 'module-b' }
|
|
364
|
+
],
|
|
365
|
+
dataflow: [
|
|
366
|
+
{ from: 'input', to: ['module-a', 'module-b'] },
|
|
367
|
+
{ from: ['module-a.output', 'module-b.output'], to: 'output', aggregate: 'merge' }
|
|
368
|
+
]
|
|
369
|
+
};
|
|
370
|
+
const result = validateCompositionConfig(config);
|
|
371
|
+
expect(result.valid).toBe(true);
|
|
372
|
+
});
|
|
373
|
+
it('should require routing rules for conditional pattern', () => {
|
|
374
|
+
const config = {
|
|
375
|
+
pattern: 'conditional',
|
|
376
|
+
dataflow: [{ from: 'input', to: 'module-a' }]
|
|
377
|
+
};
|
|
378
|
+
const result = validateCompositionConfig(config);
|
|
379
|
+
expect(result.valid).toBe(false);
|
|
380
|
+
expect(result.errors.some(e => e.includes('routing'))).toBe(true);
|
|
381
|
+
});
|
|
382
|
+
it('should require iteration config for iterative pattern', () => {
|
|
383
|
+
const config = {
|
|
384
|
+
pattern: 'iterative',
|
|
385
|
+
dataflow: [{ from: 'input', to: 'module-a' }]
|
|
386
|
+
};
|
|
387
|
+
const result = validateCompositionConfig(config);
|
|
388
|
+
expect(result.valid).toBe(false);
|
|
389
|
+
expect(result.errors.some(e => e.includes('continue_condition') || e.includes('stop_condition'))).toBe(true);
|
|
390
|
+
});
|
|
391
|
+
it('should validate correct iterative config', () => {
|
|
392
|
+
const config = {
|
|
393
|
+
pattern: 'iterative',
|
|
394
|
+
iteration: {
|
|
395
|
+
max_iterations: 10,
|
|
396
|
+
stop_condition: '$.meta.confidence > 0.9'
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
const result = validateCompositionConfig(config);
|
|
400
|
+
expect(result.valid).toBe(true);
|
|
401
|
+
});
|
|
402
|
+
it('should detect invalid pattern', () => {
|
|
403
|
+
const config = {
|
|
404
|
+
pattern: 'invalid',
|
|
405
|
+
dataflow: []
|
|
406
|
+
};
|
|
407
|
+
const result = validateCompositionConfig(config);
|
|
408
|
+
expect(result.valid).toBe(false);
|
|
409
|
+
expect(result.errors.some(e => e.includes('Invalid pattern'))).toBe(true);
|
|
410
|
+
});
|
|
411
|
+
it('should detect missing dataflow fields', () => {
|
|
412
|
+
const config = {
|
|
413
|
+
pattern: 'sequential',
|
|
414
|
+
dataflow: [
|
|
415
|
+
{ from: 'input' },
|
|
416
|
+
]
|
|
417
|
+
};
|
|
418
|
+
const result = validateCompositionConfig(config);
|
|
419
|
+
expect(result.valid).toBe(false);
|
|
420
|
+
expect(result.errors.some(e => e.includes("missing 'to'"))).toBe(true);
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
// =============================================================================
|
|
424
|
+
// Integration Test Placeholders
|
|
425
|
+
// =============================================================================
|
|
426
|
+
describe('CompositionOrchestrator', () => {
|
|
427
|
+
// Note: Full integration tests require mocking Provider and modules
|
|
428
|
+
// These are placeholder tests that should be expanded with proper mocks
|
|
429
|
+
it.skip('should execute sequential composition', async () => {
|
|
430
|
+
// TODO: Add integration test with mocked provider
|
|
431
|
+
});
|
|
432
|
+
it.skip('should execute parallel composition', async () => {
|
|
433
|
+
// TODO: Add integration test with mocked provider
|
|
434
|
+
});
|
|
435
|
+
it.skip('should execute conditional composition', async () => {
|
|
436
|
+
// TODO: Add integration test with mocked provider
|
|
437
|
+
});
|
|
438
|
+
it.skip('should execute iterative composition', async () => {
|
|
439
|
+
// TODO: Add integration test with mocked provider
|
|
440
|
+
});
|
|
441
|
+
it.skip('should handle timeouts', async () => {
|
|
442
|
+
// TODO: Add timeout test
|
|
443
|
+
});
|
|
444
|
+
it.skip('should detect circular dependencies', async () => {
|
|
445
|
+
// TODO: Add circular dependency test
|
|
446
|
+
});
|
|
447
|
+
it.skip('should use fallback modules', async () => {
|
|
448
|
+
// TODO: Add fallback test
|
|
449
|
+
});
|
|
450
|
+
});
|
package/dist/modules/index.d.ts
CHANGED
package/dist/modules/index.js
CHANGED
package/dist/modules/loader.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Module Loader - Load and parse Cognitive Modules
|
|
3
|
-
* Supports
|
|
3
|
+
* Supports v0 (6-file), v1 (MODULE.md) and v2 (module.yaml + prompt.md) formats
|
|
4
4
|
*/
|
|
5
|
-
import type { CognitiveModule } from '../types.js';
|
|
5
|
+
import type { CognitiveModule, ModuleTier, SchemaStrictness } from '../types.js';
|
|
6
6
|
/**
|
|
7
7
|
* Load a Cognitive Module (auto-detects format)
|
|
8
8
|
*/
|
|
@@ -10,3 +10,23 @@ export declare function loadModule(modulePath: string): Promise<CognitiveModule>
|
|
|
10
10
|
export declare function findModule(name: string, searchPaths: string[]): Promise<CognitiveModule | null>;
|
|
11
11
|
export declare function listModules(searchPaths: string[]): Promise<CognitiveModule[]>;
|
|
12
12
|
export declare function getDefaultSearchPaths(cwd: string): string[];
|
|
13
|
+
/**
|
|
14
|
+
* Get module tier (exec, decision, exploration).
|
|
15
|
+
*/
|
|
16
|
+
export declare function getModuleTier(module: CognitiveModule): ModuleTier | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Get schema strictness level.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getSchemaStrictness(module: CognitiveModule): SchemaStrictness;
|
|
21
|
+
/**
|
|
22
|
+
* Check if overflow (extensions.insights) is enabled.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isOverflowEnabled(module: CognitiveModule): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Get enum extension strategy.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getEnumStrategy(module: CognitiveModule): 'strict' | 'extensible';
|
|
29
|
+
/**
|
|
30
|
+
* Check if runtime should auto-wrap v2.1 to v2.2.
|
|
31
|
+
*/
|
|
32
|
+
export declare function shouldAutoWrap(module: CognitiveModule): boolean;
|