@cdot65/prisma-airs-cli 1.4.2 → 2.2.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.
Files changed (149) hide show
  1. package/README.md +8 -6
  2. package/dist/airs/management.d.ts +2 -0
  3. package/dist/airs/management.d.ts.map +1 -1
  4. package/dist/airs/management.js +14 -0
  5. package/dist/airs/management.js.map +1 -1
  6. package/dist/airs/redteam.d.ts +15 -1
  7. package/dist/airs/redteam.d.ts.map +1 -1
  8. package/dist/airs/redteam.js +105 -0
  9. package/dist/airs/redteam.js.map +1 -1
  10. package/dist/airs/runtime.js +3 -3
  11. package/dist/airs/runtime.js.map +1 -1
  12. package/dist/airs/types.d.ts +80 -0
  13. package/dist/airs/types.d.ts.map +1 -1
  14. package/dist/audit/runner.d.ts +1 -1
  15. package/dist/audit/runner.d.ts.map +1 -1
  16. package/dist/cli/commands/redteam.d.ts.map +1 -1
  17. package/dist/cli/commands/redteam.js +268 -1
  18. package/dist/cli/commands/redteam.js.map +1 -1
  19. package/dist/cli/commands/runtime.d.ts.map +1 -1
  20. package/dist/cli/commands/runtime.js +83 -50
  21. package/dist/cli/commands/runtime.js.map +1 -1
  22. package/dist/cli/commands/topics-apply.d.ts +16 -0
  23. package/dist/cli/commands/topics-apply.d.ts.map +1 -0
  24. package/dist/cli/commands/topics-apply.js +69 -0
  25. package/dist/cli/commands/topics-apply.js.map +1 -0
  26. package/dist/cli/commands/topics-create.d.ts +16 -0
  27. package/dist/cli/commands/topics-create.d.ts.map +1 -0
  28. package/dist/cli/commands/topics-create.js +71 -0
  29. package/dist/cli/commands/topics-create.js.map +1 -0
  30. package/dist/cli/commands/topics-eval.d.ts +7 -0
  31. package/dist/cli/commands/topics-eval.d.ts.map +1 -0
  32. package/dist/cli/commands/topics-eval.js +65 -0
  33. package/dist/cli/commands/topics-eval.js.map +1 -0
  34. package/dist/cli/commands/topics-revert.d.ts +9 -0
  35. package/dist/cli/commands/topics-revert.d.ts.map +1 -0
  36. package/dist/cli/commands/topics-revert.js +52 -0
  37. package/dist/cli/commands/topics-revert.js.map +1 -0
  38. package/dist/cli/commands/topics-sample.d.ts +4 -0
  39. package/dist/cli/commands/topics-sample.d.ts.map +1 -0
  40. package/dist/cli/commands/topics-sample.js +27 -0
  41. package/dist/cli/commands/topics-sample.js.map +1 -0
  42. package/dist/cli/renderer/audit.d.ts +3 -0
  43. package/dist/cli/renderer/audit.d.ts.map +1 -1
  44. package/dist/cli/renderer/audit.js +14 -0
  45. package/dist/cli/renderer/audit.js.map +1 -1
  46. package/dist/cli/renderer/eval.d.ts +30 -0
  47. package/dist/cli/renderer/eval.d.ts.map +1 -0
  48. package/dist/cli/renderer/eval.js +61 -0
  49. package/dist/cli/renderer/eval.js.map +1 -0
  50. package/dist/cli/renderer/index.d.ts +1 -1
  51. package/dist/cli/renderer/index.d.ts.map +1 -1
  52. package/dist/cli/renderer/index.js +1 -1
  53. package/dist/cli/renderer/index.js.map +1 -1
  54. package/dist/cli/renderer/redteam.d.ts +37 -0
  55. package/dist/cli/renderer/redteam.d.ts.map +1 -1
  56. package/dist/cli/renderer/redteam.js +64 -0
  57. package/dist/cli/renderer/redteam.js.map +1 -1
  58. package/dist/config/loader.d.ts.map +1 -1
  59. package/dist/config/loader.js +0 -6
  60. package/dist/config/loader.js.map +1 -1
  61. package/dist/config/schema.d.ts +0 -15
  62. package/dist/config/schema.d.ts.map +1 -1
  63. package/dist/config/schema.js +0 -6
  64. package/dist/config/schema.js.map +1 -1
  65. package/dist/core/constraints.d.ts +1 -0
  66. package/dist/core/constraints.d.ts.map +1 -1
  67. package/dist/core/constraints.js +7 -0
  68. package/dist/core/constraints.js.map +1 -1
  69. package/dist/core/prompt-loader.d.ts +14 -0
  70. package/dist/core/prompt-loader.d.ts.map +1 -0
  71. package/dist/core/prompt-loader.js +122 -0
  72. package/dist/core/prompt-loader.js.map +1 -0
  73. package/dist/core/types.d.ts +0 -74
  74. package/dist/core/types.d.ts.map +1 -1
  75. package/dist/index.d.ts +1 -10
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +0 -16
  78. package/dist/index.js.map +1 -1
  79. package/dist/llm/service.d.ts +6 -2
  80. package/dist/llm/service.d.ts.map +1 -1
  81. package/dist/llm/service.js +0 -5
  82. package/dist/llm/service.js.map +1 -1
  83. package/dist/llm/types.d.ts +18 -0
  84. package/dist/llm/types.d.ts.map +1 -0
  85. package/dist/{persistence → llm}/types.js.map +1 -1
  86. package/package.json +2 -2
  87. package/dist/cli/commands/generate.d.ts +0 -4
  88. package/dist/cli/commands/generate.d.ts.map +0 -1
  89. package/dist/cli/commands/generate.js +0 -228
  90. package/dist/cli/commands/generate.js.map +0 -1
  91. package/dist/cli/commands/list.d.ts +0 -4
  92. package/dist/cli/commands/list.d.ts.map +0 -1
  93. package/dist/cli/commands/list.js +0 -23
  94. package/dist/cli/commands/list.js.map +0 -1
  95. package/dist/cli/commands/report.d.ts +0 -4
  96. package/dist/cli/commands/report.d.ts.map +0 -1
  97. package/dist/cli/commands/report.js +0 -116
  98. package/dist/cli/commands/report.js.map +0 -1
  99. package/dist/cli/commands/resume.d.ts +0 -4
  100. package/dist/cli/commands/resume.d.ts.map +0 -1
  101. package/dist/cli/commands/resume.js +0 -135
  102. package/dist/cli/commands/resume.js.map +0 -1
  103. package/dist/cli/prompts.d.ts +0 -9
  104. package/dist/cli/prompts.d.ts.map +0 -1
  105. package/dist/cli/prompts.js +0 -90
  106. package/dist/cli/prompts.js.map +0 -1
  107. package/dist/cli/renderer/generate.d.ts +0 -29
  108. package/dist/cli/renderer/generate.d.ts.map +0 -1
  109. package/dist/cli/renderer/generate.js +0 -132
  110. package/dist/cli/renderer/generate.js.map +0 -1
  111. package/dist/core/loop.d.ts +0 -48
  112. package/dist/core/loop.d.ts.map +0 -1
  113. package/dist/core/loop.js +0 -430
  114. package/dist/core/loop.js.map +0 -1
  115. package/dist/memory/diff.d.ts +0 -4
  116. package/dist/memory/diff.d.ts.map +0 -1
  117. package/dist/memory/diff.js +0 -24
  118. package/dist/memory/diff.js.map +0 -1
  119. package/dist/memory/extractor.d.ts +0 -15
  120. package/dist/memory/extractor.d.ts.map +0 -1
  121. package/dist/memory/extractor.js +0 -133
  122. package/dist/memory/extractor.js.map +0 -1
  123. package/dist/memory/injector.d.ts +0 -22
  124. package/dist/memory/injector.d.ts.map +0 -1
  125. package/dist/memory/injector.js +0 -90
  126. package/dist/memory/injector.js.map +0 -1
  127. package/dist/memory/prompts/extract-learnings.d.ts +0 -3
  128. package/dist/memory/prompts/extract-learnings.d.ts.map +0 -1
  129. package/dist/memory/prompts/extract-learnings.js +0 -40
  130. package/dist/memory/prompts/extract-learnings.js.map +0 -1
  131. package/dist/memory/schemas.d.ts +0 -63
  132. package/dist/memory/schemas.d.ts.map +0 -1
  133. package/dist/memory/schemas.js +0 -13
  134. package/dist/memory/schemas.js.map +0 -1
  135. package/dist/memory/store.d.ts +0 -28
  136. package/dist/memory/store.d.ts.map +0 -1
  137. package/dist/memory/store.js +0 -103
  138. package/dist/memory/store.js.map +0 -1
  139. package/dist/memory/types.d.ts +0 -55
  140. package/dist/memory/types.d.ts.map +0 -1
  141. package/dist/memory/types.js +0 -6
  142. package/dist/memory/types.js.map +0 -1
  143. package/dist/persistence/store.d.ts +0 -21
  144. package/dist/persistence/store.d.ts.map +0 -1
  145. package/dist/persistence/store.js +0 -77
  146. package/dist/persistence/store.js.map +0 -1
  147. package/dist/persistence/types.d.ts +0 -23
  148. package/dist/persistence/types.d.ts.map +0 -1
  149. /package/dist/{persistence → llm}/types.js +0 -0
