flakelab 0.1.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.
- package/README.md +341 -0
- package/bin/flakelab.mjs +3 -0
- package/dist/artifacts/ndjson.d.ts +3 -0
- package/dist/artifacts/ndjson.js +16 -0
- package/dist/artifacts/ndjson.js.map +1 -0
- package/dist/bisect/archive.d.ts +1 -0
- package/dist/bisect/archive.js +14 -0
- package/dist/bisect/archive.js.map +1 -0
- package/dist/bisect/confidence.d.ts +7 -0
- package/dist/bisect/confidence.js +27 -0
- package/dist/bisect/confidence.js.map +1 -0
- package/dist/bisect/engine.d.ts +10 -0
- package/dist/bisect/engine.js +110 -0
- package/dist/bisect/engine.js.map +1 -0
- package/dist/bisect/git.d.ts +7 -0
- package/dist/bisect/git.js +56 -0
- package/dist/bisect/git.js.map +1 -0
- package/dist/bisect/schema.d.ts +82 -0
- package/dist/bisect/schema.js +33 -0
- package/dist/bisect/schema.js.map +1 -0
- package/dist/bisect/solari-command.d.ts +7 -0
- package/dist/bisect/solari-command.js +95 -0
- package/dist/bisect/solari-command.js.map +1 -0
- package/dist/bisect/solari-evaluator.d.ts +20 -0
- package/dist/bisect/solari-evaluator.js +310 -0
- package/dist/bisect/solari-evaluator.js.map +1 -0
- package/dist/ci/changed-tests.d.ts +7 -0
- package/dist/ci/changed-tests.js +104 -0
- package/dist/ci/changed-tests.js.map +1 -0
- package/dist/ci/job-summary.d.ts +11 -0
- package/dist/ci/job-summary.js +45 -0
- package/dist/ci/job-summary.js.map +1 -0
- package/dist/ci/select-command.d.ts +1 -0
- package/dist/ci/select-command.js +49 -0
- package/dist/ci/select-command.js.map +1 -0
- package/dist/ci/summary-command.d.ts +1 -0
- package/dist/ci/summary-command.js +46 -0
- package/dist/ci/summary-command.js.map +1 -0
- package/dist/cli-help.d.ts +2 -0
- package/dist/cli-help.js +47 -0
- package/dist/cli-help.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +121 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/bisect.d.ts +2 -0
- package/dist/commands/bisect.js +63 -0
- package/dist/commands/bisect.js.map +1 -0
- package/dist/commands/diagnose.d.ts +2 -0
- package/dist/commands/diagnose.js +27 -0
- package/dist/commands/diagnose.js.map +1 -0
- package/dist/commands/discover.d.ts +2 -0
- package/dist/commands/discover.js +46 -0
- package/dist/commands/discover.js.map +1 -0
- package/dist/commands/doctor.d.ts +8 -0
- package/dist/commands/doctor.js +78 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/investigate.d.ts +2 -0
- package/dist/commands/investigate.js +43 -0
- package/dist/commands/investigate.js.map +1 -0
- package/dist/commands/options.d.ts +38 -0
- package/dist/commands/options.js +35 -0
- package/dist/commands/options.js.map +1 -0
- package/dist/commands/prove.d.ts +2 -0
- package/dist/commands/prove.js +21 -0
- package/dist/commands/prove.js.map +1 -0
- package/dist/commands/repair.d.ts +2 -0
- package/dist/commands/repair.js +55 -0
- package/dist/commands/repair.js.map +1 -0
- package/dist/commands/replay.d.ts +2 -0
- package/dist/commands/replay.js +26 -0
- package/dist/commands/replay.js.map +1 -0
- package/dist/commands/report.d.ts +2 -0
- package/dist/commands/report.js +79 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/commands/scan.d.ts +12 -0
- package/dist/commands/scan.js +86 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/core/plan.d.ts +3 -0
- package/dist/core/plan.js +17 -0
- package/dist/core/plan.js.map +1 -0
- package/dist/discovery/evaluate.d.ts +22 -0
- package/dist/discovery/evaluate.js +81 -0
- package/dist/discovery/evaluate.js.map +1 -0
- package/dist/discovery/minimize.d.ts +24 -0
- package/dist/discovery/minimize.js +73 -0
- package/dist/discovery/minimize.js.map +1 -0
- package/dist/domain/schema.d.ts +155 -0
- package/dist/domain/schema.js +67 -0
- package/dist/domain/schema.js.map +1 -0
- package/dist/faults/install.d.ts +4 -0
- package/dist/faults/install.js +9 -0
- package/dist/faults/install.js.map +1 -0
- package/dist/faults/network-delay.d.ts +5 -0
- package/dist/faults/network-delay.js +34 -0
- package/dist/faults/network-delay.js.map +1 -0
- package/dist/faults/request-failure.d.ts +5 -0
- package/dist/faults/request-failure.js +24 -0
- package/dist/faults/request-failure.js.map +1 -0
- package/dist/investigator/agent.d.ts +26 -0
- package/dist/investigator/agent.js +197 -0
- package/dist/investigator/agent.js.map +1 -0
- package/dist/investigator/budget.d.ts +14 -0
- package/dist/investigator/budget.js +39 -0
- package/dist/investigator/budget.js.map +1 -0
- package/dist/investigator/file.d.ts +2 -0
- package/dist/investigator/file.js +7 -0
- package/dist/investigator/file.js.map +1 -0
- package/dist/investigator/groq.d.ts +5 -0
- package/dist/investigator/groq.js +26 -0
- package/dist/investigator/groq.js.map +1 -0
- package/dist/investigator/ledger.d.ts +17 -0
- package/dist/investigator/ledger.js +121 -0
- package/dist/investigator/ledger.js.map +1 -0
- package/dist/investigator/safe-source.d.ts +6 -0
- package/dist/investigator/safe-source.js +79 -0
- package/dist/investigator/safe-source.js.map +1 -0
- package/dist/investigator/schema.d.ts +110 -0
- package/dist/investigator/schema.js +53 -0
- package/dist/investigator/schema.js.map +1 -0
- package/dist/playwright.d.ts +3 -0
- package/dist/playwright.js +21 -0
- package/dist/playwright.js.map +1 -0
- package/dist/providers/errors.d.ts +21 -0
- package/dist/providers/errors.js +159 -0
- package/dist/providers/errors.js.map +1 -0
- package/dist/repair/file.d.ts +2 -0
- package/dist/repair/file.js +6 -0
- package/dist/repair/file.js.map +1 -0
- package/dist/repair/generator.d.ts +12 -0
- package/dist/repair/generator.js +74 -0
- package/dist/repair/generator.js.map +1 -0
- package/dist/repair/policy.d.ts +2 -0
- package/dist/repair/policy.js +70 -0
- package/dist/repair/policy.js.map +1 -0
- package/dist/repair/remote-proof-runner.d.ts +1 -0
- package/dist/repair/remote-proof-runner.js +53 -0
- package/dist/repair/remote-proof-runner.js.map +1 -0
- package/dist/repair/schema.d.ts +78 -0
- package/dist/repair/schema.js +44 -0
- package/dist/repair/schema.js.map +1 -0
- package/dist/repair/solari-validator.d.ts +25 -0
- package/dist/repair/solari-validator.js +231 -0
- package/dist/repair/solari-validator.js.map +1 -0
- package/dist/repair/validator.d.ts +16 -0
- package/dist/repair/validator.js +81 -0
- package/dist/repair/validator.js.map +1 -0
- package/dist/repair/workspace.d.ts +7 -0
- package/dist/repair/workspace.js +40 -0
- package/dist/repair/workspace.js.map +1 -0
- package/dist/report/browser-entry.d.ts +2 -0
- package/dist/report/browser-entry.js +15 -0
- package/dist/report/browser-entry.js.map +1 -0
- package/dist/report/bundle.d.ts +2 -0
- package/dist/report/bundle.js +77 -0
- package/dist/report/bundle.js.map +1 -0
- package/dist/report/classification.d.ts +9 -0
- package/dist/report/classification.js +55 -0
- package/dist/report/classification.js.map +1 -0
- package/dist/report/components/artifacts.d.ts +4 -0
- package/dist/report/components/artifacts.js +6 -0
- package/dist/report/components/artifacts.js.map +1 -0
- package/dist/report/components/experiments.d.ts +4 -0
- package/dist/report/components/experiments.js +7 -0
- package/dist/report/components/experiments.js.map +1 -0
- package/dist/report/components/hypotheses.d.ts +4 -0
- package/dist/report/components/hypotheses.js +26 -0
- package/dist/report/components/hypotheses.js.map +1 -0
- package/dist/report/components/indicators.d.ts +32 -0
- package/dist/report/components/indicators.js +42 -0
- package/dist/report/components/indicators.js.map +1 -0
- package/dist/report/components/layout.d.ts +29 -0
- package/dist/report/components/layout.js +20 -0
- package/dist/report/components/layout.js.map +1 -0
- package/dist/report/components/proof.d.ts +4 -0
- package/dist/report/components/proof.js +34 -0
- package/dist/report/components/proof.js.map +1 -0
- package/dist/report/components/reproduction.d.ts +4 -0
- package/dist/report/components/reproduction.js +19 -0
- package/dist/report/components/reproduction.js.map +1 -0
- package/dist/report/components/summary.d.ts +4 -0
- package/dist/report/components/summary.js +12 -0
- package/dist/report/components/summary.js.map +1 -0
- package/dist/report/components/verdict.d.ts +4 -0
- package/dist/report/components/verdict.js +27 -0
- package/dist/report/components/verdict.js.map +1 -0
- package/dist/report/model.d.ts +19 -0
- package/dist/report/model.js +82 -0
- package/dist/report/model.js.map +1 -0
- package/dist/report/open.d.ts +1 -0
- package/dist/report/open.js +24 -0
- package/dist/report/open.js.map +1 -0
- package/dist/report/publish.d.ts +12 -0
- package/dist/report/publish.js +67 -0
- package/dist/report/publish.js.map +1 -0
- package/dist/report/redaction.d.ts +1 -0
- package/dist/report/redaction.js +58 -0
- package/dist/report/redaction.js.map +1 -0
- package/dist/report/report-app.d.ts +6 -0
- package/dist/report/report-app.js +16 -0
- package/dist/report/report-app.js.map +1 -0
- package/dist/report/report-details.css +182 -0
- package/dist/report/report.css +404 -0
- package/dist/report/schema.d.ts +101 -0
- package/dist/report/schema.js +71 -0
- package/dist/report/schema.js.map +1 -0
- package/dist/reproducer/file.d.ts +3 -0
- package/dist/reproducer/file.js +14 -0
- package/dist/reproducer/file.js.map +1 -0
- package/dist/reproducer/schema.d.ts +17 -0
- package/dist/reproducer/schema.js +14 -0
- package/dist/reproducer/schema.js.map +1 -0
- package/dist/runner/local.d.ts +12 -0
- package/dist/runner/local.js +72 -0
- package/dist/runner/local.js.map +1 -0
- package/dist/runner/playwright-executor.d.ts +10 -0
- package/dist/runner/playwright-executor.js +148 -0
- package/dist/runner/playwright-executor.js.map +1 -0
- package/dist/security/credentials.d.ts +23 -0
- package/dist/security/credentials.js +105 -0
- package/dist/security/credentials.js.map +1 -0
- package/dist/solari/checkout-fixture.d.ts +3 -0
- package/dist/solari/checkout-fixture.js +54 -0
- package/dist/solari/checkout-fixture.js.map +1 -0
- package/dist/solari/executor.d.ts +17 -0
- package/dist/solari/executor.js +280 -0
- package/dist/solari/executor.js.map +1 -0
- package/dist/solari/retry.d.ts +7 -0
- package/dist/solari/retry.js +50 -0
- package/dist/solari/retry.js.map +1 -0
- package/dist/solari/run-demo.d.ts +21 -0
- package/dist/solari/run-demo.js +64 -0
- package/dist/solari/run-demo.js.map +1 -0
- package/dist/solari/transport.d.ts +1 -0
- package/dist/solari/transport.js +21 -0
- package/dist/solari/transport.js.map +1 -0
- package/dist/solari/usage.d.ts +23 -0
- package/dist/solari/usage.js +53 -0
- package/dist/solari/usage.js.map +1 -0
- package/dist/solari/websocket-proxy.d.ts +7 -0
- package/dist/solari/websocket-proxy.js +131 -0
- package/dist/solari/websocket-proxy.js.map +1 -0
- package/dist/ui/progress.d.ts +5 -0
- package/dist/ui/progress.js +16 -0
- package/dist/ui/progress.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { generateText, Output } from "ai";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { evaluateExperiment } from "../discovery/evaluate.js";
|
|
4
|
+
import { InvestigationBudget } from "./budget.js";
|
|
5
|
+
import { InvestigationLedger } from "./ledger.js";
|
|
6
|
+
import { readSafeTestContext } from "./safe-source.js";
|
|
7
|
+
import { experimentConditionSchema } from "./schema.js";
|
|
8
|
+
const plannedHypothesisSchema = z.object({
|
|
9
|
+
statement: z.string().min(8).max(500),
|
|
10
|
+
prediction: z.string().min(8).max(500),
|
|
11
|
+
});
|
|
12
|
+
const investigationPlanSchema = z.object({
|
|
13
|
+
hypotheses: z.array(plannedHypothesisSchema).min(2).max(3),
|
|
14
|
+
experiments: z.array(z.object({
|
|
15
|
+
hypothesisIndex: z.number().int().nonnegative(),
|
|
16
|
+
condition: experimentConditionSchema,
|
|
17
|
+
})).length(3),
|
|
18
|
+
});
|
|
19
|
+
const assessmentItemSchema = z.object({
|
|
20
|
+
hypothesisId: z.string().regex(/^H\d+$/u),
|
|
21
|
+
status: z.enum(["rejected", "confirmed"]),
|
|
22
|
+
evidenceExperimentIds: z.array(z.string().regex(/^E\d+$/u)).min(1),
|
|
23
|
+
explanation: z.string().min(8).max(1_000),
|
|
24
|
+
});
|
|
25
|
+
const assessmentSchema = z.object({
|
|
26
|
+
assessments: z.array(assessmentItemSchema).min(2).max(3),
|
|
27
|
+
conclusionHypothesisId: z.string().regex(/^H\d+$/u),
|
|
28
|
+
conclusion: z.string().min(30).max(2_000),
|
|
29
|
+
conclusionEvidenceIds: z.array(z.string().regex(/^E\d+$/u)).min(1),
|
|
30
|
+
});
|
|
31
|
+
function conditionToFault(condition, pattern) {
|
|
32
|
+
if (condition.kind === "network-delay") {
|
|
33
|
+
return { ...condition, pattern };
|
|
34
|
+
}
|
|
35
|
+
if (condition.kind === "request-failure") {
|
|
36
|
+
return { ...condition, pattern };
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
function estimatedCost(inputTokens, outputTokens, options) {
|
|
41
|
+
return (inputTokens * options.inputUsdPerMillion
|
|
42
|
+
+ outputTokens * options.outputUsdPerMillion) / 1_000_000;
|
|
43
|
+
}
|
|
44
|
+
function planningPrompt(test, sources, maximumDelayMs) {
|
|
45
|
+
return [
|
|
46
|
+
"You are planning a causal investigation of a flaky Playwright test.",
|
|
47
|
+
"Propose two or three competing, falsifiable hypotheses and exactly three experiments.",
|
|
48
|
+
"The experiment batch must contain a clean baseline, a network-delay condition, and a",
|
|
49
|
+
"request-failure condition. Associate each experiment with the hypothesis it tests by",
|
|
50
|
+
`zero-based hypothesisIndex. Network delay cannot exceed ${maximumDelayMs} ms.`,
|
|
51
|
+
"Do not propose fixes or infer results before experiments run.",
|
|
52
|
+
`Test path: ${test}`,
|
|
53
|
+
"Bounded local source context:",
|
|
54
|
+
...sources.flatMap((source) => [`--- ${source.path}`, source.content]),
|
|
55
|
+
].join("\n");
|
|
56
|
+
}
|
|
57
|
+
function assessmentPrompt(ledgerState) {
|
|
58
|
+
return [
|
|
59
|
+
"Assess this completed causal investigation using only the supplied evidence.",
|
|
60
|
+
"Return one assessment for every hypothesis. Confirm exactly one hypothesis and reject",
|
|
61
|
+
"at least one alternative. Confirmation requires a controlled fault that materially and",
|
|
62
|
+
"confidently increased failure rate above baseline. The conclusion must describe the",
|
|
63
|
+
"confirmed causal mechanism and cite only experiment IDs associated with that hypothesis.",
|
|
64
|
+
"Every rejected hypothesis must cite its own experiment where result.confirmed is false;",
|
|
65
|
+
"never use a confirmed experiment as the sole evidence for rejection.",
|
|
66
|
+
JSON.stringify(ledgerState, null, 2),
|
|
67
|
+
].join("\n");
|
|
68
|
+
}
|
|
69
|
+
function assessmentRepairPrompt(ledgerState, previous, validationError) {
|
|
70
|
+
return [
|
|
71
|
+
assessmentPrompt(ledgerState),
|
|
72
|
+
"Your previous assessment was rejected by the deterministic evidence validator.",
|
|
73
|
+
`Validation error: ${validationError}`,
|
|
74
|
+
"Previous invalid assessment:",
|
|
75
|
+
JSON.stringify(previous, null, 2),
|
|
76
|
+
"Return one corrected assessment. Do not change or invent experiment results.",
|
|
77
|
+
].join("\n");
|
|
78
|
+
}
|
|
79
|
+
function createLedgerState(plan, results) {
|
|
80
|
+
const ledger = new InvestigationLedger();
|
|
81
|
+
const hypotheses = plan.hypotheses.map((hypothesis) => ledger.propose(hypothesis.statement, hypothesis.prediction));
|
|
82
|
+
const evidence = results.map((result, index) => {
|
|
83
|
+
const experiment = plan.experiments[index];
|
|
84
|
+
const hypothesis = hypotheses[experiment.hypothesisIndex];
|
|
85
|
+
return ledger.addExperiment(hypothesis.id, experiment.condition, result);
|
|
86
|
+
});
|
|
87
|
+
return { evidence, hypotheses, ledger };
|
|
88
|
+
}
|
|
89
|
+
function applyAssessment(state, assessment) {
|
|
90
|
+
const assessedIds = new Set(assessment.assessments.map((item) => item.hypothesisId));
|
|
91
|
+
if (assessedIds.size !== state.hypotheses.length) {
|
|
92
|
+
throw new Error("Investigator must assess every proposed hypothesis exactly once");
|
|
93
|
+
}
|
|
94
|
+
for (const item of assessment.assessments) {
|
|
95
|
+
state.ledger.assess(item.hypothesisId, item.status, item.evidenceExperimentIds, item.explanation);
|
|
96
|
+
}
|
|
97
|
+
state.ledger.conclude(assessment.conclusionHypothesisId, assessment.conclusion, assessment.conclusionEvidenceIds);
|
|
98
|
+
}
|
|
99
|
+
function validatePlan(plan, options) {
|
|
100
|
+
if (plan.experiments.length > options.maxExperiments) {
|
|
101
|
+
throw new Error("Model proposed more experiments than the configured budget");
|
|
102
|
+
}
|
|
103
|
+
if (plan.experiments.some((entry) => entry.hypothesisIndex >= plan.hypotheses.length)) {
|
|
104
|
+
throw new Error("Model proposed an experiment for a missing hypothesis");
|
|
105
|
+
}
|
|
106
|
+
const coveredHypotheses = new Set(plan.experiments.map((entry) => entry.hypothesisIndex));
|
|
107
|
+
if (plan.hypotheses.some((_hypothesis, index) => !coveredHypotheses.has(index))) {
|
|
108
|
+
throw new Error("Every proposed hypothesis must receive an experiment");
|
|
109
|
+
}
|
|
110
|
+
if (plan.experiments.some((entry) => entry.condition.kind === "network-delay"
|
|
111
|
+
&& entry.condition.delayMs > options.maximumDelayMs)) {
|
|
112
|
+
throw new Error("Model proposed a network delay above the configured maximum");
|
|
113
|
+
}
|
|
114
|
+
const kinds = new Set(plan.experiments.map((entry) => entry.condition.kind));
|
|
115
|
+
const requiredKinds = ["baseline", "network-delay", "request-failure"];
|
|
116
|
+
if (!requiredKinds.every((kind) => kinds.has(kind))) {
|
|
117
|
+
throw new Error("Investigation plan must distinguish baseline, timing, and request failure");
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export async function runInvestigation(options) {
|
|
121
|
+
if (options.maxSteps < 2) {
|
|
122
|
+
throw new Error("Investigation requires a budget of two model steps");
|
|
123
|
+
}
|
|
124
|
+
const budget = new InvestigationBudget(options);
|
|
125
|
+
const timeoutSignal = AbortSignal.timeout(options.maxSeconds * 1_000);
|
|
126
|
+
const signal = options.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;
|
|
127
|
+
const sources = await readSafeTestContext(options.projectRoot, options.test);
|
|
128
|
+
const planResult = await generateText({
|
|
129
|
+
model: options.model,
|
|
130
|
+
output: Output.object({ schema: investigationPlanSchema }),
|
|
131
|
+
prompt: planningPrompt(options.test, sources, options.maximumDelayMs),
|
|
132
|
+
maxOutputTokens: options.outputTokenLimit,
|
|
133
|
+
maxRetries: 2,
|
|
134
|
+
timeout: { totalMs: budget.remainingMs() },
|
|
135
|
+
abortSignal: signal,
|
|
136
|
+
temperature: 0.2,
|
|
137
|
+
});
|
|
138
|
+
const plan = planResult.output;
|
|
139
|
+
validatePlan(plan, options);
|
|
140
|
+
plan.experiments.forEach(() => {
|
|
141
|
+
budget.reserveExperiment(options.trialsPerExperiment);
|
|
142
|
+
});
|
|
143
|
+
const results = await Promise.all(plan.experiments.map(async (experiment) => evaluateExperiment(options.execute, {
|
|
144
|
+
concurrency: options.concurrency,
|
|
145
|
+
fault: conditionToFault(experiment.condition, options.pattern),
|
|
146
|
+
minimumFailureRate: options.minimumFailureRate,
|
|
147
|
+
seed: options.seed,
|
|
148
|
+
signal,
|
|
149
|
+
trials: options.trialsPerExperiment,
|
|
150
|
+
})));
|
|
151
|
+
let state = createLedgerState(plan, results);
|
|
152
|
+
const assessmentResult = await generateText({
|
|
153
|
+
model: options.model,
|
|
154
|
+
output: Output.object({ schema: assessmentSchema }),
|
|
155
|
+
prompt: assessmentPrompt({ hypotheses: state.hypotheses, experiments: state.evidence }),
|
|
156
|
+
maxOutputTokens: options.outputTokenLimit,
|
|
157
|
+
maxRetries: 2,
|
|
158
|
+
timeout: { totalMs: budget.remainingMs() },
|
|
159
|
+
abortSignal: signal,
|
|
160
|
+
temperature: 0.2,
|
|
161
|
+
});
|
|
162
|
+
const assessmentResults = [assessmentResult];
|
|
163
|
+
try {
|
|
164
|
+
applyAssessment(state, assessmentResult.output);
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
if (options.maxSteps < 3) {
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
const validationError = error instanceof Error ? error.message : "invalid evidence assessment";
|
|
171
|
+
const repairResult = await generateText({
|
|
172
|
+
model: options.model,
|
|
173
|
+
output: Output.object({ schema: assessmentSchema }),
|
|
174
|
+
prompt: assessmentRepairPrompt({ hypotheses: state.hypotheses, experiments: state.evidence }, assessmentResult.output, validationError),
|
|
175
|
+
maxOutputTokens: options.outputTokenLimit,
|
|
176
|
+
maxRetries: 1,
|
|
177
|
+
timeout: { totalMs: budget.remainingMs() },
|
|
178
|
+
abortSignal: signal,
|
|
179
|
+
temperature: 0,
|
|
180
|
+
});
|
|
181
|
+
assessmentResults.push(repairResult);
|
|
182
|
+
state = createLedgerState(plan, results);
|
|
183
|
+
applyAssessment(state, repairResult.output);
|
|
184
|
+
}
|
|
185
|
+
const inputTokens = (planResult.usage.inputTokens ?? 0) + assessmentResults.reduce((total, result) => total + (result.usage.inputTokens ?? 0), 0);
|
|
186
|
+
const outputTokens = (planResult.usage.outputTokens ?? 0) + assessmentResults.reduce((total, result) => total + (result.usage.outputTokens ?? 0), 0);
|
|
187
|
+
const cost = estimatedCost(inputTokens, outputTokens, options);
|
|
188
|
+
if (cost > budget.maxCostUsd()) {
|
|
189
|
+
throw new Error(`Investigation cost $${cost.toFixed(4)} exceeded its configured budget`);
|
|
190
|
+
}
|
|
191
|
+
return state.ledger.buildReport(options.test, options.modelId, {
|
|
192
|
+
inputTokens,
|
|
193
|
+
outputTokens,
|
|
194
|
+
estimatedCostUsd: cost,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/investigator/agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface InvestigationBudgetOptions {
|
|
2
|
+
maxCostUsd: number;
|
|
3
|
+
maxExperiments: number;
|
|
4
|
+
maxSeconds: number;
|
|
5
|
+
maxTrials: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class InvestigationBudget {
|
|
8
|
+
#private;
|
|
9
|
+
constructor(options: InvestigationBudgetOptions);
|
|
10
|
+
reserveExperiment(trials: number): void;
|
|
11
|
+
assertTimeRemaining(): void;
|
|
12
|
+
remainingMs(): number;
|
|
13
|
+
maxCostUsd(): number;
|
|
14
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export class InvestigationBudget {
|
|
2
|
+
#deadline;
|
|
3
|
+
#options;
|
|
4
|
+
#experiments = 0;
|
|
5
|
+
#trials = 0;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
if (options.maxExperiments < 1 || options.maxTrials < 2 || options.maxSeconds < 1) {
|
|
8
|
+
throw new Error("Investigation budgets must be positive");
|
|
9
|
+
}
|
|
10
|
+
if (!Number.isFinite(options.maxCostUsd) || options.maxCostUsd <= 0) {
|
|
11
|
+
throw new Error("Investigation cost budget must be greater than zero");
|
|
12
|
+
}
|
|
13
|
+
this.#options = options;
|
|
14
|
+
this.#deadline = Date.now() + options.maxSeconds * 1_000;
|
|
15
|
+
}
|
|
16
|
+
reserveExperiment(trials) {
|
|
17
|
+
this.assertTimeRemaining();
|
|
18
|
+
if (this.#experiments + 1 > this.#options.maxExperiments) {
|
|
19
|
+
throw new Error("Investigation experiment budget exhausted");
|
|
20
|
+
}
|
|
21
|
+
if (this.#trials + trials > this.#options.maxTrials) {
|
|
22
|
+
throw new Error("Investigation trial budget exhausted");
|
|
23
|
+
}
|
|
24
|
+
this.#experiments += 1;
|
|
25
|
+
this.#trials += trials;
|
|
26
|
+
}
|
|
27
|
+
assertTimeRemaining() {
|
|
28
|
+
if (Date.now() >= this.#deadline) {
|
|
29
|
+
throw new Error("Investigation time budget exhausted");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
remainingMs() {
|
|
33
|
+
return Math.max(1, this.#deadline - Date.now());
|
|
34
|
+
}
|
|
35
|
+
maxCostUsd() {
|
|
36
|
+
return this.#options.maxCostUsd;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=budget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget.js","sourceRoot":"","sources":["../../src/investigator/budget.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,mBAAmB;IACrB,SAAS,CAAQ;IACjB,QAAQ,CAA4B;IAC7C,YAAY,GAAG,CAAC,CAAA;IAChB,OAAO,GAAG,CAAC,CAAA;IAEX,YAAY,OAAmC;QAC7C,IAAI,OAAO,CAAC,cAAc,GAAG,CAAC,IAAI,OAAO,CAAC,SAAS,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;YAClF,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;QAC3D,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC;YACpE,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAA;QACxE,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAA;QACvB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,UAAU,GAAG,KAAK,CAAA;IAC1D,CAAC;IAED,iBAAiB,CAAC,MAAc;QAC9B,IAAI,CAAC,mBAAmB,EAAE,CAAA;QAC1B,IAAI,IAAI,CAAC,YAAY,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC;YACzD,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;QAC9D,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAA;QACzD,CAAC;QACD,IAAI,CAAC,YAAY,IAAI,CAAC,CAAA;QACtB,IAAI,CAAC,OAAO,IAAI,MAAM,CAAA;IACxB,CAAC;IAED,mBAAmB;QACjB,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;QACxD,CAAC;IACH,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;IACjD,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAA;IACjC,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { investigationReportSchema } from "./schema.js";
|
|
3
|
+
export async function readInvestigationReport(filePath) {
|
|
4
|
+
const contents = await readFile(filePath, "utf8");
|
|
5
|
+
return investigationReportSchema.parse(JSON.parse(contents));
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../src/investigator/file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAG3C,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAEvD,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,QAAgB;IAC5D,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IACjD,OAAO,yBAAyB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;AAC9D,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { LanguageModel } from "ai";
|
|
2
|
+
export declare const DEFAULT_GROQ_MODEL = "qwen/qwen3.8-27b";
|
|
3
|
+
export declare const QWEN_INPUT_USD_PER_MILLION = 0.8;
|
|
4
|
+
export declare const QWEN_OUTPUT_USD_PER_MILLION = 4;
|
|
5
|
+
export declare function createGroqInvestigatorModel(apiKey: string, modelId: string): LanguageModel;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createGroq } from "@ai-sdk/groq";
|
|
2
|
+
import { defaultSettingsMiddleware, wrapLanguageModel } from "ai";
|
|
3
|
+
export const DEFAULT_GROQ_MODEL = "qwen/qwen3.8-27b";
|
|
4
|
+
export const QWEN_INPUT_USD_PER_MILLION = 0.8;
|
|
5
|
+
export const QWEN_OUTPUT_USD_PER_MILLION = 4;
|
|
6
|
+
export function createGroqInvestigatorModel(apiKey, modelId) {
|
|
7
|
+
if (!apiKey.trim()) {
|
|
8
|
+
throw new Error("GROQ_API_KEY is required for AI investigation");
|
|
9
|
+
}
|
|
10
|
+
const provider = createGroq({ apiKey });
|
|
11
|
+
return wrapLanguageModel({
|
|
12
|
+
model: provider(modelId),
|
|
13
|
+
middleware: defaultSettingsMiddleware({
|
|
14
|
+
settings: {
|
|
15
|
+
providerOptions: {
|
|
16
|
+
groq: {
|
|
17
|
+
parallelToolCalls: false,
|
|
18
|
+
reasoningEffort: "low",
|
|
19
|
+
reasoningFormat: "hidden",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
}),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=groq.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"groq.js","sourceRoot":"","sources":["../../src/investigator/groq.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAGzC,OAAO,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,IAAI,CAAA;AAEjE,MAAM,CAAC,MAAM,kBAAkB,GAAG,kBAAkB,CAAA;AACpD,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,CAAA;AAC7C,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAA;AAE5C,MAAM,UAAU,2BAA2B,CAAC,MAAc,EAAE,OAAe;IACzE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IACD,MAAM,QAAQ,GAAG,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;IACvC,OAAO,iBAAiB,CAAC;QACvB,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC;QACxB,UAAU,EAAE,yBAAyB,CAAC;YACpC,QAAQ,EAAE;gBACR,eAAe,EAAE;oBACf,IAAI,EAAE;wBACJ,iBAAiB,EAAE,KAAK;wBACxB,eAAe,EAAE,KAAK;wBACtB,eAAe,EAAE,QAAQ;qBACS;iBACrC;aACF;SACF,CAAC;KACH,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ExperimentResult } from "../discovery/evaluate.js";
|
|
2
|
+
import type { ExperimentCondition, ExperimentEvidence, Hypothesis, InvestigationReport } from "./schema.js";
|
|
3
|
+
interface UsageSummary {
|
|
4
|
+
estimatedCostUsd: number;
|
|
5
|
+
inputTokens: number;
|
|
6
|
+
outputTokens: number;
|
|
7
|
+
}
|
|
8
|
+
export declare class InvestigationLedger {
|
|
9
|
+
#private;
|
|
10
|
+
propose(statement: string, prediction: string): Hypothesis;
|
|
11
|
+
getHypothesis(id: string): Hypothesis;
|
|
12
|
+
addExperiment(hypothesisId: string, condition: ExperimentCondition, result: ExperimentResult): ExperimentEvidence;
|
|
13
|
+
assess(hypothesisId: string, status: "rejected" | "confirmed", evidenceExperimentIds: string[], explanation: string): Hypothesis;
|
|
14
|
+
conclude(hypothesisId: string, summary: string, evidenceExperimentIds: string[]): void;
|
|
15
|
+
buildReport(test: string, model: string, usage: UsageSummary): InvestigationReport;
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { investigationReportSchema } from "./schema.js";
|
|
2
|
+
export class InvestigationLedger {
|
|
3
|
+
#experiments = [];
|
|
4
|
+
#hypotheses = [];
|
|
5
|
+
#conclusion;
|
|
6
|
+
#conclusionEvidenceIds = [];
|
|
7
|
+
#conclusionHypothesisId;
|
|
8
|
+
propose(statement, prediction) {
|
|
9
|
+
const hypothesis = {
|
|
10
|
+
id: `H${this.#hypotheses.length + 1}`,
|
|
11
|
+
statement,
|
|
12
|
+
prediction,
|
|
13
|
+
status: "proposed",
|
|
14
|
+
evidenceExperimentIds: [],
|
|
15
|
+
explanation: "",
|
|
16
|
+
};
|
|
17
|
+
this.#hypotheses.push(hypothesis);
|
|
18
|
+
return hypothesis;
|
|
19
|
+
}
|
|
20
|
+
getHypothesis(id) {
|
|
21
|
+
const hypothesis = this.#hypotheses.find((candidate) => candidate.id === id);
|
|
22
|
+
if (!hypothesis) {
|
|
23
|
+
throw new Error(`Hypothesis ${id} does not exist`);
|
|
24
|
+
}
|
|
25
|
+
return hypothesis;
|
|
26
|
+
}
|
|
27
|
+
addExperiment(hypothesisId, condition, result) {
|
|
28
|
+
this.getHypothesis(hypothesisId);
|
|
29
|
+
const evidence = {
|
|
30
|
+
id: `E${this.#experiments.length + 1}`,
|
|
31
|
+
hypothesisId,
|
|
32
|
+
condition,
|
|
33
|
+
result,
|
|
34
|
+
};
|
|
35
|
+
this.#experiments.push(evidence);
|
|
36
|
+
return evidence;
|
|
37
|
+
}
|
|
38
|
+
assess(hypothesisId, status, evidenceExperimentIds, explanation) {
|
|
39
|
+
const hypothesis = this.getHypothesis(hypothesisId);
|
|
40
|
+
const evidence = this.#resolveEvidence(hypothesisId, evidenceExperimentIds);
|
|
41
|
+
if (status === "confirmed" && !this.#hasCausalIntervention(evidence)) {
|
|
42
|
+
throw new Error("Confirmation requires a fault that increased and confidently reproduced failure");
|
|
43
|
+
}
|
|
44
|
+
if (status === "rejected" && evidence.every((entry) => entry.result.confirmed)) {
|
|
45
|
+
throw new Error("Rejection requires at least one experiment that did not confirm the prediction");
|
|
46
|
+
}
|
|
47
|
+
hypothesis.status = status;
|
|
48
|
+
hypothesis.evidenceExperimentIds = evidenceExperimentIds;
|
|
49
|
+
hypothesis.explanation = explanation;
|
|
50
|
+
return hypothesis;
|
|
51
|
+
}
|
|
52
|
+
conclude(hypothesisId, summary, evidenceExperimentIds) {
|
|
53
|
+
const hypothesis = this.getHypothesis(hypothesisId);
|
|
54
|
+
if (hypothesis.status !== "confirmed") {
|
|
55
|
+
throw new Error("Conclusion must identify the confirmed hypothesis");
|
|
56
|
+
}
|
|
57
|
+
const evidence = this.#resolveEvidence(hypothesisId, evidenceExperimentIds);
|
|
58
|
+
if (!evidence.some((entry) => entry.result.confirmed && entry.condition.kind !== "baseline")) {
|
|
59
|
+
throw new Error("Conclusion must cite a confirmed intervention experiment");
|
|
60
|
+
}
|
|
61
|
+
if (!this.#describesHypothesis(summary, hypothesis.statement)) {
|
|
62
|
+
throw new Error("Conclusion must describe the confirmed causal hypothesis");
|
|
63
|
+
}
|
|
64
|
+
this.#conclusion = summary;
|
|
65
|
+
this.#conclusionEvidenceIds = evidenceExperimentIds;
|
|
66
|
+
this.#conclusionHypothesisId = hypothesisId;
|
|
67
|
+
}
|
|
68
|
+
buildReport(test, model, usage) {
|
|
69
|
+
if (!this.#conclusion) {
|
|
70
|
+
throw new Error("Investigator did not record a conclusion");
|
|
71
|
+
}
|
|
72
|
+
if (this.#hypotheses.length < 2) {
|
|
73
|
+
throw new Error("Investigator must consider at least two competing hypotheses");
|
|
74
|
+
}
|
|
75
|
+
const confirmed = this.#hypotheses.filter((hypothesis) => hypothesis.status === "confirmed");
|
|
76
|
+
if (confirmed.length !== 1 || confirmed[0]?.id !== this.#conclusionHypothesisId) {
|
|
77
|
+
throw new Error("Investigator must conclude with exactly one confirmed hypothesis");
|
|
78
|
+
}
|
|
79
|
+
if (!this.#hypotheses.some((hypothesis) => hypothesis.status === "rejected")) {
|
|
80
|
+
throw new Error("Investigator did not reject a competing hypothesis");
|
|
81
|
+
}
|
|
82
|
+
return investigationReportSchema.parse({
|
|
83
|
+
version: 1,
|
|
84
|
+
test,
|
|
85
|
+
model,
|
|
86
|
+
conclusion: this.#conclusion,
|
|
87
|
+
conclusionHypothesisId: this.#conclusionHypothesisId,
|
|
88
|
+
conclusionEvidenceIds: this.#conclusionEvidenceIds,
|
|
89
|
+
hypotheses: this.#hypotheses,
|
|
90
|
+
experiments: this.#experiments,
|
|
91
|
+
usage,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
#resolveEvidence(hypothesisId, ids) {
|
|
95
|
+
if (ids.length === 0) {
|
|
96
|
+
throw new Error("At least one experiment ID is required");
|
|
97
|
+
}
|
|
98
|
+
return ids.map((id) => {
|
|
99
|
+
const evidence = this.#experiments.find((candidate) => candidate.id === id);
|
|
100
|
+
if (!evidence || (hypothesisId && evidence.hypothesisId !== hypothesisId)) {
|
|
101
|
+
throw new Error(`Experiment ${id} is not valid evidence for this assessment`);
|
|
102
|
+
}
|
|
103
|
+
return evidence;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
#hasCausalIntervention(evidence) {
|
|
107
|
+
const baselineRate = Math.min(...this.#experiments
|
|
108
|
+
.filter((entry) => entry.condition.kind === "baseline")
|
|
109
|
+
.map((entry) => entry.result.failureRate));
|
|
110
|
+
return evidence.some((entry) => entry.condition.kind !== "baseline"
|
|
111
|
+
&& entry.result.confirmed
|
|
112
|
+
&& entry.result.failureRate > baselineRate);
|
|
113
|
+
}
|
|
114
|
+
#describesHypothesis(summary, statement) {
|
|
115
|
+
const words = (value) => new Set(value.toLowerCase().split(/[^a-z0-9]+/u).filter((word) => word.length >= 5));
|
|
116
|
+
const hypothesisWords = words(statement);
|
|
117
|
+
const sharedWords = [...words(summary)].filter((word) => hypothesisWords.has(word));
|
|
118
|
+
return summary.length >= 30 && sharedWords.length >= 2;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../src/investigator/ledger.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAQvD,MAAM,OAAO,mBAAmB;IACrB,YAAY,GAAyB,EAAE,CAAA;IACvC,WAAW,GAAiB,EAAE,CAAA;IACvC,WAAW,CAAoB;IAC/B,sBAAsB,GAAa,EAAE,CAAA;IACrC,uBAAuB,CAAoB;IAE3C,OAAO,CAAC,SAAiB,EAAE,UAAkB;QAC3C,MAAM,UAAU,GAAe;YAC7B,EAAE,EAAE,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE;YACrC,SAAS;YACT,UAAU;YACV,MAAM,EAAE,UAAU;YAClB,qBAAqB,EAAE,EAAE;YACzB,WAAW,EAAE,EAAE;SAChB,CAAA;QACD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QACjC,OAAO,UAAU,CAAA;IACnB,CAAC;IAED,aAAa,CAAC,EAAU;QACtB,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;QAC5E,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAA;QACpD,CAAC;QACD,OAAO,UAAU,CAAA;IACnB,CAAC;IAED,aAAa,CACX,YAAoB,EACpB,SAA8B,EAC9B,MAAwB;QAExB,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,CAAA;QAChC,MAAM,QAAQ,GAAuB;YACnC,EAAE,EAAE,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE;YACtC,YAAY;YACZ,SAAS;YACT,MAAM;SACP,CAAA;QACD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAChC,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,MAAM,CACJ,YAAoB,EACpB,MAAgC,EAChC,qBAA+B,EAC/B,WAAmB;QAEnB,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,CAAA;QACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,qBAAqB,CAAC,CAAA;QAC3E,IAAI,MAAM,KAAK,WAAW,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrE,MAAM,IAAI,KAAK,CAAC,iFAAiF,CAAC,CAAA;QACpG,CAAC;QACD,IAAI,MAAM,KAAK,UAAU,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/E,MAAM,IAAI,KAAK,CAAC,gFAAgF,CAAC,CAAA;QACnG,CAAC;QACD,UAAU,CAAC,MAAM,GAAG,MAAM,CAAA;QAC1B,UAAU,CAAC,qBAAqB,GAAG,qBAAqB,CAAA;QACxD,UAAU,CAAC,WAAW,GAAG,WAAW,CAAA;QACpC,OAAO,UAAU,CAAA;IACnB,CAAC;IAED,QAAQ,CAAC,YAAoB,EAAE,OAAe,EAAE,qBAA+B;QAC7E,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,CAAA;QACnD,IAAI,UAAU,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;QACtE,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,qBAAqB,CAAC,CAAA;QAC3E,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,UAAU,CAAC,EAAE,CAAC;YAC7F,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAA;QAC7E,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9D,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAA;QAC7E,CAAC;QACD,IAAI,CAAC,WAAW,GAAG,OAAO,CAAA;QAC1B,IAAI,CAAC,sBAAsB,GAAG,qBAAqB,CAAA;QACnD,IAAI,CAAC,uBAAuB,GAAG,YAAY,CAAA;IAC7C,CAAC;IAED,WAAW,CAAC,IAAY,EAAE,KAAa,EAAE,KAAmB;QAC1D,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;QAC7D,CAAC;QACD,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAA;QACjF,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,KAAK,WAAW,CAAC,CAAA;QAC5F,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC,uBAAuB,EAAE,CAAC;YAChF,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAA;QACrF,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC,EAAE,CAAC;YAC7E,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;QACvE,CAAC;QACD,OAAO,yBAAyB,CAAC,KAAK,CAAC;YACrC,OAAO,EAAE,CAAC;YACV,IAAI;YACJ,KAAK;YACL,UAAU,EAAE,IAAI,CAAC,WAAW;YAC5B,sBAAsB,EAAE,IAAI,CAAC,uBAAuB;YACpD,qBAAqB,EAAE,IAAI,CAAC,sBAAsB;YAClD,UAAU,EAAE,IAAI,CAAC,WAAW;YAC5B,WAAW,EAAE,IAAI,CAAC,YAAY;YAC9B,KAAK;SACN,CAAC,CAAA;IACJ,CAAC;IAED,gBAAgB,CACd,YAAgC,EAChC,GAAa;QAEb,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;QAC3D,CAAC;QACD,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;YACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;YAC3E,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAY,IAAI,QAAQ,CAAC,YAAY,KAAK,YAAY,CAAC,EAAE,CAAC;gBAC1E,MAAM,IAAI,KAAK,CAAC,cAAc,EAAE,4CAA4C,CAAC,CAAA;YAC/E,CAAC;YACD,OAAO,QAAQ,CAAA;QACjB,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,sBAAsB,CAAC,QAA8B;QACnD,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAC3B,GAAG,IAAI,CAAC,YAAY;aACjB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,UAAU,CAAC;aACtD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAC5C,CAAA;QACD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAC7B,KAAK,CAAC,SAAS,CAAC,IAAI,KAAK,UAAU;eAChC,KAAK,CAAC,MAAM,CAAC,SAAS;eACtB,KAAK,CAAC,MAAM,CAAC,WAAW,GAAG,YAAY,CAAC,CAAA;IAC/C,CAAC;IAED,oBAAoB,CAAC,OAAe,EAAE,SAAiB;QACrD,MAAM,KAAK,GAAG,CAAC,KAAa,EAAe,EAAE,CAAC,IAAI,GAAG,CACnD,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,CAC5E,CAAA;QACD,MAAM,eAAe,GAAG,KAAK,CAAC,SAAS,CAAC,CAAA;QACxC,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;QACnF,OAAO,OAAO,CAAC,MAAM,IAAI,EAAE,IAAI,WAAW,CAAC,MAAM,IAAI,CAAC,CAAA;IACxD,CAAC;CACF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface SafeSource {
|
|
2
|
+
content: string;
|
|
3
|
+
path: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function readSafeTestSource(projectRoot: string, selector: string): Promise<SafeSource>;
|
|
6
|
+
export declare function readSafeTestContext(projectRoot: string, selector: string): Promise<SafeSource[]>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { readFile, stat } from "node:fs/promises";
|
|
2
|
+
import { dirname, extname, relative, resolve } from "node:path";
|
|
3
|
+
const MAX_SOURCE_BYTES = 64 * 1_024;
|
|
4
|
+
const MAX_CONTEXT_FILES = 8;
|
|
5
|
+
const ALLOWED_EXTENSIONS = new Set([".js", ".jsx", ".mjs", ".ts", ".tsx"]);
|
|
6
|
+
const SECRET_ASSIGNMENT = /(?:api[_-]?key|authorization|password|secret|token)\s*[:=]\s*["'][^"']{8,}/iu;
|
|
7
|
+
const LOCAL_IMPORT = /\bfrom\s+["'](\.[^"']+)["']/gu;
|
|
8
|
+
function resolveSafeSource(projectRoot, selector) {
|
|
9
|
+
const sourcePath = resolve(projectRoot, selector);
|
|
10
|
+
const pathFromRoot = relative(projectRoot, sourcePath);
|
|
11
|
+
if (pathFromRoot.startsWith("..") || pathFromRoot.includes("node_modules")) {
|
|
12
|
+
throw new Error("Test source must stay inside the project and outside dependencies");
|
|
13
|
+
}
|
|
14
|
+
if (!ALLOWED_EXTENSIONS.has(extname(sourcePath).toLowerCase())) {
|
|
15
|
+
throw new Error("Only JavaScript or TypeScript test source can be inspected");
|
|
16
|
+
}
|
|
17
|
+
return sourcePath;
|
|
18
|
+
}
|
|
19
|
+
export async function readSafeTestSource(projectRoot, selector) {
|
|
20
|
+
const sourcePath = resolveSafeSource(projectRoot, selector);
|
|
21
|
+
const sourceStats = await stat(sourcePath);
|
|
22
|
+
if (!sourceStats.isFile() || sourceStats.size > MAX_SOURCE_BYTES) {
|
|
23
|
+
throw new Error("Test source must be a regular file no larger than 64 KiB");
|
|
24
|
+
}
|
|
25
|
+
const content = await readFile(sourcePath, "utf8");
|
|
26
|
+
if (SECRET_ASSIGNMENT.test(content)) {
|
|
27
|
+
throw new Error("Test source contains a possible credential and cannot be sent to a model");
|
|
28
|
+
}
|
|
29
|
+
return { content, path: relative(projectRoot, sourcePath) };
|
|
30
|
+
}
|
|
31
|
+
async function existingSourcePath(importer, specifier) {
|
|
32
|
+
const requested = resolve(dirname(importer), specifier);
|
|
33
|
+
const extension = extname(requested);
|
|
34
|
+
const base = extension ? requested.slice(0, -extension.length) : requested;
|
|
35
|
+
const candidates = extension === ".js"
|
|
36
|
+
? [`${base}.ts`, `${base}.tsx`, requested]
|
|
37
|
+
: [requested, `${requested}.ts`, `${requested}.tsx`, resolve(requested, "index.ts")];
|
|
38
|
+
for (const candidate of candidates) {
|
|
39
|
+
try {
|
|
40
|
+
if ((await stat(candidate)).isFile()) {
|
|
41
|
+
return candidate;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Missing candidates are expected while resolving TypeScript's emitted .js imports.
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
function localImports(content) {
|
|
51
|
+
return [...content.matchAll(LOCAL_IMPORT)].map((match) => match[1]);
|
|
52
|
+
}
|
|
53
|
+
export async function readSafeTestContext(projectRoot, selector) {
|
|
54
|
+
const rootPath = resolveSafeSource(projectRoot, selector);
|
|
55
|
+
const queue = [rootPath];
|
|
56
|
+
const visited = new Set();
|
|
57
|
+
const context = [];
|
|
58
|
+
while (queue.length > 0 && context.length < MAX_CONTEXT_FILES) {
|
|
59
|
+
const sourcePath = queue.shift();
|
|
60
|
+
if (!sourcePath || visited.has(sourcePath)) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
visited.add(sourcePath);
|
|
64
|
+
const source = await readSafeTestSource(projectRoot, sourcePath);
|
|
65
|
+
context.push(source);
|
|
66
|
+
for (const specifier of localImports(source.content)) {
|
|
67
|
+
const dependency = await existingSourcePath(sourcePath, specifier);
|
|
68
|
+
if (dependency && !visited.has(dependency)) {
|
|
69
|
+
queue.push(dependency);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const totalBytes = context.reduce((total, source) => total + Buffer.byteLength(source.content), 0);
|
|
74
|
+
if (totalBytes > MAX_SOURCE_BYTES) {
|
|
75
|
+
throw new Error("Local test context exceeds the 64 KiB model boundary");
|
|
76
|
+
}
|
|
77
|
+
return context;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=safe-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-source.js","sourceRoot":"","sources":["../../src/investigator/safe-source.ts"],"names":[],"mappings":"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"}
|