sela-core 0.1.0-alpha.39 → 0.1.0-alpha.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/boot/bootImpl.d.ts +14 -0
- package/dist/boot/bootImpl.d.ts.map +1 -0
- package/dist/boot/bootImpl.js +64 -0
- package/dist/boot/register.cjs +45 -0
- package/dist/boot/register.d.cts +2 -0
- package/dist/boot/register.d.cts.map +1 -0
- package/dist/boot/register.d.mts +2 -0
- package/dist/boot/register.d.mts.map +1 -0
- package/dist/boot/register.mjs +10 -0
- package/dist/cli/commands/init.js +48 -16
- package/dist/cli/commands/merge.d.ts.map +1 -1
- package/dist/cli/commands/merge.js +5 -0
- package/dist/cli/commands/shadowRegression.js +1 -1
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +1 -0
- package/dist/config/SelaConfig.d.ts +59 -0
- package/dist/config/SelaConfig.d.ts.map +1 -1
- package/dist/config/SelaConfig.js +36 -0
- package/dist/engine/SelaEngine.d.ts +3 -1
- package/dist/engine/SelaEngine.d.ts.map +1 -1
- package/dist/engine/SelaEngine.js +183 -3
- package/dist/errors/SelaError.d.ts +7 -0
- package/dist/errors/SelaError.d.ts.map +1 -1
- package/dist/errors/SelaError.js +7 -1
- package/dist/fixtures/index.js +2 -2
- package/dist/providers/AnthropicProvider.d.ts +9 -0
- package/dist/providers/AnthropicProvider.d.ts.map +1 -0
- package/dist/providers/AnthropicProvider.js +33 -0
- package/dist/providers/LLMProvider.d.ts +13 -0
- package/dist/providers/LLMProvider.d.ts.map +1 -0
- package/dist/providers/LLMProvider.js +7 -0
- package/dist/providers/OpenAICompatibleProvider.d.ts +8 -0
- package/dist/providers/OpenAICompatibleProvider.d.ts.map +1 -0
- package/dist/providers/OpenAICompatibleProvider.js +48 -0
- package/dist/providers/ProviderFactory.d.ts +4 -0
- package/dist/providers/ProviderFactory.d.ts.map +1 -0
- package/dist/providers/ProviderFactory.js +50 -0
- package/dist/providers/SanitizingProvider.d.ts +8 -0
- package/dist/providers/SanitizingProvider.d.ts.map +1 -0
- package/dist/providers/SanitizingProvider.js +27 -0
- package/dist/services/ASTSourceUpdater.d.ts.map +1 -1
- package/dist/services/ASTSourceUpdater.js +39 -5
- package/dist/services/CrossFileHealer.d.ts +7 -1
- package/dist/services/CrossFileHealer.d.ts.map +1 -1
- package/dist/services/CrossFileHealer.js +243 -9
- package/dist/services/DefinitionTracer.d.ts +1 -0
- package/dist/services/DefinitionTracer.d.ts.map +1 -1
- package/dist/services/DefinitionTracer.js +59 -36
- package/dist/services/HealReportService.d.ts +32 -0
- package/dist/services/HealReportService.d.ts.map +1 -1
- package/dist/services/HealReportService.js +110 -18
- package/dist/services/IntentAuditor.d.ts +9 -7
- package/dist/services/IntentAuditor.d.ts.map +1 -1
- package/dist/services/IntentAuditor.js +21 -16
- package/dist/services/LLMService.d.ts +10 -7
- package/dist/services/LLMService.d.ts.map +1 -1
- package/dist/services/LLMService.js +76 -10
- package/dist/services/PRAutomationService.d.ts +7 -2
- package/dist/services/PRAutomationService.d.ts.map +1 -1
- package/dist/services/PRAutomationService.js +143 -132
- package/dist/services/RegressionManifestService.d.ts +8 -0
- package/dist/services/RegressionManifestService.d.ts.map +1 -1
- package/dist/services/RegressionManifestService.js +8 -0
- package/dist/services/RegressionReclassifier.d.ts +25 -0
- package/dist/services/RegressionReclassifier.d.ts.map +1 -0
- package/dist/services/RegressionReclassifier.js +195 -0
- package/dist/services/ReportMergeService.d.ts +9 -0
- package/dist/services/ReportMergeService.d.ts.map +1 -1
- package/dist/services/ReportMergeService.js +28 -0
- package/dist/services/SmartDOMPruner.d.ts +154 -0
- package/dist/services/SmartDOMPruner.d.ts.map +1 -0
- package/dist/services/SmartDOMPruner.js +678 -0
- package/dist/services/TraceBackEngine.d.ts +23 -6
- package/dist/services/TraceBackEngine.d.ts.map +1 -1
- package/dist/services/TraceBackEngine.js +51 -13
- package/dist/services/VisualSnapshotService.d.ts +48 -0
- package/dist/services/VisualSnapshotService.d.ts.map +1 -0
- package/dist/services/VisualSnapshotService.js +264 -0
- package/dist/services/vcs/GitHubProvider.d.ts +17 -0
- package/dist/services/vcs/GitHubProvider.d.ts.map +1 -0
- package/dist/services/vcs/GitHubProvider.js +162 -0
- package/dist/services/vcs/GitLabProvider.d.ts +17 -0
- package/dist/services/vcs/GitLabProvider.d.ts.map +1 -0
- package/dist/services/vcs/GitLabProvider.js +175 -0
- package/dist/services/vcs/VCSProvider.d.ts +100 -0
- package/dist/services/vcs/VCSProvider.d.ts.map +1 -0
- package/dist/services/vcs/VCSProvider.js +7 -0
- package/dist/services/vcs/VCSProviderFactory.d.ts +7 -0
- package/dist/services/vcs/VCSProviderFactory.d.ts.map +1 -0
- package/dist/services/vcs/VCSProviderFactory.js +42 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/shell.d.ts +7 -0
- package/dist/utils/shell.d.ts.map +1 -0
- package/dist/utils/shell.js +32 -0
- package/package.json +7 -1
|
@@ -47,6 +47,8 @@ const ASTSourceUpdater_1 = require("../services/ASTSourceUpdater");
|
|
|
47
47
|
const SafetyGuard_1 = require("../services/SafetyGuard");
|
|
48
48
|
const HealingCacheService_1 = require("../services/HealingCacheService");
|
|
49
49
|
const ConfigLoader_1 = require("../config/ConfigLoader");
|
|
50
|
+
const ProviderFactory_1 = require("../providers/ProviderFactory");
|
|
51
|
+
const IntentAuditor_1 = require("../services/IntentAuditor");
|
|
50
52
|
const DryRunGuard_1 = require("../config/DryRunGuard");
|
|
51
53
|
const HealBudget_1 = require("../services/HealBudget");
|
|
52
54
|
const HealReportService_1 = require("../services/HealReportService");
|
|
@@ -58,6 +60,7 @@ const SelaError_1 = require("../errors/SelaError");
|
|
|
58
60
|
const SelaHealingRefusalError_1 = require("../errors/SelaHealingRefusalError");
|
|
59
61
|
const FileWriteInterceptor_1 = require("../services/interceptors/FileWriteInterceptor");
|
|
60
62
|
const SelectorSanitizer_1 = require("../services/SelectorSanitizer");
|
|
63
|
+
const VisualSnapshotService_1 = require("../services/VisualSnapshotService");
|
|
61
64
|
/**
|
|
62
65
|
* Graceful percentage formatter for engine-side log lines. Mirrors the helper
|
|
63
66
|
* in PRAutomationService / HealReportService so a missing AI/auditor
|
|
@@ -113,13 +116,24 @@ class SelaEngine {
|
|
|
113
116
|
// immediate in-memory hit without a second LLM round-trip or any page.evaluate
|
|
114
117
|
// call (which would fail when the page is already closed, e.g. unawaited promises).
|
|
115
118
|
bypassedSelectorCache = new Map();
|
|
119
|
+
// NO_HEAL cache: elementSelectorOnly → reason. Once a selector is identified
|
|
120
|
+
// as an application logic/state failure (not selector drift) in this run,
|
|
121
|
+
// all subsequent heal() calls for the same selector skip LLM entirely.
|
|
122
|
+
noHealCache = new Map();
|
|
116
123
|
constructor() {
|
|
117
124
|
this.config = ConfigLoader_1.ConfigLoader.getInstance();
|
|
118
125
|
// Seed the per-run heal budget (T2). null => unlimited.
|
|
119
126
|
HealBudget_1.sharedHealBudget.configure(this.config.maxHealsPerRun);
|
|
120
|
-
|
|
127
|
+
// Build provider-abstracted LLM clients from resolved config.
|
|
128
|
+
// Each model can point to a different provider / endpoint.
|
|
129
|
+
const healingProvider = (0, ProviderFactory_1.createProvider)(this.config.llm.healingModel, this.config.sanitization);
|
|
130
|
+
const auditProvider = (0, ProviderFactory_1.createProvider)(this.config.llm.intentAuditModel, this.config.sanitization);
|
|
131
|
+
this.llmService = new LLMService_1.LLMService({ provider: healingProvider });
|
|
121
132
|
this.snapshotService = new SnapshotService_1.SnapshotService();
|
|
122
|
-
this.safetyGuard = new SafetyGuard_1.SafetyGuard(
|
|
133
|
+
this.safetyGuard = new SafetyGuard_1.SafetyGuard({
|
|
134
|
+
thresholds: this.config.thresholds,
|
|
135
|
+
intentAuditor: new IntentAuditor_1.IntentAuditor({ provider: auditProvider }),
|
|
136
|
+
});
|
|
123
137
|
this.fileWriteInterceptor = new FileWriteInterceptor_1.FileWriteInterceptor(this.config.thresholds.vectorThresholds ?? null);
|
|
124
138
|
// Dedicated lightweight ts-morph project used only for the leading-comment
|
|
125
139
|
// pre-scan. Keeping it separate from the SourceUpdater's project avoids
|
|
@@ -243,6 +257,30 @@ CRITICAL: Do NOT return a CSS selector like "#my-select". Return plain text only
|
|
|
243
257
|
}
|
|
244
258
|
throw directiveErr;
|
|
245
259
|
}
|
|
260
|
+
// ── NO_HEAL cache pre-check ──────────────────────────────────────────
|
|
261
|
+
// If this selector was already identified as an application logic/state
|
|
262
|
+
// failure in this run, skip LLM, DNA load, and DOM extraction entirely.
|
|
263
|
+
// One LLM call pays for 50+ identical state-bug failures in large suites.
|
|
264
|
+
const cachedNoHealReason = this.noHealCache.get(elementSelectorOnly);
|
|
265
|
+
if (cachedNoHealReason !== undefined) {
|
|
266
|
+
logger_1.logger.warn(`[Sela] NO_HEAL cache hit — skipping LLM: ${cachedNoHealReason}`);
|
|
267
|
+
HealReportService_1.sharedHealReport.record({
|
|
268
|
+
kind: "FAILED",
|
|
269
|
+
stableId,
|
|
270
|
+
deterministicKey: (0, HealReportService_1.computeEventDeterministicKey)(reportFile, line, elementSelectorOnly),
|
|
271
|
+
sourceFile: reportFile,
|
|
272
|
+
sourceLine: line,
|
|
273
|
+
testTitle,
|
|
274
|
+
timestamp: new Date().toISOString(),
|
|
275
|
+
framePath: [],
|
|
276
|
+
inIframe: false,
|
|
277
|
+
inShadowDom: false,
|
|
278
|
+
oldSelector: elementSelectorOnly,
|
|
279
|
+
reason: `NO_HEAL (cached) — ${cachedNoHealReason}`,
|
|
280
|
+
dnaBefore: null,
|
|
281
|
+
});
|
|
282
|
+
return "";
|
|
283
|
+
}
|
|
246
284
|
// Snapshot for report event context (loaded once below, used at all exit paths).
|
|
247
285
|
let lastKnownStateForReport = null;
|
|
248
286
|
let aiFixForReport = null;
|
|
@@ -370,6 +408,61 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
|
|
|
370
408
|
});
|
|
371
409
|
}
|
|
372
410
|
aiFixForReport = aiFix;
|
|
411
|
+
// ── NO_HEAL gate ──────────────────────────────────────────────────
|
|
412
|
+
// LLM detected the failure is an application logic/state bug, not
|
|
413
|
+
// selector drift. Surface the native Playwright error without any
|
|
414
|
+
// AST mutation. Populate the noHealCache so subsequent calls for
|
|
415
|
+
// the same selector skip the LLM entirely.
|
|
416
|
+
if (aiFix?.status === "NO_HEAL") {
|
|
417
|
+
const noHealReason = aiFix.reason ?? "LLM detected application logic/state mismatch";
|
|
418
|
+
logger_1.logger.warn(`[Sela] Heal BLOCKED (NO_HEAL): ${noHealReason}`);
|
|
419
|
+
this.noHealCache.set(elementSelectorOnly, noHealReason);
|
|
420
|
+
HealReportService_1.sharedHealReport.record({
|
|
421
|
+
kind: "FAILED",
|
|
422
|
+
stableId,
|
|
423
|
+
deterministicKey: (0, HealReportService_1.computeEventDeterministicKey)(reportFile, line, elementSelectorOnly),
|
|
424
|
+
sourceFile: reportFile,
|
|
425
|
+
sourceLine: line,
|
|
426
|
+
testTitle,
|
|
427
|
+
timestamp: new Date().toISOString(),
|
|
428
|
+
framePath: [],
|
|
429
|
+
inIframe: false,
|
|
430
|
+
inShadowDom: false,
|
|
431
|
+
oldSelector: elementSelectorOnly,
|
|
432
|
+
reason: `NO_HEAL — ${noHealReason}`,
|
|
433
|
+
dnaBefore: (0, HealReportService_1.summariseSnapshot)(lastKnownStateForReport),
|
|
434
|
+
});
|
|
435
|
+
return "";
|
|
436
|
+
}
|
|
437
|
+
// ── Sub-threshold confidence gate ─────────────────────────────────
|
|
438
|
+
// confidence 1–19 = SEMANTIC MISMATCH per the LLM rubric. A proposed
|
|
439
|
+
// selector with near-zero semantic correlation to the original must
|
|
440
|
+
// never reach AST mutation. Record a FailedEvent with the exact reason
|
|
441
|
+
// so CI reports show WHY the heal was blocked.
|
|
442
|
+
if (aiFix?.status === "FIXED" &&
|
|
443
|
+
aiFix.confidence !== undefined &&
|
|
444
|
+
aiFix.confidence < 20) {
|
|
445
|
+
const mismatchReason = `Semantic Mismatch blocked — confidence ${aiFix.confidence}/100 < threshold 20. ` +
|
|
446
|
+
`Proposed: "${aiFix.new_selector ?? "unknown"}". ` +
|
|
447
|
+
`Original intent preserved. Check application state for functional regression.`;
|
|
448
|
+
logger_1.logger.warn(`[Sela] Heal BLOCKED (SEMANTIC_MISMATCH): ${mismatchReason}`);
|
|
449
|
+
HealReportService_1.sharedHealReport.record({
|
|
450
|
+
kind: "FAILED",
|
|
451
|
+
stableId,
|
|
452
|
+
deterministicKey: (0, HealReportService_1.computeEventDeterministicKey)(reportFile, line, elementSelectorOnly),
|
|
453
|
+
sourceFile: reportFile,
|
|
454
|
+
sourceLine: line,
|
|
455
|
+
testTitle,
|
|
456
|
+
timestamp: new Date().toISOString(),
|
|
457
|
+
framePath: [],
|
|
458
|
+
inIframe: false,
|
|
459
|
+
inShadowDom: false,
|
|
460
|
+
oldSelector: elementSelectorOnly,
|
|
461
|
+
reason: `SEMANTIC_MISMATCH — ${mismatchReason}`,
|
|
462
|
+
dnaBefore: (0, HealReportService_1.summariseSnapshot)(lastKnownStateForReport),
|
|
463
|
+
});
|
|
464
|
+
return "";
|
|
465
|
+
}
|
|
373
466
|
if (aiFix && aiFix.status === "FIXED") {
|
|
374
467
|
logger_1.logger.debug("Step 3: AI responded");
|
|
375
468
|
// ── Build new selector ────────────────────────────────────
|
|
@@ -423,6 +516,31 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
|
|
|
423
516
|
else {
|
|
424
517
|
logger_1.logger.debug("Step 3.6: live v2 capture skipped");
|
|
425
518
|
}
|
|
519
|
+
// ── Step 3.7: Visual element screenshot (async write, heal-only) ─
|
|
520
|
+
// Capture is fired here while the page is still stable and the healed
|
|
521
|
+
// selector is confirmed. Disk I/O is non-blocking. The result is
|
|
522
|
+
// attached to the HealedEvent below and, on success, stored in the
|
|
523
|
+
// DNA record so subsequent heals can show the previous baseline.
|
|
524
|
+
const _vsKey = (0, VisualSnapshotService_1.snapshotKey)(filePath, stableId);
|
|
525
|
+
const _vsLiveDest = (0, VisualSnapshotService_1.liveSnapshotPath)(process.cwd(), _vsKey);
|
|
526
|
+
let _vsCapture = { elementFound: false, capturedAt: null };
|
|
527
|
+
let _vsLiveRelPath = null;
|
|
528
|
+
let _vsDnaRelPath = null;
|
|
529
|
+
let _vsDnaCapturedAt = null;
|
|
530
|
+
try {
|
|
531
|
+
_vsCapture = await (0, VisualSnapshotService_1.captureElementScreenshot)(page, elementOnlySelector, successfulPath, _vsLiveDest);
|
|
532
|
+
if (_vsCapture.elementFound) {
|
|
533
|
+
_vsLiveRelPath = path.relative(process.cwd(), _vsLiveDest).replace(/\\/g, "/");
|
|
534
|
+
}
|
|
535
|
+
const _dnaAbsPath = (0, VisualSnapshotService_1.dnaSnapshotPath)(process.cwd(), _vsKey);
|
|
536
|
+
if (fs.existsSync(_dnaAbsPath)) {
|
|
537
|
+
_vsDnaRelPath = path.relative(process.cwd(), _dnaAbsPath).replace(/\\/g, "/");
|
|
538
|
+
_vsDnaCapturedAt = lastKnownState?.visualSnapshot?.capturedAt ?? null;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
catch {
|
|
542
|
+
// Never block the heal on screenshot failures.
|
|
543
|
+
}
|
|
426
544
|
// ── Safety: delegate all go/no-go decisions to SafetyGuard ─
|
|
427
545
|
const branch = ConfigLoader_1.ConfigLoader.getBranch() ?? undefined;
|
|
428
546
|
const safetyDecision = await this.safetyGuard.evaluate({ mode: healMode, branch }, {
|
|
@@ -837,6 +955,17 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
|
|
|
837
955
|
status: "healed",
|
|
838
956
|
definitionSite: updateResult.definitionSite,
|
|
839
957
|
blastRadius: updateResult.blastRadius,
|
|
958
|
+
// Store the planned dna path so the next heal cycle can read the
|
|
959
|
+
// baseline timestamp. The image is physically at liveSnapshotPath
|
|
960
|
+
// until runCleanRoom() promotes it.
|
|
961
|
+
visualSnapshot: _vsCapture.elementFound && _vsCapture.capturedAt
|
|
962
|
+
? {
|
|
963
|
+
path: path
|
|
964
|
+
.relative(process.cwd(), (0, VisualSnapshotService_1.dnaSnapshotPath)(process.cwd(), _vsKey))
|
|
965
|
+
.replace(/\\/g, "/"),
|
|
966
|
+
capturedAt: _vsCapture.capturedAt,
|
|
967
|
+
}
|
|
968
|
+
: undefined,
|
|
840
969
|
});
|
|
841
970
|
// ── Report: HEALED event ───────────────────────────────────────
|
|
842
971
|
const healedEvent = {
|
|
@@ -878,6 +1007,13 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
|
|
|
878
1007
|
definitionSite: updateResult.definitionSite,
|
|
879
1008
|
contentChange: aiFix.contentChange,
|
|
880
1009
|
confidenceVectors: safetyDecision.meta?.confidenceVectors,
|
|
1010
|
+
visualDiff: {
|
|
1011
|
+
dnaSnapshotPath: _vsDnaRelPath,
|
|
1012
|
+
liveSnapshotPath: _vsLiveRelPath,
|
|
1013
|
+
dnaSnapshotCapturedAt: _vsDnaCapturedAt,
|
|
1014
|
+
liveSnapshotCapturedAt: _vsCapture.capturedAt,
|
|
1015
|
+
elementFound: _vsCapture.elementFound,
|
|
1016
|
+
},
|
|
881
1017
|
};
|
|
882
1018
|
HealReportService_1.sharedHealReport.record(healedEvent);
|
|
883
1019
|
// ── Cache write - persist this safe heal for future sessions ──
|
|
@@ -1378,7 +1514,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
|
|
|
1378
1514
|
// Replaces the previous DOMUtils.getElementDNA() path with a single
|
|
1379
1515
|
// captureElement() call that collects all v2 metrics atomically.
|
|
1380
1516
|
// ─────────────────────────────────────────────────────────────
|
|
1381
|
-
async captureSuccessfulElement(page, selector, stableId) {
|
|
1517
|
+
async captureSuccessfulElement(page, selector, stableId, sourceFile) {
|
|
1382
1518
|
try {
|
|
1383
1519
|
const snapshot = await this.snapshotService.captureElement(page, selector);
|
|
1384
1520
|
if (snapshot) {
|
|
@@ -1390,11 +1526,55 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
|
|
|
1390
1526
|
};
|
|
1391
1527
|
this.dnaBuffer.set(stableId, enriched);
|
|
1392
1528
|
logger_1.logger.debug(`DNA v2 captured for: ${stableId}`);
|
|
1529
|
+
// ── Visual baseline capture (guarded) ─────────────────────
|
|
1530
|
+
// Capture a PNG baseline ONLY if the file is missing (first run)
|
|
1531
|
+
// or the DOM snapshot changed (manual edit / UI shift). Skipping
|
|
1532
|
+
// on unchanged steady-state runs avoids screenshot overhead in CI.
|
|
1533
|
+
if (sourceFile) {
|
|
1534
|
+
try {
|
|
1535
|
+
const vsKey = (0, VisualSnapshotService_1.snapshotKey)(sourceFile, stableId);
|
|
1536
|
+
const dnaDest = (0, VisualSnapshotService_1.dnaSnapshotPath)(process.cwd(), vsKey);
|
|
1537
|
+
const dnaStat = fs.existsSync(dnaDest) ? fs.statSync(dnaDest) : null;
|
|
1538
|
+
const pngMissing = !dnaStat || dnaStat.size === 0;
|
|
1539
|
+
let needsCapture = pngMissing;
|
|
1540
|
+
if (!pngMissing) {
|
|
1541
|
+
// load() reads from disk — commitUpdates() hasn't run yet,
|
|
1542
|
+
// so this returns the snapshot from the PREVIOUS run.
|
|
1543
|
+
const prevSnap = await this.snapshotService.load(stableId);
|
|
1544
|
+
needsCapture =
|
|
1545
|
+
!prevSnap ||
|
|
1546
|
+
SelaEngine._snapshotFingerprint(prevSnap) !==
|
|
1547
|
+
SelaEngine._snapshotFingerprint(enriched);
|
|
1548
|
+
}
|
|
1549
|
+
if (needsCapture) {
|
|
1550
|
+
const liveDest = (0, VisualSnapshotService_1.liveSnapshotPath)(process.cwd(), vsKey);
|
|
1551
|
+
const result = await (0, VisualSnapshotService_1.captureElementScreenshot)(page, selector, [], liveDest);
|
|
1552
|
+
if (result.elementFound) {
|
|
1553
|
+
(0, VisualSnapshotService_1.promoteLiveToBaseline)(process.cwd(), vsKey);
|
|
1554
|
+
logger_1.logger.debug(`Visual baseline ${pngMissing ? "created" : "refreshed"}: ${vsKey}`);
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
catch (vsErr) {
|
|
1559
|
+
logger_1.logger.debug(`Visual baseline skipped: ${vsErr.message}`);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1393
1562
|
}
|
|
1394
1563
|
}
|
|
1395
1564
|
catch (error) {
|
|
1396
1565
|
logger_1.logger.debug(`DNA capture skipped: ${error.message}`);
|
|
1397
1566
|
}
|
|
1398
1567
|
}
|
|
1568
|
+
// Stable fingerprint of DOM-visible fields only (excludes timestamps, rect,
|
|
1569
|
+
// and metadata). Used to decide whether the visual PNG baseline needs refresh.
|
|
1570
|
+
static _snapshotFingerprint(s) {
|
|
1571
|
+
return JSON.stringify({
|
|
1572
|
+
tagName: s.tagName,
|
|
1573
|
+
text: s.text,
|
|
1574
|
+
role: s.role,
|
|
1575
|
+
classes: [...(s.classes ?? [])].sort(),
|
|
1576
|
+
attributes: Object.fromEntries(Object.entries(s.attributes ?? {}).sort()),
|
|
1577
|
+
});
|
|
1578
|
+
}
|
|
1399
1579
|
}
|
|
1400
1580
|
exports.SelaEngine = SelaEngine;
|
|
@@ -150,4 +150,11 @@ export declare const CHAIN_VALIDATOR_CODES: {
|
|
|
150
150
|
readonly SEMANTIC_DOWNGRADE: "CV_SEMANTIC_DOWNGRADE";
|
|
151
151
|
};
|
|
152
152
|
export type ChainValidatorCode = (typeof CHAIN_VALIDATOR_CODES)[keyof typeof CHAIN_VALIDATOR_CODES];
|
|
153
|
+
export declare const ENGINE_CODES: {
|
|
154
|
+
/** LLM determined the failure is an application logic/state bug, not selector drift. */
|
|
155
|
+
readonly NO_HEAL_APP_LOGIC: "ENG_NO_HEAL_APP_LOGIC";
|
|
156
|
+
/** LLM returned a selector containing dynamic expressions — static-output contract violated. */
|
|
157
|
+
readonly DYNAMIC_OUTPUT_BLOCKED: "ENG_DYNAMIC_OUTPUT_BLOCKED";
|
|
158
|
+
};
|
|
159
|
+
export type EngineCode = (typeof ENGINE_CODES)[keyof typeof ENGINE_CODES];
|
|
153
160
|
//# sourceMappingURL=SelaError.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelaError.d.ts","sourceRoot":"","sources":["../../src/errors/SelaError.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SelaError.d.ts","sourceRoot":"","sources":["../../src/errors/SelaError.ts"],"names":[],"mappings":"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"}
|
package/dist/errors/SelaError.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// Public message regex (used by tests/unit/engine/error-indicativity.test.ts):
|
|
14
14
|
// /^\[Sela-(SafetyGuard|IntentAuditor|ASTUpdater|Proxy|LLMService|Registry|ChainValidator|Engine)\] [A-Z][A-Z0-9_]+: .+$/
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.CHAIN_VALIDATOR_CODES = exports.REPORT_CODES = exports.REGISTRY_CODES = exports.PROXY_CODES = exports.AST_UPDATER_CODES = exports.LLM_SERVICE_CODES = exports.INTENT_AUDITOR_CODES = exports.SAFETY_GUARD_CODES = exports.SelaError = void 0;
|
|
16
|
+
exports.ENGINE_CODES = exports.CHAIN_VALIDATOR_CODES = exports.REPORT_CODES = exports.REGISTRY_CODES = exports.PROXY_CODES = exports.AST_UPDATER_CODES = exports.LLM_SERVICE_CODES = exports.INTENT_AUDITOR_CODES = exports.SAFETY_GUARD_CODES = exports.SelaError = void 0;
|
|
17
17
|
exports.isSelaError = isSelaError;
|
|
18
18
|
exports.isSelaErrorFrom = isSelaErrorFrom;
|
|
19
19
|
// ───────────────────────────────────────────────────────────────────
|
|
@@ -173,3 +173,9 @@ exports.CHAIN_VALIDATOR_CODES = {
|
|
|
173
173
|
PLACEMENT: "CV_PLACEMENT",
|
|
174
174
|
SEMANTIC_DOWNGRADE: "CV_SEMANTIC_DOWNGRADE",
|
|
175
175
|
};
|
|
176
|
+
exports.ENGINE_CODES = {
|
|
177
|
+
/** LLM determined the failure is an application logic/state bug, not selector drift. */
|
|
178
|
+
NO_HEAL_APP_LOGIC: "ENG_NO_HEAL_APP_LOGIC",
|
|
179
|
+
/** LLM returned a selector containing dynamic expressions — static-output contract violated. */
|
|
180
|
+
DYNAMIC_OUTPUT_BLOCKED: "ENG_DYNAMIC_OUTPUT_BLOCKED",
|
|
181
|
+
};
|
package/dist/fixtures/index.js
CHANGED
|
@@ -325,7 +325,7 @@ async function runWithHeal(rawPage, prop, args, fullSelector, elementSelectorOnl
|
|
|
325
325
|
// can pass an explicit timeout in their test code; buildHealedArgs
|
|
326
326
|
// respects an existing timeout object if present.
|
|
327
327
|
const callArgs = buildHealedArgs(prop, args, 3000);
|
|
328
|
-
await singleton_1.sharedEngine.captureSuccessfulElement(rawPage, effectiveSelector, stableId);
|
|
328
|
+
await singleton_1.sharedEngine.captureSuccessfulElement(rawPage, effectiveSelector, stableId, callerInfo.filePath);
|
|
329
329
|
const result = await initialLocator[prop](...callArgs);
|
|
330
330
|
return {
|
|
331
331
|
result,
|
|
@@ -376,7 +376,7 @@ async function runWithHealSelector(rawPage, prop, args, fullSelector, elementSel
|
|
|
376
376
|
// We just need to build the locator for THIS call-site's retry.
|
|
377
377
|
const healedLocator = buildLiveLocator(rawPage, newFullSelector);
|
|
378
378
|
try {
|
|
379
|
-
await singleton_1.sharedEngine.captureSuccessfulElement(rawPage, newFullSelector, stableId);
|
|
379
|
+
await singleton_1.sharedEngine.captureSuccessfulElement(rawPage, newFullSelector, stableId, callerInfo.filePath);
|
|
380
380
|
const result = await healedLocator[prop](...buildHealedArgs(prop, args, 8000));
|
|
381
381
|
return {
|
|
382
382
|
result,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
+
import type { LLMProvider, CompletionParams } from "./LLMProvider";
|
|
3
|
+
export declare class AnthropicProvider implements LLMProvider {
|
|
4
|
+
private readonly modelId;
|
|
5
|
+
private readonly client;
|
|
6
|
+
constructor(modelId: string, apiKeyOrClient: string | Anthropic);
|
|
7
|
+
complete(params: CompletionParams): Promise<string>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=AnthropicProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnthropicProvider.d.ts","sourceRoot":"","sources":["../../src/providers/AnthropicProvider.ts"],"names":[],"mappings":"AAKA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEnE,qBAAa,iBAAkB,YAAW,WAAW;IAIjD,OAAO,CAAC,QAAQ,CAAC,OAAO;IAH1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;gBAGhB,OAAO,EAAE,MAAM,EAChC,cAAc,EAAE,MAAM,GAAG,SAAS;IAQ9B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;CAU1D"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/providers/AnthropicProvider.ts
|
|
3
|
+
// LLMProvider adapter for the Anthropic SDK (@anthropic-ai/sdk).
|
|
4
|
+
// Accepts either an API key string (creates a fresh client) or a pre-built
|
|
5
|
+
// Anthropic instance (used by legacy code-paths and tests that inject a mock).
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.AnthropicProvider = void 0;
|
|
11
|
+
const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
|
|
12
|
+
class AnthropicProvider {
|
|
13
|
+
modelId;
|
|
14
|
+
client;
|
|
15
|
+
constructor(modelId, apiKeyOrClient) {
|
|
16
|
+
this.modelId = modelId;
|
|
17
|
+
this.client =
|
|
18
|
+
typeof apiKeyOrClient === "string"
|
|
19
|
+
? new sdk_1.default({ apiKey: apiKeyOrClient })
|
|
20
|
+
: apiKeyOrClient;
|
|
21
|
+
}
|
|
22
|
+
async complete(params) {
|
|
23
|
+
const msg = await this.client.messages.create({
|
|
24
|
+
model: this.modelId,
|
|
25
|
+
max_tokens: params.maxTokens ?? 1024,
|
|
26
|
+
...(params.temperature !== undefined && { temperature: params.temperature }),
|
|
27
|
+
system: params.system,
|
|
28
|
+
messages: params.messages,
|
|
29
|
+
});
|
|
30
|
+
return msg.content[0]?.type === "text" ? msg.content[0].text : "";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.AnthropicProvider = AnthropicProvider;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface CompletionParams {
|
|
2
|
+
system?: string;
|
|
3
|
+
messages: Array<{
|
|
4
|
+
role: "user" | "assistant";
|
|
5
|
+
content: string;
|
|
6
|
+
}>;
|
|
7
|
+
maxTokens?: number;
|
|
8
|
+
temperature?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface LLMProvider {
|
|
11
|
+
complete(params: CompletionParams): Promise<string>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=LLMProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LLMProvider.d.ts","sourceRoot":"","sources":["../../src/providers/LLMProvider.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACrD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/providers/LLMProvider.ts
|
|
3
|
+
// Provider-agnostic interface for LLM text completion.
|
|
4
|
+
// All AI calls in Sela (healing + intent audit) route through this contract
|
|
5
|
+
// so the engine never cares whether it's talking to Claude, GPT-4o, or a
|
|
6
|
+
// self-hosted local model behind an OpenAI-compatible endpoint.
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LLMProvider, CompletionParams } from "./LLMProvider";
|
|
2
|
+
export declare class OpenAICompatibleProvider implements LLMProvider {
|
|
3
|
+
private readonly modelId;
|
|
4
|
+
private readonly client;
|
|
5
|
+
constructor(modelId: string, apiKey: string, baseUrl?: string, customHeaders?: Record<string, string>, disableSslVerification?: boolean, timeoutMs?: number);
|
|
6
|
+
complete(params: CompletionParams): Promise<string>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=OpenAICompatibleProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenAICompatibleProvider.d.ts","sourceRoot":"","sources":["../../src/providers/OpenAICompatibleProvider.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEnE,qBAAa,wBAAyB,YAAW,WAAW;IAIxD,OAAO,CAAC,QAAQ,CAAC,OAAO;IAH1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAGb,OAAO,EAAE,MAAM,EAChC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,EAChB,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACtC,sBAAsB,CAAC,EAAE,OAAO,EAChC,SAAS,CAAC,EAAE,MAAM;IAgBd,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;CAmB1D"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/providers/OpenAICompatibleProvider.ts
|
|
3
|
+
// LLMProvider adapter for any OpenAI-compatible HTTP endpoint.
|
|
4
|
+
// Covers: OpenAI SaaS, local LM Studio / Ollama, vLLM, Together AI,
|
|
5
|
+
// and air-gapped internal clusters reachable at a custom base URL.
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.OpenAICompatibleProvider = void 0;
|
|
11
|
+
const openai_1 = __importDefault(require("openai"));
|
|
12
|
+
const https_1 = __importDefault(require("https"));
|
|
13
|
+
class OpenAICompatibleProvider {
|
|
14
|
+
modelId;
|
|
15
|
+
client;
|
|
16
|
+
constructor(modelId, apiKey, baseUrl, customHeaders, disableSslVerification, timeoutMs) {
|
|
17
|
+
this.modelId = modelId;
|
|
18
|
+
this.client = new openai_1.default({
|
|
19
|
+
// Local servers often have no real key — "local" is a safe sentinel.
|
|
20
|
+
apiKey: apiKey || "local",
|
|
21
|
+
baseURL: baseUrl,
|
|
22
|
+
defaultHeaders: customHeaders,
|
|
23
|
+
...(timeoutMs !== undefined && { timeout: timeoutMs }),
|
|
24
|
+
// Air-gapped corporate proxies may use self-signed certs.
|
|
25
|
+
// Only skip verification when the user explicitly opts in.
|
|
26
|
+
...(disableSslVerification && {
|
|
27
|
+
httpAgent: new https_1.default.Agent({ rejectUnauthorized: false }),
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
async complete(params) {
|
|
32
|
+
const messages = [];
|
|
33
|
+
if (params.system) {
|
|
34
|
+
messages.push({ role: "system", content: params.system });
|
|
35
|
+
}
|
|
36
|
+
for (const m of params.messages) {
|
|
37
|
+
messages.push({ role: m.role, content: m.content });
|
|
38
|
+
}
|
|
39
|
+
const res = await this.client.chat.completions.create({
|
|
40
|
+
model: this.modelId,
|
|
41
|
+
max_tokens: params.maxTokens ?? 1024,
|
|
42
|
+
...(params.temperature !== undefined && { temperature: params.temperature }),
|
|
43
|
+
messages,
|
|
44
|
+
});
|
|
45
|
+
return res.choices[0]?.message?.content ?? "";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.OpenAICompatibleProvider = OpenAICompatibleProvider;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { LLMProvider } from "./LLMProvider";
|
|
2
|
+
import type { ResolvedLLMModelConfig, ResolvedSanitization } from "../config/SelaConfig";
|
|
3
|
+
export declare function createProvider(cfg: ResolvedLLMModelConfig, sanitization?: ResolvedSanitization): LLMProvider;
|
|
4
|
+
//# sourceMappingURL=ProviderFactory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProviderFactory.d.ts","sourceRoot":"","sources":["../../src/providers/ProviderFactory.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAIjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAIzF,wBAAgB,cAAc,CAC5B,GAAG,EAAE,sBAAsB,EAC3B,YAAY,CAAC,EAAE,oBAAoB,GAClC,WAAW,CAab"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/providers/ProviderFactory.ts
|
|
3
|
+
// Single entry-point for constructing LLMProvider instances from config.
|
|
4
|
+
// Wraps the created provider in SanitizingProvider when PII masking is enabled.
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createProvider = createProvider;
|
|
7
|
+
const AnthropicProvider_1 = require("./AnthropicProvider");
|
|
8
|
+
const OpenAICompatibleProvider_1 = require("./OpenAICompatibleProvider");
|
|
9
|
+
const SanitizingProvider_1 = require("./SanitizingProvider");
|
|
10
|
+
const Sanitizer_1 = require("../services/Sanitizer");
|
|
11
|
+
const SelaError_1 = require("../errors/SelaError");
|
|
12
|
+
function createProvider(cfg, sanitization) {
|
|
13
|
+
const inner = buildInnerProvider(cfg);
|
|
14
|
+
if (!sanitization || !sanitization.enabled)
|
|
15
|
+
return inner;
|
|
16
|
+
const patterns = (0, Sanitizer_1.compileCustomPatterns)(sanitization.customPatterns ?? []);
|
|
17
|
+
const scrub = (s) => (0, Sanitizer_1.sanitizeText)(s, {
|
|
18
|
+
redactInputValues: sanitization.redactInputValues,
|
|
19
|
+
customPatterns: patterns,
|
|
20
|
+
});
|
|
21
|
+
return new SanitizingProvider_1.SanitizingProvider(inner, scrub);
|
|
22
|
+
}
|
|
23
|
+
function buildInnerProvider(cfg) {
|
|
24
|
+
switch (cfg.provider) {
|
|
25
|
+
case "anthropic": {
|
|
26
|
+
// Fall back to process.env at provider-construction time so SelaEngine
|
|
27
|
+
// integration tests that stub ConfigLoader with an empty env still work,
|
|
28
|
+
// and so that legacy `ANTHROPIC_API_KEY` env usage is preserved.
|
|
29
|
+
const key = cfg.apiKey || process.env.ANTHROPIC_API_KEY || "";
|
|
30
|
+
if (!key) {
|
|
31
|
+
throw new SelaError_1.SelaError({
|
|
32
|
+
subsystem: "LLMService",
|
|
33
|
+
code: SelaError_1.LLM_SERVICE_CODES.NO_API_KEY,
|
|
34
|
+
reason: "No API key for Anthropic provider. Set ANTHROPIC_API_KEY or provide llm.healingModel.apiKey in sela.config.ts.",
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return new AnthropicProvider_1.AnthropicProvider(cfg.modelId, key);
|
|
38
|
+
}
|
|
39
|
+
case "openai":
|
|
40
|
+
case "openai-compatible":
|
|
41
|
+
case "local":
|
|
42
|
+
return new OpenAICompatibleProvider_1.OpenAICompatibleProvider(cfg.modelId, cfg.apiKey, cfg.baseUrl, cfg.customHeaders, cfg.disableSslVerification, cfg.timeoutMs);
|
|
43
|
+
default:
|
|
44
|
+
throw new SelaError_1.SelaError({
|
|
45
|
+
subsystem: "LLMService",
|
|
46
|
+
code: SelaError_1.LLM_SERVICE_CODES.NO_API_KEY,
|
|
47
|
+
reason: `Unknown LLM provider: "${cfg.provider}". Valid values: anthropic, openai, openai-compatible, local.`,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LLMProvider, CompletionParams } from "./LLMProvider";
|
|
2
|
+
export declare class SanitizingProvider implements LLMProvider {
|
|
3
|
+
private readonly inner;
|
|
4
|
+
private readonly scrub;
|
|
5
|
+
constructor(inner: LLMProvider, scrub: (s: string) => string);
|
|
6
|
+
complete(params: CompletionParams): Promise<string>;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=SanitizingProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SanitizingProvider.d.ts","sourceRoot":"","sources":["../../src/providers/SanitizingProvider.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEnE,qBAAa,kBAAmB,YAAW,WAAW;IAElD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBADL,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM;IAGzC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;CAU1D"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/providers/SanitizingProvider.ts
|
|
3
|
+
// LLMProvider decorator that scrubs PII/secrets from every outbound
|
|
4
|
+
// completion request before delegating to the inner provider.
|
|
5
|
+
// This is the provider-layer equivalent of the legacy SanitizingAnthropic
|
|
6
|
+
// wrapper — same guarantee, not tied to any specific SDK.
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.SanitizingProvider = void 0;
|
|
9
|
+
class SanitizingProvider {
|
|
10
|
+
inner;
|
|
11
|
+
scrub;
|
|
12
|
+
constructor(inner, scrub) {
|
|
13
|
+
this.inner = inner;
|
|
14
|
+
this.scrub = scrub;
|
|
15
|
+
}
|
|
16
|
+
async complete(params) {
|
|
17
|
+
return this.inner.complete({
|
|
18
|
+
...params,
|
|
19
|
+
system: params.system !== undefined ? this.scrub(params.system) : undefined,
|
|
20
|
+
messages: params.messages.map((m) => ({
|
|
21
|
+
...m,
|
|
22
|
+
content: this.scrub(m.content),
|
|
23
|
+
})),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.SanitizingProvider = SanitizingProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ASTSourceUpdater.d.ts","sourceRoot":"","sources":["../../src/services/ASTSourceUpdater.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAQ/C,OAAO,EAAE,cAAc,EAAgB,MAAM,mBAAmB,CAAC;AAOjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAmB,YAAY,
|
|
1
|
+
{"version":3,"file":"ASTSourceUpdater.d.ts","sourceRoot":"","sources":["../../src/services/ASTSourceUpdater.ts"],"names":[],"mappings":"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"}
|