@cdot65/prisma-airs-cli 1.0.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 (234) hide show
  1. package/README.md +42 -0
  2. package/dist/airs/management.d.ts +58 -0
  3. package/dist/airs/management.d.ts.map +1 -0
  4. package/dist/airs/management.js +287 -0
  5. package/dist/airs/management.js.map +1 -0
  6. package/dist/airs/modelsecurity.d.ts +74 -0
  7. package/dist/airs/modelsecurity.d.ts.map +1 -0
  8. package/dist/airs/modelsecurity.js +337 -0
  9. package/dist/airs/modelsecurity.js.map +1 -0
  10. package/dist/airs/promptsets.d.ts +50 -0
  11. package/dist/airs/promptsets.d.ts.map +1 -0
  12. package/dist/airs/promptsets.js +133 -0
  13. package/dist/airs/promptsets.js.map +1 -0
  14. package/dist/airs/redteam.d.ts +45 -0
  15. package/dist/airs/redteam.d.ts.map +1 -0
  16. package/dist/airs/redteam.js +219 -0
  17. package/dist/airs/redteam.js.map +1 -0
  18. package/dist/airs/runtime.d.ts +27 -0
  19. package/dist/airs/runtime.d.ts.map +1 -0
  20. package/dist/airs/runtime.js +158 -0
  21. package/dist/airs/runtime.js.map +1 -0
  22. package/dist/airs/scanner.d.ts +22 -0
  23. package/dist/airs/scanner.d.ts.map +1 -0
  24. package/dist/airs/scanner.js +62 -0
  25. package/dist/airs/scanner.js.map +1 -0
  26. package/dist/airs/types.d.ts +683 -0
  27. package/dist/airs/types.d.ts.map +1 -0
  28. package/dist/airs/types.js +6 -0
  29. package/dist/airs/types.js.map +1 -0
  30. package/dist/audit/evaluator.d.ts +17 -0
  31. package/dist/audit/evaluator.d.ts.map +1 -0
  32. package/dist/audit/evaluator.js +82 -0
  33. package/dist/audit/evaluator.js.map +1 -0
  34. package/dist/audit/report.d.ts +38 -0
  35. package/dist/audit/report.d.ts.map +1 -0
  36. package/dist/audit/report.js +141 -0
  37. package/dist/audit/report.js.map +1 -0
  38. package/dist/audit/runner.d.ts +18 -0
  39. package/dist/audit/runner.d.ts.map +1 -0
  40. package/dist/audit/runner.js +60 -0
  41. package/dist/audit/runner.js.map +1 -0
  42. package/dist/audit/types.d.ts +53 -0
  43. package/dist/audit/types.d.ts.map +1 -0
  44. package/dist/audit/types.js +5 -0
  45. package/dist/audit/types.js.map +1 -0
  46. package/dist/cli/bulk-scan-state.d.ts +15 -0
  47. package/dist/cli/bulk-scan-state.d.ts.map +1 -0
  48. package/dist/cli/bulk-scan-state.js +20 -0
  49. package/dist/cli/bulk-scan-state.js.map +1 -0
  50. package/dist/cli/commands/audit.d.ts +4 -0
  51. package/dist/cli/commands/audit.d.ts.map +1 -0
  52. package/dist/cli/commands/audit.js +113 -0
  53. package/dist/cli/commands/audit.js.map +1 -0
  54. package/dist/cli/commands/generate.d.ts +4 -0
  55. package/dist/cli/commands/generate.d.ts.map +1 -0
  56. package/dist/cli/commands/generate.js +231 -0
  57. package/dist/cli/commands/generate.js.map +1 -0
  58. package/dist/cli/commands/list.d.ts +4 -0
  59. package/dist/cli/commands/list.d.ts.map +1 -0
  60. package/dist/cli/commands/list.js +23 -0
  61. package/dist/cli/commands/list.js.map +1 -0
  62. package/dist/cli/commands/modelsecurity.d.ts +4 -0
  63. package/dist/cli/commands/modelsecurity.d.ts.map +1 -0
  64. package/dist/cli/commands/modelsecurity.js +499 -0
  65. package/dist/cli/commands/modelsecurity.js.map +1 -0
  66. package/dist/cli/commands/redteam.d.ts +4 -0
  67. package/dist/cli/commands/redteam.d.ts.map +1 -0
  68. package/dist/cli/commands/redteam.js +630 -0
  69. package/dist/cli/commands/redteam.js.map +1 -0
  70. package/dist/cli/commands/report.d.ts +4 -0
  71. package/dist/cli/commands/report.d.ts.map +1 -0
  72. package/dist/cli/commands/report.js +116 -0
  73. package/dist/cli/commands/report.js.map +1 -0
  74. package/dist/cli/commands/resume.d.ts +4 -0
  75. package/dist/cli/commands/resume.d.ts.map +1 -0
  76. package/dist/cli/commands/resume.js +138 -0
  77. package/dist/cli/commands/resume.js.map +1 -0
  78. package/dist/cli/commands/runtime.d.ts +3 -0
  79. package/dist/cli/commands/runtime.d.ts.map +1 -0
  80. package/dist/cli/commands/runtime.js +582 -0
  81. package/dist/cli/commands/runtime.js.map +1 -0
  82. package/dist/cli/index.d.ts +3 -0
  83. package/dist/cli/index.d.ts.map +1 -0
  84. package/dist/cli/index.js +46 -0
  85. package/dist/cli/index.js.map +1 -0
  86. package/dist/cli/parse-input.d.ts +9 -0
  87. package/dist/cli/parse-input.d.ts.map +1 -0
  88. package/dist/cli/parse-input.js +109 -0
  89. package/dist/cli/parse-input.js.map +1 -0
  90. package/dist/cli/prompts.d.ts +9 -0
  91. package/dist/cli/prompts.d.ts.map +1 -0
  92. package/dist/cli/prompts.js +90 -0
  93. package/dist/cli/prompts.js.map +1 -0
  94. package/dist/cli/renderer/audit.d.ts +8 -0
  95. package/dist/cli/renderer/audit.d.ts.map +1 -0
  96. package/dist/cli/renderer/audit.js +44 -0
  97. package/dist/cli/renderer/audit.js.map +1 -0
  98. package/dist/cli/renderer/common.d.ts +3 -0
  99. package/dist/cli/renderer/common.d.ts.map +1 -0
  100. package/dist/cli/renderer/common.js +6 -0
  101. package/dist/cli/renderer/common.js.map +1 -0
  102. package/dist/cli/renderer/generate.d.ts +29 -0
  103. package/dist/cli/renderer/generate.d.ts.map +1 -0
  104. package/dist/cli/renderer/generate.js +132 -0
  105. package/dist/cli/renderer/generate.js.map +1 -0
  106. package/dist/cli/renderer/index.d.ts +7 -0
  107. package/dist/cli/renderer/index.d.ts.map +1 -0
  108. package/dist/cli/renderer/index.js +7 -0
  109. package/dist/cli/renderer/index.js.map +1 -0
  110. package/dist/cli/renderer/modelsecurity.d.ts +34 -0
  111. package/dist/cli/renderer/modelsecurity.d.ts.map +1 -0
  112. package/dist/cli/renderer/modelsecurity.js +285 -0
  113. package/dist/cli/renderer/modelsecurity.js.map +1 -0
  114. package/dist/cli/renderer/redteam.d.ts +152 -0
  115. package/dist/cli/renderer/redteam.d.ts.map +1 -0
  116. package/dist/cli/renderer/redteam.js +294 -0
  117. package/dist/cli/renderer/redteam.js.map +1 -0
  118. package/dist/cli/renderer/runtime.d.ts +87 -0
  119. package/dist/cli/renderer/runtime.d.ts.map +1 -0
  120. package/dist/cli/renderer/runtime.js +230 -0
  121. package/dist/cli/renderer/runtime.js.map +1 -0
  122. package/dist/config/loader.d.ts +3 -0
  123. package/dist/config/loader.d.ts.map +1 -0
  124. package/dist/config/loader.js +65 -0
  125. package/dist/config/loader.js.map +1 -0
  126. package/dist/config/schema.d.ts +78 -0
  127. package/dist/config/schema.d.ts.map +1 -0
  128. package/dist/config/schema.js +44 -0
  129. package/dist/config/schema.js.map +1 -0
  130. package/dist/core/constraints.d.ts +18 -0
  131. package/dist/core/constraints.d.ts.map +1 -0
  132. package/dist/core/constraints.js +75 -0
  133. package/dist/core/constraints.js.map +1 -0
  134. package/dist/core/loop.d.ts +54 -0
  135. package/dist/core/loop.d.ts.map +1 -0
  136. package/dist/core/loop.js +462 -0
  137. package/dist/core/loop.js.map +1 -0
  138. package/dist/core/metrics.d.ts +13 -0
  139. package/dist/core/metrics.d.ts.map +1 -0
  140. package/dist/core/metrics.js +73 -0
  141. package/dist/core/metrics.js.map +1 -0
  142. package/dist/core/types.d.ts +175 -0
  143. package/dist/core/types.d.ts.map +1 -0
  144. package/dist/core/types.js +5 -0
  145. package/dist/core/types.js.map +1 -0
  146. package/dist/index.d.ts +35 -0
  147. package/dist/index.d.ts.map +1 -0
  148. package/dist/index.js +49 -0
  149. package/dist/index.js.map +1 -0
  150. package/dist/llm/prompts/analyze-results.d.ts +3 -0
  151. package/dist/llm/prompts/analyze-results.d.ts.map +1 -0
  152. package/dist/llm/prompts/analyze-results.js +52 -0
  153. package/dist/llm/prompts/analyze-results.js.map +1 -0
  154. package/dist/llm/prompts/generate-companion.d.ts +3 -0
  155. package/dist/llm/prompts/generate-companion.d.ts.map +1 -0
  156. package/dist/llm/prompts/generate-companion.js +42 -0
  157. package/dist/llm/prompts/generate-companion.js.map +1 -0
  158. package/dist/llm/prompts/generate-tests.d.ts +3 -0
  159. package/dist/llm/prompts/generate-tests.d.ts.map +1 -0
  160. package/dist/llm/prompts/generate-tests.js +46 -0
  161. package/dist/llm/prompts/generate-tests.js.map +1 -0
  162. package/dist/llm/prompts/generate-topic.d.ts +4 -0
  163. package/dist/llm/prompts/generate-topic.d.ts.map +1 -0
  164. package/dist/llm/prompts/generate-topic.js +41 -0
  165. package/dist/llm/prompts/generate-topic.js.map +1 -0
  166. package/dist/llm/prompts/improve-topic.d.ts +3 -0
  167. package/dist/llm/prompts/improve-topic.d.ts.map +1 -0
  168. package/dist/llm/prompts/improve-topic.js +77 -0
  169. package/dist/llm/prompts/improve-topic.js.map +1 -0
  170. package/dist/llm/prompts/simplify-topic.d.ts +3 -0
  171. package/dist/llm/prompts/simplify-topic.d.ts.map +1 -0
  172. package/dist/llm/prompts/simplify-topic.js +50 -0
  173. package/dist/llm/prompts/simplify-topic.js.map +1 -0
  174. package/dist/llm/provider.d.ts +21 -0
  175. package/dist/llm/provider.d.ts.map +1 -0
  176. package/dist/llm/provider.js +76 -0
  177. package/dist/llm/provider.js.map +1 -0
  178. package/dist/llm/schemas.d.ts +97 -0
  179. package/dist/llm/schemas.d.ts.map +1 -0
  180. package/dist/llm/schemas.js +24 -0
  181. package/dist/llm/schemas.js.map +1 -0
  182. package/dist/llm/service.d.ts +30 -0
  183. package/dist/llm/service.d.ts.map +1 -0
  184. package/dist/llm/service.js +273 -0
  185. package/dist/llm/service.js.map +1 -0
  186. package/dist/memory/diff.d.ts +4 -0
  187. package/dist/memory/diff.d.ts.map +1 -0
  188. package/dist/memory/diff.js +24 -0
  189. package/dist/memory/diff.js.map +1 -0
  190. package/dist/memory/extractor.d.ts +15 -0
  191. package/dist/memory/extractor.d.ts.map +1 -0
  192. package/dist/memory/extractor.js +133 -0
  193. package/dist/memory/extractor.js.map +1 -0
  194. package/dist/memory/injector.d.ts +22 -0
  195. package/dist/memory/injector.d.ts.map +1 -0
  196. package/dist/memory/injector.js +90 -0
  197. package/dist/memory/injector.js.map +1 -0
  198. package/dist/memory/prompts/extract-learnings.d.ts +3 -0
  199. package/dist/memory/prompts/extract-learnings.d.ts.map +1 -0
  200. package/dist/memory/prompts/extract-learnings.js +40 -0
  201. package/dist/memory/prompts/extract-learnings.js.map +1 -0
  202. package/dist/memory/schemas.d.ts +63 -0
  203. package/dist/memory/schemas.d.ts.map +1 -0
  204. package/dist/memory/schemas.js +13 -0
  205. package/dist/memory/schemas.js.map +1 -0
  206. package/dist/memory/store.d.ts +28 -0
  207. package/dist/memory/store.d.ts.map +1 -0
  208. package/dist/memory/store.js +103 -0
  209. package/dist/memory/store.js.map +1 -0
  210. package/dist/memory/types.d.ts +55 -0
  211. package/dist/memory/types.d.ts.map +1 -0
  212. package/dist/memory/types.js +6 -0
  213. package/dist/memory/types.js.map +1 -0
  214. package/dist/persistence/store.d.ts +21 -0
  215. package/dist/persistence/store.d.ts.map +1 -0
  216. package/dist/persistence/store.js +77 -0
  217. package/dist/persistence/store.js.map +1 -0
  218. package/dist/persistence/types.d.ts +23 -0
  219. package/dist/persistence/types.d.ts.map +1 -0
  220. package/dist/persistence/types.js +2 -0
  221. package/dist/persistence/types.js.map +1 -0
  222. package/dist/report/html.d.ts +6 -0
  223. package/dist/report/html.d.ts.map +1 -0
  224. package/dist/report/html.js +200 -0
  225. package/dist/report/html.js.map +1 -0
  226. package/dist/report/json.d.ts +11 -0
  227. package/dist/report/json.d.ts.map +1 -0
  228. package/dist/report/json.js +74 -0
  229. package/dist/report/json.js.map +1 -0
  230. package/dist/report/types.d.ts +58 -0
  231. package/dist/report/types.d.ts.map +1 -0
  232. package/dist/report/types.js +5 -0
  233. package/dist/report/types.js.map +1 -0
  234. package/package.json +67 -0
