cairn-engine 1.2.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/adapters/critics/assertion.d.ts +8 -3
- package/dist/adapters/critics/assertion.js +19 -9
- package/dist/adapters/critics/assertion.js.map +1 -1
- package/dist/adapters/critics/llm.d.ts +1 -1
- package/dist/adapters/critics/llm.js +2 -2
- package/dist/adapters/critics/llm.js.map +1 -1
- package/dist/adapters/drivers/chrome.d.ts +5 -4
- package/dist/adapters/drivers/chrome.js +8 -4
- package/dist/adapters/drivers/chrome.js.map +1 -1
- package/dist/adapters/drivers/self-heal.d.ts +3 -2
- package/dist/adapters/drivers/self-heal.js +10 -7
- package/dist/adapters/drivers/self-heal.js.map +1 -1
- package/dist/adapters/llm/anthropic.js +4 -1
- package/dist/adapters/llm/anthropic.js.map +1 -1
- package/dist/adapters/skills/file-store.d.ts +7 -4
- package/dist/adapters/skills/file-store.js +27 -10
- package/dist/adapters/skills/file-store.js.map +1 -1
- package/dist/browser.d.ts +1 -0
- package/dist/browser.js +1 -0
- package/dist/browser.js.map +1 -1
- package/dist/cli.js +22 -12
- package/dist/cli.js.map +1 -1
- package/dist/core/discover.d.ts +18 -2
- package/dist/core/discover.js +191 -18
- package/dist/core/discover.js.map +1 -1
- package/dist/core/pipeline.d.ts +3 -1
- package/dist/core/pipeline.js +30 -2
- package/dist/core/pipeline.js.map +1 -1
- package/dist/core/ports.d.ts +10 -4
- package/dist/core/step-heal.d.ts +14 -0
- package/dist/core/step-heal.js +55 -0
- package/dist/core/step-heal.js.map +1 -0
- package/dist/core/steps.d.ts +11 -1
- package/dist/core/steps.js +4 -2
- package/dist/core/steps.js.map +1 -1
- package/dist/core/types.d.ts +14 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/run.d.ts +18 -5
- package/dist/run.js +62 -8
- package/dist/run.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { applyDecision, parseDecision, renderElements } from "./discover.js";
|
|
2
|
+
const MAX_STEP_HEALS = 5;
|
|
3
|
+
const STEP_HEAL_SYSTEM = "You repair ONE step of a browser QA scenario that ran but didn't reach its expected outcome. " +
|
|
4
|
+
"Given the step's goal and the current page elements, reply with the SINGLE next action that " +
|
|
5
|
+
'achieves the goal, as one JSON action object (same format as discovery: {"action":"click","text":"..."}). ' +
|
|
6
|
+
'If nothing on the page can achieve it, reply {"action":"done"}. JSON only, no prose.';
|
|
7
|
+
export class LlmStepHealer {
|
|
8
|
+
llm;
|
|
9
|
+
maxHeals;
|
|
10
|
+
heals = [];
|
|
11
|
+
constructor(llm, maxHeals = MAX_STEP_HEALS) {
|
|
12
|
+
this.llm = llm;
|
|
13
|
+
this.maxHeals = maxHeals;
|
|
14
|
+
}
|
|
15
|
+
async heal(step, index, driver) {
|
|
16
|
+
if (this.heals.length >= this.maxHeals)
|
|
17
|
+
return null;
|
|
18
|
+
const elements = await driver.snapshot();
|
|
19
|
+
let decision;
|
|
20
|
+
try {
|
|
21
|
+
const reply = await this.llm.complete(stepHealPrompt(step, elements), { system: STEP_HEAL_SYSTEM });
|
|
22
|
+
decision = parseDecision(reply);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
if (decision.action === "done")
|
|
28
|
+
return null;
|
|
29
|
+
let healed;
|
|
30
|
+
try {
|
|
31
|
+
healed = await applyDecision(driver, decision);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
// Keep the original intent + expect on the re-frozen step so it stays verifiable next replay.
|
|
37
|
+
healed.intent = step.intent;
|
|
38
|
+
healed.expect = step.expect;
|
|
39
|
+
const heal = { index, step: healed };
|
|
40
|
+
this.heals.push(heal);
|
|
41
|
+
return heal;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function stepHealPrompt(step, elements) {
|
|
45
|
+
return [
|
|
46
|
+
`Step goal: ${step.intent ?? step.kind}`,
|
|
47
|
+
`Expected outcome: ${step.expect ? JSON.stringify(step.expect) : "(reach the next state)"}`,
|
|
48
|
+
``,
|
|
49
|
+
`Current page:`,
|
|
50
|
+
renderElements(elements),
|
|
51
|
+
``,
|
|
52
|
+
`Reply with the single next action that achieves the goal.`,
|
|
53
|
+
].join("\n");
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=step-heal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"step-heal.js","sourceRoot":"","sources":["../../src/core/step-heal.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAiB,MAAM,eAAe,CAAC;AAE5F,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB,MAAM,gBAAgB,GACpB,+FAA+F;IAC/F,8FAA8F;IAC9F,4GAA4G;IAC5G,sFAAsF,CAAC;AAEzF,MAAM,OAAO,aAAa;IAGL;IACA;IAHV,KAAK,GAAe,EAAE,CAAC;IAChC,YACmB,GAAc,EACd,WAAW,cAAc;QADzB,QAAG,GAAH,GAAG,CAAW;QACd,aAAQ,GAAR,QAAQ,CAAiB;IACzC,CAAC;IAEJ,KAAK,CAAC,IAAI,CAAC,IAAU,EAAE,KAAa,EAAE,MAAc;QAClD,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QACpD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;QACzC,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;YACpG,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM;YAAE,OAAO,IAAI,CAAC;QAC5C,IAAI,MAAY,CAAC;QACjB,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;QACD,8FAA8F;QAC9F,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC5B,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC5B,MAAM,IAAI,GAAa,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAC/C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,SAAS,cAAc,CAAC,IAAU,EAAE,QAAuB;IACzD,OAAO;QACL,cAAc,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE;QACxC,qBAAqB,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,wBAAwB,EAAE;QAC3F,EAAE;QACF,eAAe;QACf,cAAc,CAAC,QAAQ,CAAC;QACxB,EAAE;QACF,2DAA2D;KAC5D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
package/dist/core/steps.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* registering a handler, never editing a stage. Depends only on core ports/types.
|
|
6
6
|
*/
|
|
7
7
|
import type { CustomAction, Driver, StepHandler } from "./ports.js";
|
|
8
|
-
import type { Step } from "./types.js";
|
|
8
|
+
import type { Step, WaitUntil } from "./types.js";
|
|
9
9
|
/** Handles cairn's built-in step vocabulary — every kind except product-defined `custom`. */
|
|
10
10
|
export declare class BuiltinStepHandler implements StepHandler {
|
|
11
11
|
supports(step: Step): boolean;
|
|
@@ -20,3 +20,13 @@ export declare class CustomStepHandler implements StepHandler {
|
|
|
20
20
|
}
|
|
21
21
|
/** The engine's default Execute-stage chain: built-ins first, then product `custom` actions. */
|
|
22
22
|
export declare function defaultStepHandlers(actions?: Record<string, CustomAction>): StepHandler[];
|
|
23
|
+
/**
|
|
24
|
+
* Poll the Driver's own observation until every field of `until` holds, or throw on timeout.
|
|
25
|
+
* Uses only `observe()`/`snapshot()`, so any Driver works and replay stays deterministic (no LLM,
|
|
26
|
+
* invariant #4). This is the explicit-wait primitive the heuristic `settle()` can't express —
|
|
27
|
+
* e.g. "wait until /me returns 200" before the next step, instead of racing the app's readiness.
|
|
28
|
+
*/
|
|
29
|
+
export declare function waitForCondition(driver: Driver, until: WaitUntil, timeoutMs?: number): Promise<void>;
|
|
30
|
+
/** Whether every field of `until` holds now (Driver observation only, no LLM). Polled by `waitFor`
|
|
31
|
+
* and checked once per step for `expect` verification (spec/core/surgical-heal.md). */
|
|
32
|
+
export declare function conditionMet(driver: Driver, until: WaitUntil): Promise<boolean>;
|
package/dist/core/steps.js
CHANGED
|
@@ -65,7 +65,7 @@ export function defaultStepHandlers(actions = {}) {
|
|
|
65
65
|
* invariant #4). This is the explicit-wait primitive the heuristic `settle()` can't express —
|
|
66
66
|
* e.g. "wait until /me returns 200" before the next step, instead of racing the app's readiness.
|
|
67
67
|
*/
|
|
68
|
-
async function waitForCondition(driver, until, timeoutMs = WAIT_TIMEOUT_MS) {
|
|
68
|
+
export async function waitForCondition(driver, until, timeoutMs = WAIT_TIMEOUT_MS) {
|
|
69
69
|
const deadline = Date.now() + timeoutMs;
|
|
70
70
|
for (;;) {
|
|
71
71
|
if (await conditionMet(driver, until))
|
|
@@ -76,7 +76,9 @@ async function waitForCondition(driver, until, timeoutMs = WAIT_TIMEOUT_MS) {
|
|
|
76
76
|
await sleep(WAIT_POLL_MS);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
-
|
|
79
|
+
/** Whether every field of `until` holds now (Driver observation only, no LLM). Polled by `waitFor`
|
|
80
|
+
* and checked once per step for `expect` verification (spec/core/surgical-heal.md). */
|
|
81
|
+
export async function conditionMet(driver, until) {
|
|
80
82
|
if (until.url !== undefined || until.requestStatus !== undefined) {
|
|
81
83
|
const { execution, logic } = await driver.observe();
|
|
82
84
|
if (until.url !== undefined && !(execution.finalUrl ?? "").includes(until.url))
|
package/dist/core/steps.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"steps.js","sourceRoot":"","sources":["../../src/core/steps.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"steps.js","sourceRoot":"","sources":["../../src/core/steps.ts"],"names":[],"mappings":"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"}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
export interface Context {
|
|
3
3
|
intent: string;
|
|
4
4
|
}
|
|
5
|
-
|
|
5
|
+
/** Per-step surgical-heal metadata: `intent` is what a heal re-decides from; `expect` is a
|
|
6
|
+
* post-condition replay verifies deterministically (same shape as `waitFor`). See spec/core/surgical-heal.md. */
|
|
7
|
+
export interface StepMeta {
|
|
8
|
+
intent?: string;
|
|
9
|
+
expect?: WaitUntil;
|
|
10
|
+
}
|
|
11
|
+
export type Step = StepMeta & ({
|
|
6
12
|
kind: "goto";
|
|
7
13
|
url: string;
|
|
8
14
|
} | {
|
|
@@ -41,7 +47,7 @@ export type Step = {
|
|
|
41
47
|
kind: "custom";
|
|
42
48
|
name: string;
|
|
43
49
|
params?: Record<string, unknown>;
|
|
44
|
-
};
|
|
50
|
+
});
|
|
45
51
|
/**
|
|
46
52
|
* A condition a `waitFor` step blocks on. All provided fields must hold (AND). Checked against the
|
|
47
53
|
* Driver's `observe()`/`snapshot()` — so any Driver supports it without a new port method.
|
|
@@ -99,6 +105,9 @@ export interface Scenario {
|
|
|
99
105
|
name: string;
|
|
100
106
|
steps: Step[];
|
|
101
107
|
assertions: Assertion[];
|
|
108
|
+
/** Set by discover when it stopped at the step cap without reaching "done" — the path may be
|
|
109
|
+
* incomplete, so a host can warn before trusting the freeze. Absent on a normal finish. */
|
|
110
|
+
truncated?: boolean;
|
|
102
111
|
}
|
|
103
112
|
/** An interactive element the discover loop perceives and acts on. */
|
|
104
113
|
export interface PageElement {
|
|
@@ -125,7 +134,9 @@ export interface NetworkRequest {
|
|
|
125
134
|
status: number;
|
|
126
135
|
resourceType?: string;
|
|
127
136
|
}
|
|
128
|
-
/** Three observable layers
|
|
137
|
+
/** Three observable layers. Execution + logic drive the deterministic verdict (never "the screen
|
|
138
|
+
* looked right"); perception (screenshots) feeds the host's visual replay and is available to custom
|
|
139
|
+
* checks — built-in critics don't judge it yet (LLM-vision assertions are future). */
|
|
129
140
|
export interface Evidence {
|
|
130
141
|
execution: {
|
|
131
142
|
actions: ExecutedAction[];
|
package/dist/index.d.ts
CHANGED
|
@@ -4,8 +4,9 @@ export * from "./core/ports.js";
|
|
|
4
4
|
export { runHarness } from "./core/pipeline.js";
|
|
5
5
|
export type { RunHarnessOptions } from "./core/pipeline.js";
|
|
6
6
|
export { BuiltinStepHandler, CustomStepHandler, defaultStepHandlers } from "./core/steps.js";
|
|
7
|
-
export { runScenario, needsLlmCritic, applyHeals } from "./run.js";
|
|
7
|
+
export { runScenario, needsLlmCritic, applyHeals, applyStepHeals } from "./run.js";
|
|
8
8
|
export type { RunScenarioOptions, RunScenarioResult } from "./run.js";
|
|
9
|
+
export { LlmStepHealer } from "./core/step-heal.js";
|
|
9
10
|
export { InlineContextProvider } from "./adapters/context/inline.js";
|
|
10
11
|
export { StaticPlanner } from "./adapters/planners/static.js";
|
|
11
12
|
export { AssertionCritic, checkAssertion, resolveAssertion, judgeAssertion, MechanicalAssertionHandler, CustomAssertionHandler, } from "./adapters/critics/assertion.js";
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,8 @@ export * from "./core/types.js";
|
|
|
3
3
|
export * from "./core/ports.js";
|
|
4
4
|
export { runHarness } from "./core/pipeline.js";
|
|
5
5
|
export { BuiltinStepHandler, CustomStepHandler, defaultStepHandlers } from "./core/steps.js";
|
|
6
|
-
export { runScenario, needsLlmCritic, applyHeals } from "./run.js";
|
|
6
|
+
export { runScenario, needsLlmCritic, applyHeals, applyStepHeals } from "./run.js";
|
|
7
|
+
export { LlmStepHealer } from "./core/step-heal.js";
|
|
7
8
|
export { InlineContextProvider } from "./adapters/context/inline.js";
|
|
8
9
|
export { StaticPlanner } from "./adapters/planners/static.js";
|
|
9
10
|
export { AssertionCritic, checkAssertion, resolveAssertion, judgeAssertion, MechanicalAssertionHandler, CustomAssertionHandler, } from "./adapters/critics/assertion.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAEnF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EACL,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,0BAA0B,EAC1B,sBAAsB,GACvB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACjG,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAGrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAEhF,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/run.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CustomAction } from "./core/ports.js";
|
|
2
2
|
import type { CustomChecks } from "./adapters/critics/assertion.js";
|
|
3
|
-
import type { ContextProvider, Critic, Driver, LlmClient, Reporter } from "./core/ports.js";
|
|
3
|
+
import type { ContextProvider, Critic, Driver, LlmClient, Reporter, StepHeal } from "./core/ports.js";
|
|
4
4
|
import type { Heal } from "./adapters/drivers/self-heal.js";
|
|
5
5
|
import type { Result, Scenario, StepProgress } from "./core/types.js";
|
|
6
6
|
export interface RunScenarioOptions {
|
|
@@ -10,7 +10,12 @@ export interface RunScenarioOptions {
|
|
|
10
10
|
context?: ContextProvider;
|
|
11
11
|
reporter?: Reporter;
|
|
12
12
|
llm?: LlmClient;
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Repair broken replays with the LLM (invariant #4 sanctioned use). Two layers, both only when set:
|
|
15
|
+
* a `SelfHealingDriver` fixes a step whose target no longer resolves, and — if the run still fails
|
|
16
|
+
* its assertions (a "passed-the-steps-but-wrong-outcome" break that locator-heal can't catch) —
|
|
17
|
+
* the scenario is re-discovered from the start. A green replay triggers neither (stays LLM-free).
|
|
18
|
+
*/
|
|
14
19
|
heal?: boolean;
|
|
15
20
|
/** Fired on each self-heal — a host's signal that the frozen scenario is aging. */
|
|
16
21
|
onHeal?: (heal: Heal) => void;
|
|
@@ -23,17 +28,25 @@ export interface RunScenarioOptions {
|
|
|
23
28
|
screenshots?: boolean;
|
|
24
29
|
/** Product-defined checks for `{ kind: "custom", name }` assertions — the host defines success. */
|
|
25
30
|
custom?: CustomChecks;
|
|
31
|
+
/** URL substrings whose 4xx/5xx is product noise (e.g. analytics), excluded from `no-failed-requests`. */
|
|
32
|
+
benign?: string[];
|
|
26
33
|
/** Product-defined handlers for `{ kind: "custom", name }` steps — the host defines interactions. */
|
|
27
34
|
actions?: Record<string, CustomAction>;
|
|
28
35
|
}
|
|
29
36
|
export interface RunScenarioResult {
|
|
30
37
|
result: Result;
|
|
31
|
-
/**
|
|
38
|
+
/** Locator substitutions self-heal made (empty unless `heal` was set and a target broke). */
|
|
32
39
|
heals: Heal[];
|
|
33
|
-
/**
|
|
40
|
+
/** Surgical step repairs (empty unless `heal` was set and a step's `expect` diverged). */
|
|
41
|
+
stepHeals: StepHeal[];
|
|
42
|
+
/** Scenario rewritten with healed targets/steps, ready to re-freeze. Undefined if no heals. */
|
|
34
43
|
healedScenario?: Scenario;
|
|
35
44
|
}
|
|
36
45
|
export declare function needsLlmCritic(scenario: Scenario): boolean;
|
|
37
|
-
/** Rewrite a scenario's targets with the
|
|
46
|
+
/** Rewrite a scenario's targets with the (re-located) targets self-heal substituted, for re-freezing.
|
|
47
|
+
* Keyed by the original target's object identity — which flows unchanged from the step through the
|
|
48
|
+
* driver into the Heal — so two steps sharing a label don't rewrite together (#39). */
|
|
38
49
|
export declare function applyHeals(scenario: Scenario, heals: Heal[]): Scenario;
|
|
50
|
+
/** Replace surgically-healed steps in place (keyed by index, so same-label steps don't collide). */
|
|
51
|
+
export declare function applyStepHeals(scenario: Scenario, heals: StepHeal[]): Scenario;
|
|
39
52
|
export declare function runScenario(scenario: Scenario, opts?: RunScenarioOptions): Promise<RunScenarioResult>;
|
package/dist/run.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* `heal` needs one, so a plain mechanical replay stays deterministic (invariant #4).
|
|
5
5
|
*/
|
|
6
6
|
import { runHarness } from "./core/pipeline.js";
|
|
7
|
+
import { discover } from "./core/discover.js";
|
|
7
8
|
import { InlineContextProvider } from "./adapters/context/inline.js";
|
|
8
9
|
import { StaticPlanner } from "./adapters/planners/static.js";
|
|
9
10
|
import { AssertionCritic } from "./adapters/critics/assertion.js";
|
|
@@ -12,45 +13,98 @@ import { ChromeDevToolsDriver } from "./adapters/drivers/chrome.js";
|
|
|
12
13
|
import { SelfHealingDriver } from "./adapters/drivers/self-heal.js";
|
|
13
14
|
import { ConsoleReporter } from "./adapters/reporters/console.js";
|
|
14
15
|
import { createLlmClient } from "./adapters/llm/factory.js";
|
|
16
|
+
import { LlmStepHealer } from "./core/step-heal.js";
|
|
15
17
|
export function needsLlmCritic(scenario) {
|
|
16
18
|
return scenario.assertions.some((a) => a.kind === "expect");
|
|
17
19
|
}
|
|
18
|
-
/**
|
|
20
|
+
/** The scenario's entry URL (its first `goto`), so an outcome-heal re-discovers from the same start. */
|
|
21
|
+
function firstGotoUrl(scenario) {
|
|
22
|
+
const first = scenario.steps[0];
|
|
23
|
+
return first && first.kind === "goto" ? first.url : undefined;
|
|
24
|
+
}
|
|
25
|
+
/** Rewrite a scenario's targets with the (re-located) targets self-heal substituted, for re-freezing.
|
|
26
|
+
* Keyed by the original target's object identity — which flows unchanged from the step through the
|
|
27
|
+
* driver into the Heal — so two steps sharing a label don't rewrite together (#39). */
|
|
19
28
|
export function applyHeals(scenario, heals) {
|
|
20
29
|
if (!heals.length)
|
|
21
30
|
return scenario;
|
|
22
|
-
const byOriginal = new Map(heals.map((h) => [h.original
|
|
31
|
+
const byOriginal = new Map(heals.map((h) => [h.original, h.healed]));
|
|
23
32
|
return {
|
|
24
33
|
...scenario,
|
|
25
34
|
steps: scenario.steps.map((step) => {
|
|
26
|
-
if ("target" in step
|
|
27
|
-
const healed = byOriginal.get(step.target
|
|
35
|
+
if ("target" in step) {
|
|
36
|
+
const healed = byOriginal.get(step.target);
|
|
28
37
|
if (healed)
|
|
29
|
-
return { ...step, target:
|
|
38
|
+
return { ...step, target: healed };
|
|
30
39
|
}
|
|
31
40
|
return step;
|
|
32
41
|
}),
|
|
33
42
|
};
|
|
34
43
|
}
|
|
44
|
+
/** Replace surgically-healed steps in place (keyed by index, so same-label steps don't collide). */
|
|
45
|
+
export function applyStepHeals(scenario, heals) {
|
|
46
|
+
if (!heals.length)
|
|
47
|
+
return scenario;
|
|
48
|
+
const byIndex = new Map(heals.map((h) => [h.index, h.step]));
|
|
49
|
+
return { ...scenario, steps: scenario.steps.map((step, i) => byIndex.get(i) ?? step) };
|
|
50
|
+
}
|
|
35
51
|
export async function runScenario(scenario, opts = {}) {
|
|
36
52
|
// Build the LLM lazily and once — only if the critic or heal needs it.
|
|
37
53
|
let llmCache = opts.llm;
|
|
38
54
|
const getLlm = () => (llmCache ??= createLlmClient(opts.model ? { model: opts.model } : {}));
|
|
39
55
|
const critic = opts.critic ??
|
|
40
|
-
(needsLlmCritic(scenario)
|
|
56
|
+
(needsLlmCritic(scenario)
|
|
57
|
+
? new LlmCritic(getLlm(), opts.custom, opts.benign)
|
|
58
|
+
: new AssertionCritic(opts.custom, opts.benign));
|
|
41
59
|
const baseDriver = opts.driver ?? new ChromeDevToolsDriver();
|
|
42
60
|
let healer;
|
|
43
61
|
const driver = opts.heal
|
|
44
62
|
? (healer = new SelfHealingDriver(baseDriver, getLlm(), { onHeal: opts.onHeal }))
|
|
45
63
|
: baseDriver;
|
|
64
|
+
const stepHealer = opts.heal ? new LlmStepHealer(getLlm()) : undefined;
|
|
46
65
|
const result = await runHarness({
|
|
47
66
|
context: opts.context ?? new InlineContextProvider(),
|
|
48
67
|
planner: new StaticPlanner(scenario),
|
|
49
68
|
driver,
|
|
50
69
|
critic,
|
|
51
70
|
reporter: opts.reporter ?? new ConsoleReporter(),
|
|
52
|
-
}, scenario.name, {
|
|
71
|
+
}, scenario.name, {
|
|
72
|
+
signal: opts.signal,
|
|
73
|
+
onStep: opts.onStep,
|
|
74
|
+
captureScreenshots: opts.screenshots,
|
|
75
|
+
actions: opts.actions,
|
|
76
|
+
stepHealer,
|
|
77
|
+
});
|
|
53
78
|
const heals = healer?.heals ?? [];
|
|
54
|
-
|
|
79
|
+
const stepHeals = stepHealer?.heals ?? [];
|
|
80
|
+
// Outcome-aware heal: the steps ran (locators/steps may even have healed) but the run still failed
|
|
81
|
+
// its assertions — the frozen path no longer reaches the goal, a break surgical-heal couldn't fix.
|
|
82
|
+
// Re-discover from the start (invariant #4 sanctioned use (b)); only on failure.
|
|
83
|
+
if (opts.heal && !result.verdict.passed) {
|
|
84
|
+
const repaired = await discover(scenario.name, {
|
|
85
|
+
driver: baseDriver,
|
|
86
|
+
llm: getLlm(),
|
|
87
|
+
baseUrl: firstGotoUrl(scenario),
|
|
88
|
+
signal: opts.signal,
|
|
89
|
+
});
|
|
90
|
+
const ctx = await (opts.context ?? new InlineContextProvider()).provide(scenario.name);
|
|
91
|
+
const evidence = await baseDriver.observe();
|
|
92
|
+
// Judge against the ORIGINAL goal assertions, not the ones the re-discovery derived for itself —
|
|
93
|
+
// else a path that reaches a different end-state passes as green (P2 false green).
|
|
94
|
+
const verdict = await critic.judge(evidence, scenario.assertions, ctx);
|
|
95
|
+
return {
|
|
96
|
+
result: { scenario: repaired.name, context: ctx, evidence, verdict },
|
|
97
|
+
heals,
|
|
98
|
+
stepHeals,
|
|
99
|
+
healedScenario: { ...repaired, assertions: scenario.assertions },
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const rewritten = applyStepHeals(applyHeals(scenario, heals), stepHeals);
|
|
103
|
+
return {
|
|
104
|
+
result,
|
|
105
|
+
heals,
|
|
106
|
+
stepHeals,
|
|
107
|
+
healedScenario: heals.length || stepHeals.length ? rewritten : undefined,
|
|
108
|
+
};
|
|
55
109
|
}
|
|
56
110
|
//# sourceMappingURL=run.js.map
|
package/dist/run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
|