package/dist/core/loop.js DELETED
@@ -1,430 +0,0 @@
1
- import { nanoid } from 'nanoid';
2
- import { computeCategoryBreakdown, computeMetrics } from './metrics.js';
3
- /** Check if a topic definition matches any previous iteration's topic. Returns the iteration number or null. */
4
- function findDuplicateIteration(topic, iterations) {
5
- for (const iter of iterations) {
6
- if (iter.topic.description === topic.description &&
7
- iter.topic.examples.length === topic.examples.length &&
8
- iter.topic.examples.every((e, idx) => e === topic.examples[idx])) {
9
- return iter.iteration;
10
- }
11
- }
12
- return null;
13
- }
14
- /**
15
- * Main refinement loop — generates, deploys, tests, and iteratively improves a topic.
16
- * Yields typed {@link LoopEvent} discriminated unions at each stage.
17
- * @param input - User input seeding the generation run.
18
- * @param deps - Injected service dependencies.
19
- */
20
- export async function* runLoop(input, deps) {
21
- const maxIterations = input.maxIterations ?? 20;
22
- const targetCoverage = input.targetCoverage ?? 0.9;
23
- const runState = {
24
- id: nanoid(),
25
- createdAt: new Date().toISOString(),
26
- updatedAt: new Date().toISOString(),
27
- userInput: input,
28
- iterations: [],
29
- currentIteration: 0,
30
- bestIteration: 0,
31
- bestCoverage: 0,
32
- consecutiveRegressions: 0,
33
- hasRevertedToBest: false,
34
- hasTriedSimplification: false,
35
- status: 'running',
36
- };
37
- let currentTopic = null;
38
- let topicId = '';
39
- let companionTopicId = '';
40
- let companionTopic = null;
41
- let lockedName = '';
42
- let accumulatedTests = [];
43
- for (let i = 1; i <= maxIterations; i++) {
44
- const iterationStart = Date.now();
45
- runState.currentIteration = i;
46
- yield { type: 'iteration:start', iteration: i };
47
- // Step 1: Generate or improve topic
48
- if (i === 1) {
49
- currentTopic = await deps.llm.generateTopic(input.topicDescription, input.intent, input.seedExamples);
50
- lockedName = currentTopic.name;
51
- }
52
- else if (currentTopic) {
53
- const prevIteration = runState.iterations[runState.iterations.length - 1];
54
- currentTopic = await deps.llm.improveTopic(currentTopic, prevIteration.metrics, prevIteration.analysis, prevIteration.testResults, i, targetCoverage, input.intent, {
55
- bestCoverage: runState.bestCoverage,
56
- bestIteration: runState.bestIteration,
57
- bestTopic: runState.iterations[runState.bestIteration - 1]?.topic,
58
- });
59
- // Force the name to stay consistent across iterations
60
- currentTopic = { ...currentTopic, name: lockedName };
61
- // Skip scanning if topic is identical to a previous iteration
62
- const dupIter = findDuplicateIteration(currentTopic, runState.iterations);
63
- if (dupIter !== null) {
64
- yield {
65
- type: 'topic:duplicate',
66
- topic: currentTopic,
67
- duplicateOfIteration: dupIter,
68
- };
69
- runState.consecutiveRegressions++;
70
- runState.currentIteration = i;
71
- runState.updatedAt = new Date().toISOString();
72
- // Recovery: revert → simplify (same tiers as end-of-iteration)
73
- const recoveryThreshold = 2;
74
- // Tier 1: Revert to best
75
- if (runState.consecutiveRegressions >= recoveryThreshold &&
76
- !runState.hasRevertedToBest &&
77
- runState.bestIteration > 0) {
78
- const bestResult = runState.iterations[runState.bestIteration - 1];
79
- if (bestResult) {
80
- currentTopic = { ...bestResult.topic };
81
- runState.hasRevertedToBest = true;
82
- runState.consecutiveRegressions = 0;
83
- yield {
84
- type: 'topic:reverted',
85
- topic: currentTopic,
86
- revertedToIteration: runState.bestIteration,
87
- };
88
- }
89
- }
90
- // Tier 2: Simplify
91
- else if (runState.consecutiveRegressions >= recoveryThreshold &&
92
- !runState.hasTriedSimplification &&
93
- runState.bestIteration > 0) {
94
- const bestResult = runState.iterations[runState.bestIteration - 1];
95
- if (bestResult) {
96
- currentTopic = await deps.llm.simplifyTopic(currentTopic, bestResult.topic, bestResult.metrics, bestResult.analysis, input.intent);
97
- currentTopic = { ...currentTopic, name: lockedName };
98
- runState.hasTriedSimplification = true;
99
- runState.consecutiveRegressions = 0;
100
- yield { type: 'topic:simplified', topic: currentTopic };
101
- // If simplified topic is also a duplicate, don't reset — count it
102
- const simpDupIter = findDuplicateIteration(currentTopic, runState.iterations);
103
- if (simpDupIter !== null) {
104
- yield {
105
- type: 'topic:duplicate',
106
- topic: currentTopic,
107
- duplicateOfIteration: simpDupIter,
108
- };
109
- runState.consecutiveRegressions++;
110
- }
111
- }
112
- }
113
- const maxRegressions = input.maxRegressions ?? 3;
114
- if (maxRegressions > 0 && runState.consecutiveRegressions >= maxRegressions) {
115
- break;
116
- }
117
- continue;
118
- }
119
- }
120
- /* v8 ignore next */
121
- if (!currentTopic)
122
- throw new Error('Invariant: topic must exist');
123
- const topic = currentTopic;
124
- yield { type: 'generate:complete', topic };
125
- // Step 2: Apply topic via management API (SDK v2)
126
- if (i === 1) {
127
- // Check if a topic with this name already exists (reuse it)
128
- const existing = await deps.management.listTopics();
129
- const match = existing.find((t) => t.topic_name === topic.name);
130
- if (match?.topic_id) {
131
- topicId = match.topic_id;
132
- await deps.management.updateTopic(topicId, {
133
- topic_name: topic.name,
134
- description: topic.description,
135
- examples: topic.examples,
136
- active: true,
137
- });
138
- }
139
- else {
140
- const response = await deps.management.createTopic({
141
- topic_name: topic.name,
142
- description: topic.description,
143
- examples: topic.examples,
144
- active: true,
145
- });
146
- /* v8 ignore next */
147
- if (!response.topic_id)
148
- throw new Error('Invariant: topic_id missing from create response');
149
- topicId = response.topic_id;
150
- }
151
- // Guardrail-level action is the INVERSE of topic intent:
152
- // block-intent → guardrailAction='allow' (default: allow, block topics carve out violations)
153
- // allow-intent → guardrailAction='block' (default: block, allow topics whitelist content)
154
- const guardrailAction = input.intent === 'block' ? 'allow' : 'block';
155
- if (input.intent === 'block') {
156
- // Two-phase: generate domain-specific allow companion for block-intent.
157
- // AIRS needs both allow + block topics sharing the same vocabulary domain
158
- // for the matching engine to distinguish benign from malicious content.
159
- companionTopic = await deps.llm.generateCompanionTopic(topic.name, topic.description);
160
- yield { type: 'companion:generated', topic: companionTopic };
161
- const companionMatch = existing.find((t) => t.topic_name === companionTopic?.name);
162
- if (companionMatch?.topic_id) {
163
- companionTopicId = companionMatch.topic_id;
164
- await deps.management.updateTopic(companionTopicId, {
165
- topic_name: companionTopic.name,
166
- description: companionTopic.description,
167
- examples: companionTopic.examples,
168
- active: true,
169
- });
170
- }
171
- else {
172
- const cResponse = await deps.management.createTopic({
173
- topic_name: companionTopic.name,
174
- description: companionTopic.description,
175
- examples: companionTopic.examples,
176
- active: true,
177
- });
178
- /* v8 ignore next */
179
- if (!cResponse.topic_id)
180
- throw new Error('Invariant: topic_id missing from companion create response');
181
- companionTopicId = cResponse.topic_id;
182
- }
183
- yield { type: 'companion:created', topicId: companionTopicId, topic: companionTopic };
184
- runState.companionTopic = companionTopic;
185
- // Wire both topics to profile with guardrailAction='allow'
186
- await deps.management.assignTopicsToProfile(input.profileName, [
187
- { topicId: companionTopicId, topicName: companionTopic.name, action: 'allow' },
188
- { topicId, topicName: topic.name, action: 'block' },
189
- ], guardrailAction);
190
- }
191
- else {
192
- // Allow-intent: single topic, guardrailAction='block'
193
- await deps.management.assignTopicsToProfile(input.profileName, [{ topicId, topicName: topic.name, action: input.intent }], guardrailAction);
194
- }
195
- }
196
- else {
197
- await deps.management.updateTopic(topicId, {
198
- topic_name: topic.name,
199
- description: topic.description,
200
- examples: topic.examples,
201
- active: true,
202
- });
203
- // Re-assign topics to profile so AIRS references the new topic revision.
204
- // AIRS pins topic content to the revision in the profile — without this,
205
- // the profile would still reference the pre-update revision.
206
- const guardrailAction = input.intent === 'block' ? 'allow' : 'block';
207
- const topicEntries = [{ topicId, topicName: topic.name, action: input.intent }];
208
- if (input.intent === 'block' && companionTopicId && companionTopic) {
209
- topicEntries.unshift({
210
- topicId: companionTopicId,
211
- topicName: companionTopic.name,
212
- action: 'allow',
213
- });
214
- }
215
- await deps.management.assignTopicsToProfile(input.profileName, topicEntries, guardrailAction);
216
- }
217
- yield { type: 'apply:complete', topicId };
218
- // Step 3: Generate test cases (with category breakdown for weighted generation)
219
- const prevItResults = i > 1 ? runState.iterations[runState.iterations.length - 1] : undefined;
220
- const categoryBreakdown = prevItResults
221
- ? computeCategoryBreakdown(prevItResults.testResults)
222
- : undefined;
223
- const { positiveTests, negativeTests } = await deps.llm.generateTests(topic, input.intent, categoryBreakdown);
224
- const newTests = [...positiveTests, ...negativeTests].map((t) => ({
225
- ...t,
226
- source: 'generated',
227
- }));
228
- // Build carried failures + regression tier from previous iteration
229
- let carriedFailures = [];
230
- let regressionTier = [];
231
- if (i > 1 && prevItResults) {
232
- carriedFailures = prevItResults.testResults
233
- .filter((r) => !r.correct)
234
- .map((r) => {
235
- const source = r.testCase.expectedTriggered && !r.actualTriggered ? 'carried-fn' : 'carried-fp';
236
- return { ...r.testCase, source };
237
- });
238
- regressionTier = prevItResults.testResults
239
- .filter((r) => r.correct)
240
- .map((r) => ({ ...r.testCase, source: 'regression' }));
241
- }
242
- // Merge: carried failures > regression > generated (dedup by prompt text)
243
- const seen = new Set();
244
- const merged = [];
245
- for (const pool of [carriedFailures, regressionTier, newTests]) {
246
- for (const t of pool) {
247
- const key = t.prompt.toLowerCase().trim();
248
- if (!seen.has(key)) {
249
- seen.add(key);
250
- merged.push(t);
251
- }
252
- }
253
- }
254
- // Also merge old accumulated tests if accumulation enabled
255
- if (input.accumulateTests && i > 1) {
256
- for (const t of accumulatedTests) {
257
- const key = t.prompt.toLowerCase().trim();
258
- if (!seen.has(key)) {
259
- seen.add(key);
260
- merged.push(t);
261
- }
262
- }
263
- }
264
- // Apply max cap
265
- const maxCap = input.maxAccumulatedTests;
266
- const preCapCount = merged.length;
267
- const allTests = maxCap && merged.length > maxCap ? merged.slice(0, maxCap) : merged;
268
- // Emit composition event on iteration 2+
269
- if (i > 1) {
270
- yield {
271
- type: 'tests:composed',
272
- generated: newTests.length,
273
- carriedFailures: carriedFailures.length,
274
- regressionTier: regressionTier.length,
275
- total: allTests.length,
276
- };
277
- }
278
- // Emit legacy accumulated event when accumulation enabled
279
- if (input.accumulateTests && i > 1) {
280
- yield {
281
- type: 'tests:accumulated',
282
- newCount: newTests.length,
283
- totalCount: allTests.length,
284
- droppedCount: preCapCount - allTests.length,
285
- };
286
- }
287
- accumulatedTests = allTests;
288
- // Step 4: Run scans
289
- const sessionId = `prisma-airs-cli-${runState.id.slice(0, 7)}-iter${i}`;
290
- const testResults = [];
291
- const prompts = allTests.map((t) => t.prompt);
292
- const scanResults = await deps.scanner.scanBatch(input.profileName, prompts, undefined, sessionId);
293
- for (let j = 0; j < allTests.length; j++) {
294
- const testCase = allTests[j];
295
- const scanResult = scanResults[j];
296
- // prompt_detected.topic_violation is the sole signal for both intents.
297
- const actualTriggered = scanResult.triggered;
298
- testResults.push({
299
- testCase,
300
- actualTriggered,
301
- scanAction: scanResult.action,
302
- scanId: scanResult.scanId,
303
- reportId: scanResult.reportId,
304
- correct: testCase.expectedTriggered === actualTriggered,
305
- });
306
- yield { type: 'test:progress', completed: j + 1, total: allTests.length };
307
- }
308
- // Step 5: Evaluate
309
- const metrics = computeMetrics(testResults);
310
- yield { type: 'evaluate:complete', metrics };
311
- // Step 6: Analyze
312
- const analysis = await deps.llm.analyzeResults(topic, testResults, metrics, input.intent);
313
- yield { type: 'analyze:complete', analysis };
314
- // Record iteration
315
- const iterationResult = {
316
- iteration: i,
317
- timestamp: new Date().toISOString(),
318
- topic,
319
- testCases: allTests,
320
- testResults,
321
- metrics,
322
- analysis,
323
- durationMs: Date.now() - iterationStart,
324
- };
325
- runState.iterations.push(iterationResult);
326
- if (metrics.coverage > runState.bestCoverage) {
327
- runState.bestCoverage = metrics.coverage;
328
- runState.bestIteration = i;
329
- runState.consecutiveRegressions = 0;
330
- }
331
- else {
332
- runState.consecutiveRegressions++;
333
- }
334
- runState.updatedAt = new Date().toISOString();
335
- yield { type: 'iteration:complete', result: iterationResult };
336
- // Check stop conditions
337
- if (metrics.coverage >= targetCoverage) {
338
- break;
339
- }
340
- // Recovery strategy: revert → simplify → stop
341
- const recoveryThreshold = 2;
342
- const maxRegressions = input.maxRegressions ?? 3;
343
- // Tier 1: Revert to best-performing definition (no LLM call)
344
- if (runState.consecutiveRegressions >= recoveryThreshold &&
345
- !runState.hasRevertedToBest &&
346
- runState.bestIteration > 0) {
347
- const bestResult = runState.iterations[runState.bestIteration - 1];
348
- if (bestResult) {
349
- currentTopic = { ...bestResult.topic };
350
- runState.hasRevertedToBest = true;
351
- runState.consecutiveRegressions = 0;
352
- yield {
353
- type: 'topic:reverted',
354
- topic: currentTopic,
355
- revertedToIteration: runState.bestIteration,
356
- };
357
- }
358
- }
359
- // Tier 2: LLM simplification (after revert already tried)
360
- else if (runState.consecutiveRegressions >= recoveryThreshold &&
361
- !runState.hasTriedSimplification &&
362
- runState.bestIteration > 0) {
363
- const bestResult = runState.iterations[runState.bestIteration - 1];
364
- if (bestResult) {
365
- currentTopic = await deps.llm.simplifyTopic(topic, bestResult.topic, bestResult.metrics, bestResult.analysis, input.intent);
366
- currentTopic = { ...currentTopic, name: lockedName };
367
- runState.hasTriedSimplification = true;
368
- runState.consecutiveRegressions = 0;
369
- yield { type: 'topic:simplified', topic: currentTopic };
370
- // Check if simplified topic is a duplicate of a previous iteration
371
- const simpDupIter = findDuplicateIteration(currentTopic, runState.iterations);
372
- if (simpDupIter !== null) {
373
- yield {
374
- type: 'topic:duplicate',
375
- topic: currentTopic,
376
- duplicateOfIteration: simpDupIter,
377
- };
378
- runState.consecutiveRegressions++;
379
- }
380
- }
381
- }
382
- // Tier 3: Early stop
383
- if (maxRegressions > 0 && runState.consecutiveRegressions >= maxRegressions) {
384
- break;
385
- }
386
- // Plateau detection: coverage oscillating in narrow band without improvement (opt-in)
387
- const plateauWindow = input.plateauWindow ?? 0;
388
- const plateauBand = input.plateauBand ?? 0.05;
389
- if (plateauWindow > 0 && runState.iterations.length >= plateauWindow + 1) {
390
- const recent = runState.iterations.slice(-plateauWindow).map((r) => r.metrics.coverage);
391
- const min = Math.min(...recent);
392
- const max = Math.max(...recent);
393
- if (max - min <= plateauBand && max < runState.bestCoverage + plateauBand) {
394
- yield {
395
- type: 'loop:plateau',
396
- band: [min, max],
397
- bestCoverage: runState.bestCoverage,
398
- };
399
- break;
400
- }
401
- }
402
- }
403
- runState.status = 'completed';
404
- // Extract learnings from this run if memory is enabled
405
- if (deps.memory?.extractor) {
406
- const { learnings } = await deps.memory.extractor.extractAndSave(runState);
407
- yield { type: 'memory:extracted', learningCount: learnings.length };
408
- }
409
- const bestResult = runState.iterations[runState.bestIteration - 1] ??
410
- runState.iterations[runState.iterations.length - 1];
411
- // Create custom prompt set from best iteration's test cases if requested
412
- if (input.createPromptSet && deps.promptSets && bestResult) {
413
- const setName = input.promptSetName ?? `prisma-airs-cli-${bestResult.topic.name}-${runState.id.slice(0, 7)}`;
414
- const { uuid } = await deps.promptSets.createPromptSet(setName, `Generated by Prisma AIRS CLI run ${runState.id} — ${bestResult.testCases.length} prompts from iteration ${bestResult.iteration}`);
415
- for (const tc of bestResult.testCases) {
416
- const goal = tc.expectedTriggered
417
- ? 'Should trigger topic guardrail'
418
- : 'Should NOT trigger topic guardrail';
419
- await deps.promptSets.addPrompt(uuid, tc.prompt, goal);
420
- }
421
- yield {
422
- type: 'promptset:created',
423
- promptSetId: uuid,
424
- promptSetName: setName,
425
- promptCount: bestResult.testCases.length,
426
- };
427
- }
428
- yield { type: 'loop:complete', bestResult, runState };
429
- }
430
- //# sourceMappingURL=loop.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/core/loop.ts"],"names":[],"mappings":"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"}
@@ -1,4 +0,0 @@
1
- import type { IterationResult } from '../core/types.js';
2
- import type { IterationDiff } from './types.js';
3
- export declare function computeIterationDiff(from: IterationResult, to: IterationResult): IterationDiff;
4
- //# sourceMappingURL=diff.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/memory/diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,eAAe,EAAE,EAAE,EAAE,eAAe,GAAG,aAAa,CAwB9F"}
@@ -1,24 +0,0 @@
1
- export function computeIterationDiff(from, to) {
2
- const fromExSet = new Set(from.topic.examples);
3
- const toExSet = new Set(to.topic.examples);
4
- const examplesAdded = to.topic.examples.filter((e) => !fromExSet.has(e));
5
- const examplesRemoved = from.topic.examples.filter((e) => !toExSet.has(e));
6
- return {
7
- fromIteration: from.iteration,
8
- toIteration: to.iteration,
9
- descriptionChanged: from.topic.description !== to.topic.description,
10
- examplesChanged: examplesAdded.length > 0 || examplesRemoved.length > 0,
11
- examplesAdded,
12
- examplesRemoved,
13
- descriptionBefore: from.topic.description,
14
- descriptionAfter: to.topic.description,
15
- metricDelta: {
16
- coverage: to.metrics.coverage - from.metrics.coverage,
17
- tpr: to.metrics.truePositiveRate - from.metrics.truePositiveRate,
18
- tnr: to.metrics.trueNegativeRate - from.metrics.trueNegativeRate,
19
- accuracy: to.metrics.accuracy - from.metrics.accuracy,
20
- f1: to.metrics.f1Score - from.metrics.f1Score,
21
- },
22
- };
23
- }
24
- //# sourceMappingURL=diff.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/memory/diff.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,oBAAoB,CAAC,IAAqB,EAAE,EAAmB;IAC7E,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAE3C,MAAM,aAAa,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3E,OAAO;QACL,aAAa,EAAE,IAAI,CAAC,SAAS;QAC7B,WAAW,EAAE,EAAE,CAAC,SAAS;QACzB,kBAAkB,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,EAAE,CAAC,KAAK,CAAC,WAAW;QACnE,eAAe,EAAE,aAAa,CAAC,MAAM,GAAG,CAAC,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC;QACvE,aAAa;QACb,eAAe;QACf,iBAAiB,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW;QACzC,gBAAgB,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW;QACtC,WAAW,EAAE;YACX,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ;YACrD,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB;YAChE,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB;YAChE,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ;YACrD,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO;SAC9C;KACF,CAAC;AACJ,CAAC"}
@@ -1,15 +0,0 @@
1
- import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
2
- import type { RunState } from '../core/types.js';
3
- import { type MemoryStore } from './store.js';
4
- import type { Learning } from './types.js';
5
- export declare class LearningExtractor {
6
- private model;
7
- private store;
8
- constructor(model: BaseChatModel, store: MemoryStore);
9
- extractAndSave(runState: RunState): Promise<{
10
- learnings: Learning[];
11
- }>;
12
- private mergeLearnings;
13
- private formatIterationHistory;
14
- }
15
- //# sourceMappingURL=extractor.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/memory/extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAEjF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAIjD,OAAO,EAAE,KAAK,WAAW,EAAqB,MAAM,YAAY,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAe,MAAM,YAAY,CAAC;AAExD,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,KAAK;gBADL,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,WAAW;IAGtB,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,QAAQ,EAAE,CAAA;KAAE,CAAC;IAoF5E,OAAO,CAAC,cAAc;IAoBtB,OAAO,CAAC,sBAAsB;CAwC/B"}
@@ -1,133 +0,0 @@
1
- import { nanoid } from 'nanoid';
2
- import { computeIterationDiff } from './diff.js';
3
- import { extractLearningsPrompt } from './prompts/extract-learnings.js';
4
- import { LearningExtractionOutputSchema } from './schemas.js';
5
- import { normalizeCategory } from './store.js';
6
- export class LearningExtractor {
7
- model;
8
- store;
9
- constructor(model, store) {
10
- this.model = model;
11
- this.store = store;
12
- }
13
- async extractAndSave(runState) {
14
- if (runState.iterations.length < 1) {
15
- return { learnings: [] };
16
- }
17
- const structured = this.model.withStructuredOutput(LearningExtractionOutputSchema);
18
- const chain = extractLearningsPrompt.pipe(structured);
19
- const iterationHistory = this.formatIterationHistory(runState);
20
- const raw = (await chain.invoke({
21
- topicDescription: runState.userInput.topicDescription,
22
- intent: runState.userInput.intent,
23
- totalIterations: runState.iterations.length,
24
- bestIteration: runState.bestIteration,
25
- bestCoverage: `${(runState.bestCoverage * 100).toFixed(1)}%`,
26
- iterationHistory,
27
- }));
28
- const category = normalizeCategory(runState.userInput.topicDescription);
29
- const bestIter = runState.iterations[runState.bestIteration - 1] ??
30
- runState.iterations[runState.iterations.length - 1];
31
- // Build learnings with metadata
32
- const newLearnings = raw.learnings.map((l) => ({
33
- id: nanoid(),
34
- runId: runState.id,
35
- extractedAt: new Date().toISOString(),
36
- topicCategory: category,
37
- topicDescription: runState.userInput.topicDescription,
38
- insight: l.insight,
39
- strategy: l.strategy,
40
- outcome: l.outcome,
41
- changeType: l.changeType ?? 'initial',
42
- metrics: {
43
- coverage: bestIter.metrics.coverage,
44
- tpr: bestIter.metrics.truePositiveRate,
45
- tnr: bestIter.metrics.trueNegativeRate,
46
- accuracy: bestIter.metrics.accuracy,
47
- f1: bestIter.metrics.f1Score,
48
- },
49
- corroborations: 0,
50
- tags: l.tags,
51
- }));
52
- // Merge into existing memory
53
- const existing = (await this.store.load(category)) ?? {
54
- category,
55
- updatedAt: '',
56
- learnings: [],
57
- bestKnown: null,
58
- antiPatterns: [],
59
- };
60
- const mergedLearnings = this.mergeLearnings(existing.learnings, newLearnings);
61
- // Update bestKnown only if new run is better
62
- let { bestKnown } = existing;
63
- if (!bestKnown || runState.bestCoverage > bestKnown.metrics.coverage) {
64
- bestKnown = {
65
- runId: runState.id,
66
- iteration: bestIter.iteration,
67
- topic: bestIter.topic,
68
- metrics: bestIter.metrics,
69
- };
70
- }
71
- // Merge anti-patterns (deduplicate)
72
- const antiPatternSet = new Set([...existing.antiPatterns, ...raw.antiPatterns]);
73
- const memory = {
74
- category,
75
- updatedAt: new Date().toISOString(),
76
- learnings: mergedLearnings,
77
- bestKnown,
78
- antiPatterns: [...antiPatternSet],
79
- };
80
- await this.store.save(memory);
81
- return { learnings: newLearnings };
82
- }
83
- mergeLearnings(existing, incoming) {
84
- const merged = [...existing];
85
- for (const newL of incoming) {
86
- const match = merged.findIndex((e) => e.insight === newL.insight);
87
- if (match >= 0) {
88
- // Corroborate: increment count, keep existing metrics
89
- merged[match] = {
90
- ...merged[match],
91
- corroborations: merged[match].corroborations + 1,
92
- extractedAt: newL.extractedAt,
93
- };
94
- }
95
- else {
96
- merged.push(newL);
97
- }
98
- }
99
- return merged;
100
- }
101
- formatIterationHistory(runState) {
102
- const lines = [];
103
- for (let i = 0; i < runState.iterations.length; i++) {
104
- const iter = runState.iterations[i];
105
- lines.push(`--- Iteration ${iter.iteration} ---`);
106
- lines.push(`Description: "${iter.topic.description}"`);
107
- lines.push(`Example count: ${iter.topic.examples.length}`);
108
- lines.push(`Examples: ${iter.topic.examples.length > 0 ? iter.topic.examples.map((e) => `"${e}"`).join(', ') : 'None (description-only)'}`);
109
- lines.push(`Coverage: ${(iter.metrics.coverage * 100).toFixed(1)}% | TPR: ${(iter.metrics.truePositiveRate * 100).toFixed(1)}% | TNR: ${(iter.metrics.trueNegativeRate * 100).toFixed(1)}%`);
110
- lines.push(`Analysis: ${iter.analysis.summary}`);
111
- if (i > 0) {
112
- const diff = computeIterationDiff(runState.iterations[i - 1], iter);
113
- const changes = [];
114
- if (diff.descriptionChanged)
115
- changes.push('description changed');
116
- if (diff.examplesChanged) {
117
- const prevCount = runState.iterations[i - 1].topic.examples.length;
118
- const currCount = iter.topic.examples.length;
119
- changes.push(`example count: ${prevCount} → ${currCount}`);
120
- if (diff.examplesAdded.length)
121
- changes.push(`+examples: ${diff.examplesAdded.join(', ')}`);
122
- if (diff.examplesRemoved.length)
123
- changes.push(`-examples: ${diff.examplesRemoved.join(', ')}`);
124
- }
125
- lines.push(`Changes: ${changes.join('; ') || 'none'}`);
126
- lines.push(`Coverage delta: ${diff.metricDelta.coverage >= 0 ? '+' : ''}${(diff.metricDelta.coverage * 100).toFixed(1)}%`);
127
- }
128
- lines.push('');
129
- }
130
- return lines.join('\n');
131
- }
132
- }
133
- //# sourceMappingURL=extractor.js.map