playwright-intelligence-engine 0.0.0-stage → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +191 -0
- package/README.md +229 -3
- package/bin/pw-intel.js +37 -0
- package/dist/authoring/author.d.ts +83 -0
- package/dist/authoring/author.d.ts.map +1 -0
- package/dist/authoring/generation-contract.d.ts +90 -0
- package/dist/authoring/generation-contract.d.ts.map +1 -0
- package/dist/authoring/hybrid-author.d.ts +6 -0
- package/dist/authoring/hybrid-author.d.ts.map +1 -0
- package/dist/authoring/index.d.ts +7 -0
- package/dist/authoring/index.d.ts.map +1 -0
- package/dist/authoring/llm-author.d.ts +28 -0
- package/dist/authoring/llm-author.d.ts.map +1 -0
- package/dist/authoring/naming/index.d.ts +4 -0
- package/dist/authoring/naming/index.d.ts.map +1 -0
- package/dist/authoring/naming/name-plan.d.ts +45 -0
- package/dist/authoring/naming/name-plan.d.ts.map +1 -0
- package/dist/authoring/naming/name-planner.d.ts +25 -0
- package/dist/authoring/naming/name-planner.d.ts.map +1 -0
- package/dist/authoring/naming/naming-linter.d.ts +20 -0
- package/dist/authoring/naming/naming-linter.d.ts.map +1 -0
- package/dist/authoring/template-author.d.ts +6 -0
- package/dist/authoring/template-author.d.ts.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/collectors/collector-interface.d.ts +7 -0
- package/dist/collectors/collector-interface.d.ts.map +1 -0
- package/dist/collectors/environment-collector.d.ts +12 -0
- package/dist/collectors/environment-collector.d.ts.map +1 -0
- package/dist/collectors/error-collector.d.ts +18 -0
- package/dist/collectors/error-collector.d.ts.map +1 -0
- package/dist/collectors/git-diff-collector.d.ts +20 -0
- package/dist/collectors/git-diff-collector.d.ts.map +1 -0
- package/dist/collectors/live-browser-collector.d.ts +45 -0
- package/dist/collectors/live-browser-collector.d.ts.map +1 -0
- package/dist/collectors/network-collector.d.ts +28 -0
- package/dist/collectors/network-collector.d.ts.map +1 -0
- package/dist/collectors/static-ast-collector.d.ts +32 -0
- package/dist/collectors/static-ast-collector.d.ts.map +1 -0
- package/dist/collectors/trace-collector.d.ts +12 -0
- package/dist/collectors/trace-collector.d.ts.map +1 -0
- package/dist/config/project-config.d.ts +33 -0
- package/dist/config/project-config.d.ts.map +1 -0
- package/dist/core/errors/engine-errors.d.ts +34 -0
- package/dist/core/errors/engine-errors.d.ts.map +1 -0
- package/dist/core/types/diagnostic-context.d.ts +151 -0
- package/dist/core/types/diagnostic-context.d.ts.map +1 -0
- package/dist/core/types/repair-evidence.d.ts +56 -0
- package/dist/core/types/repair-evidence.d.ts.map +1 -0
- package/dist/core/version.d.ts +13 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/diagnostics/diagnostic-contract.d.ts +52 -0
- package/dist/diagnostics/diagnostic-contract.d.ts.map +1 -0
- package/dist/diagnostics/diagnostic-report.d.ts +11 -0
- package/dist/diagnostics/diagnostic-report.d.ts.map +1 -0
- package/dist/diagnostics/evidence-correlator.d.ts +22 -0
- package/dist/diagnostics/evidence-correlator.d.ts.map +1 -0
- package/dist/diagnostics/external-failure-evidence.d.ts +18 -0
- package/dist/diagnostics/external-failure-evidence.d.ts.map +1 -0
- package/dist/diagnostics/failure-category.d.ts +4 -0
- package/dist/diagnostics/failure-category.d.ts.map +1 -0
- package/dist/diagnostics/failure-classifier.d.ts +58 -0
- package/dist/diagnostics/failure-classifier.d.ts.map +1 -0
- package/dist/evaluation/evaluation-scorecard.d.ts +72 -0
- package/dist/evaluation/evaluation-scorecard.d.ts.map +1 -0
- package/dist/evaluation/repository-inspector.d.ts +21 -0
- package/dist/evaluation/repository-inspector.d.ts.map +1 -0
- package/dist/evaluation/repository-runner.d.ts +24 -0
- package/dist/evaluation/repository-runner.d.ts.map +1 -0
- package/dist/evidence/evidence-model.d.ts +88 -0
- package/dist/evidence/evidence-model.d.ts.map +1 -0
- package/dist/evidence/evidence-normalizer.d.ts +19 -0
- package/dist/evidence/evidence-normalizer.d.ts.map +1 -0
- package/dist/evidence/evidence-redactor.d.ts +37 -0
- package/dist/evidence/evidence-redactor.d.ts.map +1 -0
- package/dist/framework/config-adapter.d.ts +28 -0
- package/dist/framework/config-adapter.d.ts.map +1 -0
- package/dist/gate/index.d.ts +21 -0
- package/dist/gate/index.d.ts.map +1 -0
- package/dist/gate/oracle.d.ts +26 -0
- package/dist/gate/oracle.d.ts.map +1 -0
- package/dist/gate/quality.d.ts +27 -0
- package/dist/gate/quality.d.ts.map +1 -0
- package/dist/gate/safety.d.ts +28 -0
- package/dist/gate/safety.d.ts.map +1 -0
- package/dist/generator/architecture-generator.d.ts +55 -0
- package/dist/generator/architecture-generator.d.ts.map +1 -0
- package/dist/generator/assertion-quality-gate.d.ts +18 -0
- package/dist/generator/assertion-quality-gate.d.ts.map +1 -0
- package/dist/generator/candidate-writer.d.ts +34 -0
- package/dist/generator/candidate-writer.d.ts.map +1 -0
- package/dist/generator/test-generator.d.ts +26 -0
- package/dist/generator/test-generator.d.ts.map +1 -0
- package/dist/governance/audit-log.d.ts +23 -0
- package/dist/governance/audit-log.d.ts.map +1 -0
- package/dist/governance/governance-policy.d.ts +24 -0
- package/dist/governance/governance-policy.d.ts.map +1 -0
- package/dist/governance/team-dashboard.d.ts +51 -0
- package/dist/governance/team-dashboard.d.ts.map +1 -0
- package/dist/governance/workflow-audit.d.ts +13 -0
- package/dist/governance/workflow-audit.d.ts.map +1 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20318 -0
- package/dist/integrations/ci-summary.d.ts +14 -0
- package/dist/integrations/ci-summary.d.ts.map +1 -0
- package/dist/integrations/playwright-report-adapter.d.ts +22 -0
- package/dist/integrations/playwright-report-adapter.d.ts.map +1 -0
- package/dist/integrations/quality-gate.d.ts +35 -0
- package/dist/integrations/quality-gate.d.ts.map +1 -0
- package/dist/integrations/sarif-report.d.ts +48 -0
- package/dist/integrations/sarif-report.d.ts.map +1 -0
- package/dist/intelligence/autonomous-repair-workflow.d.ts +31 -0
- package/dist/intelligence/autonomous-repair-workflow.d.ts.map +1 -0
- package/dist/intelligence/business-intent.d.ts +58 -0
- package/dist/intelligence/business-intent.d.ts.map +1 -0
- package/dist/intelligence/evidence-bundle.d.ts +364 -0
- package/dist/intelligence/evidence-bundle.d.ts.map +1 -0
- package/dist/intelligence/failure-clustering.d.ts +38 -0
- package/dist/intelligence/failure-clustering.d.ts.map +1 -0
- package/dist/intelligence/generation-agent.d.ts +120 -0
- package/dist/intelligence/generation-agent.d.ts.map +1 -0
- package/dist/intelligence/generation-verifier.d.ts +151 -0
- package/dist/intelligence/generation-verifier.d.ts.map +1 -0
- package/dist/intelligence/llm-proposal.d.ts +377 -0
- package/dist/intelligence/llm-proposal.d.ts.map +1 -0
- package/dist/intelligence/locator-disambiguation-engine.d.ts +38 -0
- package/dist/intelligence/locator-disambiguation-engine.d.ts.map +1 -0
- package/dist/intelligence/model-contract.d.ts +86 -0
- package/dist/intelligence/model-contract.d.ts.map +1 -0
- package/dist/intelligence/model-provider.d.ts +75 -0
- package/dist/intelligence/model-provider.d.ts.map +1 -0
- package/dist/intelligence/project-intelligence.d.ts +22 -0
- package/dist/intelligence/project-intelligence.d.ts.map +1 -0
- package/dist/intelligence/repair-agent.d.ts +46 -0
- package/dist/intelligence/repair-agent.d.ts.map +1 -0
- package/dist/intelligence/repository-profile.d.ts +131 -0
- package/dist/intelligence/repository-profile.d.ts.map +1 -0
- package/dist/intelligence/suite-intelligence.d.ts +59 -0
- package/dist/intelligence/suite-intelligence.d.ts.map +1 -0
- package/dist/intelligence/test-intelligence.d.ts +44 -0
- package/dist/intelligence/test-intelligence.d.ts.map +1 -0
- package/dist/intelligence/trace-proposal-workflow.d.ts +30 -0
- package/dist/intelligence/trace-proposal-workflow.d.ts.map +1 -0
- package/dist/intelligence/verified-llm-repair-workflow.d.ts +21 -0
- package/dist/intelligence/verified-llm-repair-workflow.d.ts.map +1 -0
- package/dist/intelligence/workflow-planner.d.ts +278 -0
- package/dist/intelligence/workflow-planner.d.ts.map +1 -0
- package/dist/mcp/server.d.ts +32 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/memory/stability-ledger.d.ts +46 -0
- package/dist/memory/stability-ledger.d.ts.map +1 -0
- package/dist/perception/app-model.d.ts +55 -0
- package/dist/perception/app-model.d.ts.map +1 -0
- package/dist/perception/crawler.d.ts +18 -0
- package/dist/perception/crawler.d.ts.map +1 -0
- package/dist/perception/index.d.ts +3 -0
- package/dist/perception/index.d.ts.map +1 -0
- package/dist/repair/approval-service.d.ts +139 -0
- package/dist/repair/approval-service.d.ts.map +1 -0
- package/dist/repair/assertion-hasher.d.ts +62 -0
- package/dist/repair/assertion-hasher.d.ts.map +1 -0
- package/dist/repair/ast-patcher.d.ts +36 -0
- package/dist/repair/ast-patcher.d.ts.map +1 -0
- package/dist/repair/browser-operation-executor.d.ts +27 -0
- package/dist/repair/browser-operation-executor.d.ts.map +1 -0
- package/dist/repair/diff-allowlist.d.ts +74 -0
- package/dist/repair/diff-allowlist.d.ts.map +1 -0
- package/dist/repair/intent-validator.d.ts +157 -0
- package/dist/repair/intent-validator.d.ts.map +1 -0
- package/dist/repair/repair-operations.d.ts +40 -0
- package/dist/repair/repair-operations.d.ts.map +1 -0
- package/dist/repair/repair-planner.d.ts +98 -0
- package/dist/repair/repair-planner.d.ts.map +1 -0
- package/dist/repair/repair-workflow.d.ts +42 -0
- package/dist/repair/repair-workflow.d.ts.map +1 -0
- package/dist/repair/safe-operation-compiler.d.ts +15 -0
- package/dist/repair/safe-operation-compiler.d.ts.map +1 -0
- package/dist/repair/source-mapper.d.ts +19 -0
- package/dist/repair/source-mapper.d.ts.map +1 -0
- package/dist/repair/statement-patcher.d.ts +75 -0
- package/dist/repair/statement-patcher.d.ts.map +1 -0
- package/dist/repair/verification-gates.d.ts +25 -0
- package/dist/repair/verification-gates.d.ts.map +1 -0
- package/dist/repair/workflow-plan.d.ts +35 -0
- package/dist/repair/workflow-plan.d.ts.map +1 -0
- package/dist/repair/workspace-promoter.d.ts +43 -0
- package/dist/repair/workspace-promoter.d.ts.map +1 -0
- package/dist/reproduce/diagnostic-rerunner.d.ts +40 -0
- package/dist/reproduce/diagnostic-rerunner.d.ts.map +1 -0
- package/dist/reproduce/direct-browser-investigator.d.ts +41 -0
- package/dist/reproduce/direct-browser-investigator.d.ts.map +1 -0
- package/dist/reproduce/interactive-workflow-runner.d.ts +43 -0
- package/dist/reproduce/interactive-workflow-runner.d.ts.map +1 -0
- package/dist/sandbox/dependency-strategy.d.ts +45 -0
- package/dist/sandbox/dependency-strategy.d.ts.map +1 -0
- package/dist/sandbox/execution-runner.d.ts +81 -0
- package/dist/sandbox/execution-runner.d.ts.map +1 -0
- package/dist/sandbox/worktree-manager.d.ts +51 -0
- package/dist/sandbox/worktree-manager.d.ts.map +1 -0
- package/dist/selector/abstention-policy.d.ts +34 -0
- package/dist/selector/abstention-policy.d.ts.map +1 -0
- package/dist/selector/candidate-extractor.d.ts +71 -0
- package/dist/selector/candidate-extractor.d.ts.map +1 -0
- package/dist/selector/live-locator-verifier.d.ts +28 -0
- package/dist/selector/live-locator-verifier.d.ts.map +1 -0
- package/dist/selector/repair-candidate-ranker.d.ts +10 -0
- package/dist/selector/repair-candidate-ranker.d.ts.map +1 -0
- package/dist/selector/selector-scorer.d.ts +43 -0
- package/dist/selector/selector-scorer.d.ts.map +1 -0
- package/dist/trace/adapters/adapter-registry.d.ts +18 -0
- package/dist/trace/adapters/adapter-registry.d.ts.map +1 -0
- package/dist/trace/adapters/trace-adapter.d.ts +21 -0
- package/dist/trace/adapters/trace-adapter.d.ts.map +1 -0
- package/dist/trace/adapters/unknown-adapter.d.ts +10 -0
- package/dist/trace/adapters/unknown-adapter.d.ts.map +1 -0
- package/dist/trace/adapters/v10-adapter.d.ts +10 -0
- package/dist/trace/adapters/v10-adapter.d.ts.map +1 -0
- package/dist/trace/adapters/v4-adapter.d.ts +11 -0
- package/dist/trace/adapters/v4-adapter.d.ts.map +1 -0
- package/dist/trace/adapters/v8-adapter.d.ts +10 -0
- package/dist/trace/adapters/v8-adapter.d.ts.map +1 -0
- package/dist/trace/adapters/v9-adapter.d.ts +10 -0
- package/dist/trace/adapters/v9-adapter.d.ts.map +1 -0
- package/dist/trace/archive-reader.d.ts +44 -0
- package/dist/trace/archive-reader.d.ts.map +1 -0
- package/dist/trace/snapshot-resolver.d.ts +55 -0
- package/dist/trace/snapshot-resolver.d.ts.map +1 -0
- package/dist/trace/trace-parser.d.ts +50 -0
- package/dist/trace/trace-parser.d.ts.map +1 -0
- package/dist/trace/version-detector.d.ts +20 -0
- package/dist/trace/version-detector.d.ts.map +1 -0
- package/package.json +76 -6
- package/skills/README.md +20 -0
- package/skills/pie-failure-investigation/SKILL.md +16 -0
- package/skills/pie-quality-engineer/SKILL.md +66 -0
- package/skills/pie-release-readiness/SKILL.md +22 -0
- package/skills/pie-repair-review/SKILL.md +21 -0
- package/skills/pie-trace-to-repair/SKILL.md +35 -0
- package/src/authoring/author.ts +81 -0
- package/src/authoring/generation-contract.ts +283 -0
- package/src/authoring/hybrid-author.ts +115 -0
- package/src/authoring/index.ts +7 -0
- package/src/authoring/llm-author.ts +282 -0
- package/src/authoring/naming/index.ts +4 -0
- package/src/authoring/naming/name-plan.ts +28 -0
- package/src/authoring/naming/name-planner.ts +339 -0
- package/src/authoring/naming/naming-linter.ts +292 -0
- package/src/authoring/template-author.ts +39 -0
- package/src/cli/index.ts +1172 -0
- package/src/collectors/collector-interface.ts +8 -0
- package/src/collectors/environment-collector.ts +103 -0
- package/src/collectors/error-collector.ts +177 -0
- package/src/collectors/git-diff-collector.ts +190 -0
- package/src/collectors/live-browser-collector.ts +412 -0
- package/src/collectors/network-collector.ts +90 -0
- package/src/collectors/static-ast-collector.ts +226 -0
- package/src/collectors/trace-collector.ts +66 -0
- package/src/config/project-config.ts +114 -0
- package/src/core/errors/engine-errors.ts +90 -0
- package/src/core/types/diagnostic-context.ts +94 -0
- package/src/core/types/repair-evidence.ts +45 -0
- package/src/core/version.ts +25 -0
- package/src/diagnostics/diagnostic-contract.ts +79 -0
- package/src/diagnostics/diagnostic-report.ts +204 -0
- package/src/diagnostics/evidence-correlator.ts +117 -0
- package/src/diagnostics/external-failure-evidence.ts +72 -0
- package/src/diagnostics/failure-category.ts +40 -0
- package/src/diagnostics/failure-classifier.ts +701 -0
- package/src/evaluation/evaluation-scorecard.ts +198 -0
- package/src/evaluation/repository-inspector.ts +143 -0
- package/src/evaluation/repository-runner.ts +197 -0
- package/src/evidence/evidence-model.ts +76 -0
- package/src/evidence/evidence-normalizer.ts +322 -0
- package/src/evidence/evidence-redactor.ts +218 -0
- package/src/framework/config-adapter.ts +131 -0
- package/src/gate/index.ts +43 -0
- package/src/gate/oracle.ts +69 -0
- package/src/gate/quality.ts +101 -0
- package/src/gate/safety.ts +94 -0
- package/src/generator/architecture-generator.ts +582 -0
- package/src/generator/assertion-quality-gate.ts +88 -0
- package/src/generator/candidate-writer.ts +288 -0
- package/src/generator/test-generator.ts +52 -0
- package/src/governance/audit-log.ts +115 -0
- package/src/governance/governance-policy.ts +72 -0
- package/src/governance/team-dashboard.ts +189 -0
- package/src/governance/workflow-audit.ts +72 -0
- package/src/index.ts +107 -0
- package/src/integrations/ci-summary.ts +37 -0
- package/src/integrations/playwright-report-adapter.ts +173 -0
- package/src/integrations/quality-gate.ts +95 -0
- package/src/integrations/sarif-report.ts +110 -0
- package/src/intelligence/autonomous-repair-workflow.ts +139 -0
- package/src/intelligence/business-intent.ts +163 -0
- package/src/intelligence/evidence-bundle.ts +300 -0
- package/src/intelligence/failure-clustering.ts +134 -0
- package/src/intelligence/generation-agent.ts +561 -0
- package/src/intelligence/generation-verifier.ts +1115 -0
- package/src/intelligence/llm-proposal.ts +519 -0
- package/src/intelligence/locator-disambiguation-engine.ts +331 -0
- package/src/intelligence/model-contract.ts +205 -0
- package/src/intelligence/model-provider.ts +348 -0
- package/src/intelligence/project-intelligence.ts +140 -0
- package/src/intelligence/repair-agent.ts +297 -0
- package/src/intelligence/repository-profile.ts +796 -0
- package/src/intelligence/suite-intelligence.ts +305 -0
- package/src/intelligence/test-intelligence.ts +136 -0
- package/src/intelligence/trace-proposal-workflow.ts +318 -0
- package/src/intelligence/verified-llm-repair-workflow.ts +48 -0
- package/src/intelligence/workflow-planner.ts +966 -0
- package/src/mcp/server.ts +970 -0
- package/src/memory/stability-ledger.ts +243 -0
- package/src/perception/app-model.ts +32 -0
- package/src/perception/crawler.ts +263 -0
- package/src/perception/index.ts +3 -0
- package/src/repair/approval-service.ts +541 -0
- package/src/repair/assertion-hasher.ts +386 -0
- package/src/repair/ast-patcher.ts +223 -0
- package/src/repair/browser-operation-executor.ts +263 -0
- package/src/repair/diff-allowlist.ts +612 -0
- package/src/repair/intent-validator.ts +761 -0
- package/src/repair/repair-operations.ts +65 -0
- package/src/repair/repair-planner.ts +467 -0
- package/src/repair/repair-workflow.ts +241 -0
- package/src/repair/safe-operation-compiler.ts +68 -0
- package/src/repair/source-mapper.ts +156 -0
- package/src/repair/statement-patcher.ts +544 -0
- package/src/repair/verification-gates.ts +46 -0
- package/src/repair/workflow-plan.ts +59 -0
- package/src/repair/workspace-promoter.ts +313 -0
- package/src/reproduce/diagnostic-rerunner.ts +287 -0
- package/src/reproduce/direct-browser-investigator.ts +208 -0
- package/src/reproduce/interactive-workflow-runner.ts +828 -0
- package/src/sandbox/dependency-strategy.ts +215 -0
- package/src/sandbox/execution-runner.ts +408 -0
- package/src/sandbox/worktree-manager.ts +287 -0
- package/src/selector/abstention-policy.ts +175 -0
- package/src/selector/candidate-extractor.ts +343 -0
- package/src/selector/live-locator-verifier.ts +139 -0
- package/src/selector/repair-candidate-ranker.ts +92 -0
- package/src/selector/selector-scorer.ts +344 -0
- package/src/trace/adapters/adapter-registry.ts +49 -0
- package/src/trace/adapters/trace-adapter.ts +28 -0
- package/src/trace/adapters/unknown-adapter.ts +50 -0
- package/src/trace/adapters/v10-adapter.ts +39 -0
- package/src/trace/adapters/v4-adapter.ts +31 -0
- package/src/trace/adapters/v8-adapter.ts +42 -0
- package/src/trace/adapters/v9-adapter.ts +39 -0
- package/src/trace/archive-reader.ts +246 -0
- package/src/trace/snapshot-resolver.ts +308 -0
- package/src/trace/trace-parser.ts +467 -0
- package/src/trace/version-detector.ts +81 -0
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { RepairOperation, RepairOperationSchema, validateRepairOperation } from '../repair/repair-operations.js';
|
|
3
|
+
|
|
4
|
+
export const EvidenceBundleSchema = z.object({
|
|
5
|
+
bundleId: z.string().min(1),
|
|
6
|
+
executionId: z.string().min(1),
|
|
7
|
+
testIdentity: z.string().min(1),
|
|
8
|
+
failedActionId: z.string().optional(),
|
|
9
|
+
failureCategory: z.string().optional(),
|
|
10
|
+
sourceContext: z.array(z.object({
|
|
11
|
+
filePath: z.string(),
|
|
12
|
+
startLine: z.number().int().positive().optional(),
|
|
13
|
+
endLine: z.number().int().positive().optional(),
|
|
14
|
+
content: z.string(),
|
|
15
|
+
})).default([]),
|
|
16
|
+
artifacts: z.array(z.object({
|
|
17
|
+
kind: z.enum(['trace', 'screenshot', 'dom', 'aria', 'network', 'console', 'video', 'git-diff']),
|
|
18
|
+
reference: z.string(),
|
|
19
|
+
redacted: z.boolean(),
|
|
20
|
+
})).default([]),
|
|
21
|
+
diagnostic: z.object({
|
|
22
|
+
playwrightVersion: z.string(),
|
|
23
|
+
traceFormatVersion: z.number(),
|
|
24
|
+
failedAction: z.object({
|
|
25
|
+
callId: z.string(),
|
|
26
|
+
action: z.string(),
|
|
27
|
+
selector: z.string().optional(),
|
|
28
|
+
sourceFile: z.string().optional(),
|
|
29
|
+
line: z.number().optional(),
|
|
30
|
+
column: z.number().optional(),
|
|
31
|
+
errorMessage: z.string().optional(),
|
|
32
|
+
errorStack: z.string().optional(),
|
|
33
|
+
durationMs: z.number().optional(),
|
|
34
|
+
logs: z.array(z.string()).optional(),
|
|
35
|
+
}),
|
|
36
|
+
snapshots: z.object({
|
|
37
|
+
before: z.string().optional(),
|
|
38
|
+
action: z.string().optional(),
|
|
39
|
+
after: z.string().optional(),
|
|
40
|
+
}),
|
|
41
|
+
networkEvents: z.array(z.object({
|
|
42
|
+
method: z.string(),
|
|
43
|
+
url: z.string(),
|
|
44
|
+
status: z.number(),
|
|
45
|
+
statusText: z.string().optional(),
|
|
46
|
+
errorText: z.string().optional(),
|
|
47
|
+
})),
|
|
48
|
+
consoleEvents: z.array(z.object({ type: z.string(), text: z.string() })),
|
|
49
|
+
evidenceCompleteness: z.object({
|
|
50
|
+
domAvailable: z.boolean(),
|
|
51
|
+
networkAvailable: z.boolean(),
|
|
52
|
+
sourceAvailable: z.boolean(),
|
|
53
|
+
}),
|
|
54
|
+
}).optional(),
|
|
55
|
+
redactionComplete: z.boolean(),
|
|
56
|
+
limitations: z.array(z.string()).default([]),
|
|
57
|
+
}).strict();
|
|
58
|
+
|
|
59
|
+
export type EvidenceBundle = z.infer<typeof EvidenceBundleSchema>;
|
|
60
|
+
|
|
61
|
+
export const LlmRepairProposalSchema = z.object({
|
|
62
|
+
proposalVersion: z.literal('1'),
|
|
63
|
+
decision: z.enum(['PROPOSE', 'ABSTAIN']),
|
|
64
|
+
failureKind: z.string().min(1),
|
|
65
|
+
confidence: z.number().min(0).max(1),
|
|
66
|
+
reasoningSummary: z.string().min(1),
|
|
67
|
+
operations: z.array(RepairOperationSchema).max(20),
|
|
68
|
+
requiredVerification: z.array(z.string()).min(1),
|
|
69
|
+
evidenceReferences: z.array(z.string()),
|
|
70
|
+
}).strict();
|
|
71
|
+
|
|
72
|
+
export type LlmRepairProposal = z.infer<typeof LlmRepairProposalSchema>;
|
|
73
|
+
|
|
74
|
+
export interface ProposalParseResult {
|
|
75
|
+
isValid: boolean;
|
|
76
|
+
proposal?: LlmRepairProposal;
|
|
77
|
+
errors: string[];
|
|
78
|
+
normalizationNotes?: string[] | undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const AgentActionKindSchema = z.enum([
|
|
82
|
+
'inspect_evidence',
|
|
83
|
+
'inspect_browser_state',
|
|
84
|
+
'inspect_repository',
|
|
85
|
+
'read_source_file',
|
|
86
|
+
'search_repository',
|
|
87
|
+
'discover_source_mapping',
|
|
88
|
+
'rank_locator_candidates',
|
|
89
|
+
'build_repair_proposal',
|
|
90
|
+
'run_target_test',
|
|
91
|
+
'verify_repair',
|
|
92
|
+
'abstain',
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
export type AgentActionKind = z.infer<typeof AgentActionKindSchema>;
|
|
96
|
+
|
|
97
|
+
export const AgentActionSchema = z.object({
|
|
98
|
+
kind: AgentActionKindSchema,
|
|
99
|
+
selector: z.string().min(1).optional(),
|
|
100
|
+
target: z.string().min(1).optional(),
|
|
101
|
+
locator: z.string().min(1).optional(),
|
|
102
|
+
path: z.string().min(1).optional(),
|
|
103
|
+
query: z.string().min(1).optional(),
|
|
104
|
+
testFile: z.string().min(1).optional(),
|
|
105
|
+
configPath: z.string().min(1).optional(),
|
|
106
|
+
sourceFile: z.string().min(1).optional(),
|
|
107
|
+
className: z.string().min(1).optional(),
|
|
108
|
+
memberName: z.string().min(1).optional(),
|
|
109
|
+
reason: z.string().min(1).optional(),
|
|
110
|
+
}).strict();
|
|
111
|
+
|
|
112
|
+
export type AgentAction = z.infer<typeof AgentActionSchema>;
|
|
113
|
+
|
|
114
|
+
const AgentClassificationSchema = z.object({
|
|
115
|
+
category: z.string().min(1),
|
|
116
|
+
confidence: z.number().min(0).max(1),
|
|
117
|
+
}).strict();
|
|
118
|
+
|
|
119
|
+
const AgentStepResponseSchema = z.object({
|
|
120
|
+
protocolVersion: z.literal('2'),
|
|
121
|
+
responseType: z.literal('STEP'),
|
|
122
|
+
status: z.literal('CONTINUE'),
|
|
123
|
+
decision: z.enum([
|
|
124
|
+
'INSPECT_EVIDENCE',
|
|
125
|
+
'INSPECT_BROWSER_STATE',
|
|
126
|
+
'INSPECT_REPOSITORY',
|
|
127
|
+
'READ_SOURCE_FILE',
|
|
128
|
+
'SEARCH_REPOSITORY',
|
|
129
|
+
'DISCOVER_SOURCE_MAPPING',
|
|
130
|
+
'RANK_LOCATOR_CANDIDATES',
|
|
131
|
+
'BUILD_REPAIR_PROPOSAL',
|
|
132
|
+
'RUN_TARGET_TEST',
|
|
133
|
+
'VERIFY_REPAIR',
|
|
134
|
+
'ABSTAIN',
|
|
135
|
+
]),
|
|
136
|
+
confidence: z.number().min(0).max(1),
|
|
137
|
+
reasoningSummary: z.string().min(1),
|
|
138
|
+
evidenceReferences: z.array(z.string()),
|
|
139
|
+
action: AgentActionSchema,
|
|
140
|
+
requiredObservation: z.string().min(1),
|
|
141
|
+
}).strict();
|
|
142
|
+
|
|
143
|
+
const AgentFinalResponseSchema = z.object({
|
|
144
|
+
protocolVersion: z.literal('2'),
|
|
145
|
+
responseType: z.literal('FINAL'),
|
|
146
|
+
status: z.enum(['PROPOSAL_READY', 'VERIFIED_READY_FOR_APPROVAL', 'ABSTAIN', 'BLOCKED', 'REJECTED']),
|
|
147
|
+
classification: AgentClassificationSchema,
|
|
148
|
+
reasoningSummary: z.string().min(1),
|
|
149
|
+
evidenceReferences: z.array(z.string()),
|
|
150
|
+
proposal: LlmRepairProposalSchema.optional(),
|
|
151
|
+
verification: z.object({
|
|
152
|
+
isolatedTestPassed: z.boolean().optional(),
|
|
153
|
+
assertionsChanged: z.boolean().optional(),
|
|
154
|
+
unrelatedFilesChanged: z.boolean().optional(),
|
|
155
|
+
}).strict().optional(),
|
|
156
|
+
humanApprovalRequired: z.boolean(),
|
|
157
|
+
}).strict();
|
|
158
|
+
|
|
159
|
+
export const AgentResponseSchema = z.discriminatedUnion('responseType', [AgentStepResponseSchema, AgentFinalResponseSchema]);
|
|
160
|
+
|
|
161
|
+
export type AgentStepResponse = z.infer<typeof AgentStepResponseSchema>;
|
|
162
|
+
export type AgentFinalResponse = z.infer<typeof AgentFinalResponseSchema>;
|
|
163
|
+
export type AgentResponse = z.infer<typeof AgentResponseSchema>;
|
|
164
|
+
|
|
165
|
+
export interface AgentResponseParseResult {
|
|
166
|
+
isValid: boolean;
|
|
167
|
+
response?: AgentResponse;
|
|
168
|
+
errors: string[];
|
|
169
|
+
normalizationNotes?: string[] | undefined;
|
|
170
|
+
/** Recognized transport metadata removed before strict protocol validation. */
|
|
171
|
+
protocolMetadata?: AgentProtocolMetadata | undefined;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface AgentProtocolMetadata {
|
|
175
|
+
callId?: string | undefined;
|
|
176
|
+
requestId?: string | undefined;
|
|
177
|
+
responseId?: string | undefined;
|
|
178
|
+
messageId?: string | undefined;
|
|
179
|
+
model?: string | undefined;
|
|
180
|
+
provider?: string | undefined;
|
|
181
|
+
finishReason?: string | undefined;
|
|
182
|
+
usage?: unknown;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function extractJsonCandidate(input: string): string {
|
|
186
|
+
const trimmed = input.trim();
|
|
187
|
+
const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)\s*```/i);
|
|
188
|
+
if (fenced?.[1]) return fenced[1].trim();
|
|
189
|
+
const start = trimmed.indexOf('{');
|
|
190
|
+
const end = trimmed.lastIndexOf('}');
|
|
191
|
+
return start >= 0 && end > start ? trimmed.slice(start, end + 1) : trimmed;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function parseJsonInput(input: unknown): { candidate?: unknown; errors: string[] } {
|
|
195
|
+
if (typeof input !== 'string') return { candidate: input, errors: [] };
|
|
196
|
+
try {
|
|
197
|
+
return { candidate: JSON.parse(extractJsonCandidate(input)), errors: [] };
|
|
198
|
+
} catch (error) {
|
|
199
|
+
return { errors: [`Response is not valid JSON: ${String(error)}`] };
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function normalizeAgentCandidate(input: unknown): { candidate: unknown; notes: string[]; metadata?: AgentProtocolMetadata | undefined } {
|
|
204
|
+
if (!input || typeof input !== 'object' || Array.isArray(input)) return { candidate: input, notes: [] };
|
|
205
|
+
const envelope = normalizeAgentEnvelope(input as Record<string, unknown>);
|
|
206
|
+
const source = envelope.candidate as Record<string, unknown>;
|
|
207
|
+
const withEnvelope = (candidate: unknown, notes: string[] = []) => ({
|
|
208
|
+
candidate,
|
|
209
|
+
notes: [...envelope.notes, ...notes],
|
|
210
|
+
...(envelope.metadata ? { metadata: envelope.metadata } : {}),
|
|
211
|
+
});
|
|
212
|
+
if (source.responseType === 'FINAL') {
|
|
213
|
+
const allowedFinalKeys = new Set([
|
|
214
|
+
'protocolVersion', 'responseType', 'status', 'classification',
|
|
215
|
+
'reasoningSummary', 'evidenceReferences', 'proposal', 'verification',
|
|
216
|
+
'humanApprovalRequired',
|
|
217
|
+
]);
|
|
218
|
+
if (Object.keys(source).some((key) => !allowedFinalKeys.has(key))) return withEnvelope(source);
|
|
219
|
+
// Accept a complete PIE final response unchanged. Compatibility handling
|
|
220
|
+
// below is deliberately limited to documented sparse-final variants.
|
|
221
|
+
if (AgentFinalResponseSchema.safeParse(source).success) return withEnvelope(source);
|
|
222
|
+
|
|
223
|
+
const notes: string[] = [];
|
|
224
|
+
const classification = source.classification && typeof source.classification === 'object' && !Array.isArray(source.classification)
|
|
225
|
+
? source.classification as Record<string, unknown>
|
|
226
|
+
: {};
|
|
227
|
+
const normalizedClassification = typeof classification.category === 'string'
|
|
228
|
+
&& typeof classification.confidence === 'number'
|
|
229
|
+
&& classification.confidence >= 0
|
|
230
|
+
&& classification.confidence <= 1
|
|
231
|
+
? { category: classification.category, confidence: classification.confidence }
|
|
232
|
+
: { category: 'MODEL_RESPONSE', confidence: 0 };
|
|
233
|
+
const evidenceReferences = Array.isArray(source.evidenceReferences)
|
|
234
|
+
? source.evidenceReferences.filter((value): value is string => typeof value === 'string')
|
|
235
|
+
: [];
|
|
236
|
+
const reasoningSummary = typeof source.reasoningSummary === 'string'
|
|
237
|
+
? source.reasoningSummary
|
|
238
|
+
: 'The model returned an incomplete final response.';
|
|
239
|
+
const humanApprovalRequired = typeof source.humanApprovalRequired === 'boolean' ? source.humanApprovalRequired : true;
|
|
240
|
+
|
|
241
|
+
if (source.status === 'ABSTAIN') {
|
|
242
|
+
notes.push('Normalized sparse FINAL ABSTAIN response with conservative classification and approval defaults.');
|
|
243
|
+
return withEnvelope({
|
|
244
|
+
protocolVersion: '2',
|
|
245
|
+
responseType: 'FINAL',
|
|
246
|
+
status: 'ABSTAIN',
|
|
247
|
+
classification: normalizedClassification,
|
|
248
|
+
reasoningSummary,
|
|
249
|
+
evidenceReferences,
|
|
250
|
+
humanApprovalRequired,
|
|
251
|
+
}, notes);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (source.status === 'PROPOSAL' && source.proposal && typeof source.proposal === 'object' && !Array.isArray(source.proposal)) {
|
|
255
|
+
const legacyProposal = source.proposal as Record<string, unknown>;
|
|
256
|
+
const target = legacyProposal.target;
|
|
257
|
+
const locator = legacyProposal.locator;
|
|
258
|
+
if (target && typeof target === 'object' && !Array.isArray(target)
|
|
259
|
+
&& typeof (target as Record<string, unknown>).filePath === 'string'
|
|
260
|
+
&& typeof locator === 'string' && locator.length > 0) {
|
|
261
|
+
notes.push('Mapped recognized legacy FINAL PROPOSAL shape to BLOCKED because it lacks a safe old-locator operation.');
|
|
262
|
+
return withEnvelope({
|
|
263
|
+
protocolVersion: '2',
|
|
264
|
+
responseType: 'FINAL',
|
|
265
|
+
status: 'BLOCKED',
|
|
266
|
+
classification: normalizedClassification,
|
|
267
|
+
reasoningSummary: 'The model returned a source-location proposal without a complete PIE repair operation; no mutation was synthesized.',
|
|
268
|
+
evidenceReferences,
|
|
269
|
+
humanApprovalRequired: true,
|
|
270
|
+
}, notes);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const legacyFinalStatuses = new Set(['OK', 'PROPOSED', 'PROPOSAL_ONLY', 'REPAIR_PROPOSAL', 'COMPLETE']);
|
|
275
|
+
if (typeof source.status === 'string' && legacyFinalStatuses.has(source.status)
|
|
276
|
+
&& source.proposal && typeof source.proposal === 'object' && !Array.isArray(source.proposal)) {
|
|
277
|
+
const legacyProposal = source.proposal as Record<string, unknown>;
|
|
278
|
+
const failureCategory = typeof legacyProposal.failureCategory === 'string'
|
|
279
|
+
? legacyProposal.failureCategory.trim().toUpperCase()
|
|
280
|
+
: typeof legacyProposal.failureKind === 'string'
|
|
281
|
+
? legacyProposal.failureKind.trim().toUpperCase()
|
|
282
|
+
: typeof legacyProposal.category === 'string'
|
|
283
|
+
? legacyProposal.category.trim().toUpperCase()
|
|
284
|
+
: undefined;
|
|
285
|
+
const confidence = typeof legacyProposal.confidence === 'number' && legacyProposal.confidence >= 0 && legacyProposal.confidence <= 1
|
|
286
|
+
? legacyProposal.confidence
|
|
287
|
+
: 0;
|
|
288
|
+
const summary = typeof legacyProposal.summary === 'string'
|
|
289
|
+
? legacyProposal.summary
|
|
290
|
+
: typeof legacyProposal.rationale === 'string'
|
|
291
|
+
? legacyProposal.rationale
|
|
292
|
+
: 'The model returned a legacy locator proposal.';
|
|
293
|
+
const directTarget = typeof legacyProposal.oldLocator === 'string' ? legacyProposal.oldLocator
|
|
294
|
+
: typeof legacyProposal.oldText === 'string' ? legacyProposal.oldText
|
|
295
|
+
: typeof legacyProposal.originalLocator === 'string' ? legacyProposal.originalLocator : undefined;
|
|
296
|
+
const directLocator = typeof legacyProposal.newLocator === 'string' ? legacyProposal.newLocator
|
|
297
|
+
: typeof legacyProposal.newText === 'string' ? legacyProposal.newText
|
|
298
|
+
: typeof legacyProposal.proposedLocator === 'string' ? legacyProposal.proposedLocator : undefined;
|
|
299
|
+
const edits = Array.isArray(legacyProposal.edits) ? legacyProposal.edits : Array.isArray(legacyProposal.changes) ? legacyProposal.changes : [];
|
|
300
|
+
const firstEdit = edits[0] && typeof edits[0] === 'object' && !Array.isArray(edits[0]) ? edits[0] as Record<string, unknown> : {};
|
|
301
|
+
const target = directTarget
|
|
302
|
+
?? (typeof firstEdit.oldLocator === 'string' ? firstEdit.oldLocator : typeof firstEdit.oldText === 'string' ? firstEdit.oldText : undefined)
|
|
303
|
+
?? (typeof legacyProposal.target === 'string' ? legacyProposal.target : undefined);
|
|
304
|
+
const locator = directLocator
|
|
305
|
+
?? (typeof firstEdit.newLocator === 'string' ? firstEdit.newLocator : typeof firstEdit.newText === 'string' ? firstEdit.newText : undefined)
|
|
306
|
+
?? (typeof legacyProposal.locator === 'string' ? legacyProposal.locator : undefined);
|
|
307
|
+
const hasLegacyLocatorShape = typeof target === 'string'
|
|
308
|
+
|| typeof locator === 'string'
|
|
309
|
+
|| typeof legacyProposal.target === 'string'
|
|
310
|
+
|| typeof legacyProposal.locator === 'string'
|
|
311
|
+
|| edits.length > 0;
|
|
312
|
+
const inferredLocatorDrift = failureCategory === undefined
|
|
313
|
+
&& source.status === 'PROPOSED'
|
|
314
|
+
&& typeof legacyProposal.target === 'string'
|
|
315
|
+
&& typeof legacyProposal.locator === 'string';
|
|
316
|
+
|
|
317
|
+
if ((failureCategory === 'LOCATOR_DRIFT' || inferredLocatorDrift) && target && locator) {
|
|
318
|
+
notes.push('Normalized recognized legacy locator proposal into the PIE replacement-operation schema.');
|
|
319
|
+
return withEnvelope({
|
|
320
|
+
protocolVersion: '2',
|
|
321
|
+
responseType: 'FINAL',
|
|
322
|
+
status: 'PROPOSAL_READY',
|
|
323
|
+
classification: { category: 'LOCATOR_DRIFT', confidence },
|
|
324
|
+
reasoningSummary: summary,
|
|
325
|
+
evidenceReferences,
|
|
326
|
+
proposal: {
|
|
327
|
+
proposalVersion: '1',
|
|
328
|
+
decision: 'PROPOSE',
|
|
329
|
+
failureKind: 'LOCATOR_DRIFT',
|
|
330
|
+
confidence,
|
|
331
|
+
reasoningSummary: summary,
|
|
332
|
+
operations: [{ kind: 'replace_locator', target, locator }],
|
|
333
|
+
requiredVerification: ['isolated target test', 'assertions unchanged'],
|
|
334
|
+
evidenceReferences,
|
|
335
|
+
},
|
|
336
|
+
humanApprovalRequired: true,
|
|
337
|
+
}, notes);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (hasLegacyLocatorShape) {
|
|
341
|
+
notes.push('Mapped an incomplete or non-locator legacy final proposal to BLOCKED; no mutation operation was synthesized.');
|
|
342
|
+
return withEnvelope({
|
|
343
|
+
protocolVersion: '2',
|
|
344
|
+
responseType: 'FINAL',
|
|
345
|
+
status: 'BLOCKED',
|
|
346
|
+
classification: normalizedClassification,
|
|
347
|
+
reasoningSummary: 'The legacy proposal did not contain a safe LOCATOR_DRIFT replacement operation; no mutation was synthesized.',
|
|
348
|
+
evidenceReferences,
|
|
349
|
+
humanApprovalRequired: true,
|
|
350
|
+
}, notes);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return withEnvelope(source, notes);
|
|
355
|
+
}
|
|
356
|
+
if (source.responseType === 'STEP') {
|
|
357
|
+
const allowedStepKeys = new Set([
|
|
358
|
+
'protocolVersion', 'responseType', 'status', 'decision', 'confidence',
|
|
359
|
+
'reasoningSummary', 'evidenceReferences', 'action', 'requiredObservation',
|
|
360
|
+
]);
|
|
361
|
+
if (Object.keys(source).some((key) => !allowedStepKeys.has(key))) return withEnvelope(source);
|
|
362
|
+
}
|
|
363
|
+
if (source.responseType !== 'STEP' || source.status !== 'CONTINUE' || !source.action
|
|
364
|
+
|| (typeof source.action !== 'object' && typeof source.action !== 'string')) {
|
|
365
|
+
return withEnvelope(source);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const rawAction = typeof source.action === 'string'
|
|
369
|
+
? { kind: source.action }
|
|
370
|
+
: source.action as Record<string, unknown>;
|
|
371
|
+
const kind = rawAction.kind;
|
|
372
|
+
const allowedActionFields = ['kind', 'selector', 'target', 'locator', 'path', 'query', 'testFile', 'configPath', 'sourceFile', 'className', 'memberName', 'reason'];
|
|
373
|
+
const action: Record<string, unknown> = {};
|
|
374
|
+
for (const field of allowedActionFields) {
|
|
375
|
+
if (typeof rawAction[field] === 'string' && rawAction[field].length > 0) action[field] = rawAction[field];
|
|
376
|
+
}
|
|
377
|
+
const notes: string[] = [];
|
|
378
|
+
if (typeof source.action === 'string') notes.push('Normalized a recognized string action into the PIE action object schema.');
|
|
379
|
+
const legacyProposal = rawAction.proposal;
|
|
380
|
+
if (legacyProposal && typeof legacyProposal === 'object') {
|
|
381
|
+
const legacy = legacyProposal as Record<string, unknown>;
|
|
382
|
+
if (typeof legacy.oldLocator === 'string' && action.target === undefined) action.target = legacy.oldLocator;
|
|
383
|
+
if (typeof legacy.oldText === 'string' && action.target === undefined) action.target = legacy.oldText;
|
|
384
|
+
if (typeof legacy.newLocator === 'string' && action.locator === undefined) action.locator = legacy.newLocator;
|
|
385
|
+
if (typeof legacy.newText === 'string' && action.locator === undefined) action.locator = legacy.newText;
|
|
386
|
+
const edits = Array.isArray(legacy.edits) ? legacy.edits : Array.isArray(legacy.changes) ? legacy.changes : [];
|
|
387
|
+
const firstEdit = edits[0] && typeof edits[0] === 'object' && !Array.isArray(edits[0]) ? edits[0] as Record<string, unknown> : {};
|
|
388
|
+
if (typeof firstEdit.oldLocator === 'string' && action.target === undefined) action.target = firstEdit.oldLocator;
|
|
389
|
+
if (typeof firstEdit.oldText === 'string' && action.target === undefined) action.target = firstEdit.oldText;
|
|
390
|
+
if (typeof firstEdit.newLocator === 'string' && action.locator === undefined) action.locator = firstEdit.newLocator;
|
|
391
|
+
if (typeof firstEdit.newText === 'string' && action.locator === undefined) action.locator = firstEdit.newText;
|
|
392
|
+
notes.push('Dropped unsupported nested proposal metadata; retained only allowlisted locator fields.');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const decisionByAction: Record<string, string> = {
|
|
396
|
+
inspect_evidence: 'INSPECT_EVIDENCE',
|
|
397
|
+
inspect_browser_state: 'INSPECT_BROWSER_STATE',
|
|
398
|
+
inspect_repository: 'INSPECT_REPOSITORY',
|
|
399
|
+
read_source_file: 'READ_SOURCE_FILE',
|
|
400
|
+
search_repository: 'SEARCH_REPOSITORY',
|
|
401
|
+
discover_source_mapping: 'DISCOVER_SOURCE_MAPPING',
|
|
402
|
+
rank_locator_candidates: 'RANK_LOCATOR_CANDIDATES',
|
|
403
|
+
build_repair_proposal: 'BUILD_REPAIR_PROPOSAL',
|
|
404
|
+
run_target_test: 'RUN_TARGET_TEST',
|
|
405
|
+
verify_repair: 'VERIFY_REPAIR',
|
|
406
|
+
abstain: 'ABSTAIN',
|
|
407
|
+
};
|
|
408
|
+
const normalized: Record<string, unknown> = {
|
|
409
|
+
protocolVersion: source.protocolVersion === '2' ? '2' : '2',
|
|
410
|
+
responseType: 'STEP',
|
|
411
|
+
status: 'CONTINUE',
|
|
412
|
+
decision: typeof source.decision === 'string' ? source.decision : decisionByAction[String(kind)] ?? kind,
|
|
413
|
+
confidence: typeof source.confidence === 'number' ? source.confidence : 0,
|
|
414
|
+
reasoningSummary: typeof source.reasoningSummary === 'string' ? source.reasoningSummary : 'Model requested an allowlisted PIE observation.',
|
|
415
|
+
evidenceReferences: Array.isArray(source.evidenceReferences) ? source.evidenceReferences.filter((value): value is string => typeof value === 'string') : [],
|
|
416
|
+
action,
|
|
417
|
+
requiredObservation: typeof source.requiredObservation === 'string' ? source.requiredObservation : 'Return the PIE action observation.',
|
|
418
|
+
};
|
|
419
|
+
if (source.decision === undefined) notes.push('Derived decision from the allowlisted action kind.');
|
|
420
|
+
if (source.confidence === undefined) notes.push('Applied conservative confidence default 0.');
|
|
421
|
+
if (source.reasoningSummary === undefined) notes.push('Applied a neutral reasoning summary because none was returned.');
|
|
422
|
+
if (source.evidenceReferences === undefined) notes.push('Applied an empty evidence-reference list because none was returned.');
|
|
423
|
+
if (source.requiredObservation === undefined) notes.push('Applied a default observation requirement because none was returned.');
|
|
424
|
+
return withEnvelope(normalized, notes);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Some OpenAI-compatible endpoints and models place correlation metadata next
|
|
429
|
+
* to the PIE response object. These fields are transport metadata, not model
|
|
430
|
+
* instructions. Remove only this explicit allowlist before strict validation;
|
|
431
|
+
* every other unknown field remains an error.
|
|
432
|
+
*/
|
|
433
|
+
function normalizeAgentEnvelope(input: Record<string, unknown>): {
|
|
434
|
+
candidate: Record<string, unknown>;
|
|
435
|
+
notes: string[];
|
|
436
|
+
metadata?: AgentProtocolMetadata | undefined;
|
|
437
|
+
} {
|
|
438
|
+
const metadataKeys = [
|
|
439
|
+
'callId', 'requestId', 'responseId', 'messageId', 'model', 'provider',
|
|
440
|
+
'finishReason', 'finish_reason', 'usage', 'id',
|
|
441
|
+
] as const;
|
|
442
|
+
const candidate = { ...input };
|
|
443
|
+
const metadata: AgentProtocolMetadata = {};
|
|
444
|
+
const notes: string[] = [];
|
|
445
|
+
for (const key of metadataKeys) {
|
|
446
|
+
if (!(key in candidate)) continue;
|
|
447
|
+
const value = candidate[key];
|
|
448
|
+
delete candidate[key];
|
|
449
|
+
if (key === 'finish_reason') {
|
|
450
|
+
if (typeof value === 'string') metadata.finishReason = value;
|
|
451
|
+
} else if (key === 'usage') {
|
|
452
|
+
metadata.usage = value;
|
|
453
|
+
} else if (typeof value === 'string') {
|
|
454
|
+
switch (key) {
|
|
455
|
+
case 'callId': metadata.callId = value; break;
|
|
456
|
+
case 'requestId': metadata.requestId = value; break;
|
|
457
|
+
case 'responseId': metadata.responseId = value; break;
|
|
458
|
+
case 'messageId': metadata.messageId = value; break;
|
|
459
|
+
case 'model': metadata.model = value; break;
|
|
460
|
+
case 'provider': metadata.provider = value; break;
|
|
461
|
+
case 'finishReason': metadata.finishReason = value; break;
|
|
462
|
+
case 'id': metadata.responseId = value; break;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
notes.push(`Normalized recognized response envelope metadata '${key}'.`);
|
|
466
|
+
}
|
|
467
|
+
return {
|
|
468
|
+
candidate,
|
|
469
|
+
notes,
|
|
470
|
+
...(Object.keys(metadata).length > 0 ? { metadata } : {}),
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export function parseLlmRepairProposal(input: unknown): ProposalParseResult {
|
|
475
|
+
const parsedInput = parseJsonInput(input);
|
|
476
|
+
if (parsedInput.errors.length > 0) return { isValid: false, errors: parsedInput.errors.map((error) => error.replace(/^Response/, 'Proposal')) };
|
|
477
|
+
const candidate = parsedInput.candidate;
|
|
478
|
+
|
|
479
|
+
const parsed = LlmRepairProposalSchema.safeParse(candidate);
|
|
480
|
+
if (!parsed.success) {
|
|
481
|
+
return { isValid: false, errors: parsed.error.issues.map((issue) => issue.message) };
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const operationErrors = parsed.data.operations.flatMap((operation) => {
|
|
485
|
+
const result = validateRepairOperation(operation);
|
|
486
|
+
return result.isValid ? [] : [result.reason ?? 'Invalid repair operation'];
|
|
487
|
+
});
|
|
488
|
+
if (operationErrors.length > 0) return { isValid: false, errors: operationErrors };
|
|
489
|
+
|
|
490
|
+
if (parsed.data.decision === 'ABSTAIN' && parsed.data.operations.some((operation) => operation.kind !== 'abstain')) {
|
|
491
|
+
return { isValid: false, errors: ['ABSTAIN proposals cannot contain source mutation operations'] };
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return { isValid: true, proposal: parsed.data, errors: [] };
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
export function proposalOperations(proposal: LlmRepairProposal): RepairOperation[] {
|
|
498
|
+
return proposal.operations;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
export function parseAgentResponse(input: unknown): AgentResponseParseResult {
|
|
502
|
+
const parsedInput = parseJsonInput(input);
|
|
503
|
+
if (parsedInput.errors.length > 0) return { isValid: false, errors: parsedInput.errors };
|
|
504
|
+
const normalized = normalizeAgentCandidate(parsedInput.candidate);
|
|
505
|
+
const parsed = AgentResponseSchema.safeParse(normalized.candidate);
|
|
506
|
+
if (!parsed.success) return {
|
|
507
|
+
isValid: false,
|
|
508
|
+
errors: parsed.error.issues.map((issue) => issue.message),
|
|
509
|
+
normalizationNotes: normalized.notes,
|
|
510
|
+
protocolMetadata: normalized.metadata,
|
|
511
|
+
};
|
|
512
|
+
if (parsed.data.responseType === 'FINAL' && parsed.data.proposal) {
|
|
513
|
+
const proposal = parseLlmRepairProposal(parsed.data.proposal);
|
|
514
|
+
if (!proposal.isValid || !proposal.proposal) return { isValid: false, errors: proposal.errors, normalizationNotes: normalized.notes, protocolMetadata: normalized.metadata };
|
|
515
|
+
return { isValid: true, response: { ...parsed.data, proposal: proposal.proposal }, errors: [], normalizationNotes: normalized.notes, protocolMetadata: normalized.metadata };
|
|
516
|
+
}
|
|
517
|
+
return { isValid: true, response: parsed.data, errors: [], normalizationNotes: normalized.notes, protocolMetadata: normalized.metadata };
|
|
518
|
+
}
|
|
519
|
+
|