@taodigital/agents 0.0.0-stage → 1.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 (76) hide show
  1. package/README.md +99 -2
  2. package/dist/api-test-agent.d.ts +126 -0
  3. package/dist/api-test-agent.js +267 -0
  4. package/dist/artifact-intel-agent.d.ts +11 -0
  5. package/dist/artifact-intel-agent.js +152 -0
  6. package/dist/coverage-gap-agent.d.ts +25 -0
  7. package/dist/coverage-gap-agent.js +269 -0
  8. package/dist/coverage-map-agent.d.ts +15 -0
  9. package/dist/coverage-map-agent.js +255 -0
  10. package/dist/crawl-diff-agent.d.ts +27 -0
  11. package/dist/crawl-diff-agent.js +412 -0
  12. package/dist/data-agent.d.ts +101 -0
  13. package/dist/data-agent.js +2284 -0
  14. package/dist/document-agent.d.ts +10 -0
  15. package/dist/document-agent.js +32 -0
  16. package/dist/enhancement-agent.d.ts +48 -0
  17. package/dist/enhancement-agent.js +342 -0
  18. package/dist/field-detector-agent.d.ts +35 -0
  19. package/dist/field-detector-agent.js +220 -0
  20. package/dist/flow-agent.d.ts +130 -0
  21. package/dist/flow-agent.js +169 -0
  22. package/dist/github-agent.d.ts +18 -0
  23. package/dist/github-agent.js +39 -0
  24. package/dist/github-write-agent.d.ts +67 -0
  25. package/dist/github-write-agent.js +249 -0
  26. package/dist/grouping-agent.d.ts +18 -0
  27. package/dist/grouping-agent.js +338 -0
  28. package/dist/healing-agent.d.ts +73 -0
  29. package/dist/healing-agent.js +137 -0
  30. package/dist/index.d.ts +36 -0
  31. package/dist/index.js +67 -0
  32. package/dist/integration-test-agent.d.ts +118 -0
  33. package/dist/integration-test-agent.js +165 -0
  34. package/dist/label-assignment-agent.d.ts +15 -0
  35. package/dist/label-assignment-agent.js +97 -0
  36. package/dist/llm-config.d.ts +38 -0
  37. package/dist/llm-config.js +287 -0
  38. package/dist/llm-mock.d.ts +77 -0
  39. package/dist/llm-mock.js +192 -0
  40. package/dist/llm.d.ts +58 -0
  41. package/dist/llm.js +438 -0
  42. package/dist/nlp-agent.d.ts +208 -0
  43. package/dist/nlp-agent.js +340 -0
  44. package/dist/orchestrator.d.ts +285 -0
  45. package/dist/orchestrator.js +141 -0
  46. package/dist/plan-agent.d.ts +4 -0
  47. package/dist/plan-agent.js +200 -0
  48. package/dist/repo-scan-agent.d.ts +189 -0
  49. package/dist/repo-scan-agent.js +2032 -0
  50. package/dist/requirements-agent.d.ts +59 -0
  51. package/dist/requirements-agent.js +641 -0
  52. package/dist/scenario-agent.d.ts +20 -0
  53. package/dist/scenario-agent.js +123 -0
  54. package/dist/script-agent.d.ts +447 -0
  55. package/dist/script-agent.js +11813 -0
  56. package/dist/security-test-agent.d.ts +111 -0
  57. package/dist/security-test-agent.js +141 -0
  58. package/dist/skill-file-agent.d.ts +264 -0
  59. package/dist/skill-file-agent.js +3470 -0
  60. package/dist/step-coverage.d.ts +46 -0
  61. package/dist/step-coverage.js +288 -0
  62. package/dist/step-utils.d.ts +2 -0
  63. package/dist/step-utils.js +62 -0
  64. package/dist/test-case-agent.d.ts +206 -0
  65. package/dist/test-case-agent.js +2141 -0
  66. package/dist/test-import-agent.d.ts +148 -0
  67. package/dist/test-import-agent.js +3235 -0
  68. package/dist/test-script-agent.d.ts +16 -0
  69. package/dist/test-script-agent.js +48 -0
  70. package/dist/token-pricing.d.ts +14 -0
  71. package/dist/token-pricing.js +62 -0
  72. package/dist/types.d.ts +232 -0
  73. package/dist/types.js +7 -0
  74. package/dist/visual-agent.d.ts +114 -0
  75. package/dist/visual-agent.js +261 -0
  76. package/package.json +26 -4
