@archmax-ai/harness 0.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/LICENSE +21 -0
- package/README.md +219 -0
- package/dist/agent.d.ts +174 -0
- package/dist/agent.js +140 -0
- package/dist/agent.js.map +1 -0
- package/dist/assembly/compose.d.ts +170 -0
- package/dist/assembly/compose.js +391 -0
- package/dist/assembly/compose.js.map +1 -0
- package/dist/assembly/delegation-registry.d.ts +5 -0
- package/dist/assembly/delegation-registry.js +118 -0
- package/dist/assembly/delegation-registry.js.map +1 -0
- package/dist/assembly/index.d.ts +192 -0
- package/dist/assembly/index.js +265 -0
- package/dist/assembly/index.js.map +1 -0
- package/dist/assembly/plain.d.ts +7 -0
- package/dist/assembly/plain.js +41 -0
- package/dist/assembly/plain.js.map +1 -0
- package/dist/authoring-skill/archmax-harness/README.md +76 -0
- package/dist/authoring-skill/archmax-harness/SKILL.md +241 -0
- package/dist/authoring-skill/archmax-harness/references/backend-integration.md +626 -0
- package/dist/authoring-skill/archmax-harness/references/cases.md +41 -0
- package/dist/authoring-skill/archmax-harness/references/diagnostics.md +51 -0
- package/dist/authoring-skill/archmax-harness/references/hook-and-test-scripts.md +1070 -0
- package/dist/authoring-skill/archmax-harness/references/hooks-and-scripts.md +82 -0
- package/dist/authoring-skill/archmax-harness/references/wiring.md +101 -0
- package/dist/authoring-skill/archmax-harness/references/workflow-schema.md +1631 -0
- package/dist/authoring-skill/archmax-harness/references/workflow-yaml.md +241 -0
- package/dist/behaviour/support.d.ts +232 -0
- package/dist/behaviour/support.js +339 -0
- package/dist/behaviour/support.js.map +1 -0
- package/dist/cli/banner.d.ts +11 -0
- package/dist/cli/banner.js +29 -0
- package/dist/cli/banner.js.map +1 -0
- package/dist/cli/bootstrap.d.ts +33 -0
- package/dist/cli/bootstrap.js +153 -0
- package/dist/cli/bootstrap.js.map +1 -0
- package/dist/cli/command.d.ts +39 -0
- package/dist/cli/command.js +97 -0
- package/dist/cli/command.js.map +1 -0
- package/dist/cli/state-flow.d.ts +46 -0
- package/dist/cli/state-flow.js +268 -0
- package/dist/cli/state-flow.js.map +1 -0
- package/dist/cli/style.d.ts +41 -0
- package/dist/cli/style.js +64 -0
- package/dist/cli/style.js.map +1 -0
- package/dist/cli/turn.d.ts +41 -0
- package/dist/cli/turn.js +161 -0
- package/dist/cli/turn.js.map +1 -0
- package/dist/cli.d.ts +10 -0
- package/dist/cli.js +426 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/code-description.d.ts +22 -0
- package/dist/core/code-description.js +38 -0
- package/dist/core/code-description.js.map +1 -0
- package/dist/core/deepagents.d.ts +183 -0
- package/dist/core/deepagents.js +128 -0
- package/dist/core/deepagents.js.map +1 -0
- package/dist/core/events.d.ts +350 -0
- package/dist/core/events.js +205 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/frontmatter.d.ts +15 -0
- package/dist/core/frontmatter.js +32 -0
- package/dist/core/frontmatter.js.map +1 -0
- package/dist/core/listing-redact.d.ts +37 -0
- package/dist/core/listing-redact.js +88 -0
- package/dist/core/listing-redact.js.map +1 -0
- package/dist/core/match.d.ts +26 -0
- package/dist/core/match.js +75 -0
- package/dist/core/match.js.map +1 -0
- package/dist/core/message-readers.d.ts +84 -0
- package/dist/core/message-readers.js +159 -0
- package/dist/core/message-readers.js.map +1 -0
- package/dist/core/messages.d.ts +49 -0
- package/dist/core/messages.js +85 -0
- package/dist/core/messages.js.map +1 -0
- package/dist/core/mount-prompt.d.ts +28 -0
- package/dist/core/mount-prompt.js +55 -0
- package/dist/core/mount-prompt.js.map +1 -0
- package/dist/core/mount-redact.d.ts +28 -0
- package/dist/core/mount-redact.js +32 -0
- package/dist/core/mount-redact.js.map +1 -0
- package/dist/core/mounts.d.ts +88 -0
- package/dist/core/mounts.js +147 -0
- package/dist/core/mounts.js.map +1 -0
- package/dist/core/path-mapping.d.ts +52 -0
- package/dist/core/path-mapping.js +113 -0
- package/dist/core/path-mapping.js.map +1 -0
- package/dist/core/platform-prompt.generated.d.ts +2 -0
- package/dist/core/platform-prompt.generated.js +4 -0
- package/dist/core/platform-prompt.generated.js.map +1 -0
- package/dist/core/prompt.d.ts +42 -0
- package/dist/core/prompt.js +75 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/core/session-id.d.ts +38 -0
- package/dist/core/session-id.js +61 -0
- package/dist/core/session-id.js.map +1 -0
- package/dist/core/session-store.d.ts +85 -0
- package/dist/core/session-store.js +149 -0
- package/dist/core/session-store.js.map +1 -0
- package/dist/core/session-zone.d.ts +54 -0
- package/dist/core/session-zone.js +82 -0
- package/dist/core/session-zone.js.map +1 -0
- package/dist/core/skill-prompt.d.ts +31 -0
- package/dist/core/skill-prompt.js +54 -0
- package/dist/core/skill-prompt.js.map +1 -0
- package/dist/core/skill-redact.d.ts +15 -0
- package/dist/core/skill-redact.js +27 -0
- package/dist/core/skill-redact.js.map +1 -0
- package/dist/core/skills.d.ts +172 -0
- package/dist/core/skills.js +214 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/tool-mocks.d.ts +23 -0
- package/dist/core/tool-mocks.js +39 -0
- package/dist/core/tool-mocks.js.map +1 -0
- package/dist/core/tool-telemetry.d.ts +16 -0
- package/dist/core/tool-telemetry.js +40 -0
- package/dist/core/tool-telemetry.js.map +1 -0
- package/dist/core/usage.d.ts +114 -0
- package/dist/core/usage.js +226 -0
- package/dist/core/usage.js.map +1 -0
- package/dist/core/workspace-context.d.ts +136 -0
- package/dist/core/workspace-context.js +178 -0
- package/dist/core/workspace-context.js.map +1 -0
- package/dist/core/workspace-prompt.d.ts +7 -0
- package/dist/core/workspace-prompt.js +102 -0
- package/dist/core/workspace-prompt.js.map +1 -0
- package/dist/core/workspace-router.d.ts +61 -0
- package/dist/core/workspace-router.js +145 -0
- package/dist/core/workspace-router.js.map +1 -0
- package/dist/core/workspace.d.ts +85 -0
- package/dist/core/workspace.js +193 -0
- package/dist/core/workspace.js.map +1 -0
- package/dist/core/zones.d.ts +181 -0
- package/dist/core/zones.js +202 -0
- package/dist/core/zones.js.map +1 -0
- package/dist/env.d.ts +99 -0
- package/dist/env.js +271 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +265 -0
- package/dist/index.js +197 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel/kernel.d.ts +192 -0
- package/dist/kernel/kernel.js +751 -0
- package/dist/kernel/kernel.js.map +1 -0
- package/dist/lifecycle/hook-shape.d.ts +44 -0
- package/dist/lifecycle/hook-shape.js +66 -0
- package/dist/lifecycle/hook-shape.js.map +1 -0
- package/dist/lifecycle/runner.d.ts +177 -0
- package/dist/lifecycle/runner.js +372 -0
- package/dist/lifecycle/runner.js.map +1 -0
- package/dist/lifecycle/transcript.d.ts +27 -0
- package/dist/lifecycle/transcript.js +43 -0
- package/dist/lifecycle/transcript.js.map +1 -0
- package/dist/machine/allow.d.ts +65 -0
- package/dist/machine/allow.js +107 -0
- package/dist/machine/allow.js.map +1 -0
- package/dist/machine/delegation.d.ts +9 -0
- package/dist/machine/delegation.js +10 -0
- package/dist/machine/delegation.js.map +1 -0
- package/dist/machine/diagnostic.d.ts +14 -0
- package/dist/machine/diagnostic.js +2 -0
- package/dist/machine/diagnostic.js.map +1 -0
- package/dist/machine/lint-spec.d.ts +4 -0
- package/dist/machine/lint-spec.js +266 -0
- package/dist/machine/lint-spec.js.map +1 -0
- package/dist/machine/load-spec.d.ts +90 -0
- package/dist/machine/load-spec.js +120 -0
- package/dist/machine/load-spec.js.map +1 -0
- package/dist/machine/machine.d.ts +273 -0
- package/dist/machine/machine.js +551 -0
- package/dist/machine/machine.js.map +1 -0
- package/dist/machine/mount-grants.d.ts +25 -0
- package/dist/machine/mount-grants.js +24 -0
- package/dist/machine/mount-grants.js.map +1 -0
- package/dist/machine/slug.d.ts +14 -0
- package/dist/machine/slug.js +17 -0
- package/dist/machine/slug.js.map +1 -0
- package/dist/machine/spec-schema.d.ts +662 -0
- package/dist/machine/spec-schema.js +717 -0
- package/dist/machine/spec-schema.js.map +1 -0
- package/dist/machine/tool-names.d.ts +98 -0
- package/dist/machine/tool-names.js +144 -0
- package/dist/machine/tool-names.js.map +1 -0
- package/dist/machine/triggers.d.ts +114 -0
- package/dist/machine/triggers.js +165 -0
- package/dist/machine/triggers.js.map +1 -0
- package/dist/machine/types.d.ts +186 -0
- package/dist/machine/types.js +12 -0
- package/dist/machine/types.js.map +1 -0
- package/dist/machine/validate-spec.d.ts +42 -0
- package/dist/machine/validate-spec.js +29 -0
- package/dist/machine/validate-spec.js.map +1 -0
- package/dist/machine/variables.d.ts +196 -0
- package/dist/machine/variables.js +415 -0
- package/dist/machine/variables.js.map +1 -0
- package/dist/public/cli.d.ts +15 -0
- package/dist/public/cli.js +14 -0
- package/dist/public/cli.js.map +1 -0
- package/dist/public/messages.d.ts +33 -0
- package/dist/public/messages.js +33 -0
- package/dist/public/messages.js.map +1 -0
- package/dist/public/sandbox.d.ts +99 -0
- package/dist/public/sandbox.js +32 -0
- package/dist/public/sandbox.js.map +1 -0
- package/dist/public/spec.d.ts +147 -0
- package/dist/public/spec.js +149 -0
- package/dist/public/spec.js.map +1 -0
- package/dist/public/testing.d.ts +71 -0
- package/dist/public/testing.js +39 -0
- package/dist/public/testing.js.map +1 -0
- package/dist/rubrics/rubrics.d.ts +135 -0
- package/dist/rubrics/rubrics.js +145 -0
- package/dist/rubrics/rubrics.js.map +1 -0
- package/dist/runtime/contract.d.ts +73 -0
- package/dist/runtime/contract.js +96 -0
- package/dist/runtime/contract.js.map +1 -0
- package/dist/sandbox/assets/parts/core.js +22 -0
- package/dist/sandbox/assets/parts/lifecycle-hook.js +47 -0
- package/dist/sandbox/bridge.d.ts +16 -0
- package/dist/sandbox/bridge.js +95 -0
- package/dist/sandbox/bridge.js.map +1 -0
- package/dist/sandbox/executor.d.ts +46 -0
- package/dist/sandbox/executor.js +119 -0
- package/dist/sandbox/executor.js.map +1 -0
- package/dist/sandbox/imports.d.ts +33 -0
- package/dist/sandbox/imports.js +67 -0
- package/dist/sandbox/imports.js.map +1 -0
- package/dist/sandbox/prelude.d.ts +12 -0
- package/dist/sandbox/prelude.js +51 -0
- package/dist/sandbox/prelude.js.map +1 -0
- package/dist/sandbox/ptc-gateway.d.ts +104 -0
- package/dist/sandbox/ptc-gateway.js +167 -0
- package/dist/sandbox/ptc-gateway.js.map +1 -0
- package/dist/sandbox/runtime.d.ts +59 -0
- package/dist/sandbox/runtime.js +51 -0
- package/dist/sandbox/runtime.js.map +1 -0
- package/dist/sandbox/tools.d.ts +34 -0
- package/dist/sandbox/tools.js +147 -0
- package/dist/sandbox/tools.js.map +1 -0
- package/dist/sessions/operations.d.ts +79 -0
- package/dist/sessions/operations.js +121 -0
- package/dist/sessions/operations.js.map +1 -0
- package/dist/sessions/resolve.d.ts +97 -0
- package/dist/sessions/resolve.js +145 -0
- package/dist/sessions/resolve.js.map +1 -0
- package/dist/sessions/resume.d.ts +242 -0
- package/dist/sessions/resume.js +288 -0
- package/dist/sessions/resume.js.map +1 -0
- package/dist/sessions/scope.d.ts +99 -0
- package/dist/sessions/scope.js +145 -0
- package/dist/sessions/scope.js.map +1 -0
- package/dist/sessions/summary.d.ts +65 -0
- package/dist/sessions/summary.js +56 -0
- package/dist/sessions/summary.js.map +1 -0
- package/dist/testing/assertions.d.ts +30 -0
- package/dist/testing/assertions.js +231 -0
- package/dist/testing/assertions.js.map +1 -0
- package/dist/testing/case-document.d.ts +141 -0
- package/dist/testing/case-document.js +51 -0
- package/dist/testing/case-document.js.map +1 -0
- package/dist/testing/case-schema.d.ts +29 -0
- package/dist/testing/case-schema.js +519 -0
- package/dist/testing/case-schema.js.map +1 -0
- package/dist/testing/discovery.d.ts +10 -0
- package/dist/testing/discovery.js +24 -0
- package/dist/testing/discovery.js.map +1 -0
- package/dist/testing/driver.d.ts +78 -0
- package/dist/testing/driver.js +117 -0
- package/dist/testing/driver.js.map +1 -0
- package/dist/testing/grade.d.ts +116 -0
- package/dist/testing/grade.js +261 -0
- package/dist/testing/grade.js.map +1 -0
- package/dist/testing/interpreter.d.ts +55 -0
- package/dist/testing/interpreter.js +103 -0
- package/dist/testing/interpreter.js.map +1 -0
- package/dist/testing/mock-middleware.d.ts +5 -0
- package/dist/testing/mock-middleware.js +33 -0
- package/dist/testing/mock-middleware.js.map +1 -0
- package/dist/testing/runner.d.ts +205 -0
- package/dist/testing/runner.js +266 -0
- package/dist/testing/runner.js.map +1 -0
- package/dist/testing/target.d.ts +27 -0
- package/dist/testing/target.js +21 -0
- package/dist/testing/target.js.map +1 -0
- package/dist/validate/validate.d.ts +41 -0
- package/dist/validate/validate.js +669 -0
- package/dist/validate/validate.js.map +1 -0
- package/dist/workflow/agent-tools.d.ts +10 -0
- package/dist/workflow/agent-tools.js +10 -0
- package/dist/workflow/agent-tools.js.map +1 -0
- package/dist/workflow/checkpointer.d.ts +52 -0
- package/dist/workflow/checkpointer.js +200 -0
- package/dist/workflow/checkpointer.js.map +1 -0
- package/dist/workflow/control-tools.d.ts +174 -0
- package/dist/workflow/control-tools.js +468 -0
- package/dist/workflow/control-tools.js.map +1 -0
- package/dist/workflow/governance.d.ts +104 -0
- package/dist/workflow/governance.js +546 -0
- package/dist/workflow/governance.js.map +1 -0
- package/dist/workflow/middleware.d.ts +85 -0
- package/dist/workflow/middleware.js +283 -0
- package/dist/workflow/middleware.js.map +1 -0
- package/dist/workflow/on-error.d.ts +25 -0
- package/dist/workflow/on-error.js +58 -0
- package/dist/workflow/on-error.js.map +1 -0
- package/dist/workflow/parks.d.ts +46 -0
- package/dist/workflow/parks.js +513 -0
- package/dist/workflow/parks.js.map +1 -0
- package/dist/workflow/paths.d.ts +67 -0
- package/dist/workflow/paths.js +108 -0
- package/dist/workflow/paths.js.map +1 -0
- package/dist/workflow/prompt-cache.d.ts +70 -0
- package/dist/workflow/prompt-cache.js +103 -0
- package/dist/workflow/prompt-cache.js.map +1 -0
- package/dist/workflow/prompt-pruning.d.ts +20 -0
- package/dist/workflow/prompt-pruning.js +83 -0
- package/dist/workflow/prompt-pruning.js.map +1 -0
- package/dist/workflow/render-prompt.d.ts +45 -0
- package/dist/workflow/render-prompt.js +140 -0
- package/dist/workflow/render-prompt.js.map +1 -0
- package/dist/workflow/runtime-config.d.ts +7 -0
- package/dist/workflow/runtime-config.js +9 -0
- package/dist/workflow/runtime-config.js.map +1 -0
- package/dist/workflow/session-artifacts.d.ts +90 -0
- package/dist/workflow/session-artifacts.js +134 -0
- package/dist/workflow/session-artifacts.js.map +1 -0
- package/dist/workflow/session-view.d.ts +31 -0
- package/dist/workflow/session-view.js +94 -0
- package/dist/workflow/session-view.js.map +1 -0
- package/dist/workflow/snapshot.d.ts +14 -0
- package/dist/workflow/snapshot.js +97 -0
- package/dist/workflow/snapshot.js.map +1 -0
- package/dist/workflow/state.d.ts +347 -0
- package/dist/workflow/state.js +322 -0
- package/dist/workflow/state.js.map +1 -0
- package/dist/workflow/sub-workflow.d.ts +174 -0
- package/dist/workflow/sub-workflow.js +392 -0
- package/dist/workflow/sub-workflow.js.map +1 -0
- package/dist/workflow/tool-service.d.ts +48 -0
- package/dist/workflow/tool-service.js +291 -0
- package/dist/workflow/tool-service.js.map +1 -0
- package/dist/workflow/turn-boundary.d.ts +39 -0
- package/dist/workflow/turn-boundary.js +128 -0
- package/dist/workflow/turn-boundary.js.map +1 -0
- package/dist/workflow/turn-runner.d.ts +40 -0
- package/dist/workflow/turn-runner.js +122 -0
- package/dist/workflow/turn-runner.js.map +1 -0
- package/dist/workflow/workflow-tools.d.ts +46 -0
- package/dist/workflow/workflow-tools.js +90 -0
- package/dist/workflow/workflow-tools.js.map +1 -0
- package/package.json +119 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { isWorkflowToolName } from "../machine/tool-names.js";
|
|
2
|
+
import { evaluateExpectations, haltsCaseOnFailure, notExecutedRecord, } from "./assertions.js";
|
|
3
|
+
import { DEFAULT_SESSION_ID, createSessionEngine, unDelegatableMocksMessage, unInterceptableMocksMessage, } from "./driver.js";
|
|
4
|
+
/**
|
|
5
|
+
* Describe every assertion step a case did not account for, as `not-executed`
|
|
6
|
+
* records. The one place un-run steps are built, so the three ways a case can
|
|
7
|
+
* stop early — a structural halt, a thrown action, and the runner's wall-clock
|
|
8
|
+
* timeout — cannot drift apart in what they report.
|
|
9
|
+
*/
|
|
10
|
+
export function notExecutedRecords(doc, alreadyAccountedFor) {
|
|
11
|
+
const out = [];
|
|
12
|
+
for (const [index, step] of doc.steps.entries()) {
|
|
13
|
+
if (step.kind !== "assert" || alreadyAccountedFor(index))
|
|
14
|
+
continue;
|
|
15
|
+
out.push(notExecutedRecord(step.expect, index));
|
|
16
|
+
}
|
|
17
|
+
return out;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Why a case's declared mocks cannot be honoured by this target, or `null`.
|
|
21
|
+
* Checked once, before anything runs: a mock-declaring case never executes
|
|
22
|
+
* with partial interception — and never seeds or drives first.
|
|
23
|
+
*/
|
|
24
|
+
function mockRefusal(doc, agent) {
|
|
25
|
+
if (doc.mocks.length === 0)
|
|
26
|
+
return null;
|
|
27
|
+
// Without the tool-mock middleware, declared mocks would intercept only
|
|
28
|
+
// scripts' PTC calls while the agent's own calls hit real tools. Absence of
|
|
29
|
+
// the capability field (a hand-rolled runtime) counts as "cannot intercept".
|
|
30
|
+
if (agent.toolMocks !== true)
|
|
31
|
+
return unInterceptableMocksMessage(doc.mocks.length);
|
|
32
|
+
// A delegation mock stands in for a whole other governed machine: without a
|
|
33
|
+
// governed assembly to dispatch one, the mock is inert.
|
|
34
|
+
if (doc.mocks.some((mock) => isWorkflowToolName(mock.name)) && !agent.workflow) {
|
|
35
|
+
return unDelegatableMocksMessage();
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
/** Execute one case document against the agent under test. */
|
|
40
|
+
export async function executeCase(opts) {
|
|
41
|
+
const { doc, seeds, agent, sessionId, grade, onRecord } = opts;
|
|
42
|
+
const engine = createSessionEngine({
|
|
43
|
+
agent,
|
|
44
|
+
defaultSessionId: sessionId,
|
|
45
|
+
...(opts.signal ? { signal: opts.signal } : {}),
|
|
46
|
+
});
|
|
47
|
+
const records = [];
|
|
48
|
+
const collect = (produced) => {
|
|
49
|
+
for (const record of produced) {
|
|
50
|
+
records.push(record);
|
|
51
|
+
onRecord?.(record);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const notExecutedFrom = (from) => notExecutedRecords(doc, (step) => step < from);
|
|
55
|
+
const refused = mockRefusal(doc, agent);
|
|
56
|
+
if (refused)
|
|
57
|
+
return { records, error: refused };
|
|
58
|
+
// The step the loop is currently attempting, so the catch below knows where
|
|
59
|
+
// execution stopped. -1 until the first step: a throw from `engine.open`
|
|
60
|
+
// leaves every assertion step un-run.
|
|
61
|
+
let attemptedStep = -1;
|
|
62
|
+
try {
|
|
63
|
+
// Start conditions apply before any step: a bad trigger declaration or a
|
|
64
|
+
// failed workspace seed fails the case even when it has no steps.
|
|
65
|
+
await engine.open(DEFAULT_SESSION_ID, {
|
|
66
|
+
...(doc.trigger !== undefined ? { trigger: doc.trigger } : {}),
|
|
67
|
+
...(doc.variables !== undefined ? { variables: doc.variables } : {}),
|
|
68
|
+
files: seeds,
|
|
69
|
+
});
|
|
70
|
+
// The schema guarantees every assertion follows an action, so `view` is
|
|
71
|
+
// always set by the time an assertion evaluates.
|
|
72
|
+
let view = null;
|
|
73
|
+
for (const [index, step] of doc.steps.entries()) {
|
|
74
|
+
attemptedStep = index;
|
|
75
|
+
if (step.kind === "action") {
|
|
76
|
+
view = await runAction(step.action);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const produced = await evaluateExpectations([step.expect], view, index, grade);
|
|
80
|
+
collect(produced);
|
|
81
|
+
// A failed structural assertion means the session is no longer the one
|
|
82
|
+
// this case describes, so driving it further grades the wrong session.
|
|
83
|
+
// Stop, and account for the steps that will not run.
|
|
84
|
+
if (haltsCaseOnFailure(step.expect.assert) && produced.some((r) => r.status === "failed")) {
|
|
85
|
+
collect(notExecutedFrom(index + 1));
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
collect(notExecutedFrom(attemptedStep + 1));
|
|
92
|
+
return { records, error: err.message };
|
|
93
|
+
}
|
|
94
|
+
return { records };
|
|
95
|
+
async function runAction(action) {
|
|
96
|
+
if (action.action === "send")
|
|
97
|
+
return engine.send(DEFAULT_SESSION_ID, action.message, doc.mocks);
|
|
98
|
+
if (action.action === "deliver")
|
|
99
|
+
return engine.deliver(DEFAULT_SESSION_ID, action.trigger, action.variables);
|
|
100
|
+
return engine.decide(DEFAULT_SESSION_ID, action.to, action.comment);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=interpreter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interpreter.js","sourceRoot":"","sources":["../../src/testing/interpreter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AgentMiddleware } from "langchain";
|
|
2
|
+
import { type ToolMockSpec } from "../core/tool-mocks.js";
|
|
3
|
+
export type { ToolMockSpec };
|
|
4
|
+
/** Short-circuit governed tool calls with declarative mock results (test cases only). */
|
|
5
|
+
export declare function createToolMockMiddleware(): AgentMiddleware;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ToolMessage } from "@langchain/core/messages";
|
|
2
|
+
import { createMiddleware } from "langchain";
|
|
3
|
+
import { isWorkflowToolName } from "../machine/tool-names.js";
|
|
4
|
+
import { findMock, mockPayload, readMocks, TOOL_MOCK_MIDDLEWARE_NAME, } from "../core/tool-mocks.js";
|
|
5
|
+
/** Short-circuit governed tool calls with declarative mock results (test cases only). */
|
|
6
|
+
export function createToolMockMiddleware() {
|
|
7
|
+
return createMiddleware({
|
|
8
|
+
// The name is the assembly-time detection handle for `capabilities.toolMocks`.
|
|
9
|
+
name: TOOL_MOCK_MIDDLEWARE_NAME,
|
|
10
|
+
wrapToolCall: async (request, handler) => {
|
|
11
|
+
const toolName = request.toolCall?.name ?? "";
|
|
12
|
+
const args = (request.toolCall?.args ?? {});
|
|
13
|
+
const configurable = request.runtime?.configurable ?? request.config?.configurable ?? {};
|
|
14
|
+
// A delegation mock is served by the **dispatcher**, not here. Short-
|
|
15
|
+
// circuiting it at this seam would skip the dispatch entirely — no
|
|
16
|
+
// sub-workflow event, no trail step, no check that the answer matches what
|
|
17
|
+
// the target declares it returns — leaving a case asserting against a
|
|
18
|
+
// delegation the run has no record of making.
|
|
19
|
+
const mock = isWorkflowToolName(toolName)
|
|
20
|
+
? undefined
|
|
21
|
+
: findMock(readMocks(configurable), toolName, args);
|
|
22
|
+
if (mock) {
|
|
23
|
+
return new ToolMessage({
|
|
24
|
+
content: mockPayload(mock),
|
|
25
|
+
tool_call_id: request.toolCall?.id ?? "",
|
|
26
|
+
name: toolName,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return handler(request);
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=mock-middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-middleware.js","sourceRoot":"","sources":["../../src/testing/mock-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAG7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EACL,QAAQ,EACR,WAAW,EACX,SAAS,EACT,yBAAyB,GAE1B,MAAM,uBAAuB,CAAC;AAI/B,yFAAyF;AACzF,MAAM,UAAU,wBAAwB;IACtC,OAAO,gBAAgB,CAAC;QACtB,+EAA+E;QAC/E,IAAI,EAAE,yBAAyB;QAC/B,YAAY,EAAE,KAAK,EAAE,OAA2B,EAAE,OAA2B,EAAE,EAAE;YAC/E,MAAM,QAAQ,GAAW,OAAO,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC;YACtD,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE,CAA4B,CAAC;YACvE,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,YAAY,IAAI,OAAO,CAAC,MAAM,EAAE,YAAY,IAAI,EAAE,CAAC;YAEzF,sEAAsE;YACtE,mEAAmE;YACnE,2EAA2E;YAC3E,sEAAsE;YACtE,8CAA8C;YAC9C,MAAM,IAAI,GAAG,kBAAkB,CAAC,QAAQ,CAAC;gBACvC,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YACtD,IAAI,IAAI,EAAE,CAAC;gBACT,OAAO,IAAI,WAAW,CAAC;oBACrB,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC;oBAC1B,YAAY,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE;oBACxC,IAAI,EAAE,QAAQ;iBACf,CAAC,CAAC;YACL,CAAC;YAED,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;QAC1B,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Running a suite of cases.
|
|
3
|
+
*
|
|
4
|
+
* Three steps, each its own exported function: {@link discoverCases} finds and
|
|
5
|
+
* parses the case files, {@link runCase} drives one against the agent under
|
|
6
|
+
* test, and {@link runTests} wires the two together with suite configuration.
|
|
7
|
+
* The **verdict** a case settles to and the **contract** a target must satisfy
|
|
8
|
+
* live here too, because nothing else reads them.
|
|
9
|
+
*
|
|
10
|
+
* The runner returns data and prints nothing: the CLI's test view is the
|
|
11
|
+
* renderer, and a host reporter reads the same `CaseResult`s.
|
|
12
|
+
*
|
|
13
|
+
* What is deliberately *not* here is `createCaseTarget` — see `target.ts`. The
|
|
14
|
+
* runner reaches its target through that builder and a host replaces it, so
|
|
15
|
+
* folding it in would make the seam unreplaceable in fact rather than in type.
|
|
16
|
+
*/
|
|
17
|
+
import type { BackendProtocolV2 } from "deepagents";
|
|
18
|
+
import type { Agent, GovernedAgent } from "../agent.js";
|
|
19
|
+
import type { WorkflowEventHandler } from "../core/events.js";
|
|
20
|
+
import type { SandboxRuntime } from "../sandbox/runtime.js";
|
|
21
|
+
import { type ModelFactory } from "../env.js";
|
|
22
|
+
import { Workspace } from "../core/workspace.js";
|
|
23
|
+
import { type CaseDocument } from "./case-schema.js";
|
|
24
|
+
import type { GradeFn } from "./assertions.js";
|
|
25
|
+
/**
|
|
26
|
+
* The outcome of one assertion. `not-executed` is a first-class case, not an
|
|
27
|
+
* absence: a case that stopped early still accounts for the assertion steps it
|
|
28
|
+
* never reached.
|
|
29
|
+
*/
|
|
30
|
+
export type AssertionStatus = "passed" | "failed" | "not-executed";
|
|
31
|
+
export interface AssertionRecord {
|
|
32
|
+
kind: string;
|
|
33
|
+
/** @deprecated Derived: `status === "passed"`. Kept for one release; read `status`. */
|
|
34
|
+
pass: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* The `atLeast` bar a `grade` assertion had to clear, `null` for every other
|
|
37
|
+
* kind. Descriptive only — it is rendered beside the score; whether the
|
|
38
|
+
* record failed is already decided in `status`.
|
|
39
|
+
*/
|
|
40
|
+
threshold: number | null;
|
|
41
|
+
/**
|
|
42
|
+
* The assertion's outcome — the single authoritative one, computed by the
|
|
43
|
+
* engine and the field verdict reduction keys off. A `grade` record takes its
|
|
44
|
+
* status from the case's declared `atLeast` threshold, so it can never
|
|
45
|
+
* contradict the verdict computed from the same score.
|
|
46
|
+
*/
|
|
47
|
+
status: AssertionStatus;
|
|
48
|
+
/** A `grade` record's score; absent for deterministic assertions. */
|
|
49
|
+
score?: number;
|
|
50
|
+
detail?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Zero-based index, in the case document's flat `steps` list, of the
|
|
53
|
+
* assertion step that produced this record — the same index the case schema
|
|
54
|
+
* uses in its `steps[i]` error locations. Values are sparse with respect to
|
|
55
|
+
* `steps`: action steps produce no records.
|
|
56
|
+
*/
|
|
57
|
+
step: number;
|
|
58
|
+
}
|
|
59
|
+
export type CaseStatus = "passed" | "failed" | "skipped";
|
|
60
|
+
export interface CaseVerdict {
|
|
61
|
+
status: CaseStatus;
|
|
62
|
+
failures: string[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Reduce recorded assertions to a verdict. Every failed record fails its case —
|
|
66
|
+
* there is no severity tier that records a failure without failing. A `grade`
|
|
67
|
+
* miss reads as a failure like any other, with its score beside the bar it
|
|
68
|
+
* missed. Every branch keys off `status`: with `not-executed` records present,
|
|
69
|
+
* "did not pass" and "failed" are different things.
|
|
70
|
+
*/
|
|
71
|
+
export declare function reduceVerdict(records: AssertionRecord[]): CaseVerdict;
|
|
72
|
+
/** Map a verdict to a process exit code. */
|
|
73
|
+
export declare function exitCodeForVerdict(verdict: CaseVerdict): number;
|
|
74
|
+
/**
|
|
75
|
+
* The one contract a case target must satisfy, wherever it came from. Cases
|
|
76
|
+
* drive the agent through the workflow graph (and may resume human states), so
|
|
77
|
+
* the target must be workflow-governed. Both the default target builder and
|
|
78
|
+
* `runTests` enforce this, so a caller-supplied target is refused on the same
|
|
79
|
+
* terms as one the SDK built.
|
|
80
|
+
*/
|
|
81
|
+
export declare function assertWorkflowGovernedTarget(agent: Agent, workflow: string): asserts agent is GovernedAgent;
|
|
82
|
+
export interface RunTestsOptions {
|
|
83
|
+
workflow: string;
|
|
84
|
+
rootDir?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Backend serving the **authored governance plane** this suite reads — the
|
|
87
|
+
* machine spec, the case documents under `workflows/<slug>/tests/`, and the
|
|
88
|
+
* fixtures their `from:` entries name. The same option `createAgent` takes,
|
|
89
|
+
* and for the same reason: a host whose authored tree lives in a store rather
|
|
90
|
+
* than on local disk has nothing under `<rootDir>/workflows/`, so discovery
|
|
91
|
+
* over a filesystem root would find no cases at all and report an empty suite
|
|
92
|
+
* rather than a missing one.
|
|
93
|
+
*
|
|
94
|
+
* Defaults to a filesystem backend over the resolved root — what `archmax test`
|
|
95
|
+
* uses, and what a host keeps when its cases really are files on disk. A host
|
|
96
|
+
* that supplies this also supplies its own `createTarget`: the two describe
|
|
97
|
+
* the same authored content, one to read the suite from and one to run it.
|
|
98
|
+
*/
|
|
99
|
+
authoring?: BackendProtocolV2;
|
|
100
|
+
/** Only run case files whose workspace-relative path contains this substring. */
|
|
101
|
+
filter?: string;
|
|
102
|
+
/** Forwarded to the workflow agent under test for lifecycle diagnostics. */
|
|
103
|
+
onEvent?: WorkflowEventHandler;
|
|
104
|
+
/**
|
|
105
|
+
* Reporter callback invoked before each case file runs, with the session id
|
|
106
|
+
* the case will drive — so a live renderer can show only that session's events.
|
|
107
|
+
*/
|
|
108
|
+
onCaseStart?: (file: string, sessionId: string) => void;
|
|
109
|
+
/** Reporter callback invoked with each case result as it completes. */
|
|
110
|
+
onCaseResult?: (result: CaseResult) => void;
|
|
111
|
+
/**
|
|
112
|
+
* Script-execution backend forwarded to the agent under test (its lifecycle
|
|
113
|
+
* hooks and `archmax_run` sources). Case documents themselves are YAML
|
|
114
|
+
* interpreted on the host — no sandbox is involved in running them.
|
|
115
|
+
*/
|
|
116
|
+
sandboxRuntime?: SandboxRuntime;
|
|
117
|
+
/** Model factory forwarded to the agent under test and the grading model. */
|
|
118
|
+
modelFactory?: ModelFactory;
|
|
119
|
+
/**
|
|
120
|
+
* The agent under test — an already-built workflow-governed runtime, or a
|
|
121
|
+
* factory that builds one. Defaults to `createCaseTarget({ workflow,
|
|
122
|
+
* rootDir, onEvent, sandboxRuntime, modelFactory })`.
|
|
123
|
+
*
|
|
124
|
+
* A host that assembles its own workflow agent supplies it here rather than
|
|
125
|
+
* describing it through options; the case protocol stays the runtime's, the
|
|
126
|
+
* agent stays the caller's. A supplied target owns its whole assembly, which
|
|
127
|
+
* includes the mocks: a case that declares `mocks:` against a target without
|
|
128
|
+
* the tool-mock middleware is refused before the agent runs (see
|
|
129
|
+
* `toolMocks`). In the factory form, `rootDir` is the
|
|
130
|
+
* *resolved* workspace root.
|
|
131
|
+
*/
|
|
132
|
+
createTarget?: GovernedAgent | ((ctx: {
|
|
133
|
+
workflow: string;
|
|
134
|
+
rootDir: string;
|
|
135
|
+
onEvent?: WorkflowEventHandler;
|
|
136
|
+
}) => Promise<GovernedAgent>);
|
|
137
|
+
/**
|
|
138
|
+
* Names the agent session a case runs on, given the case file's
|
|
139
|
+
* workspace-relative path. Defaults to `test-default-<runId>-<file>`. A case
|
|
140
|
+
* is one conversation on one session, which is what lets a host correlate a
|
|
141
|
+
* case's checkpoints, artifacts, and token usage with its own records — the
|
|
142
|
+
* chosen id is reported back on `CaseResult.sessionId`.
|
|
143
|
+
*/
|
|
144
|
+
sessionIdForCase?: (file: string) => string;
|
|
145
|
+
}
|
|
146
|
+
export interface CaseResult {
|
|
147
|
+
id: string;
|
|
148
|
+
/** The case's short label — what reporters print beside the verdict. */
|
|
149
|
+
title?: string;
|
|
150
|
+
description?: string;
|
|
151
|
+
/** The session the case ran on; absent when nothing ran (skipped, or unparseable). */
|
|
152
|
+
sessionId?: string;
|
|
153
|
+
verdict: CaseVerdict;
|
|
154
|
+
records: AssertionRecord[];
|
|
155
|
+
/** @deprecated Derived: `verdict.status === "skipped"`. Kept for one release. */
|
|
156
|
+
skipped?: boolean;
|
|
157
|
+
/** Why the case was skipped (`verdict.status === "skipped"`). */
|
|
158
|
+
skipReason?: string;
|
|
159
|
+
/** The terminating error of a case that died rather than halted. */
|
|
160
|
+
error?: string;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Why a suite ran no cases although its workflow loaded: `disabled` means the
|
|
164
|
+
* workflow declares itself out of service — "not run" rather than "nothing to run".
|
|
165
|
+
*/
|
|
166
|
+
export type SuiteSkip = "disabled";
|
|
167
|
+
export interface RunTestsResult {
|
|
168
|
+
results: CaseResult[];
|
|
169
|
+
exitCode: number;
|
|
170
|
+
/** How many case files the suite holds, before `filter` — so a filter that matched nothing can say so. */
|
|
171
|
+
discovered: number;
|
|
172
|
+
/** Set when the suite was skipped rather than run (see {@link SuiteSkip}). */
|
|
173
|
+
skipped?: SuiteSkip;
|
|
174
|
+
}
|
|
175
|
+
/** One discovered case file: parsed, or the parse error that failed it. */
|
|
176
|
+
export interface DiscoveredCase {
|
|
177
|
+
file: string;
|
|
178
|
+
doc?: CaseDocument;
|
|
179
|
+
parseError?: string;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Find and parse a suite's case files. Every file is parsed up front so a suite
|
|
183
|
+
* never half-runs against an unreadable file: a schema violation becomes that
|
|
184
|
+
* case's failed result rather than a thrown error.
|
|
185
|
+
*/
|
|
186
|
+
export declare function discoverCases(authoring: Workspace, testsDir: string): Promise<DiscoveredCase[]>;
|
|
187
|
+
export interface RunCaseOptions {
|
|
188
|
+
discovered: DiscoveredCase;
|
|
189
|
+
agent: GovernedAgent;
|
|
190
|
+
authoring: Workspace;
|
|
191
|
+
testsDir: string;
|
|
192
|
+
/** The agent session this case runs its conversation on. */
|
|
193
|
+
sessionId: string;
|
|
194
|
+
grade?: GradeFn;
|
|
195
|
+
caseTimeoutMs?: number;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Drive one case against the agent under test and settle its result. Never
|
|
199
|
+
* throws for a case's own failure — a died case reports its terminating error
|
|
200
|
+
* first, then whatever its already-evaluated records had missed, then the
|
|
201
|
+
* steps that never ran as `not-executed`.
|
|
202
|
+
*/
|
|
203
|
+
export declare function runCase(opts: RunCaseOptions): Promise<CaseResult>;
|
|
204
|
+
/** Discover and run a workflow's cases. */
|
|
205
|
+
export declare function runTests(opts: RunTestsOptions): Promise<RunTestsResult>;
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { createCaseTarget } from "./target.js";
|
|
2
|
+
import { resolveWorkspaceRoot } from "../env.js";
|
|
3
|
+
import { createWorkspaceContext } from "../core/workspace-context.js";
|
|
4
|
+
import { Workspace } from "../core/workspace.js";
|
|
5
|
+
import { workflowPaths } from "../workflow/paths.js";
|
|
6
|
+
import { loadMachineSpec } from "../machine/load-spec.js";
|
|
7
|
+
import { specDisabled } from "../machine/types.js";
|
|
8
|
+
import { createJudgeModel, gradeClosedQA } from "./grade.js";
|
|
9
|
+
import { CaseSchemaError, normalizeFixturePath, parseCaseDocument, } from "./case-schema.js";
|
|
10
|
+
import { listCaseFiles } from "./discovery.js";
|
|
11
|
+
import { executeCase, notExecutedRecords } from "./interpreter.js";
|
|
12
|
+
/**
|
|
13
|
+
* Reduce recorded assertions to a verdict. Every failed record fails its case —
|
|
14
|
+
* there is no severity tier that records a failure without failing. A `grade`
|
|
15
|
+
* miss reads as a failure like any other, with its score beside the bar it
|
|
16
|
+
* missed. Every branch keys off `status`: with `not-executed` records present,
|
|
17
|
+
* "did not pass" and "failed" are different things.
|
|
18
|
+
*/
|
|
19
|
+
export function reduceVerdict(records) {
|
|
20
|
+
const failures = [];
|
|
21
|
+
for (const r of records) {
|
|
22
|
+
if (r.status !== "failed")
|
|
23
|
+
continue;
|
|
24
|
+
const label = r.detail ? `${r.kind}: ${r.detail}` : r.kind;
|
|
25
|
+
failures.push(r.threshold != null ? `${label} (score ${r.score ?? 0} < ${r.threshold})` : label);
|
|
26
|
+
}
|
|
27
|
+
return failures.length > 0 ? { status: "failed", failures } : { status: "passed", failures: [] };
|
|
28
|
+
}
|
|
29
|
+
/** Map a verdict to a process exit code. */
|
|
30
|
+
export function exitCodeForVerdict(verdict) {
|
|
31
|
+
return verdict.status === "failed" ? 1 : 0;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The one contract a case target must satisfy, wherever it came from. Cases
|
|
35
|
+
* drive the agent through the workflow graph (and may resume human states), so
|
|
36
|
+
* the target must be workflow-governed. Both the default target builder and
|
|
37
|
+
* `runTests` enforce this, so a caller-supplied target is refused on the same
|
|
38
|
+
* terms as one the SDK built.
|
|
39
|
+
*/
|
|
40
|
+
export function assertWorkflowGovernedTarget(agent, workflow) {
|
|
41
|
+
if (!agent.workflow) {
|
|
42
|
+
throw new Error(`Case target '${workflow}' has no workflow machine; cases require a workflow-governed agent.`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const DEFAULT_CASE_TIMEOUT_MS = 120_000;
|
|
46
|
+
/**
|
|
47
|
+
* Find and parse a suite's case files. Every file is parsed up front so a suite
|
|
48
|
+
* never half-runs against an unreadable file: a schema violation becomes that
|
|
49
|
+
* case's failed result rather than a thrown error.
|
|
50
|
+
*/
|
|
51
|
+
export async function discoverCases(authoring, testsDir) {
|
|
52
|
+
const discovered = [];
|
|
53
|
+
for (const file of await listCaseFiles(authoring, testsDir)) {
|
|
54
|
+
const source = await authoring.readText(file);
|
|
55
|
+
if (source == null) {
|
|
56
|
+
discovered.push({ file, parseError: `missing test file '${file}'` });
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
discovered.push({ file, doc: parseCaseDocument(file, source, testsDir) });
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
if (!(err instanceof CaseSchemaError))
|
|
64
|
+
throw err;
|
|
65
|
+
discovered.push({ file, parseError: err.message });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return discovered;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Reject when a case's execution exceeds its wall-clock budget, and abort the
|
|
72
|
+
* run behind it: a timed-out case that kept executing would go on spending
|
|
73
|
+
* tokens and emitting events under the next case's rendering.
|
|
74
|
+
*/
|
|
75
|
+
async function withTimeout(work, ms, label, onTimeout) {
|
|
76
|
+
let timer;
|
|
77
|
+
try {
|
|
78
|
+
return await Promise.race([
|
|
79
|
+
work,
|
|
80
|
+
new Promise((_, reject) => {
|
|
81
|
+
timer = setTimeout(() => {
|
|
82
|
+
onTimeout();
|
|
83
|
+
reject(new Error(`${label} timed out after ${ms}ms (tests.caseTimeoutMs)`));
|
|
84
|
+
}, ms);
|
|
85
|
+
}),
|
|
86
|
+
]);
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
clearTimeout(timer);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Materialize a case's seed files: inline workspace entries pass through
|
|
94
|
+
* (strings verbatim, non-strings JSON-serialized by the seed handle) and
|
|
95
|
+
* `from:` references are read from the tests directory. A missing fixture or
|
|
96
|
+
* an escaping path fails here — before any step runs.
|
|
97
|
+
*/
|
|
98
|
+
async function materializeSeeds(authoring, testsDir, doc) {
|
|
99
|
+
const seeds = {};
|
|
100
|
+
for (const [path, entry] of Object.entries(doc.workspace)) {
|
|
101
|
+
if (entry.source === "inline") {
|
|
102
|
+
seeds[path] = entry.content;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const fixture = normalizeFixturePath(entry.from, doc.file);
|
|
106
|
+
const content = await authoring.readText(`${testsDir}/${fixture}`);
|
|
107
|
+
if (content == null) {
|
|
108
|
+
throw new Error(`workspace entry '${path}' references 'from: ${entry.from}', but '${testsDir}/${fixture}' does not exist`);
|
|
109
|
+
}
|
|
110
|
+
seeds[path] = content;
|
|
111
|
+
}
|
|
112
|
+
return seeds;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Drive one case against the agent under test and settle its result. Never
|
|
116
|
+
* throws for a case's own failure — a died case reports its terminating error
|
|
117
|
+
* first, then whatever its already-evaluated records had missed, then the
|
|
118
|
+
* steps that never ran as `not-executed`.
|
|
119
|
+
*/
|
|
120
|
+
export async function runCase(opts) {
|
|
121
|
+
const { discovered, agent, authoring, testsDir, sessionId } = opts;
|
|
122
|
+
if (discovered.parseError !== undefined) {
|
|
123
|
+
return {
|
|
124
|
+
id: discovered.file,
|
|
125
|
+
verdict: { status: "failed", failures: [discovered.parseError] },
|
|
126
|
+
records: [],
|
|
127
|
+
error: discovered.parseError,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const doc = discovered.doc;
|
|
131
|
+
const head = { id: doc.id, title: doc.title, description: doc.description };
|
|
132
|
+
if (doc.skip !== undefined) {
|
|
133
|
+
return {
|
|
134
|
+
...head,
|
|
135
|
+
verdict: { status: "skipped", failures: [] },
|
|
136
|
+
records: [],
|
|
137
|
+
skipped: true,
|
|
138
|
+
skipReason: doc.skip,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
// Every record the case produces lands here as it is produced, and this is
|
|
142
|
+
// the only source the result reads — so the timeout path (which lets go of
|
|
143
|
+
// the `executeCase` promise) still reports what the case established.
|
|
144
|
+
const produced = [];
|
|
145
|
+
const failed = (message) => {
|
|
146
|
+
const recorded = new Set(produced.map((r) => r.step));
|
|
147
|
+
const records = [...produced, ...notExecutedRecords(doc, (step) => recorded.has(step))];
|
|
148
|
+
return {
|
|
149
|
+
...head,
|
|
150
|
+
sessionId,
|
|
151
|
+
verdict: { status: "failed", failures: [message, ...reduceVerdict(records).failures] },
|
|
152
|
+
records,
|
|
153
|
+
error: message,
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
const controller = new AbortController();
|
|
157
|
+
try {
|
|
158
|
+
const seeds = await materializeSeeds(authoring, testsDir, doc);
|
|
159
|
+
const outcome = await withTimeout(executeCase({
|
|
160
|
+
doc,
|
|
161
|
+
seeds,
|
|
162
|
+
agent,
|
|
163
|
+
sessionId,
|
|
164
|
+
signal: controller.signal,
|
|
165
|
+
onRecord: (record) => produced.push(record),
|
|
166
|
+
...(opts.grade ? { grade: opts.grade } : {}),
|
|
167
|
+
}), opts.caseTimeoutMs ?? DEFAULT_CASE_TIMEOUT_MS, `case '${doc.id}'`, () => controller.abort(new Error(`case '${doc.id}' timed out`)));
|
|
168
|
+
if (outcome.error !== undefined)
|
|
169
|
+
return failed(outcome.error);
|
|
170
|
+
return { ...head, sessionId, verdict: reduceVerdict(produced), records: [...produced] };
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
return failed(err.message);
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
// Hermetic by session isolation: each case drives its own session, so its
|
|
177
|
+
// `scratchpad/…` files resolve per session — no cleanup between files.
|
|
178
|
+
agent.dispose(sessionId);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** Discover and run a workflow's cases. */
|
|
182
|
+
export async function runTests(opts) {
|
|
183
|
+
const { workflow, filter } = opts;
|
|
184
|
+
const paths = workflowPaths(workflow);
|
|
185
|
+
const { testsDir } = paths;
|
|
186
|
+
// Every file this function reads — the spec, the suite config, the case
|
|
187
|
+
// documents, their `from:` fixtures — lives on the authoring backend under
|
|
188
|
+
// `workflows/<slug>/`. The agent driven by a case reaches none of it.
|
|
189
|
+
// Without `authoring` only a root is given, so one is always resolved
|
|
190
|
+
// (explicit, or the documented zero-config cwd) and the authoring plane is the
|
|
191
|
+
// filesystem under it. With `authoring` the whole context is skipped rather
|
|
192
|
+
// than built and half-used: its other members — the mount table, the session
|
|
193
|
+
// store — are the agent's, and the agent here is the host's own target. A
|
|
194
|
+
// host whose authored tree is a store would otherwise have to invent a local
|
|
195
|
+
// `rootDir` for filesystem defaults nothing reads.
|
|
196
|
+
const filesystem = opts.authoring === undefined ? createWorkspaceContext({ rootDir: opts.rootDir }) : undefined;
|
|
197
|
+
const authoring = opts.authoring !== undefined ? new Workspace(opts.authoring) : filesystem.authoring;
|
|
198
|
+
// Only the default target builder reads this; a host supplying `authoring`
|
|
199
|
+
// supplies its target too, so the cwd fallback here is never what runs.
|
|
200
|
+
const workspaceRoot = filesystem?.rootDir ?? resolveWorkspaceRoot(opts.rootDir);
|
|
201
|
+
// Suite configuration is declarative data in the spec (`tests:` block).
|
|
202
|
+
const { spec } = await loadMachineSpec(authoring, paths);
|
|
203
|
+
const config = spec?.tests ?? {};
|
|
204
|
+
// A disabled workflow runs nothing — including here. Skipped rather than
|
|
205
|
+
// failed, with a zero exit code: retiring a workflow must not turn CI red.
|
|
206
|
+
if (specDisabled(spec))
|
|
207
|
+
return { results: [], exitCode: 0, discovered: 0, skipped: "disabled" };
|
|
208
|
+
// Case concurrency is not implemented; a declared `maxConcurrency` above 1
|
|
209
|
+
// fails loudly rather than being accepted and then silently run sequentially.
|
|
210
|
+
if ((config.maxConcurrency ?? 1) > 1) {
|
|
211
|
+
throw new Error(`'tests.maxConcurrency' is ${config.maxConcurrency}, but case concurrency is not ` +
|
|
212
|
+
`implemented — cases run sequentially. Set it to 1 or remove the field.`);
|
|
213
|
+
}
|
|
214
|
+
const all = await discoverCases(authoring, testsDir);
|
|
215
|
+
const selected = filter ? all.filter((c) => c.file.includes(filter)) : all;
|
|
216
|
+
// Nothing to run — say so before assembling an agent (and before needing a
|
|
217
|
+
// model at all); the caller decides whether an empty selection is an error.
|
|
218
|
+
if (selected.length === 0)
|
|
219
|
+
return { results: [], exitCode: 0, discovered: all.length };
|
|
220
|
+
const agent = typeof opts.createTarget === "function"
|
|
221
|
+
? await opts.createTarget({
|
|
222
|
+
workflow,
|
|
223
|
+
rootDir: workspaceRoot,
|
|
224
|
+
...(opts.onEvent ? { onEvent: opts.onEvent } : {}),
|
|
225
|
+
})
|
|
226
|
+
: (opts.createTarget ??
|
|
227
|
+
(await createCaseTarget({
|
|
228
|
+
workflow,
|
|
229
|
+
rootDir: workspaceRoot,
|
|
230
|
+
onEvent: opts.onEvent,
|
|
231
|
+
...(opts.sandboxRuntime ? { sandboxRuntime: opts.sandboxRuntime } : {}),
|
|
232
|
+
...(opts.modelFactory ? { modelFactory: opts.modelFactory } : {}),
|
|
233
|
+
})));
|
|
234
|
+
// Re-checked here rather than trusted from the builder: a caller-supplied
|
|
235
|
+
// target has passed through no such gate, and a misconfigured host should
|
|
236
|
+
// fail on its first move instead of midway through a suite.
|
|
237
|
+
assertWorkflowGovernedTarget(agent, workflow);
|
|
238
|
+
// The grading model is wired only when the spec declares one; a `grade:`
|
|
239
|
+
// step without it records an actionable failure.
|
|
240
|
+
let grade;
|
|
241
|
+
if (config.judge !== undefined) {
|
|
242
|
+
const model = createJudgeModel(config, opts.modelFactory);
|
|
243
|
+
grade = (criteria, evidence) => gradeClosedQA(model, criteria, evidence);
|
|
244
|
+
}
|
|
245
|
+
const runId = `test-run-${Date.now()}`;
|
|
246
|
+
const results = [];
|
|
247
|
+
for (const discovered of selected) {
|
|
248
|
+
const sessionId = opts.sessionIdForCase?.(discovered.file) ??
|
|
249
|
+
`test-default-${runId}-${discovered.file.replace(/\//g, "-")}`;
|
|
250
|
+
opts.onCaseStart?.(discovered.file, sessionId);
|
|
251
|
+
const result = await runCase({
|
|
252
|
+
discovered,
|
|
253
|
+
agent,
|
|
254
|
+
authoring,
|
|
255
|
+
testsDir,
|
|
256
|
+
sessionId,
|
|
257
|
+
...(grade ? { grade } : {}),
|
|
258
|
+
...(config.caseTimeoutMs !== undefined ? { caseTimeoutMs: config.caseTimeoutMs } : {}),
|
|
259
|
+
});
|
|
260
|
+
results.push(result);
|
|
261
|
+
opts.onCaseResult?.(result);
|
|
262
|
+
}
|
|
263
|
+
const exitCode = results.some((r) => exitCodeForVerdict(r.verdict) !== 0) ? 1 : 0;
|
|
264
|
+
return { results, exitCode, discovered: all.length };
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/testing/runner.ts"],"names":[],"mappings":"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"}
|