@@ -0,0 +1,462 @@
1
+ import { nanoid } from 'nanoid';
2
+ import { computeCategoryBreakdown, computeMetrics } from './metrics.js';
3
+ function delay(ms) {
4
+ return new Promise((resolve) => setTimeout(resolve, ms));
5
+ }
6
+ /** Check if a topic definition matches any previous iteration's topic. Returns the iteration number or null. */
7
+ function findDuplicateIteration(topic, iterations) {
8
+ for (const iter of iterations) {
9
+ if (iter.topic.description === topic.description &&
10
+ iter.topic.examples.length === topic.examples.length &&
11
+ iter.topic.examples.every((e, idx) => e === topic.examples[idx])) {
12
+ return iter.iteration;
13
+ }
14
+ }
15
+ return null;
16
+ }
17
+ /**
18
+ * Main refinement loop — generates, deploys, tests, and iteratively improves a topic.
19
+ * Yields typed {@link LoopEvent} discriminated unions at each stage.
20
+ * @param input - User input seeding the generation run.
21
+ * @param deps - Injected service dependencies.
22
+ */
23
+ export async function* runLoop(input, deps) {
24
+ const maxIterations = input.maxIterations ?? 20;
25
+ const targetCoverage = input.targetCoverage ?? 0.9;
26
+ const propagationDelay = deps.propagationDelayMs ?? 10000;
27
+ const runState = {
28
+ id: nanoid(),
29
+ createdAt: new Date().toISOString(),
30
+ updatedAt: new Date().toISOString(),
31
+ userInput: input,
32
+ iterations: [],
33
+ currentIteration: 0,
34
+ bestIteration: 0,
35
+ bestCoverage: 0,
36
+ consecutiveRegressions: 0,
37
+ hasRevertedToBest: false,
38
+ hasTriedSimplification: false,
39
+ status: 'running',
40
+ };
41
+ let currentTopic = null;
42
+ let topicId = '';
43
+ let companionTopicId = '';
44
+ let companionTopic = null;
45
+ let lockedName = '';
46
+ let accumulatedTests = [];
47
+ for (let i = 1; i <= maxIterations; i++) {
48
+ const iterationStart = Date.now();
49
+ runState.currentIteration = i;
50
+ yield { type: 'iteration:start', iteration: i };
51
+ // Step 1: Generate or improve topic
52
+ if (i === 1) {
53
+ currentTopic = await deps.llm.generateTopic(input.topicDescription, input.intent, input.seedExamples);
54
+ lockedName = currentTopic.name;
55
+ }
56
+ else if (currentTopic) {
57
+ const prevIteration = runState.iterations[runState.iterations.length - 1];
58
+ currentTopic = await deps.llm.improveTopic(currentTopic, prevIteration.metrics, prevIteration.analysis, prevIteration.testResults, i, targetCoverage, input.intent, {
59
+ bestCoverage: runState.bestCoverage,
60
+ bestIteration: runState.bestIteration,
61
+ bestTopic: runState.iterations[runState.bestIteration - 1]?.topic,
62
+ });
63
+ // Force the name to stay consistent across iterations
64
+ currentTopic = { ...currentTopic, name: lockedName };
65
+ // Skip scanning if topic is identical to a previous iteration
66
+ const dupIter = findDuplicateIteration(currentTopic, runState.iterations);
67
+ if (dupIter !== null) {
68
+ yield {
69
+ type: 'topic:duplicate',
70
+ topic: currentTopic,
71
+ duplicateOfIteration: dupIter,
72
+ };
73
+ runState.consecutiveRegressions++;
74
+ runState.currentIteration = i;
75
+ runState.updatedAt = new Date().toISOString();
76
+ // Recovery: revert → simplify (same tiers as end-of-iteration)
77
+ const recoveryThreshold = 2;
78
+ // Tier 1: Revert to best
79
+ if (runState.consecutiveRegressions >= recoveryThreshold &&
80
+ !runState.hasRevertedToBest &&
81
+ runState.bestIteration > 0) {
82
+ const bestResult = runState.iterations[runState.bestIteration - 1];
83
+ if (bestResult) {
84
+ currentTopic = { ...bestResult.topic };
85
+ runState.hasRevertedToBest = true;
86
+ runState.consecutiveRegressions = 0;
87
+ yield {
88
+ type: 'topic:reverted',
89
+ topic: currentTopic,
90
+ revertedToIteration: runState.bestIteration,
91
+ };
92
+ }
93
+ }
94
+ // Tier 2: Simplify
95
+ else if (runState.consecutiveRegressions >= recoveryThreshold &&
96
+ !runState.hasTriedSimplification &&
97
+ runState.bestIteration > 0) {
98
+ const bestResult = runState.iterations[runState.bestIteration - 1];
99
+ if (bestResult) {
100
+ currentTopic = await deps.llm.simplifyTopic(currentTopic, bestResult.topic, bestResult.metrics, bestResult.analysis, input.intent);
101
+ currentTopic = { ...currentTopic, name: lockedName };
102
+ runState.hasTriedSimplification = true;
103
+ runState.consecutiveRegressions = 0;
104
+ yield { type: 'topic:simplified', topic: currentTopic };
105
+ // If simplified topic is also a duplicate, don't reset — count it
106
+ const simpDupIter = findDuplicateIteration(currentTopic, runState.iterations);
107
+ if (simpDupIter !== null) {
108
+ yield {
109
+ type: 'topic:duplicate',
110
+ topic: currentTopic,
111
+ duplicateOfIteration: simpDupIter,
112
+ };
113
+ runState.consecutiveRegressions++;
114
+ }
115
+ }
116
+ }
117
+ const maxRegressions = input.maxRegressions ?? 3;
118
+ if (maxRegressions > 0 && runState.consecutiveRegressions >= maxRegressions) {
119
+ break;
120
+ }
121
+ continue;
122
+ }
123
+ }
124
+ /* v8 ignore next */
125
+ if (!currentTopic)
126
+ throw new Error('Invariant: topic must exist');
127
+ const topic = currentTopic;
128
+ yield { type: 'generate:complete', topic };
129
+ // Step 2: Apply topic via management API (SDK v2)
130
+ if (i === 1) {
131
+ // Check if a topic with this name already exists (reuse it)
132
+ const existing = await deps.management.listTopics();
133
+ const match = existing.find((t) => t.topic_name === topic.name);
134
+ if (match?.topic_id) {
135
+ topicId = match.topic_id;
136
+ await deps.management.updateTopic(topicId, {
137
+ topic_name: topic.name,
138
+ description: topic.description,
139
+ examples: topic.examples,
140
+ active: true,
141
+ });
142
+ }
143
+ else {
144
+ const response = await deps.management.createTopic({
145
+ topic_name: topic.name,
146
+ description: topic.description,
147
+ examples: topic.examples,
148
+ active: true,
149
+ });
150
+ /* v8 ignore next */
151
+ if (!response.topic_id)
152
+ throw new Error('Invariant: topic_id missing from create response');
153
+ topicId = response.topic_id;
154
+ }
155
+ // Guardrail-level action is the INVERSE of topic intent:
156
+ // block-intent → guardrailAction='allow' (default: allow, block topics carve out violations)
157
+ // allow-intent → guardrailAction='block' (default: block, allow topics whitelist content)
158
+ const guardrailAction = input.intent === 'block' ? 'allow' : 'block';
159
+ if (input.intent === 'block') {
160
+ // Two-phase: generate domain-specific allow companion for block-intent.
161
+ // AIRS needs both allow + block topics sharing the same vocabulary domain
162
+ // for the matching engine to distinguish benign from malicious content.
163
+ companionTopic = await deps.llm.generateCompanionTopic(topic.name, topic.description);
164
+ yield { type: 'companion:generated', topic: companionTopic };
165
+ const companionMatch = existing.find((t) => t.topic_name === companionTopic?.name);
166
+ if (companionMatch?.topic_id) {
167
+ companionTopicId = companionMatch.topic_id;
168
+ await deps.management.updateTopic(companionTopicId, {
169
+ topic_name: companionTopic.name,
170
+ description: companionTopic.description,
171
+ examples: companionTopic.examples,
172
+ active: true,
173
+ });
174
+ }
175
+ else {
176
+ const cResponse = await deps.management.createTopic({
177
+ topic_name: companionTopic.name,
178
+ description: companionTopic.description,
179
+ examples: companionTopic.examples,
180
+ active: true,
181
+ });
182
+ /* v8 ignore next */
183
+ if (!cResponse.topic_id)
184
+ throw new Error('Invariant: topic_id missing from companion create response');
185
+ companionTopicId = cResponse.topic_id;
186
+ }
187
+ yield { type: 'companion:created', topicId: companionTopicId, topic: companionTopic };
188
+ runState.companionTopic = companionTopic;
189
+ // Wire both topics to profile with guardrailAction='allow'
190
+ await deps.management.assignTopicsToProfile(input.profileName, [
191
+ { topicId: companionTopicId, topicName: companionTopic.name, action: 'allow' },
192
+ { topicId, topicName: topic.name, action: 'block' },
193
+ ], guardrailAction);
194
+ }
195
+ else {
196
+ // Allow-intent: single topic, guardrailAction='block'
197
+ await deps.management.assignTopicsToProfile(input.profileName, [{ topicId, topicName: topic.name, action: input.intent }], guardrailAction);
198
+ }
199
+ }
200
+ else {
201
+ await deps.management.updateTopic(topicId, {
202
+ topic_name: topic.name,
203
+ description: topic.description,
204
+ examples: topic.examples,
205
+ active: true,
206
+ });
207
+ // Re-assign topics to profile so AIRS references the new topic revision.
208
+ // AIRS pins topic content to the revision in the profile — without this,
209
+ // the profile would still reference the pre-update revision.
210
+ const guardrailAction = input.intent === 'block' ? 'allow' : 'block';
211
+ const topicEntries = [{ topicId, topicName: topic.name, action: input.intent }];
212
+ if (input.intent === 'block' && companionTopicId && companionTopic) {
213
+ topicEntries.unshift({
214
+ topicId: companionTopicId,
215
+ topicName: companionTopic.name,
216
+ action: 'allow',
217
+ });
218
+ }
219
+ await deps.management.assignTopicsToProfile(input.profileName, topicEntries, guardrailAction);
220
+ }
221
+ yield { type: 'apply:complete', topicId };
222
+ // Wait for propagation
223
+ if (propagationDelay > 0) {
224
+ await delay(propagationDelay);
225
+ }
226
+ // Warm-up probe: verify topic is active before first scan.
227
+ // Iteration 1 requires both topic creation AND profile revision propagation,
228
+ // which takes longer than the content-only updates on iteration 2+.
229
+ if (i === 1 && topic.examples.length > 0) {
230
+ const probePrompt = topic.examples[0];
231
+ const maxProbeAttempts = deps.maxProbeAttempts ?? 6;
232
+ const probeIntervalMs = deps.probeIntervalMs ?? 5000;
233
+ for (let attempt = 1; attempt <= maxProbeAttempts; attempt++) {
234
+ const probeResult = await deps.scanner.scan(input.profileName, probePrompt, `prisma-airs-cli-${runState.id.slice(0, 7)}-probe`);
235
+ const matched = probeResult.triggered;
236
+ if (matched) {
237
+ yield { type: 'probe:ready', attempts: attempt };
238
+ break;
239
+ }
240
+ if (attempt < maxProbeAttempts) {
241
+ yield {
242
+ type: 'probe:waiting',
243
+ attempt,
244
+ maxAttempts: maxProbeAttempts,
245
+ };
246
+ await delay(probeIntervalMs);
247
+ }
248
+ }
249
+ }
250
+ // Step 3: Generate test cases (with category breakdown for weighted generation)
251
+ const prevItResults = i > 1 ? runState.iterations[runState.iterations.length - 1] : undefined;
252
+ const categoryBreakdown = prevItResults
253
+ ? computeCategoryBreakdown(prevItResults.testResults)
254
+ : undefined;
255
+ const { positiveTests, negativeTests } = await deps.llm.generateTests(topic, input.intent, categoryBreakdown);
256
+ const newTests = [...positiveTests, ...negativeTests].map((t) => ({
257
+ ...t,
258
+ source: 'generated',
259
+ }));
260
+ // Build carried failures + regression tier from previous iteration
261
+ let carriedFailures = [];
262
+ let regressionTier = [];
263
+ if (i > 1 && prevItResults) {
264
+ carriedFailures = prevItResults.testResults
265
+ .filter((r) => !r.correct)
266
+ .map((r) => {
267
+ const source = r.testCase.expectedTriggered && !r.actualTriggered ? 'carried-fn' : 'carried-fp';
268
+ return { ...r.testCase, source };
269
+ });
270
+ regressionTier = prevItResults.testResults
271
+ .filter((r) => r.correct)
272
+ .map((r) => ({ ...r.testCase, source: 'regression' }));
273
+ }
274
+ // Merge: carried failures > regression > generated (dedup by prompt text)
275
+ const seen = new Set();
276
+ const merged = [];
277
+ for (const pool of [carriedFailures, regressionTier, newTests]) {
278
+ for (const t of pool) {
279
+ const key = t.prompt.toLowerCase().trim();
280
+ if (!seen.has(key)) {
281
+ seen.add(key);
282
+ merged.push(t);
283
+ }
284
+ }
285
+ }
286
+ // Also merge old accumulated tests if accumulation enabled
287
+ if (input.accumulateTests && i > 1) {
288
+ for (const t of accumulatedTests) {
289
+ const key = t.prompt.toLowerCase().trim();
290
+ if (!seen.has(key)) {
291
+ seen.add(key);
292
+ merged.push(t);
293
+ }
294
+ }
295
+ }
296
+ // Apply max cap
297
+ const maxCap = input.maxAccumulatedTests;
298
+ const preCapCount = merged.length;
299
+ const allTests = maxCap && merged.length > maxCap ? merged.slice(0, maxCap) : merged;
300
+ // Emit composition event on iteration 2+
301
+ if (i > 1) {
302
+ yield {
303
+ type: 'tests:composed',
304
+ generated: newTests.length,
305
+ carriedFailures: carriedFailures.length,
306
+ regressionTier: regressionTier.length,
307
+ total: allTests.length,
308
+ };
309
+ }
310
+ // Emit legacy accumulated event when accumulation enabled
311
+ if (input.accumulateTests && i > 1) {
312
+ yield {
313
+ type: 'tests:accumulated',
314
+ newCount: newTests.length,
315
+ totalCount: allTests.length,
316
+ droppedCount: preCapCount - allTests.length,
317
+ };
318
+ }
319
+ accumulatedTests = allTests;
320
+ // Step 4: Run scans
321
+ const sessionId = `prisma-airs-cli-${runState.id.slice(0, 7)}-iter${i}`;
322
+ const testResults = [];
323
+ const prompts = allTests.map((t) => t.prompt);
324
+ const scanResults = await deps.scanner.scanBatch(input.profileName, prompts, undefined, sessionId);
325
+ for (let j = 0; j < allTests.length; j++) {
326
+ const testCase = allTests[j];
327
+ const scanResult = scanResults[j];
328
+ // prompt_detected.topic_violation is the sole signal for both intents.
329
+ const actualTriggered = scanResult.triggered;
330
+ testResults.push({
331
+ testCase,
332
+ actualTriggered,
333
+ scanAction: scanResult.action,
334
+ scanId: scanResult.scanId,
335
+ reportId: scanResult.reportId,
336
+ correct: testCase.expectedTriggered === actualTriggered,
337
+ });
338
+ yield { type: 'test:progress', completed: j + 1, total: allTests.length };
339
+ }
340
+ // Step 5: Evaluate
341
+ const metrics = computeMetrics(testResults);
342
+ yield { type: 'evaluate:complete', metrics };
343
+ // Step 6: Analyze
344
+ const analysis = await deps.llm.analyzeResults(topic, testResults, metrics, input.intent);
345
+ yield { type: 'analyze:complete', analysis };
346
+ // Record iteration
347
+ const iterationResult = {
348
+ iteration: i,
349
+ timestamp: new Date().toISOString(),
350
+ topic,
351
+ testCases: allTests,
352
+ testResults,
353
+ metrics,
354
+ analysis,
355
+ durationMs: Date.now() - iterationStart,
356
+ };
357
+ runState.iterations.push(iterationResult);
358
+ if (metrics.coverage > runState.bestCoverage) {
359
+ runState.bestCoverage = metrics.coverage;
360
+ runState.bestIteration = i;
361
+ runState.consecutiveRegressions = 0;
362
+ }
363
+ else {
364
+ runState.consecutiveRegressions++;
365
+ }
366
+ runState.updatedAt = new Date().toISOString();
367
+ yield { type: 'iteration:complete', result: iterationResult };
368
+ // Check stop conditions
369
+ if (metrics.coverage >= targetCoverage) {
370
+ break;
371
+ }
372
+ // Recovery strategy: revert → simplify → stop
373
+ const recoveryThreshold = 2;
374
+ const maxRegressions = input.maxRegressions ?? 3;
375
+ // Tier 1: Revert to best-performing definition (no LLM call)
376
+ if (runState.consecutiveRegressions >= recoveryThreshold &&
377
+ !runState.hasRevertedToBest &&
378
+ runState.bestIteration > 0) {
379
+ const bestResult = runState.iterations[runState.bestIteration - 1];
380
+ if (bestResult) {
381
+ currentTopic = { ...bestResult.topic };
382
+ runState.hasRevertedToBest = true;
383
+ runState.consecutiveRegressions = 0;
384
+ yield {
385
+ type: 'topic:reverted',
386
+ topic: currentTopic,
387
+ revertedToIteration: runState.bestIteration,
388
+ };
389
+ }
390
+ }
391
+ // Tier 2: LLM simplification (after revert already tried)
392
+ else if (runState.consecutiveRegressions >= recoveryThreshold &&
393
+ !runState.hasTriedSimplification &&
394
+ runState.bestIteration > 0) {
395
+ const bestResult = runState.iterations[runState.bestIteration - 1];
396
+ if (bestResult) {
397
+ currentTopic = await deps.llm.simplifyTopic(topic, bestResult.topic, bestResult.metrics, bestResult.analysis, input.intent);
398
+ currentTopic = { ...currentTopic, name: lockedName };
399
+ runState.hasTriedSimplification = true;
400
+ runState.consecutiveRegressions = 0;
401
+ yield { type: 'topic:simplified', topic: currentTopic };
402
+ // Check if simplified topic is a duplicate of a previous iteration
403
+ const simpDupIter = findDuplicateIteration(currentTopic, runState.iterations);
404
+ if (simpDupIter !== null) {
405
+ yield {
406
+ type: 'topic:duplicate',
407
+ topic: currentTopic,
408
+ duplicateOfIteration: simpDupIter,
409
+ };
410
+ runState.consecutiveRegressions++;
411
+ }
412
+ }
413
+ }
414
+ // Tier 3: Early stop
415
+ if (maxRegressions > 0 && runState.consecutiveRegressions >= maxRegressions) {
416
+ break;
417
+ }
418
+ // Plateau detection: coverage oscillating in narrow band without improvement (opt-in)
419
+ const plateauWindow = input.plateauWindow ?? 0;
420
+ const plateauBand = input.plateauBand ?? 0.05;
421
+ if (plateauWindow > 0 && runState.iterations.length >= plateauWindow + 1) {
422
+ const recent = runState.iterations.slice(-plateauWindow).map((r) => r.metrics.coverage);
423
+ const min = Math.min(...recent);
424
+ const max = Math.max(...recent);
425
+ if (max - min <= plateauBand && max < runState.bestCoverage + plateauBand) {
426
+ yield {
427
+ type: 'loop:plateau',
428
+ band: [min, max],
429
+ bestCoverage: runState.bestCoverage,
430
+ };
431
+ break;
432
+ }
433
+ }
434
+ }
435
+ runState.status = 'completed';
436
+ // Extract learnings from this run if memory is enabled
437
+ if (deps.memory?.extractor) {
438
+ const { learnings } = await deps.memory.extractor.extractAndSave(runState);
439
+ yield { type: 'memory:extracted', learningCount: learnings.length };
440
+ }
441
+ const bestResult = runState.iterations[runState.bestIteration - 1] ??
442
+ runState.iterations[runState.iterations.length - 1];
443
+ // Create custom prompt set from best iteration's test cases if requested
444
+ if (input.createPromptSet && deps.promptSets && bestResult) {
445
+ const setName = input.promptSetName ?? `prisma-airs-cli-${bestResult.topic.name}-${runState.id.slice(0, 7)}`;
446
+ const { uuid } = await deps.promptSets.createPromptSet(setName, `Generated by Prisma AIRS CLI run ${runState.id} — ${bestResult.testCases.length} prompts from iteration ${bestResult.iteration}`);
447
+ for (const tc of bestResult.testCases) {
448
+ const goal = tc.expectedTriggered
449
+ ? 'Should trigger topic guardrail'
450
+ : 'Should NOT trigger topic guardrail';
451
+ await deps.promptSets.addPrompt(uuid, tc.prompt, goal);
452
+ }
453
+ yield {
454
+ type: 'promptset:created',
455
+ promptSetId: uuid,
456
+ promptSetName: setName,
457
+ promptCount: bestResult.testCases.length,
458
+ };
459
+ }
460
+ yield { type: 'loop:complete', bestResult, runState };
461
+ }
462
+ //# sourceMappingURL=loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/core/loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { CategoryBreakdown, EfficacyMetrics, TestResult } from './types.js';
2
+ /**
3
+ * Classify test results into TP/TN/FP/FN and compute efficacy metrics.
4
+ *
5
+ * @param results - Scan results paired with their expected outcomes.
6
+ * @returns Confusion matrix counts, rates (TPR, TNR, accuracy, coverage, F1),
7
+ * and regression failure count. Division-by-zero yields 0.
8
+ * Coverage = min(TPR, TNR) — the loop's stop condition target.
9
+ */
10
+ export declare function computeMetrics(results: TestResult[]): EfficacyMetrics;
11
+ /** Compute per-category error breakdown from test results. Sorted by error rate descending. */
12
+ export declare function computeCategoryBreakdown(results: TestResult[]): CategoryBreakdown[];
13
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/core/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEjF;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,eAAe,CA0CrE;AAED,+FAA+F;AAC/F,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,iBAAiB,EAAE,CAqBnF"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Classify test results into TP/TN/FP/FN and compute efficacy metrics.
3
+ *
4
+ * @param results - Scan results paired with their expected outcomes.
5
+ * @returns Confusion matrix counts, rates (TPR, TNR, accuracy, coverage, F1),
6
+ * and regression failure count. Division-by-zero yields 0.
7
+ * Coverage = min(TPR, TNR) — the loop's stop condition target.
8
+ */
9
+ export function computeMetrics(results) {
10
+ let truePositives = 0;
11
+ let trueNegatives = 0;
12
+ let falsePositives = 0;
13
+ let falseNegatives = 0;
14
+ let regressionCount = 0;
15
+ for (const r of results) {
16
+ if (r.testCase.expectedTriggered && r.actualTriggered)
17
+ truePositives++;
18
+ else if (!r.testCase.expectedTriggered && !r.actualTriggered)
19
+ trueNegatives++;
20
+ else if (!r.testCase.expectedTriggered && r.actualTriggered)
21
+ falsePositives++;
22
+ else if (r.testCase.expectedTriggered && !r.actualTriggered)
23
+ falseNegatives++;
24
+ if (r.testCase.source === 'regression' && !r.correct)
25
+ regressionCount++;
26
+ }
27
+ const totalPositives = truePositives + falseNegatives;
28
+ const totalNegatives = trueNegatives + falsePositives;
29
+ const total = results.length;
30
+ const truePositiveRate = totalPositives > 0 ? truePositives / totalPositives : 0;
31
+ const trueNegativeRate = totalNegatives > 0 ? trueNegatives / totalNegatives : 0;
32
+ const accuracy = total > 0 ? (truePositives + trueNegatives) / total : 0;
33
+ const coverage = Math.min(truePositiveRate, trueNegativeRate);
34
+ const precision = truePositives + falsePositives > 0 ? truePositives / (truePositives + falsePositives) : 0;
35
+ const recall = truePositiveRate;
36
+ const f1Score = precision + recall > 0 ? (2 * precision * recall) / (precision + recall) : 0;
37
+ return {
38
+ truePositives,
39
+ trueNegatives,
40
+ falsePositives,
41
+ falseNegatives,
42
+ truePositiveRate,
43
+ trueNegativeRate,
44
+ accuracy,
45
+ coverage,
46
+ f1Score,
47
+ regressionCount,
48
+ };
49
+ }
50
+ /** Compute per-category error breakdown from test results. Sorted by error rate descending. */
51
+ export function computeCategoryBreakdown(results) {
52
+ const map = new Map();
53
+ for (const r of results) {
54
+ const cat = r.testCase.category;
55
+ const entry = map.get(cat) ?? { total: 0, fp: 0, fn: 0 };
56
+ entry.total++;
57
+ if (!r.testCase.expectedTriggered && r.actualTriggered)
58
+ entry.fp++;
59
+ if (r.testCase.expectedTriggered && !r.actualTriggered)
60
+ entry.fn++;
61
+ map.set(cat, entry);
62
+ }
63
+ return [...map.entries()]
64
+ .map(([category, { total, fp, fn }]) => ({
65
+ category,
66
+ total,
67
+ fp,
68
+ fn,
69
+ errorRate: total > 0 ? (fp + fn) / total : 0,
70
+ }))
71
+ .sort((a, b) => b.errorRate - a.errorRate);
72
+ }
73
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/core/metrics.ts"],"names":[],"mappings":"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"}