@@ -0,0 +1,412 @@
1
+ "use strict";
2
+ /**
3
+ * ZeTa-AI Crawl Diff Agent
4
+ *
5
+ * Compares DOM elements and navigation flows across two crawl runs to detect
6
+ * structural UI changes. Drives the approval gate state machine that gates
7
+ * script generation until all diffs are reviewed.
8
+ *
9
+ * Public entry points:
10
+ * computeCrawlDiffs — diff elements + flows between two crawl jobs
11
+ * createCrawlContextEnhancement — create ContextEnhancement record for a crawl job
12
+ * approveCrawlDiff — mark a diff approved, flag affected test cases suspect
13
+ * recomputeApprovalGateSummary — recompute contextPhase based on pending diffs
14
+ * computeCoverageGaps — find UI elements not covered by any test case
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.computeCrawlDiffs = computeCrawlDiffs;
18
+ exports.createCrawlContextEnhancement = createCrawlContextEnhancement;
19
+ exports.approveCrawlDiff = approveCrawlDiff;
20
+ exports.recomputeApprovalGateSummary = recomputeApprovalGateSummary;
21
+ exports.computeCoverageGaps = computeCoverageGaps;
22
+ const database_1 = require("@taodigital/database");
23
+ // ─── Constants ────────────────────────────────────────────────────────────────
24
+ const PHASE_ORDER = [
25
+ 'PENDING_CONTEXT',
26
+ 'CONTEXT_PARTIAL',
27
+ 'CONTEXT_ENRICHED',
28
+ 'DIFF_PENDING_APPROVAL',
29
+ 'ALL_DIFFS_APPROVED',
30
+ 'READY_FOR_SCRIPT_GEN',
31
+ ];
32
+ const CONTEXT_THRESHOLDS = {
33
+ WEB: 80,
34
+ API: 40,
35
+ NATIVE: 60,
36
+ HYBRID: 70,
37
+ };
38
+ // Non-interactive roles to skip in coverage gap analysis
39
+ const NON_INTERACTIVE_ROLES = new Set(['link', 'heading', 'image', 'text']);
40
+ // ─── 1. computeCrawlDiffs ─────────────────────────────────────────────────────
41
+ async function computeCrawlDiffs(tenantId, projectId, fromJobId, toJobId) {
42
+ // Load screens for each job run, keyed by url (fallback to name)
43
+ const [fromScreens, toScreens] = await Promise.all([
44
+ database_1.prismaAdmin.screen.findMany({
45
+ where: { tenantId, projectId, lastCrawlJobId: fromJobId },
46
+ }),
47
+ database_1.prismaAdmin.screen.findMany({
48
+ where: { tenantId, projectId, lastCrawlJobId: toJobId },
49
+ }),
50
+ ]);
51
+ const fromScreenMap = new Map(fromScreens.map((s) => [s.url ?? s.name, s]));
52
+ const toScreenMap = new Map(toScreens.map((s) => [s.url ?? s.name, s]));
53
+ // Find screens present in both runs
54
+ const commonKeys = [...fromScreenMap.keys()].filter((k) => toScreenMap.has(k));
55
+ const diffsToCreate = [];
56
+ // ── Element diffs for common screens ──────────────────────────────────────
57
+ for (const key of commonKeys) {
58
+ const fromScreen = fromScreenMap.get(key);
59
+ const toScreen = toScreenMap.get(key);
60
+ const [fromElements, toElements] = await Promise.all([
61
+ database_1.prismaAdmin.element.findMany({ where: { tenantId, screenId: fromScreen.id } }),
62
+ database_1.prismaAdmin.element.findMany({ where: { tenantId, screenId: toScreen.id } }),
63
+ ]);
64
+ // Key elements by role+meaning for comparison
65
+ const makeElementKey = (e) => `${e.role ?? ''}::${e.meaning ?? e.text ?? ''}`;
66
+ const fromElemMap = new Map(fromElements.map((e) => [makeElementKey(e), e]));
67
+ const toElemMap = new Map(toElements.map((e) => [makeElementKey(e), e]));
68
+ // Removed elements (in from, not in to)
69
+ for (const [eKey, elem] of fromElemMap) {
70
+ if (!toElemMap.has(eKey)) {
71
+ const affectedTestCaseIds = await findAffectedTestCases(tenantId, projectId, [elem.id]);
72
+ const severity = computeSeverity(affectedTestCaseIds.length);
73
+ diffsToCreate.push({
74
+ tenantId,
75
+ projectId,
76
+ fromJobId,
77
+ toJobId,
78
+ diffType: 'ELEMENT_REMOVED',
79
+ severity,
80
+ status: severity === 'NONE' ? 'APPROVED' : 'PENDING',
81
+ fromScreenId: fromScreen.id,
82
+ toScreenId: toScreen.id,
83
+ elementRole: elem.role,
84
+ elementMeaning: elem.meaning,
85
+ affectedTestCaseIds,
86
+ });
87
+ }
88
+ }
89
+ // Added elements (in to, not in from)
90
+ for (const [eKey, elem] of toElemMap) {
91
+ if (!fromElemMap.has(eKey)) {
92
+ const affectedTestCaseIds = await findAffectedTestCases(tenantId, projectId, [elem.id]);
93
+ const severity = computeSeverity(affectedTestCaseIds.length);
94
+ diffsToCreate.push({
95
+ tenantId,
96
+ projectId,
97
+ fromJobId,
98
+ toJobId,
99
+ diffType: 'ELEMENT_ADDED',
100
+ severity,
101
+ status: severity === 'NONE' ? 'APPROVED' : 'PENDING',
102
+ fromScreenId: fromScreen.id,
103
+ toScreenId: toScreen.id,
104
+ elementRole: elem.role,
105
+ elementMeaning: elem.meaning,
106
+ affectedTestCaseIds,
107
+ });
108
+ }
109
+ }
110
+ }
111
+ // ── Flow diffs (DiscoveredLink) ────────────────────────────────────────────
112
+ const [fromLinks, toLinks] = await Promise.all([
113
+ database_1.prismaAdmin.discoveredLink.findMany({ where: { tenantId, projectId, jobId: fromJobId } }),
114
+ database_1.prismaAdmin.discoveredLink.findMany({ where: { tenantId, projectId, jobId: toJobId } }),
115
+ ]);
116
+ const fromLinkSet = new Set(fromLinks.map((l) => l.href));
117
+ const toLinkSet = new Set(toLinks.map((l) => l.href));
118
+ // Links added in toJob (not in fromJob)
119
+ for (const link of toLinks) {
120
+ if (!fromLinkSet.has(link.href)) {
121
+ diffsToCreate.push({
122
+ tenantId,
123
+ projectId,
124
+ fromJobId,
125
+ toJobId,
126
+ diffType: 'FLOW_ADDED',
127
+ severity: 'MINOR',
128
+ status: 'PENDING',
129
+ fromScreenId: null,
130
+ toScreenId: link.toScreenId,
131
+ fromHref: null,
132
+ toHref: link.href,
133
+ affectedTestCaseIds: [],
134
+ });
135
+ }
136
+ }
137
+ // Links removed (in fromJob, not in toJob)
138
+ for (const link of fromLinks) {
139
+ if (!toLinkSet.has(link.href)) {
140
+ diffsToCreate.push({
141
+ tenantId,
142
+ projectId,
143
+ fromJobId,
144
+ toJobId,
145
+ diffType: 'FLOW_REMOVED',
146
+ severity: 'SIGNIFICANT',
147
+ status: 'PENDING',
148
+ fromScreenId: link.toScreenId,
149
+ toScreenId: null,
150
+ fromHref: link.href,
151
+ toHref: null,
152
+ affectedTestCaseIds: [],
153
+ });
154
+ }
155
+ }
156
+ // ── Batch-create all diffs ─────────────────────────────────────────────────
157
+ if (diffsToCreate.length > 0) {
158
+ await database_1.prismaAdmin.crawlDiff.createMany({
159
+ data: diffsToCreate.map((d) => ({
160
+ ...d,
161
+ affectedTestCaseIds: JSON.stringify(d.affectedTestCaseIds),
162
+ createdAt: new Date(),
163
+ })),
164
+ skipDuplicates: true,
165
+ });
166
+ }
167
+ const criticalCount = diffsToCreate.filter((d) => d.severity === 'CRITICAL').length;
168
+ const significantCount = diffsToCreate.filter((d) => d.severity === 'SIGNIFICANT').length;
169
+ // ── Create context enhancement record ────────────────────────────────────
170
+ await createCrawlContextEnhancement(tenantId, projectId, toJobId, diffsToCreate.map((d) => ({ severity: d.severity })));
171
+ return {
172
+ diffCount: diffsToCreate.length,
173
+ criticalCount,
174
+ significantCount,
175
+ };
176
+ }
177
+ // ─── 2. createCrawlContextEnhancement ────────────────────────────────────────
178
+ async function createCrawlContextEnhancement(tenantId, projectId, toJobId, diffs) {
179
+ const hasPendingDiffs = diffs.filter((d) => d.severity !== 'NONE').length > 0;
180
+ const status = hasPendingDiffs ? 'DIFF_READY' : 'APPROVED';
181
+ return database_1.prismaAdmin.contextEnhancement.create({
182
+ data: {
183
+ tenantId,
184
+ projectId,
185
+ sourceType: 'CRAWL',
186
+ crawlJobId: toJobId,
187
+ status,
188
+ proposedChanges: [],
189
+ createdAt: new Date(),
190
+ },
191
+ });
192
+ }
193
+ // ─── 3. approveCrawlDiff ──────────────────────────────────────────────────────
194
+ async function approveCrawlDiff(tenantId, projectId, diffId, reviewedBy) {
195
+ const diff = await database_1.prismaAdmin.crawlDiff.findFirstOrThrow({
196
+ where: { id: diffId, tenantId },
197
+ });
198
+ await database_1.prismaAdmin.$transaction([
199
+ database_1.prismaAdmin.crawlDiff.update({
200
+ where: { id: diffId },
201
+ data: {
202
+ status: 'APPROVED',
203
+ reviewedBy,
204
+ reviewedAt: new Date(),
205
+ },
206
+ }),
207
+ ]);
208
+ // Flag affected test cases as suspect
209
+ const affectedTestCaseIds = (() => {
210
+ try {
211
+ const raw = diff.affectedTestCaseIds;
212
+ if (Array.isArray(raw))
213
+ return raw;
214
+ if (typeof raw === 'string')
215
+ return JSON.parse(raw);
216
+ return [];
217
+ }
218
+ catch {
219
+ return [];
220
+ }
221
+ })();
222
+ if (affectedTestCaseIds.length > 0) {
223
+ await database_1.prismaAdmin.testCase.updateMany({
224
+ where: { id: { in: affectedTestCaseIds }, tenantId },
225
+ data: { suspect: true },
226
+ });
227
+ }
228
+ await recomputeApprovalGateSummary(tenantId, projectId);
229
+ }
230
+ // ─── 4. recomputeApprovalGateSummary ─────────────────────────────────────────
231
+ async function recomputeApprovalGateSummary(tenantId, projectId) {
232
+ const [screenshotPending, figmaPending, crawlPending, apiSpecPending] = await Promise.all([
233
+ database_1.prismaAdmin.contextEnhancement.count({
234
+ where: { tenantId, projectId, sourceType: 'SCREENSHOT', status: { in: ['DIFF_READY', 'PENDING'] } },
235
+ }),
236
+ database_1.prismaAdmin.contextEnhancement.count({
237
+ where: { tenantId, projectId, sourceType: 'FIGMA', status: { in: ['DIFF_READY', 'PENDING'] } },
238
+ }),
239
+ database_1.prismaAdmin.crawlDiff.count({
240
+ where: { tenantId, projectId, status: 'PENDING' },
241
+ }),
242
+ database_1.prismaAdmin.contextEnhancement.count({
243
+ where: { tenantId, projectId, sourceType: 'API_SPEC', status: { in: ['DIFF_READY', 'PENDING'] } },
244
+ }),
245
+ ]);
246
+ const project = await database_1.prismaAdmin.project.findFirstOrThrow({
247
+ where: { id: projectId, tenantId },
248
+ select: {
249
+ projectKind: true,
250
+ contextScore: true,
251
+ contextPhase: true,
252
+ contextSourceRequirements: true,
253
+ },
254
+ });
255
+ const req = project.contextSourceRequirements ?? {};
256
+ const summary = {
257
+ screenshotsDone: screenshotPending === 0,
258
+ figmaDone: figmaPending === 0,
259
+ crawlDone: crawlPending === 0,
260
+ apiSpecDone: apiSpecPending === 0,
261
+ pendingCounts: {
262
+ screenshot: screenshotPending,
263
+ figma: figmaPending,
264
+ crawl: crawlPending,
265
+ apiSpec: apiSpecPending,
266
+ },
267
+ };
268
+ const allRequiredDone = Object.entries(req).every(([src, level]) => {
269
+ if (level !== 'REQUIRED')
270
+ return true;
271
+ const key = src === 'apiSpec' ? 'apiSpecDone' : src + 'Done';
272
+ return summary[key] === true;
273
+ });
274
+ const projectKind = project.projectKind ?? 'WEB';
275
+ const contextScore = project.contextScore ?? 0;
276
+ const currentPhase = project.contextPhase ?? 'PENDING_CONTEXT';
277
+ const threshold = CONTEXT_THRESHOLDS[projectKind] ?? 80;
278
+ const totalPending = screenshotPending + figmaPending + crawlPending + apiSpecPending;
279
+ const currentIdx = PHASE_ORDER.indexOf(currentPhase);
280
+ let newPhase = currentPhase;
281
+ if (currentPhase === 'CONTEXT_ENRICHED' &&
282
+ totalPending > 0) {
283
+ newPhase = 'DIFF_PENDING_APPROVAL';
284
+ }
285
+ else if (currentIdx <= PHASE_ORDER.indexOf('ALL_DIFFS_APPROVED') &&
286
+ allRequiredDone &&
287
+ totalPending === 0) {
288
+ newPhase = 'ALL_DIFFS_APPROVED';
289
+ }
290
+ if (newPhase === 'ALL_DIFFS_APPROVED' && contextScore >= threshold) {
291
+ newPhase = 'READY_FOR_SCRIPT_GEN';
292
+ }
293
+ // Never regress to an earlier phase
294
+ const newIdx = PHASE_ORDER.indexOf(newPhase);
295
+ const finalPhase = newIdx > currentIdx ? newPhase : currentPhase;
296
+ await database_1.prismaAdmin.project.update({
297
+ where: { id: projectId },
298
+ data: {
299
+ approvalGateSummary: summary,
300
+ contextPhase: finalPhase,
301
+ },
302
+ });
303
+ return { ...summary, allRequiredDone, contextPhase: finalPhase };
304
+ }
305
+ // ─── 5. computeCoverageGaps ───────────────────────────────────────────────────
306
+ async function computeCoverageGaps(tenantId, projectId) {
307
+ const [elements, testCases] = await Promise.all([
308
+ database_1.prismaAdmin.element.findMany({
309
+ where: { tenantId, projectId },
310
+ take: 500,
311
+ }),
312
+ database_1.prismaAdmin.testCase.findMany({
313
+ where: { tenantId, projectId },
314
+ select: { id: true, groundedOn: true, steps: true },
315
+ }),
316
+ ]);
317
+ // Build set of element IDs referenced by any test case
318
+ const coveredElementIds = new Set();
319
+ for (const tc of testCases) {
320
+ const groundedOn = (() => {
321
+ try {
322
+ const raw = tc.groundedOn;
323
+ if (Array.isArray(raw))
324
+ return raw;
325
+ if (typeof raw === 'string')
326
+ return JSON.parse(raw);
327
+ return [];
328
+ }
329
+ catch {
330
+ return [];
331
+ }
332
+ })();
333
+ for (const id of groundedOn)
334
+ coveredElementIds.add(id);
335
+ }
336
+ // Find interactive elements not covered by any test case
337
+ const uncoveredElements = elements.filter((e) => !coveredElementIds.has(e.id) &&
338
+ e.role != null &&
339
+ !NON_INTERACTIVE_ROLES.has(e.role.toLowerCase()));
340
+ // Upsert BugSignal for each uncovered element
341
+ for (const element of uncoveredElements) {
342
+ await database_1.prismaAdmin.bugSignal.upsert({
343
+ where: {
344
+ tenantId_elementId_signalType: {
345
+ tenantId,
346
+ elementId: element.id,
347
+ signalType: 'ELEMENT_NOT_IN_TESTS',
348
+ },
349
+ },
350
+ update: {
351
+ updatedAt: new Date(),
352
+ },
353
+ create: {
354
+ tenantId,
355
+ projectId,
356
+ elementId: element.id,
357
+ signalType: 'ELEMENT_NOT_IN_TESTS',
358
+ severity: 'LOW',
359
+ title: `UI element not covered: ${element.role ?? 'unknown'}/${element.meaning ?? element.text ?? element.id}`,
360
+ status: 'OPEN',
361
+ createdAt: new Date(),
362
+ updatedAt: new Date(),
363
+ },
364
+ });
365
+ }
366
+ return { gapsFound: uncoveredElements.length };
367
+ }
368
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
369
+ /**
370
+ * Find test case IDs whose groundedOn array contains any of the given element IDs.
371
+ */
372
+ async function findAffectedTestCases(tenantId, projectId, elementIds) {
373
+ if (elementIds.length === 0)
374
+ return [];
375
+ const testCases = await database_1.prismaAdmin.testCase.findMany({
376
+ where: { tenantId, projectId },
377
+ select: { id: true, groundedOn: true },
378
+ });
379
+ const affected = [];
380
+ for (const tc of testCases) {
381
+ const groundedOn = (() => {
382
+ try {
383
+ const raw = tc.groundedOn;
384
+ if (Array.isArray(raw))
385
+ return raw;
386
+ if (typeof raw === 'string')
387
+ return JSON.parse(raw);
388
+ return [];
389
+ }
390
+ catch {
391
+ return [];
392
+ }
393
+ })();
394
+ if (elementIds.some((id) => groundedOn.includes(id))) {
395
+ affected.push(tc.id);
396
+ }
397
+ }
398
+ return affected;
399
+ }
400
+ /**
401
+ * Compute diff severity based on how many test cases are affected.
402
+ * > 5 → CRITICAL
403
+ * 1-5 → SIGNIFICANT
404
+ * 0 → MINOR (auto-approve as NONE would hide it; keep MINOR for awareness)
405
+ */
406
+ function computeSeverity(affectedCount) {
407
+ if (affectedCount > 5)
408
+ return 'CRITICAL';
409
+ if (affectedCount >= 1)
410
+ return 'SIGNIFICANT';
411
+ return 'NONE';
412
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * ZeTa-AI Test Data Generation Agent
3
+ *
4
+ * Field-schema grounded: loads typed AppField catalog before generating.
5
+ * If all grounded elements are non-data-bearing (buttons/links/toggles)
6
+ * → returns interaction variations, NOT fabricated field:value datasets.
7
+ *
8
+ * Four generation modes:
9
+ * FORM — ≥1 data-bearing field → typed, constraint-aware parameterized datasets
10
+ * STATE — all non-data-bearing → precondition-state datasets
11
+ * VOLUME — PERFORMANCE / LOAD kinds → data-setup specs (row counts, concurrency, seed)
12
+ * SKIP — kinds not suited to any parameterized data (EXPLORATORY, MUTATION, AB_TEST, etc.)
13
+ */
14
+ import type { LLMConfig } from './llm.js';
15
+ export declare function scheduleSkillFileRefresh(tenantId: string, projectId: string, delayMs?: number): void;
16
+ export declare function generateTestData(opts: {
17
+ tenantId: string;
18
+ projectId: string;
19
+ testCaseId: string;
20
+ jobId?: string;
21
+ targetCount?: number;
22
+ }): Promise<{
23
+ dataSets: never[];
24
+ saved: never[];
25
+ skipped: boolean;
26
+ reason: string;
27
+ mode?: undefined;
28
+ source?: undefined;
29
+ } | {
30
+ dataSets: {
31
+ label: string;
32
+ category: string;
33
+ values: Record<string, string>;
34
+ expectedOutcome: string;
35
+ }[];
36
+ saved: {
37
+ tenantId: string;
38
+ id: string;
39
+ projectId: string;
40
+ source: string;
41
+ kind: string;
42
+ testCaseId: string;
43
+ payload: import("@prisma/client/runtime/library").JsonValue;
44
+ supersededAt: Date | null;
45
+ }[];
46
+ mode: string;
47
+ source: string;
48
+ skipped?: undefined;
49
+ reason?: undefined;
50
+ }>;
51
+ /**
52
+ * Generates test data for up to 5 test cases in a single LLM call.
53
+ *
54
+ * Caller is responsible for chunking: pass batches of up to 5 cases.
55
+ * Returns a Map keyed by the original case id, value is the dataSets array
56
+ * using the same per-dataset shape as generateTestData().
57
+ *
58
+ * Cases that the LLM omits from its response are absent from the returned Map
59
+ * (caller should fall back to generateTestData() for those).
60
+ */
61
+ export declare function generateTestDataBatch(cases: Array<{
62
+ id: string;
63
+ title: string;
64
+ steps: string[];
65
+ expectedResult: string;
66
+ preconditions?: string;
67
+ testDataInline?: object;
68
+ }>, options?: {
69
+ llmCfg?: LLMConfig;
70
+ skillFile?: string;
71
+ tenantId?: string;
72
+ projectId?: string;
73
+ }): Promise<Map<string, unknown>>;
74
+ /**
75
+ * Shape used by parseCsvToDatasets / mergeExternalDatasets.
76
+ * Matches the inline dataset shape used throughout this module.
77
+ */
78
+ type CsvDataSet = {
79
+ label: string;
80
+ category: string;
81
+ values: Record<string, string>;
82
+ expectedOutcome: string;
83
+ };
84
+ /**
85
+ * Parse a CSV string (with header row) into VALID/INVALID/EDGE test datasets.
86
+ * Column names map to dataset field names.
87
+ * Rows are assigned categories based on a 'category' column (if present) or
88
+ * positionally: first 40% VALID, next 40% INVALID, last 20% EDGE.
89
+ *
90
+ * @param csvContent - Raw CSV string content
91
+ * @param fieldMap - Optional alias map: { csvColumnName: normalizedFieldName }
92
+ * @returns Array of dataset objects ready for use in test data generation
93
+ */
94
+ export declare function parseCsvToDatasets(csvContent: string, fieldMap?: Record<string, string>): CsvDataSet[];
95
+ /**
96
+ * Merge externally-provided datasets (from CSV upload) with LLM-generated datasets.
97
+ * External datasets take priority for matching categories.
98
+ * Deduplicates by category label.
99
+ */
100
+ export declare function mergeExternalDatasets(generated: CsvDataSet[], external: CsvDataSet[]): CsvDataSet[];
101
+ export {};