@prismatic-io/lux 0.0.2-preview.27 → 0.0.2-preview.29
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/lib/authoring.d.ts +1 -0
- package/lib/authoring.d.ts.map +1 -1
- package/lib/authoring.js +1 -0
- package/lib/authoring.js.map +1 -1
- package/lib/container/driver.d.ts +27 -0
- package/lib/container/driver.d.ts.map +1 -0
- package/lib/container/driver.js +197 -0
- package/lib/container/driver.js.map +1 -0
- package/lib/container/protocol.d.ts +12 -0
- package/lib/container/protocol.d.ts.map +1 -0
- package/lib/container/protocol.js +38 -0
- package/lib/container/protocol.js.map +1 -0
- package/lib/container/resources.d.ts +12 -0
- package/lib/container/resources.d.ts.map +1 -0
- package/lib/container/resources.js +133 -0
- package/lib/container/resources.js.map +1 -0
- package/lib/container/worker.d.ts +2 -0
- package/lib/container/worker.d.ts.map +1 -0
- package/lib/container/worker.js +85 -0
- package/lib/container/worker.js.map +1 -0
- package/lib/core/case.d.ts +80 -0
- package/lib/core/case.d.ts.map +1 -1
- package/lib/core/case.js +8 -1
- package/lib/core/case.js.map +1 -1
- package/lib/core/driver-execution.d.ts +83 -0
- package/lib/core/driver-execution.d.ts.map +1 -0
- package/lib/core/driver-execution.js +72 -0
- package/lib/core/driver-execution.js.map +1 -0
- package/lib/core/driver.d.ts +5 -1
- package/lib/core/driver.d.ts.map +1 -1
- package/lib/core/driver.js +5 -1
- package/lib/core/driver.js.map +1 -1
- package/lib/core/harness-catalogs/cursor.js +1 -1
- package/lib/core/harness-catalogs/cursor.js.map +1 -1
- package/lib/core/harness-matrix.d.ts +84 -0
- package/lib/core/harness-matrix.d.ts.map +1 -1
- package/lib/core/harness-matrix.js +11 -1
- package/lib/core/harness-matrix.js.map +1 -1
- package/lib/core/run.d.ts +40 -0
- package/lib/core/run.d.ts.map +1 -1
- package/lib/drivers/antigravity/artifacts.d.ts +2 -0
- package/lib/drivers/antigravity/artifacts.d.ts.map +1 -0
- package/lib/drivers/antigravity/artifacts.js +33 -0
- package/lib/drivers/antigravity/artifacts.js.map +1 -0
- package/lib/drivers/antigravity/config.d.ts +27 -0
- package/lib/drivers/antigravity/config.d.ts.map +1 -1
- package/lib/drivers/antigravity/config.js +35 -0
- package/lib/drivers/antigravity/config.js.map +1 -1
- package/lib/drivers/antigravity/index.d.ts +35 -0
- package/lib/drivers/antigravity/index.d.ts.map +1 -1
- package/lib/drivers/antigravity/index.js +42 -20
- package/lib/drivers/antigravity/index.js.map +1 -1
- package/lib/drivers/antigravity/runtime.d.ts +7 -0
- package/lib/drivers/antigravity/runtime.d.ts.map +1 -0
- package/lib/drivers/antigravity/runtime.js +78 -0
- package/lib/drivers/antigravity/runtime.js.map +1 -0
- package/lib/drivers/copilot/config.d.ts +3 -3
- package/lib/drivers/copilot/config.js +5 -5
- package/lib/drivers/copilot/config.js.map +1 -1
- package/lib/drivers/copilot/index.d.ts +4 -4
- package/lib/drivers/copilot/index.d.ts.map +1 -1
- package/lib/drivers/copilot/index.js +13 -3
- package/lib/drivers/copilot/index.js.map +1 -1
- package/lib/drivers/cursor/config.js +1 -1
- package/lib/drivers/cursor/config.js.map +1 -1
- package/lib/drivers/cursor/index.d.ts.map +1 -1
- package/lib/drivers/cursor/index.js +8 -3
- package/lib/drivers/cursor/index.js.map +1 -1
- package/lib/drivers/shared/acp-session.d.ts +4 -0
- package/lib/drivers/shared/acp-session.d.ts.map +1 -0
- package/lib/drivers/shared/acp-session.js +23 -0
- package/lib/drivers/shared/acp-session.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/orchestrator/config.d.ts +122 -1
- package/lib/orchestrator/config.d.ts.map +1 -1
- package/lib/orchestrator/config.js +2 -1
- package/lib/orchestrator/config.js.map +1 -1
- package/lib/orchestrator/doctor.d.ts.map +1 -1
- package/lib/orchestrator/doctor.js +3 -1
- package/lib/orchestrator/doctor.js.map +1 -1
- package/lib/orchestrator/driver-capabilities.d.ts +2 -1
- package/lib/orchestrator/driver-capabilities.d.ts.map +1 -1
- package/lib/orchestrator/driver-capabilities.js +5 -2
- package/lib/orchestrator/driver-capabilities.js.map +1 -1
- package/lib/orchestrator/driver-identity.d.ts.map +1 -1
- package/lib/orchestrator/driver-identity.js +11 -1
- package/lib/orchestrator/driver-identity.js.map +1 -1
- package/lib/orchestrator/experiment-context.d.ts +34 -0
- package/lib/orchestrator/experiment-context.d.ts.map +1 -1
- package/lib/orchestrator/orchestrator.d.ts.map +1 -1
- package/lib/orchestrator/orchestrator.js +16 -3
- package/lib/orchestrator/orchestrator.js.map +1 -1
- package/package.json +1 -1
- package/skills/lux-answerer/SKILL.md +1 -1
- package/src/authoring.ts +6 -0
- package/src/container/driver.ts +211 -0
- package/src/container/protocol.ts +48 -0
- package/src/container/resources.ts +153 -0
- package/src/container/worker.ts +107 -0
- package/src/core/case.ts +8 -1
- package/src/core/driver-execution.ts +84 -0
- package/src/core/driver.ts +9 -1
- package/src/core/harness-catalogs/cursor.ts +1 -1
- package/src/core/harness-matrix.ts +19 -1
- package/src/drivers/antigravity/README.md +108 -10
- package/src/drivers/antigravity/artifacts.ts +37 -0
- package/src/drivers/antigravity/config.ts +35 -0
- package/src/drivers/antigravity/index.ts +41 -22
- package/src/drivers/antigravity/runtime.ts +88 -0
- package/src/drivers/copilot/README.md +19 -11
- package/src/drivers/copilot/config.ts +5 -5
- package/src/drivers/copilot/index.ts +20 -4
- package/src/drivers/cursor/README.md +14 -8
- package/src/drivers/cursor/config.ts +1 -1
- package/src/drivers/cursor/index.ts +11 -7
- package/src/drivers/shared/acp-session.ts +40 -0
- package/src/index.ts +6 -0
- package/src/orchestrator/config.ts +4 -1
- package/src/orchestrator/doctor.ts +3 -1
- package/src/orchestrator/driver-capabilities.ts +6 -1
- package/src/orchestrator/driver-identity.ts +11 -1
- package/src/orchestrator/orchestrator.ts +19 -3
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
# Cursor driver
|
|
2
2
|
|
|
3
3
|
The `cursor` driver uses Cursor CLI's ACP transport. Install Cursor CLI and
|
|
4
|
-
authenticate it before running Lux.
|
|
5
|
-
|
|
4
|
+
authenticate it before running Lux. Lux defaults to the unambiguous
|
|
5
|
+
`cursor-agent` executable because other harnesses also install `agent`.
|
|
6
|
+
Set `command` to an absolute path or to `agent` if that is your Cursor installation.
|
|
6
7
|
|
|
7
8
|
```ts
|
|
8
9
|
{
|
|
9
10
|
name: "cursor",
|
|
10
11
|
config: {
|
|
11
|
-
command: "/absolute/path/to/cursor
|
|
12
|
+
command: "/absolute/path/to/cursor-agent",
|
|
12
13
|
model: "YOUR_CURSOR_MODEL_ID",
|
|
13
14
|
// Optional: one of low, medium, high, xhigh; applied only when ACP advertises it.
|
|
14
15
|
// reasoningEffort: "low",
|
|
@@ -16,11 +17,13 @@ set `command` to its absolute path if another application owns that name.
|
|
|
16
17
|
}
|
|
17
18
|
```
|
|
18
19
|
|
|
19
|
-
`model` is required. Cursor's model list is account-scoped (`agent
|
|
20
|
+
`model` is required. Cursor's model list is account-scoped (`cursor-agent
|
|
20
21
|
--list-models` after login), so the harness catalog keeps it open: any ID is
|
|
21
22
|
accepted in configuration and in a `matrix`, and some IDs encode reasoning
|
|
22
|
-
effort.
|
|
23
|
-
|
|
23
|
+
effort. Use the exact ACP model ID, including bracketed settings such as
|
|
24
|
+
`composer-2.5[fast=true]`. Lux passes the ID through `--model`, selects it with
|
|
25
|
+
ACP when the session advertises a model selector, and rejects a different
|
|
26
|
+
reported model. If `reasoningEffort` is supplied (`low`, `medium`,
|
|
24
27
|
`high`, or `xhigh`), Lux requires a matching advertised ACP thought-level
|
|
25
28
|
selector and checks the response confirms the requested value before sending
|
|
26
29
|
the prompt. No default effort is applied.
|
|
@@ -49,8 +52,11 @@ managed process tree before collecting artifacts. Aborting a run also terminates
|
|
|
49
52
|
the managed tree. Unsupported client filesystem/terminal operations are not
|
|
50
53
|
advertised and unsupported requests receive a JSON-RPC error.
|
|
51
54
|
|
|
52
|
-
The adapter
|
|
53
|
-
|
|
55
|
+
The adapter has synthetic protocol and lifecycle tests plus an opt-in live
|
|
56
|
+
smoke task: `mise run smoke:harnesses -- cursor` from the repository root.
|
|
57
|
+
The live task checks tool evidence, exact file output, and normal completion;
|
|
58
|
+
it uses your installed CLI, existing login, and model quota. Cursor CLI
|
|
59
|
+
`2026.09.23-86fc751` passed the basic authenticated file-copy smoke on 2026-09-30.
|
|
54
60
|
|
|
55
61
|
Protocol references:
|
|
56
62
|
|
|
@@ -4,7 +4,7 @@ import { cursorCatalog } from "../../core/index.js";
|
|
|
4
4
|
|
|
5
5
|
export const CursorDriverConfigSchema = z
|
|
6
6
|
.object({
|
|
7
|
-
command: z.string().min(1).default("agent"),
|
|
7
|
+
command: z.string().min(1).default("cursor-agent"),
|
|
8
8
|
model: z.string().min(1),
|
|
9
9
|
reasoningEffort: z.enum(cursorCatalog.efforts).optional(),
|
|
10
10
|
mode: z.enum(["agent", "plan", "ask"]).default("agent"),
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from "../../core/index.js";
|
|
15
15
|
import { AcpEvents } from "../shared/acp-events.js";
|
|
16
16
|
import { permissionRequestText, records } from "../shared/acp-interaction.js";
|
|
17
|
+
import { acpModel, selectAcpModel } from "../shared/acp-session.js";
|
|
17
18
|
import { AcpTransport, asRecord, type RpcId, type RpcRecord } from "../shared/acp-transport.js";
|
|
18
19
|
import { walkArtifacts } from "../shared/artifacts.js";
|
|
19
20
|
import { buildCursorArgs, type CursorDriverConfig, CursorDriverConfigSchema } from "./config.js";
|
|
@@ -91,6 +92,9 @@ class CursorDriver implements AgentDriver {
|
|
|
91
92
|
let session = await this.request("session/new", { cwd: this.cwd, mcpServers: [] });
|
|
92
93
|
if (typeof session.sessionId !== "string") throw new Error("Cursor ACP omitted sessionId");
|
|
93
94
|
this.sessionId = session.sessionId;
|
|
95
|
+
session = await selectAcpModel("Cursor", session, this.config.model, (method, params) =>
|
|
96
|
+
this.request(method, params),
|
|
97
|
+
);
|
|
94
98
|
if (this.config.reasoningEffort) {
|
|
95
99
|
const selection = effortSelector(session, this.config.reasoningEffort);
|
|
96
100
|
const updated = await this.request("session/set_config_option", {
|
|
@@ -104,10 +108,7 @@ class CursorDriver implements AgentDriver {
|
|
|
104
108
|
throw new Error("Cursor ACP did not apply the requested reasoning effort");
|
|
105
109
|
session = { ...session, ...updated };
|
|
106
110
|
}
|
|
107
|
-
const model =
|
|
108
|
-
records(session.configOptions).find(
|
|
109
|
-
(option) => option.category === "model" || option.id === "model",
|
|
110
|
-
)?.currentValue ?? asRecord(session.models)?.currentModelId;
|
|
111
|
+
const model = acpModel(session);
|
|
111
112
|
if (typeof model === "string" && model !== this.config.model)
|
|
112
113
|
throw new Error(
|
|
113
114
|
`Cursor ACP selected '${model}' instead of requested '${this.config.model}'`,
|
|
@@ -182,8 +183,11 @@ class CursorDriver implements AgentDriver {
|
|
|
182
183
|
});
|
|
183
184
|
return;
|
|
184
185
|
}
|
|
185
|
-
if (++this.interruptCount > this.config.maxInterrupts)
|
|
186
|
-
|
|
186
|
+
if (++this.interruptCount > this.config.maxInterrupts) {
|
|
187
|
+
this.transport?.write({ id, result: { outcome: { outcome: "cancelled" } } });
|
|
188
|
+
this.fail(new Error("Cursor exceeded maxInterrupts"), "max-interactions");
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
187
191
|
const interruptId = `cursor-${id}`;
|
|
188
192
|
if (this.interrupts.has(interruptId)) throw new Error("Cursor reused a pending request ID");
|
|
189
193
|
this.interrupts.set(interruptId, { id, method, params });
|
|
@@ -245,7 +249,7 @@ class CursorDriver implements AgentDriver {
|
|
|
245
249
|
);
|
|
246
250
|
}
|
|
247
251
|
|
|
248
|
-
private fail(error: unknown, exitReason: "error"
|
|
252
|
+
private fail(error: unknown, exitReason: DriverEventMap["error"]["exitReason"] = "error"): void {
|
|
249
253
|
if (this.terminal) return;
|
|
250
254
|
this.terminal = true;
|
|
251
255
|
clearTimeout(this.idleTimer);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { records } from "./acp-interaction.js";
|
|
2
|
+
import { asRecord, type RpcRecord } from "./acp-transport.js";
|
|
3
|
+
|
|
4
|
+
export const acpModel = (session: RpcRecord): unknown =>
|
|
5
|
+
records(session.configOptions).find(
|
|
6
|
+
(option) => option.category === "model" || option.id === "model",
|
|
7
|
+
)?.currentValue ?? asRecord(session.models)?.currentModelId;
|
|
8
|
+
|
|
9
|
+
const hasOption = (options: unknown, value: string): boolean =>
|
|
10
|
+
records(options).some((option) => option.value === value || hasOption(option.options, value));
|
|
11
|
+
|
|
12
|
+
export const selectAcpModel = async (
|
|
13
|
+
label: string,
|
|
14
|
+
session: RpcRecord,
|
|
15
|
+
model: string,
|
|
16
|
+
request: (method: string, params: RpcRecord) => Promise<RpcRecord>,
|
|
17
|
+
): Promise<RpcRecord> => {
|
|
18
|
+
let selected = session;
|
|
19
|
+
const selector = records(session.configOptions).find(
|
|
20
|
+
(option) => option.category === "model" || option.id === "model",
|
|
21
|
+
);
|
|
22
|
+
if (
|
|
23
|
+
acpModel(session) !== model &&
|
|
24
|
+
typeof selector?.id === "string" &&
|
|
25
|
+
hasOption(selector.options, model)
|
|
26
|
+
) {
|
|
27
|
+
const updated = await request("session/set_config_option", {
|
|
28
|
+
sessionId: session.sessionId,
|
|
29
|
+
configId: selector.id,
|
|
30
|
+
value: model,
|
|
31
|
+
});
|
|
32
|
+
selected = { ...session, ...updated };
|
|
33
|
+
}
|
|
34
|
+
const reported = acpModel(selected);
|
|
35
|
+
if (typeof reported === "string" && reported !== model)
|
|
36
|
+
throw new Error(
|
|
37
|
+
`${label} ACP selected '${reported}' instead of requested '${model}'; use an exact model ID advertised by the ACP session`,
|
|
38
|
+
);
|
|
39
|
+
return selected;
|
|
40
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -265,6 +265,12 @@ export {
|
|
|
265
265
|
type StartContext,
|
|
266
266
|
selectModelAndReasoningEffort,
|
|
267
267
|
} from "./core/driver.js";
|
|
268
|
+
export {
|
|
269
|
+
type ContainerExecution,
|
|
270
|
+
ContainerExecutionSchema,
|
|
271
|
+
type DriverExecution,
|
|
272
|
+
DriverExecutionSchema,
|
|
273
|
+
} from "./core/driver-execution.js";
|
|
268
274
|
export {
|
|
269
275
|
type DriverMetric,
|
|
270
276
|
type DriverMetricDescriptor,
|
|
@@ -74,7 +74,7 @@ const LifecycleHooksPluginSchema = z.custom<LifecycleHooksPlugin>().superRefine(
|
|
|
74
74
|
if (issue) ctx.addIssue({ code: "custom", message: issue });
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
const LuxConfigSchema = z
|
|
77
|
+
export const LuxConfigSchema = z
|
|
78
78
|
.object({
|
|
79
79
|
environment: EnvironmentDeclarationSchema.optional(),
|
|
80
80
|
casesRoot: z.string().optional(),
|
|
@@ -194,6 +194,9 @@ const builtinDrivers: DriverPlugin<never>[] = [
|
|
|
194
194
|
subprocessDriver,
|
|
195
195
|
mcpProbeDriver,
|
|
196
196
|
];
|
|
197
|
+
export const isBuiltinDriver = (plugin: DriverPlugin): boolean =>
|
|
198
|
+
builtinDrivers.some((builtin) => builtin === plugin);
|
|
199
|
+
|
|
197
200
|
const builtinAnswerers: AnswererPlugin<never>[] = [
|
|
198
201
|
personaAnswerer,
|
|
199
202
|
claudeCodeAnswerer,
|
|
@@ -4,6 +4,7 @@ import { resolve } from "node:path";
|
|
|
4
4
|
import { glob } from "tinyglobby";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { RubricConfigSchema } from "../assertions/rubric/index.js";
|
|
7
|
+
import { driverExecutionOf } from "../core/driver-execution.js";
|
|
7
8
|
import {
|
|
8
9
|
casePermutations,
|
|
9
10
|
type EvalCase,
|
|
@@ -143,6 +144,7 @@ const effectiveDriverReference = (local: unknown, fallback: unknown): unknown =>
|
|
|
143
144
|
return {
|
|
144
145
|
name: refName(local),
|
|
145
146
|
config: mergeRecords(rawRefConfig(fallback), rawRefConfig(local)),
|
|
147
|
+
execution: driverExecutionOf(local) ?? driverExecutionOf(fallback),
|
|
146
148
|
};
|
|
147
149
|
};
|
|
148
150
|
|
|
@@ -511,7 +513,7 @@ const caseDriverFailure = (
|
|
|
511
513
|
rawRefConfig(reference),
|
|
512
514
|
`case '${caseId}' driver '${name}'`,
|
|
513
515
|
);
|
|
514
|
-
validateDriverCapabilities(plugin, config, required);
|
|
516
|
+
validateDriverCapabilities(plugin, config, required, driverExecutionOf(reference));
|
|
515
517
|
return null;
|
|
516
518
|
} catch (error) {
|
|
517
519
|
return firstLine(error);
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import type { DriverCapability, DriverPlugin } from "../core/driver.js";
|
|
2
|
+
import type { DriverExecution } from "../core/driver-execution.js";
|
|
2
3
|
|
|
3
4
|
export const validateDriverCapabilities = (
|
|
4
5
|
plugin: DriverPlugin,
|
|
5
6
|
config: unknown,
|
|
6
7
|
required: readonly DriverCapability[] = [],
|
|
8
|
+
execution?: DriverExecution,
|
|
7
9
|
): void => {
|
|
8
10
|
if (required.length === 0) return;
|
|
9
|
-
const capabilities =
|
|
11
|
+
const capabilities = {
|
|
12
|
+
...plugin.runtime?.(config).capabilities,
|
|
13
|
+
...(execution?.kind === "container" ? { isolation: true } : {}),
|
|
14
|
+
};
|
|
10
15
|
const missing = required.filter((capability) => capabilities?.[capability] !== true);
|
|
11
16
|
if (missing.length > 0) {
|
|
12
17
|
throw new Error(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DriverPlugin, DriverRuntime } from "../core/driver.js";
|
|
2
|
+
import { driverExecutionOf } from "../core/driver-execution.js";
|
|
2
3
|
import type { Registry } from "../core/registry.js";
|
|
3
4
|
import { cliIdentity } from "./experiment-runtime-identity.js";
|
|
4
5
|
import { validatePluginConfig } from "./validate-plugin-config.js";
|
|
@@ -21,7 +22,14 @@ const resolvedDriver = (
|
|
|
21
22
|
|
|
22
23
|
export const referencedDriverRuntime = (reference: unknown, registry: Registry): DriverRuntime => {
|
|
23
24
|
const resolved = resolvedDriver(reference, registry);
|
|
24
|
-
|
|
25
|
+
const runtime = resolved?.plugin.runtime?.(resolved.config) ?? { commands: [], capabilities: {} };
|
|
26
|
+
const execution = driverExecutionOf(reference);
|
|
27
|
+
return execution?.kind === "container"
|
|
28
|
+
? {
|
|
29
|
+
commands: [execution.command ?? "docker"],
|
|
30
|
+
capabilities: { ...runtime.capabilities, isolation: true },
|
|
31
|
+
}
|
|
32
|
+
: runtime;
|
|
25
33
|
};
|
|
26
34
|
|
|
27
35
|
export const experimentDriverIdentity = async (
|
|
@@ -29,6 +37,8 @@ export const experimentDriverIdentity = async (
|
|
|
29
37
|
registry: Registry,
|
|
30
38
|
rootDir: string,
|
|
31
39
|
): Promise<unknown> => {
|
|
40
|
+
if (driverExecutionOf(reference)?.kind === "container")
|
|
41
|
+
throw new Error("container execution does not yet support controlled experiments");
|
|
32
42
|
const resolved = resolvedDriver(reference, registry);
|
|
33
43
|
if (!resolved) return null;
|
|
34
44
|
const { plugin, config } = resolved;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { basename, extname, join, resolve } from "node:path";
|
|
2
|
+
import { ContainerDriver } from "../container/driver.js";
|
|
3
|
+
import { driverExecutionOf } from "../core/driver-execution.js";
|
|
2
4
|
import { type EnvironmentDeclaration, EnvironmentDeclarationSchema } from "../core/environment.js";
|
|
3
5
|
import {
|
|
4
6
|
type Answerer,
|
|
@@ -28,6 +30,7 @@ import {
|
|
|
28
30
|
registryForEvalCase,
|
|
29
31
|
valuesForFixtures,
|
|
30
32
|
} from "./case-extensions.js";
|
|
33
|
+
import { isBuiltinDriver } from "./config.js";
|
|
31
34
|
import { validateDriverCapabilities } from "./driver-capabilities.js";
|
|
32
35
|
import { evaluatorImplementationHash } from "./evaluator-identity.js";
|
|
33
36
|
import {
|
|
@@ -249,6 +252,7 @@ export const resolveDriverReference = (
|
|
|
249
252
|
return {
|
|
250
253
|
name: driverNameOf(local),
|
|
251
254
|
config: mergePluginConfig(driverConfigOf(base), driverConfigOf(local)),
|
|
255
|
+
execution: driverExecutionOf(local) ?? driverExecutionOf(base),
|
|
252
256
|
};
|
|
253
257
|
};
|
|
254
258
|
|
|
@@ -390,8 +394,20 @@ export class Orchestrator {
|
|
|
390
394
|
`answerer '${answererName}'`,
|
|
391
395
|
);
|
|
392
396
|
|
|
393
|
-
|
|
394
|
-
|
|
397
|
+
const execution = driverExecutionOf(driverRef);
|
|
398
|
+
if (execution?.kind === "container" && request.experimentId)
|
|
399
|
+
throw new Error("container execution does not yet support controlled experiments");
|
|
400
|
+
if (
|
|
401
|
+
execution?.kind === "container" &&
|
|
402
|
+
!execution.driverModule &&
|
|
403
|
+
!isBuiltinDriver(driverPlugin)
|
|
404
|
+
)
|
|
405
|
+
throw new Error("custom container drivers require execution.driverModule in the image");
|
|
406
|
+
validateDriverCapabilities(driverPlugin, driverCfg, evalCase.requires, execution);
|
|
407
|
+
const driver =
|
|
408
|
+
execution?.kind === "container"
|
|
409
|
+
? new ContainerDriver(driverName, driverCfg, execution)
|
|
410
|
+
: await driverPlugin.create(driverCfg);
|
|
395
411
|
let answerer: Answerer;
|
|
396
412
|
try {
|
|
397
413
|
answerer = await answererPlugin.create(answererCfg);
|
|
@@ -427,7 +443,7 @@ export class Orchestrator {
|
|
|
427
443
|
permutationId: request.permutationId,
|
|
428
444
|
answererName,
|
|
429
445
|
answererConfig: answererCfg,
|
|
430
|
-
driverConfigHash: valueHash(driverCfg),
|
|
446
|
+
driverConfigHash: valueHash(execution ? { config: driverCfg, execution } : driverCfg),
|
|
431
447
|
answererConfigHash: valueHash(answererCfg),
|
|
432
448
|
validatedAssertionsHash,
|
|
433
449
|
graderConfigHash: graderHash,
|