@prismatic-io/lux 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/lib/answerers/claude-code/index.d.ts +17 -0
- package/lib/answerers/claude-code/index.d.ts.map +1 -0
- package/lib/answerers/claude-code/index.js +280 -0
- package/lib/answerers/claude-code/index.js.map +1 -0
- package/lib/answerers/persona/index.d.ts +40 -0
- package/lib/answerers/persona/index.d.ts.map +1 -0
- package/lib/answerers/persona/index.js +265 -0
- package/lib/answerers/persona/index.js.map +1 -0
- package/lib/answerers/scripted/index.d.ts +8 -0
- package/lib/answerers/scripted/index.d.ts.map +1 -0
- package/lib/answerers/scripted/index.js +163 -0
- package/lib/answerers/scripted/index.js.map +1 -0
- package/lib/answerers/shared.d.ts +13 -0
- package/lib/answerers/shared.d.ts.map +1 -0
- package/lib/answerers/shared.js +17 -0
- package/lib/answerers/shared.js.map +1 -0
- package/lib/answerers/terminal/index.d.ts +9 -0
- package/lib/answerers/terminal/index.d.ts.map +1 -0
- package/lib/answerers/terminal/index.js +97 -0
- package/lib/answerers/terminal/index.js.map +1 -0
- package/lib/assertions/core/command-exits-zero.d.ts +21 -0
- package/lib/assertions/core/command-exits-zero.d.ts.map +1 -0
- package/lib/assertions/core/command-exits-zero.js +87 -0
- package/lib/assertions/core/command-exits-zero.js.map +1 -0
- package/lib/assertions/core/event-checks.d.ts +57 -0
- package/lib/assertions/core/event-checks.d.ts.map +1 -0
- package/lib/assertions/core/event-checks.js +123 -0
- package/lib/assertions/core/event-checks.js.map +1 -0
- package/lib/assertions/core/file-checks.d.ts +103 -0
- package/lib/assertions/core/file-checks.d.ts.map +1 -0
- package/lib/assertions/core/file-checks.js +288 -0
- package/lib/assertions/core/file-checks.js.map +1 -0
- package/lib/assertions/core/helpers.d.ts +66 -0
- package/lib/assertions/core/helpers.d.ts.map +1 -0
- package/lib/assertions/core/helpers.js +170 -0
- package/lib/assertions/core/helpers.js.map +1 -0
- package/lib/assertions/core/index.d.ts +15 -0
- package/lib/assertions/core/index.d.ts.map +1 -0
- package/lib/assertions/core/index.js +56 -0
- package/lib/assertions/core/index.js.map +1 -0
- package/lib/assertions/core/json-pointer-equals.d.ts +19 -0
- package/lib/assertions/core/json-pointer-equals.d.ts.map +1 -0
- package/lib/assertions/core/json-pointer-equals.js +71 -0
- package/lib/assertions/core/json-pointer-equals.js.map +1 -0
- package/lib/assertions/core/output-checks.d.ts +46 -0
- package/lib/assertions/core/output-checks.d.ts.map +1 -0
- package/lib/assertions/core/output-checks.js +121 -0
- package/lib/assertions/core/output-checks.js.map +1 -0
- package/lib/assertions/core/predicate.d.ts +14 -0
- package/lib/assertions/core/predicate.d.ts.map +1 -0
- package/lib/assertions/core/predicate.js +55 -0
- package/lib/assertions/core/predicate.js.map +1 -0
- package/lib/assertions/core/resource-checks.d.ts +71 -0
- package/lib/assertions/core/resource-checks.d.ts.map +1 -0
- package/lib/assertions/core/resource-checks.js +159 -0
- package/lib/assertions/core/resource-checks.js.map +1 -0
- package/lib/assertions/core/safe-regex.d.ts +23 -0
- package/lib/assertions/core/safe-regex.d.ts.map +1 -0
- package/lib/assertions/core/safe-regex.js +102 -0
- package/lib/assertions/core/safe-regex.js.map +1 -0
- package/lib/assertions/core/tool-called-with.d.ts +21 -0
- package/lib/assertions/core/tool-called-with.d.ts.map +1 -0
- package/lib/assertions/core/tool-called-with.js +69 -0
- package/lib/assertions/core/tool-called-with.js.map +1 -0
- package/lib/assertions/core/tool-calls.d.ts +22 -0
- package/lib/assertions/core/tool-calls.d.ts.map +1 -0
- package/lib/assertions/core/tool-calls.js +17 -0
- package/lib/assertions/core/tool-calls.js.map +1 -0
- package/lib/assertions/core/tool-invocation.d.ts +36 -0
- package/lib/assertions/core/tool-invocation.d.ts.map +1 -0
- package/lib/assertions/core/tool-invocation.js +170 -0
- package/lib/assertions/core/tool-invocation.js.map +1 -0
- package/lib/assertions/core/tool-result-checks.d.ts +59 -0
- package/lib/assertions/core/tool-result-checks.d.ts.map +1 -0
- package/lib/assertions/core/tool-result-checks.js +193 -0
- package/lib/assertions/core/tool-result-checks.js.map +1 -0
- package/lib/assertions/mcp/discovery-checks.d.ts +36 -0
- package/lib/assertions/mcp/discovery-checks.d.ts.map +1 -0
- package/lib/assertions/mcp/discovery-checks.js +122 -0
- package/lib/assertions/mcp/discovery-checks.js.map +1 -0
- package/lib/assertions/mcp/index.d.ts +10 -0
- package/lib/assertions/mcp/index.d.ts.map +1 -0
- package/lib/assertions/mcp/index.js +25 -0
- package/lib/assertions/mcp/index.js.map +1 -0
- package/lib/assertions/rubric/index.d.ts +104 -0
- package/lib/assertions/rubric/index.d.ts.map +1 -0
- package/lib/assertions/rubric/index.js +191 -0
- package/lib/assertions/rubric/index.js.map +1 -0
- package/lib/assertions/rubric/internal.d.ts +14 -0
- package/lib/assertions/rubric/internal.d.ts.map +1 -0
- package/lib/assertions/rubric/internal.js +335 -0
- package/lib/assertions/rubric/internal.js.map +1 -0
- package/lib/authoring.d.ts +3 -0
- package/lib/authoring.d.ts.map +1 -0
- package/lib/authoring.js +3 -0
- package/lib/authoring.js.map +1 -0
- package/lib/cli/bin.d.ts +3 -0
- package/lib/cli/bin.d.ts.map +1 -0
- package/lib/cli/bin.js +15 -0
- package/lib/cli/bin.js.map +1 -0
- package/lib/cli/command-runtime.d.ts +5 -0
- package/lib/cli/command-runtime.d.ts.map +1 -0
- package/lib/cli/command-runtime.js +30 -0
- package/lib/cli/command-runtime.js.map +1 -0
- package/lib/cli/init.d.ts +21 -0
- package/lib/cli/init.d.ts.map +1 -0
- package/lib/cli/init.js +340 -0
- package/lib/cli/init.js.map +1 -0
- package/lib/cli/program.d.ts +22 -0
- package/lib/cli/program.d.ts.map +1 -0
- package/lib/cli/program.js +757 -0
- package/lib/cli/program.js.map +1 -0
- package/lib/cli/render/format.d.ts +14 -0
- package/lib/cli/render/format.d.ts.map +1 -0
- package/lib/cli/render/format.js +71 -0
- package/lib/cli/render/format.js.map +1 -0
- package/lib/cli/render/reporter.d.ts +73 -0
- package/lib/cli/render/reporter.d.ts.map +1 -0
- package/lib/cli/render/reporter.js +519 -0
- package/lib/cli/render/reporter.js.map +1 -0
- package/lib/cli/render/tty.d.ts +77 -0
- package/lib/cli/render/tty.d.ts.map +1 -0
- package/lib/cli/render/tty.js +283 -0
- package/lib/cli/render/tty.js.map +1 -0
- package/lib/cli/run-options.d.ts +27 -0
- package/lib/cli/run-options.d.ts.map +1 -0
- package/lib/cli/run-options.js +58 -0
- package/lib/cli/run-options.js.map +1 -0
- package/lib/cli/skills.d.ts +38 -0
- package/lib/cli/skills.d.ts.map +1 -0
- package/lib/cli/skills.js +84 -0
- package/lib/cli/skills.js.map +1 -0
- package/lib/core/annotation.d.ts +56 -0
- package/lib/core/annotation.d.ts.map +1 -0
- package/lib/core/annotation.js +92 -0
- package/lib/core/annotation.js.map +1 -0
- package/lib/core/answerer.d.ts +68 -0
- package/lib/core/answerer.d.ts.map +1 -0
- package/lib/core/answerer.js +17 -0
- package/lib/core/answerer.js.map +1 -0
- package/lib/core/artifact-evidence.d.ts +50 -0
- package/lib/core/artifact-evidence.d.ts.map +1 -0
- package/lib/core/artifact-evidence.js +185 -0
- package/lib/core/artifact-evidence.js.map +1 -0
- package/lib/core/artifact-snapshot.d.ts +37 -0
- package/lib/core/artifact-snapshot.d.ts.map +1 -0
- package/lib/core/artifact-snapshot.js +339 -0
- package/lib/core/artifact-snapshot.js.map +1 -0
- package/lib/core/assertion.d.ts +129 -0
- package/lib/core/assertion.d.ts.map +1 -0
- package/lib/core/assertion.js +75 -0
- package/lib/core/assertion.js.map +1 -0
- package/lib/core/case.d.ts +79 -0
- package/lib/core/case.d.ts.map +1 -0
- package/lib/core/case.js +90 -0
- package/lib/core/case.js.map +1 -0
- package/lib/core/conversation-turn.d.ts +23 -0
- package/lib/core/conversation-turn.d.ts.map +1 -0
- package/lib/core/conversation-turn.js +31 -0
- package/lib/core/conversation-turn.js.map +1 -0
- package/lib/core/driver.d.ts +64 -0
- package/lib/core/driver.d.ts.map +1 -0
- package/lib/core/driver.js +18 -0
- package/lib/core/driver.js.map +1 -0
- package/lib/core/emitter.d.ts +20 -0
- package/lib/core/emitter.d.ts.map +1 -0
- package/lib/core/emitter.js +34 -0
- package/lib/core/emitter.js.map +1 -0
- package/lib/core/events.d.ts +202 -0
- package/lib/core/events.d.ts.map +1 -0
- package/lib/core/events.js +107 -0
- package/lib/core/events.js.map +1 -0
- package/lib/core/exec.d.ts +82 -0
- package/lib/core/exec.d.ts.map +1 -0
- package/lib/core/exec.js +168 -0
- package/lib/core/exec.js.map +1 -0
- package/lib/core/experiment.d.ts +285 -0
- package/lib/core/experiment.d.ts.map +1 -0
- package/lib/core/experiment.js +389 -0
- package/lib/core/experiment.js.map +1 -0
- package/lib/core/glob.d.ts +3 -0
- package/lib/core/glob.d.ts.map +1 -0
- package/lib/core/glob.js +32 -0
- package/lib/core/glob.js.map +1 -0
- package/lib/core/hash.d.ts +8 -0
- package/lib/core/hash.d.ts.map +1 -0
- package/lib/core/hash.js +214 -0
- package/lib/core/hash.js.map +1 -0
- package/lib/core/index.d.ts +29 -0
- package/lib/core/index.d.ts.map +1 -0
- package/lib/core/index.js +29 -0
- package/lib/core/index.js.map +1 -0
- package/lib/core/lifecycle-fixtures.d.ts +20 -0
- package/lib/core/lifecycle-fixtures.d.ts.map +1 -0
- package/lib/core/lifecycle-fixtures.js +109 -0
- package/lib/core/lifecycle-fixtures.js.map +1 -0
- package/lib/core/lifecycle-hooks.d.ts +52 -0
- package/lib/core/lifecycle-hooks.d.ts.map +1 -0
- package/lib/core/lifecycle-hooks.js +42 -0
- package/lib/core/lifecycle-hooks.js.map +1 -0
- package/lib/core/mcp-events.d.ts +44 -0
- package/lib/core/mcp-events.d.ts.map +1 -0
- package/lib/core/mcp-events.js +23 -0
- package/lib/core/mcp-events.js.map +1 -0
- package/lib/core/model-cli.d.ts +57 -0
- package/lib/core/model-cli.d.ts.map +1 -0
- package/lib/core/model-cli.js +237 -0
- package/lib/core/model-cli.js.map +1 -0
- package/lib/core/observer.d.ts +31 -0
- package/lib/core/observer.d.ts.map +1 -0
- package/lib/core/observer.js +25 -0
- package/lib/core/observer.js.map +1 -0
- package/lib/core/platform-process.d.ts +33 -0
- package/lib/core/platform-process.d.ts.map +1 -0
- package/lib/core/platform-process.js +214 -0
- package/lib/core/platform-process.js.map +1 -0
- package/lib/core/registry.d.ts +22 -0
- package/lib/core/registry.d.ts.map +1 -0
- package/lib/core/registry.js +45 -0
- package/lib/core/registry.js.map +1 -0
- package/lib/core/rubric.d.ts +18 -0
- package/lib/core/rubric.d.ts.map +1 -0
- package/lib/core/rubric.js +49 -0
- package/lib/core/rubric.js.map +1 -0
- package/lib/core/run.d.ts +419 -0
- package/lib/core/run.d.ts.map +1 -0
- package/lib/core/run.js +126 -0
- package/lib/core/run.js.map +1 -0
- package/lib/core/statistics.d.ts +39 -0
- package/lib/core/statistics.d.ts.map +1 -0
- package/lib/core/statistics.js +163 -0
- package/lib/core/statistics.js.map +1 -0
- package/lib/core/subject.d.ts +4 -0
- package/lib/core/subject.d.ts.map +1 -0
- package/lib/core/subject.js +46 -0
- package/lib/core/subject.js.map +1 -0
- package/lib/core/tool-events.d.ts +69 -0
- package/lib/core/tool-events.d.ts.map +1 -0
- package/lib/core/tool-events.js +242 -0
- package/lib/core/tool-events.js.map +1 -0
- package/lib/core/usage.d.ts +78 -0
- package/lib/core/usage.d.ts.map +1 -0
- package/lib/core/usage.js +104 -0
- package/lib/core/usage.js.map +1 -0
- package/lib/core/wire.d.ts +83 -0
- package/lib/core/wire.d.ts.map +1 -0
- package/lib/core/wire.js +101 -0
- package/lib/core/wire.js.map +1 -0
- package/lib/core/zod.d.ts +10 -0
- package/lib/core/zod.d.ts.map +1 -0
- package/lib/core/zod.js +18 -0
- package/lib/core/zod.js.map +1 -0
- package/lib/drivers/claude-code/index.d.ts +55 -0
- package/lib/drivers/claude-code/index.d.ts.map +1 -0
- package/lib/drivers/claude-code/index.js +779 -0
- package/lib/drivers/claude-code/index.js.map +1 -0
- package/lib/drivers/claude-code/parse-events.d.ts +46 -0
- package/lib/drivers/claude-code/parse-events.d.ts.map +1 -0
- package/lib/drivers/claude-code/parse-events.js +387 -0
- package/lib/drivers/claude-code/parse-events.js.map +1 -0
- package/lib/drivers/codex/app-events.d.ts +16 -0
- package/lib/drivers/codex/app-events.d.ts.map +1 -0
- package/lib/drivers/codex/app-events.js +184 -0
- package/lib/drivers/codex/app-events.js.map +1 -0
- package/lib/drivers/codex/config.d.ts +55 -0
- package/lib/drivers/codex/config.d.ts.map +1 -0
- package/lib/drivers/codex/config.js +125 -0
- package/lib/drivers/codex/config.js.map +1 -0
- package/lib/drivers/codex/index.d.ts +8 -0
- package/lib/drivers/codex/index.d.ts.map +1 -0
- package/lib/drivers/codex/index.js +904 -0
- package/lib/drivers/codex/index.js.map +1 -0
- package/lib/drivers/mcp/index.d.ts +52 -0
- package/lib/drivers/mcp/index.d.ts.map +1 -0
- package/lib/drivers/mcp/index.js +282 -0
- package/lib/drivers/mcp/index.js.map +1 -0
- package/lib/drivers/mcp/transport.d.ts +50 -0
- package/lib/drivers/mcp/transport.d.ts.map +1 -0
- package/lib/drivers/mcp/transport.js +190 -0
- package/lib/drivers/mcp/transport.js.map +1 -0
- package/lib/drivers/shared/artifacts.d.ts +4 -0
- package/lib/drivers/shared/artifacts.d.ts.map +1 -0
- package/lib/drivers/shared/artifacts.js +81 -0
- package/lib/drivers/shared/artifacts.js.map +1 -0
- package/lib/drivers/shared/secure-copy.d.ts +2 -0
- package/lib/drivers/shared/secure-copy.d.ts.map +1 -0
- package/lib/drivers/shared/secure-copy.js +35 -0
- package/lib/drivers/shared/secure-copy.js.map +1 -0
- package/lib/drivers/subprocess/index.d.ts +24 -0
- package/lib/drivers/subprocess/index.d.ts.map +1 -0
- package/lib/drivers/subprocess/index.js +451 -0
- package/lib/drivers/subprocess/index.js.map +1 -0
- package/lib/index.d.ts +40 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +48 -0
- package/lib/index.js.map +1 -0
- package/lib/optimization/reflective.d.ts +27 -0
- package/lib/optimization/reflective.d.ts.map +1 -0
- package/lib/optimization/reflective.js +257 -0
- package/lib/optimization/reflective.js.map +1 -0
- package/lib/orchestrator/annotation-loader.d.ts +65 -0
- package/lib/orchestrator/annotation-loader.d.ts.map +1 -0
- package/lib/orchestrator/annotation-loader.js +73 -0
- package/lib/orchestrator/annotation-loader.js.map +1 -0
- package/lib/orchestrator/annotation-store.d.ts +3 -0
- package/lib/orchestrator/annotation-store.d.ts.map +1 -0
- package/lib/orchestrator/annotation-store.js +100 -0
- package/lib/orchestrator/annotation-store.js.map +1 -0
- package/lib/orchestrator/authored-dependencies.d.ts +3 -0
- package/lib/orchestrator/authored-dependencies.d.ts.map +1 -0
- package/lib/orchestrator/authored-dependencies.js +146 -0
- package/lib/orchestrator/authored-dependencies.js.map +1 -0
- package/lib/orchestrator/campaign-lifecycle.d.ts +105 -0
- package/lib/orchestrator/campaign-lifecycle.d.ts.map +1 -0
- package/lib/orchestrator/campaign-lifecycle.js +141 -0
- package/lib/orchestrator/campaign-lifecycle.js.map +1 -0
- package/lib/orchestrator/candidate-integrity.d.ts +4 -0
- package/lib/orchestrator/candidate-integrity.d.ts.map +1 -0
- package/lib/orchestrator/candidate-integrity.js +14 -0
- package/lib/orchestrator/candidate-integrity.js.map +1 -0
- package/lib/orchestrator/candidates.d.ts +13 -0
- package/lib/orchestrator/candidates.d.ts.map +1 -0
- package/lib/orchestrator/candidates.js +577 -0
- package/lib/orchestrator/candidates.js.map +1 -0
- package/lib/orchestrator/compare.d.ts +80 -0
- package/lib/orchestrator/compare.d.ts.map +1 -0
- package/lib/orchestrator/compare.js +270 -0
- package/lib/orchestrator/compare.js.map +1 -0
- package/lib/orchestrator/comparison-identity.d.ts +10 -0
- package/lib/orchestrator/comparison-identity.d.ts.map +1 -0
- package/lib/orchestrator/comparison-identity.js +39 -0
- package/lib/orchestrator/comparison-identity.js.map +1 -0
- package/lib/orchestrator/config.d.ts +121 -0
- package/lib/orchestrator/config.d.ts.map +1 -0
- package/lib/orchestrator/config.js +176 -0
- package/lib/orchestrator/config.js.map +1 -0
- package/lib/orchestrator/content-bound-json.d.ts +5 -0
- package/lib/orchestrator/content-bound-json.d.ts.map +1 -0
- package/lib/orchestrator/content-bound-json.js +59 -0
- package/lib/orchestrator/content-bound-json.js.map +1 -0
- package/lib/orchestrator/discover.d.ts +45 -0
- package/lib/orchestrator/discover.d.ts.map +1 -0
- package/lib/orchestrator/discover.js +98 -0
- package/lib/orchestrator/discover.js.map +1 -0
- package/lib/orchestrator/doctor.d.ts +141 -0
- package/lib/orchestrator/doctor.d.ts.map +1 -0
- package/lib/orchestrator/doctor.js +525 -0
- package/lib/orchestrator/doctor.js.map +1 -0
- package/lib/orchestrator/driver-session.d.ts +177 -0
- package/lib/orchestrator/driver-session.d.ts.map +1 -0
- package/lib/orchestrator/driver-session.js +396 -0
- package/lib/orchestrator/driver-session.js.map +1 -0
- package/lib/orchestrator/evaluator-identity.d.ts +7 -0
- package/lib/orchestrator/evaluator-identity.d.ts.map +1 -0
- package/lib/orchestrator/evaluator-identity.js +42 -0
- package/lib/orchestrator/evaluator-identity.js.map +1 -0
- package/lib/orchestrator/experiment-budget.d.ts +11 -0
- package/lib/orchestrator/experiment-budget.d.ts.map +1 -0
- package/lib/orchestrator/experiment-budget.js +51 -0
- package/lib/orchestrator/experiment-budget.js.map +1 -0
- package/lib/orchestrator/experiment-context.d.ts +43 -0
- package/lib/orchestrator/experiment-context.d.ts.map +1 -0
- package/lib/orchestrator/experiment-context.js +9 -0
- package/lib/orchestrator/experiment-context.js.map +1 -0
- package/lib/orchestrator/experiment-contracts.d.ts +290 -0
- package/lib/orchestrator/experiment-contracts.d.ts.map +1 -0
- package/lib/orchestrator/experiment-contracts.js +38 -0
- package/lib/orchestrator/experiment-contracts.js.map +1 -0
- package/lib/orchestrator/experiment-corpus.d.ts +21 -0
- package/lib/orchestrator/experiment-corpus.d.ts.map +1 -0
- package/lib/orchestrator/experiment-corpus.js +276 -0
- package/lib/orchestrator/experiment-corpus.js.map +1 -0
- package/lib/orchestrator/experiment-evaluation.d.ts +44 -0
- package/lib/orchestrator/experiment-evaluation.d.ts.map +1 -0
- package/lib/orchestrator/experiment-evaluation.js +542 -0
- package/lib/orchestrator/experiment-evaluation.js.map +1 -0
- package/lib/orchestrator/experiment-finish.d.ts +6 -0
- package/lib/orchestrator/experiment-finish.d.ts.map +1 -0
- package/lib/orchestrator/experiment-finish.js +19 -0
- package/lib/orchestrator/experiment-finish.js.map +1 -0
- package/lib/orchestrator/experiment-identity.d.ts +6 -0
- package/lib/orchestrator/experiment-identity.d.ts.map +1 -0
- package/lib/orchestrator/experiment-identity.js +257 -0
- package/lib/orchestrator/experiment-identity.js.map +1 -0
- package/lib/orchestrator/experiment-loader.d.ts +175 -0
- package/lib/orchestrator/experiment-loader.d.ts.map +1 -0
- package/lib/orchestrator/experiment-loader.js +77 -0
- package/lib/orchestrator/experiment-loader.js.map +1 -0
- package/lib/orchestrator/experiment-report.d.ts +450 -0
- package/lib/orchestrator/experiment-report.d.ts.map +1 -0
- package/lib/orchestrator/experiment-report.js +570 -0
- package/lib/orchestrator/experiment-report.js.map +1 -0
- package/lib/orchestrator/experiment-runs.d.ts +379 -0
- package/lib/orchestrator/experiment-runs.d.ts.map +1 -0
- package/lib/orchestrator/experiment-runs.js +796 -0
- package/lib/orchestrator/experiment-runs.js.map +1 -0
- package/lib/orchestrator/experiment-runtime-identity.d.ts +41 -0
- package/lib/orchestrator/experiment-runtime-identity.d.ts.map +1 -0
- package/lib/orchestrator/experiment-runtime-identity.js +411 -0
- package/lib/orchestrator/experiment-runtime-identity.js.map +1 -0
- package/lib/orchestrator/experiment-selection.d.ts +25 -0
- package/lib/orchestrator/experiment-selection.d.ts.map +1 -0
- package/lib/orchestrator/experiment-selection.js +286 -0
- package/lib/orchestrator/experiment-selection.js.map +1 -0
- package/lib/orchestrator/experiment.d.ts +11 -0
- package/lib/orchestrator/experiment.d.ts.map +1 -0
- package/lib/orchestrator/experiment.js +639 -0
- package/lib/orchestrator/experiment.js.map +1 -0
- package/lib/orchestrator/fixture-identity.d.ts +7 -0
- package/lib/orchestrator/fixture-identity.d.ts.map +1 -0
- package/lib/orchestrator/fixture-identity.js +55 -0
- package/lib/orchestrator/fixture-identity.js.map +1 -0
- package/lib/orchestrator/fs-read.d.ts +19 -0
- package/lib/orchestrator/fs-read.d.ts.map +1 -0
- package/lib/orchestrator/fs-read.js +113 -0
- package/lib/orchestrator/fs-read.js.map +1 -0
- package/lib/orchestrator/grader-experiment.d.ts +190 -0
- package/lib/orchestrator/grader-experiment.d.ts.map +1 -0
- package/lib/orchestrator/grader-experiment.js +579 -0
- package/lib/orchestrator/grader-experiment.js.map +1 -0
- package/lib/orchestrator/grading.d.ts +31 -0
- package/lib/orchestrator/grading.d.ts.map +1 -0
- package/lib/orchestrator/grading.js +186 -0
- package/lib/orchestrator/grading.js.map +1 -0
- package/lib/orchestrator/index.d.ts +22 -0
- package/lib/orchestrator/index.d.ts.map +1 -0
- package/lib/orchestrator/index.js +30 -0
- package/lib/orchestrator/index.js.map +1 -0
- package/lib/orchestrator/lifecycle-hook-execution.d.ts +4 -0
- package/lib/orchestrator/lifecycle-hook-execution.d.ts.map +1 -0
- package/lib/orchestrator/lifecycle-hook-execution.js +67 -0
- package/lib/orchestrator/lifecycle-hook-execution.js.map +1 -0
- package/lib/orchestrator/list-runs.d.ts +33 -0
- package/lib/orchestrator/list-runs.d.ts.map +1 -0
- package/lib/orchestrator/list-runs.js +308 -0
- package/lib/orchestrator/list-runs.js.map +1 -0
- package/lib/orchestrator/loader.d.ts +3 -0
- package/lib/orchestrator/loader.d.ts.map +1 -0
- package/lib/orchestrator/loader.js +17 -0
- package/lib/orchestrator/loader.js.map +1 -0
- package/lib/orchestrator/optimization-lifecycle.d.ts +12 -0
- package/lib/orchestrator/optimization-lifecycle.d.ts.map +1 -0
- package/lib/orchestrator/optimization-lifecycle.js +92 -0
- package/lib/orchestrator/optimization-lifecycle.js.map +1 -0
- package/lib/orchestrator/orchestrator.d.ts +144 -0
- package/lib/orchestrator/orchestrator.d.ts.map +1 -0
- package/lib/orchestrator/orchestrator.js +632 -0
- package/lib/orchestrator/orchestrator.js.map +1 -0
- package/lib/orchestrator/owned-lock.d.ts +17 -0
- package/lib/orchestrator/owned-lock.d.ts.map +1 -0
- package/lib/orchestrator/owned-lock.js +149 -0
- package/lib/orchestrator/owned-lock.js.map +1 -0
- package/lib/orchestrator/package-version.d.ts +2 -0
- package/lib/orchestrator/package-version.d.ts.map +1 -0
- package/lib/orchestrator/package-version.js +4 -0
- package/lib/orchestrator/package-version.js.map +1 -0
- package/lib/orchestrator/provenance.d.ts +5 -0
- package/lib/orchestrator/provenance.d.ts.map +1 -0
- package/lib/orchestrator/provenance.js +137 -0
- package/lib/orchestrator/provenance.js.map +1 -0
- package/lib/orchestrator/regrade.d.ts +80 -0
- package/lib/orchestrator/regrade.d.ts.map +1 -0
- package/lib/orchestrator/regrade.js +433 -0
- package/lib/orchestrator/regrade.js.map +1 -0
- package/lib/orchestrator/rubric-loader.d.ts +7 -0
- package/lib/orchestrator/rubric-loader.d.ts.map +1 -0
- package/lib/orchestrator/rubric-loader.js +65 -0
- package/lib/orchestrator/rubric-loader.js.map +1 -0
- package/lib/orchestrator/run-dir.d.ts +40 -0
- package/lib/orchestrator/run-dir.d.ts.map +1 -0
- package/lib/orchestrator/run-dir.js +161 -0
- package/lib/orchestrator/run-dir.js.map +1 -0
- package/lib/orchestrator/run-execution.d.ts +30 -0
- package/lib/orchestrator/run-execution.d.ts.map +1 -0
- package/lib/orchestrator/run-execution.js +531 -0
- package/lib/orchestrator/run-execution.js.map +1 -0
- package/lib/orchestrator/run-lifecycle.d.ts +115 -0
- package/lib/orchestrator/run-lifecycle.d.ts.map +1 -0
- package/lib/orchestrator/run-lifecycle.js +136 -0
- package/lib/orchestrator/run-lifecycle.js.map +1 -0
- package/lib/orchestrator/suite-compare.d.ts +76 -0
- package/lib/orchestrator/suite-compare.d.ts.map +1 -0
- package/lib/orchestrator/suite-compare.js +159 -0
- package/lib/orchestrator/suite-compare.js.map +1 -0
- package/lib/orchestrator/suite-lifecycle.d.ts +157 -0
- package/lib/orchestrator/suite-lifecycle.d.ts.map +1 -0
- package/lib/orchestrator/suite-lifecycle.js +253 -0
- package/lib/orchestrator/suite-lifecycle.js.map +1 -0
- package/lib/orchestrator/suite-runs.d.ts +91 -0
- package/lib/orchestrator/suite-runs.d.ts.map +1 -0
- package/lib/orchestrator/suite-runs.js +157 -0
- package/lib/orchestrator/suite-runs.js.map +1 -0
- package/lib/orchestrator/suite-summary.d.ts +109 -0
- package/lib/orchestrator/suite-summary.d.ts.map +1 -0
- package/lib/orchestrator/suite-summary.js +213 -0
- package/lib/orchestrator/suite-summary.js.map +1 -0
- package/lib/orchestrator/trace-limits.d.ts +20 -0
- package/lib/orchestrator/trace-limits.d.ts.map +1 -0
- package/lib/orchestrator/trace-limits.js +28 -0
- package/lib/orchestrator/trace-limits.js.map +1 -0
- package/lib/orchestrator/validate-plugin-config.d.ts +10 -0
- package/lib/orchestrator/validate-plugin-config.d.ts.map +1 -0
- package/lib/orchestrator/validate-plugin-config.js +26 -0
- package/lib/orchestrator/validate-plugin-config.js.map +1 -0
- package/package.json +84 -0
- package/skills/lux/SKILL.md +85 -0
- package/skills/lux/references/cli.md +102 -0
- package/skills/lux/references/eval-authoring.md +105 -0
- package/skills/lux-answerer/SKILL.md +169 -0
- package/src/answerers/claude-code/index.ts +342 -0
- package/src/answerers/persona/index.ts +327 -0
- package/src/answerers/scripted/index.ts +186 -0
- package/src/answerers/shared.ts +23 -0
- package/src/answerers/terminal/index.ts +117 -0
- package/src/assertions/core/command-exits-zero.ts +94 -0
- package/src/assertions/core/event-checks.ts +138 -0
- package/src/assertions/core/file-checks.ts +336 -0
- package/src/assertions/core/helpers.ts +203 -0
- package/src/assertions/core/index.ts +80 -0
- package/src/assertions/core/json-pointer-equals.ts +84 -0
- package/src/assertions/core/output-checks.ts +134 -0
- package/src/assertions/core/predicate.ts +67 -0
- package/src/assertions/core/resource-checks.ts +180 -0
- package/src/assertions/core/safe-regex.ts +196 -0
- package/src/assertions/core/tool-called-with.ts +68 -0
- package/src/assertions/core/tool-calls.ts +28 -0
- package/src/assertions/core/tool-invocation.ts +198 -0
- package/src/assertions/core/tool-result-checks.ts +211 -0
- package/src/assertions/mcp/discovery-checks.ts +139 -0
- package/src/assertions/mcp/index.ts +37 -0
- package/src/assertions/rubric/index.ts +258 -0
- package/src/assertions/rubric/internal.ts +367 -0
- package/src/authoring.ts +2 -0
- package/src/cli/bin.ts +14 -0
- package/src/cli/command-runtime.ts +34 -0
- package/src/cli/init.ts +410 -0
- package/src/cli/program.ts +992 -0
- package/src/cli/render/format.ts +69 -0
- package/src/cli/render/reporter.ts +643 -0
- package/src/cli/render/tty.ts +314 -0
- package/src/cli/run-options.ts +82 -0
- package/src/cli/skills.ts +129 -0
- package/src/core/annotation.ts +104 -0
- package/src/core/answerer.ts +75 -0
- package/src/core/artifact-evidence.ts +249 -0
- package/src/core/artifact-snapshot.ts +429 -0
- package/src/core/assertion.ts +156 -0
- package/src/core/case.ts +103 -0
- package/src/core/conversation-turn.ts +47 -0
- package/src/core/driver.ts +75 -0
- package/src/core/emitter.ts +38 -0
- package/src/core/events.ts +135 -0
- package/src/core/exec.ts +263 -0
- package/src/core/experiment.ts +467 -0
- package/src/core/glob.ts +31 -0
- package/src/core/hash.ts +237 -0
- package/src/core/index.ts +28 -0
- package/src/core/lifecycle-fixtures.ts +145 -0
- package/src/core/lifecycle-hooks.ts +101 -0
- package/src/core/mcp-events.ts +57 -0
- package/src/core/model-cli.ts +271 -0
- package/src/core/observer.ts +50 -0
- package/src/core/platform-process.ts +284 -0
- package/src/core/registry.ts +57 -0
- package/src/core/rubric.ts +52 -0
- package/src/core/run.ts +144 -0
- package/src/core/statistics.ts +194 -0
- package/src/core/subject.ts +50 -0
- package/src/core/tool-events.ts +292 -0
- package/src/core/usage.ts +123 -0
- package/src/core/wire.ts +135 -0
- package/src/core/zod.ts +20 -0
- package/src/drivers/claude-code/index.ts +866 -0
- package/src/drivers/claude-code/parse-events.ts +464 -0
- package/src/drivers/codex/app-events.ts +218 -0
- package/src/drivers/codex/config.ts +128 -0
- package/src/drivers/codex/index.ts +995 -0
- package/src/drivers/mcp/index.ts +351 -0
- package/src/drivers/mcp/transport.ts +222 -0
- package/src/drivers/shared/artifacts.ts +86 -0
- package/src/drivers/shared/secure-copy.ts +40 -0
- package/src/drivers/subprocess/index.ts +490 -0
- package/src/index.ts +594 -0
- package/src/optimization/reflective.ts +319 -0
- package/src/orchestrator/annotation-loader.ts +97 -0
- package/src/orchestrator/annotation-store.ts +112 -0
- package/src/orchestrator/authored-dependencies.ts +193 -0
- package/src/orchestrator/campaign-lifecycle.ts +181 -0
- package/src/orchestrator/candidate-integrity.ts +18 -0
- package/src/orchestrator/candidates.ts +683 -0
- package/src/orchestrator/compare.ts +358 -0
- package/src/orchestrator/comparison-identity.ts +45 -0
- package/src/orchestrator/config.ts +205 -0
- package/src/orchestrator/content-bound-json.ts +71 -0
- package/src/orchestrator/discover.ts +132 -0
- package/src/orchestrator/doctor.ts +781 -0
- package/src/orchestrator/driver-session.ts +507 -0
- package/src/orchestrator/evaluator-identity.ts +45 -0
- package/src/orchestrator/experiment-budget.ts +61 -0
- package/src/orchestrator/experiment-context.ts +41 -0
- package/src/orchestrator/experiment-contracts.ts +43 -0
- package/src/orchestrator/experiment-corpus.ts +416 -0
- package/src/orchestrator/experiment-evaluation.ts +749 -0
- package/src/orchestrator/experiment-finish.ts +33 -0
- package/src/orchestrator/experiment-identity.ts +356 -0
- package/src/orchestrator/experiment-loader.ts +105 -0
- package/src/orchestrator/experiment-report.ts +788 -0
- package/src/orchestrator/experiment-runs.ts +960 -0
- package/src/orchestrator/experiment-runtime-identity.ts +465 -0
- package/src/orchestrator/experiment-selection.ts +467 -0
- package/src/orchestrator/experiment.ts +991 -0
- package/src/orchestrator/fixture-identity.ts +67 -0
- package/src/orchestrator/fs-read.ts +126 -0
- package/src/orchestrator/grader-experiment.ts +856 -0
- package/src/orchestrator/grading.ts +260 -0
- package/src/orchestrator/index.ts +186 -0
- package/src/orchestrator/lifecycle-hook-execution.ts +90 -0
- package/src/orchestrator/list-runs.ts +384 -0
- package/src/orchestrator/loader.ts +19 -0
- package/src/orchestrator/optimization-lifecycle.ts +126 -0
- package/src/orchestrator/orchestrator.ts +919 -0
- package/src/orchestrator/owned-lock.ts +147 -0
- package/src/orchestrator/package-version.ts +5 -0
- package/src/orchestrator/provenance.ts +140 -0
- package/src/orchestrator/regrade.ts +580 -0
- package/src/orchestrator/rubric-loader.ts +74 -0
- package/src/orchestrator/run-dir.ts +209 -0
- package/src/orchestrator/run-execution.ts +694 -0
- package/src/orchestrator/run-lifecycle.ts +174 -0
- package/src/orchestrator/suite-compare.ts +195 -0
- package/src/orchestrator/suite-lifecycle.ts +335 -0
- package/src/orchestrator/suite-runs.ts +202 -0
- package/src/orchestrator/suite-summary.ts +276 -0
- package/src/orchestrator/trace-limits.ts +65 -0
- package/src/orchestrator/validate-plugin-config.ts +34 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal primitives for the live runner. Hand-rolled: the CLI needs
|
|
3
|
+
* perhaps 40 lines of this, and a dependency here would have to ship as a
|
|
4
|
+
* runtime dep of the published package for the sake of its `bin`.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Assembled from a variable so the escape byte never appears as a literal
|
|
8
|
+
// control character inside a regex or string constant.
|
|
9
|
+
const ESC = String.fromCharCode(27);
|
|
10
|
+
const ANSI_PATTERN = new RegExp(`${ESC}\\[[0-9;?]*[A-Za-z]`, "g");
|
|
11
|
+
const ANSI_PREFIX = new RegExp(`^${ESC}\\[[0-9;?]*[A-Za-z]`);
|
|
12
|
+
const RESET = `${ESC}[0m`;
|
|
13
|
+
|
|
14
|
+
const CURSOR_HIDE = `${ESC}[?25l`;
|
|
15
|
+
const CURSOR_SHOW = `${ESC}[?25h`;
|
|
16
|
+
const ERASE_BELOW = `${ESC}[0J`;
|
|
17
|
+
const cursorUp = (rows: number): string => (rows > 0 ? `${ESC}[${rows}A` : "");
|
|
18
|
+
|
|
19
|
+
export const stripAnsi = (text: string): string => text.replace(ANSI_PATTERN, "");
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Code points we render that occupy two terminal cells. The CJK/emoji block
|
|
23
|
+
* ranges cover most of it; the explicit set is the handful of pre-emoji
|
|
24
|
+
* symbols (⚡ especially) that default to emoji presentation and therefore
|
|
25
|
+
* render wide despite living below U+1F300.
|
|
26
|
+
*/
|
|
27
|
+
const WIDE_SINGLETONS = new Set([0x231a, 0x231b, 0x23f0, 0x23f3, 0x26a1, 0x2705, 0x274c, 0x2b50]);
|
|
28
|
+
|
|
29
|
+
const charWidth = (codePoint: number): number => {
|
|
30
|
+
if (WIDE_SINGLETONS.has(codePoint)) return 2;
|
|
31
|
+
if (codePoint >= 0x1100 && codePoint <= 0x115f) return 2;
|
|
32
|
+
if (codePoint >= 0x2e80 && codePoint <= 0xa4cf) return 2;
|
|
33
|
+
if (codePoint >= 0xac00 && codePoint <= 0xd7a3) return 2;
|
|
34
|
+
if (codePoint >= 0xf900 && codePoint <= 0xfaff) return 2;
|
|
35
|
+
if (codePoint >= 0xfe30 && codePoint <= 0xfe6f) return 2;
|
|
36
|
+
if (codePoint >= 0xff00 && codePoint <= 0xff60) return 2;
|
|
37
|
+
if (codePoint >= 0xffe0 && codePoint <= 0xffe6) return 2;
|
|
38
|
+
if (codePoint >= 0x1f300 && codePoint <= 0x1faff) return 2;
|
|
39
|
+
return 1;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const graphemes = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
43
|
+
|
|
44
|
+
// Per-code-point counting over-counts ZWJ emoji sequences (a family emoji is
|
|
45
|
+
// seven code points but one two-cell glyph), so width is measured per
|
|
46
|
+
// grapheme cluster: any wide code point inside makes the whole cluster wide.
|
|
47
|
+
const clusterWidth = (cluster: string): number => {
|
|
48
|
+
for (const char of cluster) {
|
|
49
|
+
if (charWidth(char.codePointAt(0) ?? 0) === 2) return 2;
|
|
50
|
+
}
|
|
51
|
+
return 1;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const visibleWidth = (text: string): number => {
|
|
55
|
+
let width = 0;
|
|
56
|
+
for (const { segment } of graphemes.segment(stripAnsi(text))) width += clusterWidth(segment);
|
|
57
|
+
return width;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Cut `text` to `maxWidth` visible cells, counting styling as zero-width.
|
|
62
|
+
* A line wider than the terminal would wrap, and a wrapped line breaks the
|
|
63
|
+
* cursor arithmetic the live region depends on — so every painted row goes
|
|
64
|
+
* through here.
|
|
65
|
+
*/
|
|
66
|
+
export const truncate = (text: string, maxWidth: number): string => {
|
|
67
|
+
if (maxWidth <= 0) return "";
|
|
68
|
+
if (visibleWidth(text) <= maxWidth) return text;
|
|
69
|
+
|
|
70
|
+
let out = "";
|
|
71
|
+
let width = 0;
|
|
72
|
+
let index = 0;
|
|
73
|
+
let styled = false;
|
|
74
|
+
|
|
75
|
+
scan: while (index < text.length) {
|
|
76
|
+
if (text.startsWith(ESC, index)) {
|
|
77
|
+
const sequence = text.slice(index).match(ANSI_PREFIX)?.[0];
|
|
78
|
+
if (!sequence) break;
|
|
79
|
+
out += sequence;
|
|
80
|
+
styled = true;
|
|
81
|
+
index += sequence.length;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
// Segment the plain-text run up to the next escape so a grapheme cluster
|
|
85
|
+
// is never split mid-sequence.
|
|
86
|
+
const nextEsc = text.indexOf(ESC, index);
|
|
87
|
+
const run = text.slice(index, nextEsc === -1 ? text.length : nextEsc);
|
|
88
|
+
for (const { segment } of graphemes.segment(run)) {
|
|
89
|
+
const next = width + clusterWidth(segment);
|
|
90
|
+
// Reserve one cell for the ellipsis.
|
|
91
|
+
if (next > maxWidth - 1) break scan;
|
|
92
|
+
out += segment;
|
|
93
|
+
width = next;
|
|
94
|
+
}
|
|
95
|
+
index += run.length;
|
|
96
|
+
}
|
|
97
|
+
return `${out}…${styled ? RESET : ""}`;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export type Theme = {
|
|
101
|
+
bold: (s: string) => string;
|
|
102
|
+
dim: (s: string) => string;
|
|
103
|
+
green: (s: string) => string;
|
|
104
|
+
red: (s: string) => string;
|
|
105
|
+
yellow: (s: string) => string;
|
|
106
|
+
cyan: (s: string) => string;
|
|
107
|
+
inverse: (s: string) => string;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const wrap =
|
|
111
|
+
(open: string, close: string) =>
|
|
112
|
+
(s: string): string =>
|
|
113
|
+
`${ESC}[${open}m${s}${ESC}[${close}m`;
|
|
114
|
+
|
|
115
|
+
const plain = (s: string): string => s;
|
|
116
|
+
|
|
117
|
+
export const makeTheme = (color: boolean): Theme =>
|
|
118
|
+
color
|
|
119
|
+
? {
|
|
120
|
+
bold: wrap("1", "22"),
|
|
121
|
+
dim: wrap("2", "22"),
|
|
122
|
+
green: wrap("32", "39"),
|
|
123
|
+
red: wrap("31", "39"),
|
|
124
|
+
yellow: wrap("33", "39"),
|
|
125
|
+
cyan: wrap("36", "39"),
|
|
126
|
+
inverse: wrap("7", "27"),
|
|
127
|
+
}
|
|
128
|
+
: {
|
|
129
|
+
bold: plain,
|
|
130
|
+
dim: plain,
|
|
131
|
+
green: plain,
|
|
132
|
+
red: plain,
|
|
133
|
+
yellow: plain,
|
|
134
|
+
cyan: plain,
|
|
135
|
+
inverse: plain,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Honour the two conventions users actually rely on: `NO_COLOR` to force
|
|
140
|
+
* plain output anywhere, `FORCE_COLOR` to keep colour through a pipe (CI
|
|
141
|
+
* log viewers that render ANSI).
|
|
142
|
+
*/
|
|
143
|
+
export const shouldColor = (stream: NodeJS.WriteStream, env: NodeJS.ProcessEnv): boolean => {
|
|
144
|
+
if (env.NO_COLOR) return false;
|
|
145
|
+
if (env.FORCE_COLOR) return env.FORCE_COLOR !== "0";
|
|
146
|
+
return Boolean(stream.isTTY);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] as const;
|
|
150
|
+
|
|
151
|
+
export const spinnerFrame = (tick: number): string =>
|
|
152
|
+
SPINNER_FRAMES[tick % SPINNER_FRAMES.length] ?? "-";
|
|
153
|
+
|
|
154
|
+
type Patched = {
|
|
155
|
+
stream: NodeJS.WriteStream;
|
|
156
|
+
original: (chunk: string) => void;
|
|
157
|
+
restore: () => void;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export type LiveRegionOptions = {
|
|
161
|
+
stdout?: NodeJS.WriteStream | undefined;
|
|
162
|
+
/** Force live painting on/off. Defaults to `stdout.isTTY`. */
|
|
163
|
+
live?: boolean | undefined;
|
|
164
|
+
frameIntervalMs?: number | undefined;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* A block of lines pinned to the bottom of the terminal, repainted on a
|
|
169
|
+
* timer so elapsed clocks tick. Anything else that writes to the terminal
|
|
170
|
+
* while it is active is intercepted, printed *above* the block, and the
|
|
171
|
+
* block repainted underneath — otherwise a stray write lands mid-frame and
|
|
172
|
+
* every subsequent cursor-up is off by one. Off a TTY the whole mechanism
|
|
173
|
+
* collapses to plain `staticLine` writes.
|
|
174
|
+
*/
|
|
175
|
+
export class LiveRegion {
|
|
176
|
+
private readonly stdout: NodeJS.WriteStream;
|
|
177
|
+
private readonly writeRaw: (chunk: string) => void;
|
|
178
|
+
private readonly frameIntervalMs: number;
|
|
179
|
+
readonly live: boolean;
|
|
180
|
+
|
|
181
|
+
private renderFrame: () => string[] = () => [];
|
|
182
|
+
private paintedRows = 0;
|
|
183
|
+
private timer: NodeJS.Timeout | null = null;
|
|
184
|
+
private patched: Patched[] = [];
|
|
185
|
+
private held = new Map<NodeJS.WriteStream, string>();
|
|
186
|
+
private started = false;
|
|
187
|
+
|
|
188
|
+
constructor(options: LiveRegionOptions = {}) {
|
|
189
|
+
this.stdout = options.stdout ?? process.stdout;
|
|
190
|
+
// Captured before any interception, so the region's own paints never
|
|
191
|
+
// recurse back through the patched writer.
|
|
192
|
+
const original = this.stdout.write.bind(this.stdout);
|
|
193
|
+
this.writeRaw = (chunk) => {
|
|
194
|
+
original(chunk);
|
|
195
|
+
};
|
|
196
|
+
this.live = options.live ?? Boolean(this.stdout.isTTY);
|
|
197
|
+
this.frameIntervalMs = options.frameIntervalMs ?? 80;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
start(renderFrame: () => string[]): void {
|
|
201
|
+
this.renderFrame = renderFrame;
|
|
202
|
+
if (!this.live || this.started) return;
|
|
203
|
+
this.started = true;
|
|
204
|
+
this.writeRaw(CURSOR_HIDE);
|
|
205
|
+
this.intercept(process.stderr);
|
|
206
|
+
this.timer = setInterval(() => this.repaint(), this.frameIntervalMs);
|
|
207
|
+
// Never let the repaint timer be the reason the process stays alive.
|
|
208
|
+
this.timer.unref();
|
|
209
|
+
// Interrupt handling belongs to the CLI, which has a run to unwind; the
|
|
210
|
+
// region only guarantees the cursor comes back however the process ends.
|
|
211
|
+
process.once("exit", this.onExit);
|
|
212
|
+
this.paint();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Print a permanent line above the live block. Before `start()` and after
|
|
217
|
+
* `stop()` there is no block to move, so the line goes straight out — which
|
|
218
|
+
* is also exactly the non-TTY behaviour.
|
|
219
|
+
*/
|
|
220
|
+
staticLine(text: string): void {
|
|
221
|
+
if (!this.live || !this.started) {
|
|
222
|
+
this.writeRaw(`${text}\n`);
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
this.clear();
|
|
226
|
+
this.writeRaw(`${text}\n`);
|
|
227
|
+
this.paint();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
repaint(): void {
|
|
231
|
+
if (!this.live || !this.started) return;
|
|
232
|
+
this.clear();
|
|
233
|
+
this.paint();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
stop(): void {
|
|
237
|
+
if (!this.live || !this.started) return;
|
|
238
|
+
this.started = false;
|
|
239
|
+
if (this.timer) clearInterval(this.timer);
|
|
240
|
+
this.timer = null;
|
|
241
|
+
this.clear();
|
|
242
|
+
for (const { stream, original, restore } of this.patched) {
|
|
243
|
+
const rest = this.held.get(stream);
|
|
244
|
+
if (rest) original(`${rest}\n`);
|
|
245
|
+
restore();
|
|
246
|
+
}
|
|
247
|
+
this.patched = [];
|
|
248
|
+
this.held.clear();
|
|
249
|
+
this.writeRaw(CURSOR_SHOW);
|
|
250
|
+
process.off("exit", this.onExit);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private readonly onExit = (): void => {
|
|
254
|
+
if (this.started) this.writeRaw(CURSOR_SHOW);
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
private clear(): void {
|
|
258
|
+
if (this.paintedRows === 0) return;
|
|
259
|
+
this.writeRaw(cursorUp(this.paintedRows) + ERASE_BELOW);
|
|
260
|
+
this.paintedRows = 0;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private paint(): void {
|
|
264
|
+
const columns = this.stdout.columns ?? 80;
|
|
265
|
+
const maxRows = Math.max(1, (this.stdout.rows ?? 24) - 1);
|
|
266
|
+
const lines = this.renderFrame()
|
|
267
|
+
.slice(-maxRows)
|
|
268
|
+
.map((line) => truncate(line, columns - 1));
|
|
269
|
+
if (lines.length === 0) return;
|
|
270
|
+
this.writeRaw(lines.map((line) => `${line}\n`).join(""));
|
|
271
|
+
this.paintedRows = lines.length;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Buffer a foreign stream to whole lines before letting it through: a
|
|
276
|
+
* half-written line cannot be painted over cleanly, and the subprocess
|
|
277
|
+
* driver relays agent stderr in arbitrary chunks.
|
|
278
|
+
*/
|
|
279
|
+
private intercept(stream: NodeJS.WriteStream): void {
|
|
280
|
+
if (!stream.isTTY) return;
|
|
281
|
+
const original = stream.write.bind(stream);
|
|
282
|
+
const emit = (chunk: string): void => {
|
|
283
|
+
original(chunk);
|
|
284
|
+
};
|
|
285
|
+
const patched = (
|
|
286
|
+
chunk: string | Uint8Array,
|
|
287
|
+
encoding?: unknown,
|
|
288
|
+
callback?: unknown,
|
|
289
|
+
): boolean => {
|
|
290
|
+
const done = typeof encoding === "function" ? encoding : callback;
|
|
291
|
+
const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf-8");
|
|
292
|
+
const buffered = (this.held.get(stream) ?? "") + text;
|
|
293
|
+
const lastBreak = buffered.lastIndexOf("\n");
|
|
294
|
+
if (lastBreak === -1) {
|
|
295
|
+
this.held.set(stream, buffered);
|
|
296
|
+
} else {
|
|
297
|
+
this.held.set(stream, buffered.slice(lastBreak + 1));
|
|
298
|
+
this.clear();
|
|
299
|
+
emit(buffered.slice(0, lastBreak + 1));
|
|
300
|
+
this.paint();
|
|
301
|
+
}
|
|
302
|
+
if (typeof done === "function") (done as () => void)();
|
|
303
|
+
return true;
|
|
304
|
+
};
|
|
305
|
+
stream.write = patched as unknown as typeof stream.write;
|
|
306
|
+
this.patched.push({
|
|
307
|
+
stream,
|
|
308
|
+
original: emit,
|
|
309
|
+
restore: () => {
|
|
310
|
+
stream.write = original as typeof stream.write;
|
|
311
|
+
},
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { InvalidArgumentError } from "commander";
|
|
2
|
+
|
|
3
|
+
export type RunOptions = {
|
|
4
|
+
tag?: string[];
|
|
5
|
+
loop?: number;
|
|
6
|
+
concurrency?: number;
|
|
7
|
+
list?: boolean;
|
|
8
|
+
listTags?: boolean;
|
|
9
|
+
interactive?: boolean;
|
|
10
|
+
claudeAnswerer?: boolean;
|
|
11
|
+
runsRoot?: string;
|
|
12
|
+
profile?: string;
|
|
13
|
+
subjectRoot?: string;
|
|
14
|
+
verbose?: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const collectTags = (value: string, previous: string[]): string[] =>
|
|
18
|
+
previous.concat(
|
|
19
|
+
value
|
|
20
|
+
.split(",")
|
|
21
|
+
.map((tag) => tag.trim())
|
|
22
|
+
.filter(Boolean),
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
export const collectValues = (value: string, previous: string[]): string[] => [...previous, value];
|
|
26
|
+
|
|
27
|
+
export const parseAnnotationAssertion = (
|
|
28
|
+
value: string,
|
|
29
|
+
): [string, { passed: boolean; score?: number }] => {
|
|
30
|
+
const match = /^(.+)=(pass|fail)(?::(.+))?$/.exec(value);
|
|
31
|
+
if (!match?.[1] || !match[2]) {
|
|
32
|
+
throw new InvalidArgumentError("--assertion must use id=pass, id=fail, or id=pass:0.8 syntax");
|
|
33
|
+
}
|
|
34
|
+
const score = match[3] === undefined ? undefined : parseUnitInterval(match[3]);
|
|
35
|
+
return [
|
|
36
|
+
match[1],
|
|
37
|
+
{
|
|
38
|
+
passed: match[2] === "pass",
|
|
39
|
+
...(score !== undefined ? { score } : {}),
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const parsePositiveInt = (value: string): number => {
|
|
45
|
+
// Number() rejects partial numbers such as "3abc" and "2.9".
|
|
46
|
+
const parsed = Number(value);
|
|
47
|
+
if (!Number.isInteger(parsed) || parsed < 1) {
|
|
48
|
+
throw new InvalidArgumentError("must be a positive integer");
|
|
49
|
+
}
|
|
50
|
+
return parsed;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const parseUnitInterval = (value: string): number => {
|
|
54
|
+
const parsed = Number(value);
|
|
55
|
+
if (!Number.isFinite(parsed) || parsed < 0 || parsed > 1) {
|
|
56
|
+
throw new InvalidArgumentError("must be a number between 0 and 1");
|
|
57
|
+
}
|
|
58
|
+
return parsed;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const resolveConcurrency = (
|
|
62
|
+
options: Pick<RunOptions, "concurrency" | "interactive" | "claudeAnswerer">,
|
|
63
|
+
configured: number,
|
|
64
|
+
): { concurrency: number; note?: string } => {
|
|
65
|
+
const requested = options.concurrency ?? configured;
|
|
66
|
+
let liveFlag: "--interactive" | "--claude-answerer" | null = null;
|
|
67
|
+
if (options.interactive) liveFlag = "--interactive";
|
|
68
|
+
else if (options.claudeAnswerer) liveFlag = "--claude-answerer";
|
|
69
|
+
if (liveFlag && requested > 1) {
|
|
70
|
+
return {
|
|
71
|
+
concurrency: 1,
|
|
72
|
+
note: `lux: ${liveFlag} is a live session; running one case at a time (ignoring concurrency ${requested})\n`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return { concurrency: requested };
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const resolveAnswererOverride = (options: RunOptions): string | undefined => {
|
|
79
|
+
if (options.interactive) return "terminal";
|
|
80
|
+
if (options.claudeAnswerer) return "claude-code";
|
|
81
|
+
return undefined;
|
|
82
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { lstat, mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
const PlatformSchema = z.enum(["claude", "claude-code", "codex", "all"]);
|
|
8
|
+
export type SkillsPlatform = z.infer<typeof PlatformSchema>;
|
|
9
|
+
const SkillNameSchema = z.enum(["lux", "lux-answerer"]);
|
|
10
|
+
export type BundledSkillName = z.infer<typeof SkillNameSchema>;
|
|
11
|
+
|
|
12
|
+
const InstallSkillsOptionsSchema = z
|
|
13
|
+
.object({
|
|
14
|
+
cwd: z.string().min(1),
|
|
15
|
+
platform: PlatformSchema,
|
|
16
|
+
project: z.boolean().default(false),
|
|
17
|
+
dir: z.string().min(1).optional(),
|
|
18
|
+
name: SkillNameSchema.optional(),
|
|
19
|
+
})
|
|
20
|
+
.strict();
|
|
21
|
+
|
|
22
|
+
export interface InstalledSkill {
|
|
23
|
+
name: BundledSkillName;
|
|
24
|
+
platform: "claude-code" | "codex";
|
|
25
|
+
path: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const BUNDLED_SKILLS = [
|
|
29
|
+
{
|
|
30
|
+
name: "lux",
|
|
31
|
+
description: "Author and drive coding-agent evals with Lux",
|
|
32
|
+
platforms: ["claude-code", "codex"],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "lux-answerer",
|
|
36
|
+
description: "Play a simulated user for a running Lux eval",
|
|
37
|
+
platforms: ["claude-code"],
|
|
38
|
+
},
|
|
39
|
+
] as const satisfies readonly {
|
|
40
|
+
name: BundledSkillName;
|
|
41
|
+
description: string;
|
|
42
|
+
platforms: readonly ("claude-code" | "codex")[];
|
|
43
|
+
}[];
|
|
44
|
+
|
|
45
|
+
export const formatSkillsList = (): string =>
|
|
46
|
+
BUNDLED_SKILLS.map(
|
|
47
|
+
({ name, description, platforms }) => `${name}\t${description}\t${platforms.join(",")}`,
|
|
48
|
+
).join("\n");
|
|
49
|
+
|
|
50
|
+
const targetsFor = (
|
|
51
|
+
platform: SkillsPlatform,
|
|
52
|
+
cwd: string,
|
|
53
|
+
project: boolean,
|
|
54
|
+
dir?: string,
|
|
55
|
+
name?: BundledSkillName,
|
|
56
|
+
): (InstalledSkill & { source: string })[] => {
|
|
57
|
+
const platforms =
|
|
58
|
+
platform === "all"
|
|
59
|
+
? (["claude-code", "codex"] as const)
|
|
60
|
+
: ([platform === "claude" ? "claude-code" : platform] as const);
|
|
61
|
+
const scopeRoot = project ? resolve(cwd) : homedir();
|
|
62
|
+
const skills = name ? BUNDLED_SKILLS.filter((skill) => skill.name === name) : BUNDLED_SKILLS;
|
|
63
|
+
return platforms.flatMap((platformName) =>
|
|
64
|
+
skills
|
|
65
|
+
.filter((skill) =>
|
|
66
|
+
(skill.platforms as readonly ("claude-code" | "codex")[]).includes(platformName),
|
|
67
|
+
)
|
|
68
|
+
.map((skill) => ({
|
|
69
|
+
name: skill.name,
|
|
70
|
+
platform: platformName,
|
|
71
|
+
source: fileURLToPath(new URL(`../../skills/${skill.name}`, import.meta.url)),
|
|
72
|
+
path: dir
|
|
73
|
+
? join(resolve(dir), skill.name)
|
|
74
|
+
: join(
|
|
75
|
+
scopeRoot,
|
|
76
|
+
platformName === "claude-code" ? ".claude" : ".codex",
|
|
77
|
+
"skills",
|
|
78
|
+
skill.name,
|
|
79
|
+
),
|
|
80
|
+
})),
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const copySkillDirectory = async (source: string, target: string): Promise<void> => {
|
|
85
|
+
const sourceInfo = await lstat(source);
|
|
86
|
+
if (!sourceInfo.isDirectory() || sourceInfo.isSymbolicLink()) {
|
|
87
|
+
throw new Error(`lux skills: bundled skill source is not a real directory: ${source}`);
|
|
88
|
+
}
|
|
89
|
+
await mkdir(target, { recursive: true });
|
|
90
|
+
for (const entry of await readdir(source, { withFileTypes: true })) {
|
|
91
|
+
const sourcePath = join(source, entry.name);
|
|
92
|
+
const targetPath = join(target, entry.name);
|
|
93
|
+
if (entry.isSymbolicLink()) {
|
|
94
|
+
throw new Error(`lux skills: bundled skill contains a symbolic link: ${sourcePath}`);
|
|
95
|
+
}
|
|
96
|
+
if (entry.isDirectory()) {
|
|
97
|
+
await copySkillDirectory(sourcePath, targetPath);
|
|
98
|
+
} else if (entry.isFile()) {
|
|
99
|
+
await mkdir(dirname(targetPath), { recursive: true });
|
|
100
|
+
await writeFile(targetPath, await readFile(sourcePath));
|
|
101
|
+
} else {
|
|
102
|
+
throw new Error(`lux skills: bundled skill contains an unsupported entry: ${sourcePath}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export const installSkills = async (
|
|
108
|
+
options: z.input<typeof InstallSkillsOptionsSchema>,
|
|
109
|
+
): Promise<InstalledSkill[]> => {
|
|
110
|
+
const parsed = InstallSkillsOptionsSchema.parse(options);
|
|
111
|
+
const targets = targetsFor(parsed.platform, parsed.cwd, parsed.project, parsed.dir, parsed.name);
|
|
112
|
+
if (targets.length === 0) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
`lux skills: '${parsed.name}' is not available for platform '${parsed.platform}'`,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
for (const target of targets) await copySkillDirectory(target.source, target.path);
|
|
118
|
+
return targets.map(({ source: _, ...installed }) => installed);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const formatSkillsInstall = (installed: InstalledSkill[], cwd: string): string =>
|
|
122
|
+
installed
|
|
123
|
+
.map(
|
|
124
|
+
({ name, platform, path }) =>
|
|
125
|
+
`installed ${name} skill for ${platform} at ${
|
|
126
|
+
relative(cwd, path).split(sep).join("/") || "."
|
|
127
|
+
}`,
|
|
128
|
+
)
|
|
129
|
+
.join("\n");
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatZodIssues } from "./zod.js";
|
|
3
|
+
|
|
4
|
+
const ExpectedBooleanLabelSchema = z
|
|
5
|
+
.object({
|
|
6
|
+
passed: z.boolean(),
|
|
7
|
+
score: z.number().min(0).max(1).optional(),
|
|
8
|
+
})
|
|
9
|
+
.strict();
|
|
10
|
+
|
|
11
|
+
export const GraderAnnotationSchema = z
|
|
12
|
+
.object({
|
|
13
|
+
/** Stable label identity within the dataset. */
|
|
14
|
+
id: z.string().min(1),
|
|
15
|
+
/** Persisted Lux run containing the evidence to grade. */
|
|
16
|
+
runDir: z.string().min(1),
|
|
17
|
+
/** Candidate-relative declarative rubric whose assertions grade this run. */
|
|
18
|
+
rubricPath: z
|
|
19
|
+
.string()
|
|
20
|
+
.min(1)
|
|
21
|
+
.transform((path) => path.replaceAll("\\", "/")),
|
|
22
|
+
/** Optional selection labels used by experiment split selectors. */
|
|
23
|
+
tags: z.array(z.string()).default([]),
|
|
24
|
+
expected: z
|
|
25
|
+
.object({
|
|
26
|
+
casePassed: z.boolean().optional(),
|
|
27
|
+
caseScore: z.number().min(0).max(1).optional(),
|
|
28
|
+
assertions: z.record(z.string(), ExpectedBooleanLabelSchema).default({}),
|
|
29
|
+
})
|
|
30
|
+
.strict(),
|
|
31
|
+
/** Whether the label was independently authored or generated as test data. */
|
|
32
|
+
source: z.enum(["human", "synthetic"]),
|
|
33
|
+
annotator: z.string().min(1).optional(),
|
|
34
|
+
labeledAt: z.string().datetime().optional(),
|
|
35
|
+
reviewer: z.string().min(1).optional(),
|
|
36
|
+
/** Human rationale supplied to the rubric optimizer on mismatches. */
|
|
37
|
+
feedback: z.string().optional(),
|
|
38
|
+
meta: z.record(z.string(), z.unknown()).optional(),
|
|
39
|
+
})
|
|
40
|
+
.strict()
|
|
41
|
+
.superRefine((annotation, ctx) => {
|
|
42
|
+
if (
|
|
43
|
+
annotation.expected.casePassed === undefined &&
|
|
44
|
+
annotation.expected.caseScore === undefined &&
|
|
45
|
+
Object.keys(annotation.expected.assertions).length === 0
|
|
46
|
+
) {
|
|
47
|
+
ctx.addIssue({
|
|
48
|
+
code: "custom",
|
|
49
|
+
path: ["expected"],
|
|
50
|
+
message: "annotation requires a case pass/score label or at least one assertion label",
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
if (
|
|
54
|
+
annotation.rubricPath.startsWith("/") ||
|
|
55
|
+
annotation.rubricPath.split(/[\\/]/).includes("..")
|
|
56
|
+
) {
|
|
57
|
+
ctx.addIssue({
|
|
58
|
+
code: "custom",
|
|
59
|
+
path: ["rubricPath"],
|
|
60
|
+
message: "rubricPath must stay within the experiment subject root",
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (!annotation.rubricPath.toLowerCase().endsWith(".json")) {
|
|
64
|
+
ctx.addIssue({
|
|
65
|
+
code: "custom",
|
|
66
|
+
path: ["rubricPath"],
|
|
67
|
+
message: "grader experiments require a declarative .json rubric",
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
export type GraderAnnotation = z.output<typeof GraderAnnotationSchema>;
|
|
72
|
+
|
|
73
|
+
export const GraderAnnotationDatasetSchema = z
|
|
74
|
+
.object({
|
|
75
|
+
schemaVersion: z.literal(1),
|
|
76
|
+
annotations: z.array(GraderAnnotationSchema).min(1),
|
|
77
|
+
meta: z.record(z.string(), z.unknown()).optional(),
|
|
78
|
+
})
|
|
79
|
+
.strict()
|
|
80
|
+
.superRefine((dataset, ctx) => {
|
|
81
|
+
const ids = new Set<string>();
|
|
82
|
+
for (const [index, annotation] of dataset.annotations.entries()) {
|
|
83
|
+
if (ids.has(annotation.id)) {
|
|
84
|
+
ctx.addIssue({
|
|
85
|
+
code: "custom",
|
|
86
|
+
path: ["annotations", index, "id"],
|
|
87
|
+
message: `duplicate annotation id '${annotation.id}'`,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
ids.add(annotation.id);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
export type GraderAnnotationDatasetInput = z.input<typeof GraderAnnotationDatasetSchema>;
|
|
94
|
+
export type GraderAnnotationDataset = z.output<typeof GraderAnnotationDatasetSchema>;
|
|
95
|
+
|
|
96
|
+
export const defineGraderAnnotations = (
|
|
97
|
+
input: GraderAnnotationDatasetInput,
|
|
98
|
+
): GraderAnnotationDataset => {
|
|
99
|
+
const parsed = GraderAnnotationDatasetSchema.safeParse(input);
|
|
100
|
+
if (!parsed.success) {
|
|
101
|
+
throw new Error(`Invalid Lux grader annotations: ${formatZodIssues(parsed.error)}`);
|
|
102
|
+
}
|
|
103
|
+
return parsed.data;
|
|
104
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { Answer, Interrupt } from "./events.js";
|
|
3
|
+
import { type TokenUsage, TokenUsageSchema } from "./usage.js";
|
|
4
|
+
|
|
5
|
+
export type AnswerHistoryEntry = {
|
|
6
|
+
interrupt: Interrupt;
|
|
7
|
+
answer: Answer;
|
|
8
|
+
durationMs: number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type AnswererContext = {
|
|
12
|
+
persona: string | null;
|
|
13
|
+
prompt: string;
|
|
14
|
+
history: AnswerHistoryEntry[];
|
|
15
|
+
runDir: string;
|
|
16
|
+
/**
|
|
17
|
+
* Fires when the run is being torn down. Answerers that spawn subprocesses
|
|
18
|
+
* or block on external input must abandon the in-flight answer, or a
|
|
19
|
+
* Ctrl-C leaves billable agent calls running past the run's end.
|
|
20
|
+
*/
|
|
21
|
+
abortSignal?: AbortSignal;
|
|
22
|
+
/**
|
|
23
|
+
* Persists a model-attempt start before a model-backed answerer invokes its
|
|
24
|
+
* provider.
|
|
25
|
+
*/
|
|
26
|
+
recordModelAttemptStart?: (kind: "answerer") => Promise<string>;
|
|
27
|
+
/**
|
|
28
|
+
* Atomically settles one model-backed answer and re-checks campaign limits
|
|
29
|
+
* before another interrupt may invoke the provider.
|
|
30
|
+
*/
|
|
31
|
+
recordModelAttemptComplete?: (
|
|
32
|
+
attemptId: string,
|
|
33
|
+
accounting: AnswererModelCallAccounting,
|
|
34
|
+
) => Promise<void>;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const AnswererModelCallAccountingSchema = z
|
|
38
|
+
.object({
|
|
39
|
+
usage: TokenUsageSchema,
|
|
40
|
+
costUsd: z.number().nonnegative().optional(),
|
|
41
|
+
unpricedModelCalls: z.number().int().nonnegative(),
|
|
42
|
+
})
|
|
43
|
+
.strict();
|
|
44
|
+
export type AnswererModelCallAccounting = z.infer<typeof AnswererModelCallAccountingSchema>;
|
|
45
|
+
|
|
46
|
+
export const AnswererModelAccountingSchema = z
|
|
47
|
+
.object({
|
|
48
|
+
calls: z.number().int().nonnegative(),
|
|
49
|
+
reportedCostUsd: z.number().nonnegative(),
|
|
50
|
+
unpricedModelCalls: z.number().int().nonnegative(),
|
|
51
|
+
})
|
|
52
|
+
.strict();
|
|
53
|
+
export type AnswererModelAccounting = z.infer<typeof AnswererModelAccountingSchema>;
|
|
54
|
+
|
|
55
|
+
export interface Answerer {
|
|
56
|
+
prepare(ctx: AnswererContext): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Must settle within a bounded time (every bundled answerer enforces its
|
|
59
|
+
* own wait budget). Drivers pause their idle clock while a question is
|
|
60
|
+
* outstanding — the user's thinking time is not the agent's — so an
|
|
61
|
+
* answer() that never settles hangs the run until its abort signal fires.
|
|
62
|
+
*/
|
|
63
|
+
answer(interrupt: Interrupt, ctx: AnswererContext): Promise<Answer>;
|
|
64
|
+
close(): Promise<void>;
|
|
65
|
+
/** Tokens spent playing the user, accumulated across every answer. */
|
|
66
|
+
usage?(): TokenUsage;
|
|
67
|
+
/** Model calls made by the answerer, kept separate from the subject driver. */
|
|
68
|
+
modelAccounting?(): AnswererModelAccounting;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type AnswererPlugin<Cfg = unknown> = {
|
|
72
|
+
name: string;
|
|
73
|
+
configSchema?: z.ZodTypeAny;
|
|
74
|
+
create: (config: Cfg) => Answerer | Promise<Answerer>;
|
|
75
|
+
};
|