@prismatic-io/lux 0.0.2-preview.25 → 0.0.2-preview.27
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/answerers/claude-code/index.d.ts +3 -3
- package/lib/answerers/claude-code/index.d.ts.map +1 -1
- package/lib/answerers/claude-code/index.js +3 -2
- package/lib/answerers/claude-code/index.js.map +1 -1
- package/lib/answerers/persona/index.d.ts +3 -3
- package/lib/answerers/persona/index.d.ts.map +1 -1
- package/lib/answerers/persona/index.js +3 -2
- package/lib/answerers/persona/index.js.map +1 -1
- package/lib/answerers/terminal/index.d.ts +3 -3
- package/lib/answerers/terminal/index.d.ts.map +1 -1
- package/lib/answerers/terminal/index.js +3 -2
- package/lib/answerers/terminal/index.js.map +1 -1
- package/lib/assertions/core/command-exits-zero.d.ts +1 -1
- package/lib/assertions/core/command-exits-zero.d.ts.map +1 -1
- package/lib/assertions/core/command-exits-zero.js +4 -3
- package/lib/assertions/core/command-exits-zero.js.map +1 -1
- package/lib/assertions/rubric/index.d.ts +7 -2
- package/lib/assertions/rubric/index.d.ts.map +1 -1
- package/lib/assertions/rubric/index.js +18 -10
- package/lib/assertions/rubric/index.js.map +1 -1
- package/lib/assertions/rubric/internal.d.ts +1 -1
- package/lib/assertions/rubric/internal.d.ts.map +1 -1
- package/lib/assertions/rubric/internal.js +7 -2
- package/lib/assertions/rubric/internal.js.map +1 -1
- 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/cli/output-schemas.d.ts +2 -2
- package/lib/cli/program.js +2 -2
- package/lib/cli/program.js.map +1 -1
- package/lib/core/duration.d.ts +5 -0
- package/lib/core/duration.d.ts.map +1 -0
- package/lib/core/duration.js +49 -0
- package/lib/core/duration.js.map +1 -0
- package/lib/core/experiment.d.ts +2 -2
- package/lib/core/experiment.d.ts.map +1 -1
- package/lib/core/experiment.js +2 -1
- package/lib/core/experiment.js.map +1 -1
- package/lib/core/index.d.ts +1 -0
- package/lib/core/index.d.ts.map +1 -1
- package/lib/core/index.js +1 -0
- package/lib/core/index.js.map +1 -1
- package/lib/drivers/antigravity/config.d.ts +3 -3
- package/lib/drivers/antigravity/config.d.ts.map +1 -1
- package/lib/drivers/antigravity/config.js +2 -1
- package/lib/drivers/antigravity/config.js.map +1 -1
- package/lib/drivers/antigravity/index.d.ts +4 -4
- package/lib/drivers/antigravity/index.js +1 -1
- package/lib/drivers/antigravity/index.js.map +1 -1
- package/lib/drivers/claude-code/index.d.ts +14 -14
- package/lib/drivers/claude-code/index.d.ts.map +1 -1
- package/lib/drivers/claude-code/index.js +10 -9
- package/lib/drivers/claude-code/index.js.map +1 -1
- package/lib/drivers/codex/config.d.ts +3 -3
- package/lib/drivers/codex/config.d.ts.map +1 -1
- package/lib/drivers/codex/config.js +2 -1
- package/lib/drivers/codex/config.js.map +1 -1
- package/lib/drivers/codex/index.d.ts +4 -4
- package/lib/drivers/codex/index.d.ts.map +1 -1
- package/lib/drivers/codex/index.js +4 -3
- package/lib/drivers/codex/index.js.map +1 -1
- package/lib/drivers/copilot/config.d.ts +6 -6
- package/lib/drivers/copilot/config.d.ts.map +1 -1
- package/lib/drivers/copilot/config.js +3 -2
- package/lib/drivers/copilot/config.js.map +1 -1
- package/lib/drivers/copilot/index.d.ts +8 -8
- package/lib/drivers/copilot/index.d.ts.map +1 -1
- package/lib/drivers/copilot/index.js +3 -2
- package/lib/drivers/copilot/index.js.map +1 -1
- package/lib/drivers/cursor/config.d.ts +2 -2
- package/lib/drivers/cursor/config.d.ts.map +1 -1
- package/lib/drivers/cursor/config.js +3 -2
- package/lib/drivers/cursor/config.js.map +1 -1
- package/lib/drivers/cursor/index.d.ts +4 -4
- package/lib/drivers/cursor/index.d.ts.map +1 -1
- package/lib/drivers/cursor/index.js +3 -2
- package/lib/drivers/cursor/index.js.map +1 -1
- package/lib/drivers/grok-build/config.d.ts +9 -9
- package/lib/drivers/grok-build/config.d.ts.map +1 -1
- package/lib/drivers/grok-build/config.js +4 -3
- package/lib/drivers/grok-build/config.js.map +1 -1
- package/lib/drivers/grok-build/index.d.ts +12 -12
- package/lib/drivers/grok-build/index.d.ts.map +1 -1
- package/lib/drivers/grok-build/index.js +5 -4
- package/lib/drivers/grok-build/index.js.map +1 -1
- package/lib/drivers/mcp/index.d.ts +6 -6
- package/lib/drivers/mcp/index.d.ts.map +1 -1
- package/lib/drivers/mcp/index.js +9 -8
- package/lib/drivers/mcp/index.js.map +1 -1
- package/lib/drivers/shared/artifacts.d.ts.map +1 -1
- package/lib/drivers/shared/artifacts.js +3 -2
- package/lib/drivers/shared/artifacts.js.map +1 -1
- package/lib/drivers/subprocess/index.d.ts +3 -3
- package/lib/drivers/subprocess/index.d.ts.map +1 -1
- package/lib/drivers/subprocess/index.js +4 -3
- package/lib/drivers/subprocess/index.js.map +1 -1
- 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/optimization/reflective.d.ts +1 -1
- package/lib/optimization/reflective.d.ts.map +1 -1
- package/lib/optimization/reflective.js +3 -2
- package/lib/optimization/reflective.js.map +1 -1
- package/lib/orchestrator/candidates.d.ts.map +1 -1
- package/lib/orchestrator/candidates.js +3 -2
- package/lib/orchestrator/candidates.js.map +1 -1
- package/lib/orchestrator/experiment-contracts.d.ts +1 -1
- package/lib/orchestrator/experiment-evaluation.d.ts.map +1 -1
- package/lib/orchestrator/experiment-evaluation.js +3 -2
- package/lib/orchestrator/experiment-evaluation.js.map +1 -1
- package/lib/orchestrator/experiment-loader.d.ts +1 -1
- package/lib/orchestrator/experiment-report.d.ts +1 -1
- package/lib/orchestrator/experiment-runs.d.ts +1 -1
- package/lib/orchestrator/grader-experiment.d.ts.map +1 -1
- package/lib/orchestrator/grader-experiment.js +2 -2
- package/lib/orchestrator/grader-experiment.js.map +1 -1
- package/lib/orchestrator/grading.js +1 -1
- package/lib/orchestrator/grading.js.map +1 -1
- package/lib/orchestrator/harness-registry.d.ts +4 -0
- package/lib/orchestrator/harness-registry.d.ts.map +1 -0
- package/lib/orchestrator/harness-registry.js +5 -0
- package/lib/orchestrator/harness-registry.js.map +1 -0
- package/lib/orchestrator/rubric-loader.js +1 -1
- package/lib/orchestrator/rubric-loader.js.map +1 -1
- package/package.json +1 -1
- package/skills/lux-answerer/SKILL.md +2 -2
- package/src/answerers/claude-code/index.ts +3 -2
- package/src/answerers/persona/index.ts +3 -2
- package/src/answerers/terminal/index.ts +3 -2
- package/src/assertions/core/command-exits-zero.ts +4 -3
- package/src/assertions/rubric/index.ts +23 -10
- package/src/assertions/rubric/internal.ts +8 -2
- package/src/authoring.ts +1 -0
- package/src/cli/program.ts +2 -2
- package/src/core/duration.ts +52 -0
- package/src/core/experiment.ts +2 -1
- package/src/core/index.ts +1 -0
- package/src/drivers/antigravity/config.ts +2 -1
- package/src/drivers/antigravity/index.ts +1 -1
- package/src/drivers/claude-code/index.ts +10 -9
- package/src/drivers/codex/config.ts +2 -1
- package/src/drivers/codex/index.ts +4 -3
- package/src/drivers/copilot/config.ts +3 -2
- package/src/drivers/copilot/index.ts +4 -3
- package/src/drivers/cursor/config.ts +3 -2
- package/src/drivers/cursor/index.ts +4 -3
- package/src/drivers/grok-build/README.md +2 -2
- package/src/drivers/grok-build/config.ts +4 -3
- package/src/drivers/grok-build/index.ts +6 -5
- package/src/drivers/mcp/index.ts +9 -8
- package/src/drivers/shared/artifacts.ts +6 -2
- package/src/drivers/subprocess/index.ts +4 -3
- package/src/index.ts +1 -0
- package/src/optimization/reflective.ts +3 -2
- package/src/orchestrator/candidates.ts +3 -2
- package/src/orchestrator/experiment-evaluation.ts +3 -5
- package/src/orchestrator/grader-experiment.ts +2 -5
- package/src/orchestrator/grading.ts +1 -1
- package/src/orchestrator/harness-registry.ts +12 -0
- package/src/orchestrator/rubric-loader.ts +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { DurationSchema } from "../../core/duration.js";
|
|
2
3
|
import { antigravityCatalog, applyCatalogEffort } from "../../core/index.js";
|
|
3
4
|
|
|
4
5
|
export const AntigravityDriverConfigSchema = z
|
|
@@ -23,7 +24,7 @@ export const AntigravityDriverConfigSchema = z
|
|
|
23
24
|
cwd: z.string().optional(),
|
|
24
25
|
env: z.record(z.string(), z.string()).optional(),
|
|
25
26
|
extraArgs: z.array(z.string()).optional(),
|
|
26
|
-
|
|
27
|
+
idleTimeout: DurationSchema.default("10 minutes"),
|
|
27
28
|
maxLineBytes: z.number().positive().default(10_000_000),
|
|
28
29
|
})
|
|
29
30
|
.strict()
|
|
@@ -58,7 +58,7 @@ class AntigravityDriver implements AgentDriver {
|
|
|
58
58
|
`The task workspace is ${JSON.stringify(this.cwd)}. Treat that directory as the current directory for this task and create task artifacts there.\n\n${prompt}`,
|
|
59
59
|
),
|
|
60
60
|
closeStdinAfterPrompt: true,
|
|
61
|
-
|
|
61
|
+
idleTimeout: this.config.idleTimeout,
|
|
62
62
|
maxLineBytes: this.config.maxLineBytes,
|
|
63
63
|
maxInterrupts: 1,
|
|
64
64
|
});
|
|
@@ -3,6 +3,7 @@ import { homedir } from "node:os";
|
|
|
3
3
|
import { dirname, join, resolve, sep } from "node:path";
|
|
4
4
|
import { temporaryDirectory } from "tempy";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
+
import { DurationSchema, durationMs } from "../../core/duration.js";
|
|
6
7
|
import {
|
|
7
8
|
type AgentDriver,
|
|
8
9
|
type Answer,
|
|
@@ -108,19 +109,19 @@ export const ClaudeCodeDriverConfigSchema = z
|
|
|
108
109
|
*/
|
|
109
110
|
textQuestionFallback: z.boolean().default(false),
|
|
110
111
|
/** Maximum silence between recognized protocol events; excludes answerer wait time. */
|
|
111
|
-
|
|
112
|
+
idleTimeout: DurationSchema.default("10 minutes"),
|
|
112
113
|
/** Optional elapsed-time cap per defer-resume CLI invocation, regardless of activity. */
|
|
113
|
-
|
|
114
|
+
turnTimeout: DurationSchema.optional(),
|
|
114
115
|
/** Cap on outstanding interrupts before the driver aborts. */
|
|
115
116
|
maxInterrupts: z.number().positive().default(20),
|
|
116
117
|
})
|
|
117
118
|
.strict()
|
|
118
119
|
.superRefine((config, ctx) => {
|
|
119
|
-
if (config.
|
|
120
|
+
if (config.turnTimeout !== undefined && config.interactionMode !== "defer-resume") {
|
|
120
121
|
ctx.addIssue({
|
|
121
122
|
code: "custom",
|
|
122
|
-
path: ["
|
|
123
|
-
message: "
|
|
123
|
+
path: ["turnTimeout"],
|
|
124
|
+
message: "turnTimeout requires defer-resume mode",
|
|
124
125
|
});
|
|
125
126
|
}
|
|
126
127
|
if (config.interactionMode === "defer-resume") {
|
|
@@ -596,7 +597,7 @@ class ClaudeCodeDriverImpl implements AgentDriver {
|
|
|
596
597
|
parseEvent: makeParseEvent(this.config, cliVersion),
|
|
597
598
|
formatAnswer,
|
|
598
599
|
formatPrompt,
|
|
599
|
-
|
|
600
|
+
idleTimeout: this.config.idleTimeout,
|
|
600
601
|
maxInterrupts: this.config.maxInterrupts,
|
|
601
602
|
});
|
|
602
603
|
for (const queued of this.pendingAttach) queued.attach(inner);
|
|
@@ -752,10 +753,10 @@ class ClaudeCodeDriverImpl implements AgentDriver {
|
|
|
752
753
|
...(answer ? { LUX_CLAUDE_DEFERRED_ANSWER: JSON.stringify(answer) } : {}),
|
|
753
754
|
},
|
|
754
755
|
...input,
|
|
755
|
-
idleTimeoutMs: this.config.
|
|
756
|
-
...(this.config.
|
|
756
|
+
idleTimeoutMs: durationMs(this.config.idleTimeout),
|
|
757
|
+
...(this.config.turnTimeout === undefined
|
|
757
758
|
? {}
|
|
758
|
-
: { turnTimeoutMs: this.config.
|
|
759
|
+
: { turnTimeoutMs: durationMs(this.config.turnTimeout) }),
|
|
759
760
|
signal: AbortSignal.any([ctx.abortSignal, this.deferredAbort.signal]),
|
|
760
761
|
parse: (line) => {
|
|
761
762
|
try {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { DurationSchema } from "../../core/duration.js";
|
|
2
3
|
import { applyCatalogEffort, codexCatalog, DEFAULT_CODEX_MODEL } from "../../core/index.js";
|
|
3
4
|
|
|
4
5
|
export type CodexConfigValue =
|
|
@@ -51,7 +52,7 @@ export const CodexDriverConfigSchema = z
|
|
|
51
52
|
isolation: IsolationSchema.optional(),
|
|
52
53
|
maxInterrupts: z.number().positive().default(20),
|
|
53
54
|
maxLineBytes: z.number().positive().default(10_000_000),
|
|
54
|
-
|
|
55
|
+
idleTimeout: DurationSchema.default("10 minutes"),
|
|
55
56
|
})
|
|
56
57
|
.strict()
|
|
57
58
|
.superRefine((config, ctx) => {
|
|
@@ -3,6 +3,7 @@ import { homedir } from "node:os";
|
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { createInterface } from "node:readline";
|
|
5
5
|
import { temporaryDirectory } from "tempy";
|
|
6
|
+
import { durationMs } from "../../core/duration.js";
|
|
6
7
|
import {
|
|
7
8
|
type AgentDriver,
|
|
8
9
|
type Answer,
|
|
@@ -654,8 +655,8 @@ class CodexAppServerDriverImpl implements AgentDriver {
|
|
|
654
655
|
this.idleTimer = setTimeout(() => {
|
|
655
656
|
this.idleTimer = null;
|
|
656
657
|
if (this.interrupts.size > 0) return;
|
|
657
|
-
this.fail(`no event for ${this.config.
|
|
658
|
-
}, this.config.
|
|
658
|
+
this.fail(`no event for ${durationMs(this.config.idleTimeout)}ms`, "idle-timeout");
|
|
659
|
+
}, durationMs(this.config.idleTimeout));
|
|
659
660
|
}
|
|
660
661
|
|
|
661
662
|
private clearIdleTimer(): void {
|
|
@@ -718,7 +719,7 @@ class CodexExecDriverImpl implements AgentDriver {
|
|
|
718
719
|
parseEvent: makeParseEvent(this.config, cliVersion),
|
|
719
720
|
formatPrompt: (prompt) => prompt,
|
|
720
721
|
closeStdinAfterPrompt: true,
|
|
721
|
-
|
|
722
|
+
idleTimeout: this.config.idleTimeout,
|
|
722
723
|
maxLineBytes: this.config.maxLineBytes,
|
|
723
724
|
maxInterrupts: 1,
|
|
724
725
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { DurationSchema } from "../../core/duration.js";
|
|
2
3
|
import { applyCatalogEffort, copilotCatalog } from "../../core/index.js";
|
|
3
4
|
|
|
4
5
|
export const CopilotDriverConfigSchema = z
|
|
@@ -23,8 +24,8 @@ export const CopilotDriverConfigSchema = z
|
|
|
23
24
|
extraArgs: z.array(z.string()).optional(),
|
|
24
25
|
cwd: z.string().optional(),
|
|
25
26
|
env: z.record(z.string(), z.string()).optional(),
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
startupTimeout: DurationSchema.default("30 seconds"),
|
|
28
|
+
idleTimeout: DurationSchema.default("10 minutes"),
|
|
28
29
|
maxInterrupts: z.number().int().positive().default(20),
|
|
29
30
|
maxLineBytes: z.number().int().positive().default(10_000_000),
|
|
30
31
|
maxQueuedBytes: z.number().int().positive().default(20_000_000),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { realpath } from "node:fs/promises";
|
|
2
|
+
import { durationMs } from "../../core/duration.js";
|
|
2
3
|
import {
|
|
3
4
|
type AgentDriver,
|
|
4
5
|
type Answer,
|
|
@@ -130,7 +131,7 @@ class CopilotDriver implements AgentDriver {
|
|
|
130
131
|
|
|
131
132
|
private request(method: string, params: RpcRecord): Promise<RpcRecord> {
|
|
132
133
|
if (!this.transport) throw new Error("Copilot ACP has not started");
|
|
133
|
-
return this.transport.request(method, params, this.config.
|
|
134
|
+
return this.transport.request(method, params, durationMs(this.config.startupTimeout));
|
|
134
135
|
}
|
|
135
136
|
|
|
136
137
|
private async run(prompt: string): Promise<void> {
|
|
@@ -209,10 +210,10 @@ class CopilotDriver implements AgentDriver {
|
|
|
209
210
|
this.idleTimer = setTimeout(
|
|
210
211
|
() =>
|
|
211
212
|
this.fail(
|
|
212
|
-
new Error(`Copilot emitted no event for ${this.config.
|
|
213
|
+
new Error(`Copilot emitted no event for ${durationMs(this.config.idleTimeout)}ms`),
|
|
213
214
|
"idle-timeout",
|
|
214
215
|
),
|
|
215
|
-
this.config.
|
|
216
|
+
durationMs(this.config.idleTimeout),
|
|
216
217
|
);
|
|
217
218
|
}
|
|
218
219
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { DurationSchema } from "../../core/duration.js";
|
|
2
3
|
import { cursorCatalog } from "../../core/index.js";
|
|
3
4
|
|
|
4
5
|
export const CursorDriverConfigSchema = z
|
|
@@ -9,8 +10,8 @@ export const CursorDriverConfigSchema = z
|
|
|
9
10
|
mode: z.enum(["agent", "plan", "ask"]).default("agent"),
|
|
10
11
|
cwd: z.string().optional(),
|
|
11
12
|
env: z.record(z.string(), z.string()).optional(),
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
startupTimeout: DurationSchema.default("30 seconds"),
|
|
14
|
+
idleTimeout: DurationSchema.default("10 minutes"),
|
|
14
15
|
maxInterrupts: z.number().int().positive().default(20),
|
|
15
16
|
maxLineBytes: z.number().int().positive().default(10_000_000),
|
|
16
17
|
maxQueuedBytes: z.number().int().positive().default(20_000_000),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { realpath } from "node:fs/promises";
|
|
2
|
+
import { durationMs } from "../../core/duration.js";
|
|
2
3
|
import {
|
|
3
4
|
type AgentDriver,
|
|
4
5
|
type Answer,
|
|
@@ -136,7 +137,7 @@ class CursorDriver implements AgentDriver {
|
|
|
136
137
|
|
|
137
138
|
private request(method: string, params: RpcRecord): Promise<RpcRecord> {
|
|
138
139
|
if (!this.transport) throw new Error("Cursor ACP has not started");
|
|
139
|
-
return this.transport.request(method, params, this.config.
|
|
140
|
+
return this.transport.request(method, params, durationMs(this.config.startupTimeout));
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
private async run(prompt: string): Promise<void> {
|
|
@@ -237,10 +238,10 @@ class CursorDriver implements AgentDriver {
|
|
|
237
238
|
this.idleTimer = setTimeout(
|
|
238
239
|
() =>
|
|
239
240
|
this.fail(
|
|
240
|
-
new Error(`Cursor emitted no event for ${this.config.
|
|
241
|
+
new Error(`Cursor emitted no event for ${durationMs(this.config.idleTimeout)}ms`),
|
|
241
242
|
"idle-timeout",
|
|
242
243
|
),
|
|
243
|
-
this.config.
|
|
244
|
+
durationMs(this.config.idleTimeout),
|
|
244
245
|
);
|
|
245
246
|
}
|
|
246
247
|
|
|
@@ -64,8 +64,8 @@ text and invalid fields still deny the operation. If the agent offers no matchin
|
|
|
64
64
|
one-operation option, Lux cancels and reports an error rather than widening the
|
|
65
65
|
grant. Native auto decisions are handled inside Grok and are not Lux interrupts.
|
|
66
66
|
|
|
67
|
-
Permission reviews have a separate `
|
|
68
|
-
default), while ordinary inactivity uses `
|
|
67
|
+
Permission reviews have a separate `permissionTimeout` (150 seconds by
|
|
68
|
+
default), while ordinary inactivity uses `idleTimeout` (10 minutes). Startup
|
|
69
69
|
RPCs time out after 30 seconds. Cancelled turns, process failures, unanswered
|
|
70
70
|
reviews, and turns ending with pending approvals cannot count as successful runs.
|
|
71
71
|
A completed turn can still contain denied tool calls: assert the expected files
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { DurationSchema } from "../../core/duration.js";
|
|
2
3
|
import { applyCatalogEffort, grokBuildCatalog } from "../../core/index.js";
|
|
3
4
|
|
|
4
5
|
export const GrokBuildDriverConfigSchema = z
|
|
@@ -11,9 +12,9 @@ export const GrokBuildDriverConfigSchema = z
|
|
|
11
12
|
sandbox: z.enum(["workspace", "read-only", "strict"]).default("workspace"),
|
|
12
13
|
cwd: z.string().optional(),
|
|
13
14
|
env: z.record(z.string(), z.string()).optional(),
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
startupTimeout: DurationSchema.default("30 seconds"),
|
|
16
|
+
idleTimeout: DurationSchema.default("10 minutes"),
|
|
17
|
+
permissionTimeout: DurationSchema.default("150 seconds"),
|
|
17
18
|
maxInterrupts: z.number().int().positive().default(20),
|
|
18
19
|
maxLineBytes: z.number().int().positive().default(10_000_000),
|
|
19
20
|
maxQueuedBytes: z.number().int().positive().default(20_000_000),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { realpath } from "node:fs/promises";
|
|
2
|
+
import { durationMs } from "../../core/duration.js";
|
|
2
3
|
import {
|
|
3
4
|
type AgentDriver,
|
|
4
5
|
type Answer,
|
|
@@ -143,7 +144,7 @@ class GrokBuildDriver implements AgentDriver {
|
|
|
143
144
|
|
|
144
145
|
private request(method: string, params: RpcRecord): Promise<RpcRecord> {
|
|
145
146
|
if (!this.transport) throw new Error("Grok.build ACP has not started");
|
|
146
|
-
return this.transport.request(method, params, this.config.
|
|
147
|
+
return this.transport.request(method, params, durationMs(this.config.startupTimeout));
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
private async run(prompt: string): Promise<void> {
|
|
@@ -198,10 +199,10 @@ class GrokBuildDriver implements AgentDriver {
|
|
|
198
199
|
this.interrupts.delete(interruptId);
|
|
199
200
|
this.fail(
|
|
200
201
|
new Error(
|
|
201
|
-
`Grok.build permission review timed out after ${this.config.
|
|
202
|
+
`Grok.build permission review timed out after ${durationMs(this.config.permissionTimeout)}ms`,
|
|
202
203
|
),
|
|
203
204
|
);
|
|
204
|
-
}, this.config.
|
|
205
|
+
}, durationMs(this.config.permissionTimeout));
|
|
205
206
|
this.interrupts.set(interruptId, { id, params, timer });
|
|
206
207
|
clearTimeout(this.idleTimer);
|
|
207
208
|
void this.emitter
|
|
@@ -243,10 +244,10 @@ class GrokBuildDriver implements AgentDriver {
|
|
|
243
244
|
this.idleTimer = setTimeout(
|
|
244
245
|
() =>
|
|
245
246
|
this.fail(
|
|
246
|
-
new Error(`Grok.build emitted no event for ${this.config.
|
|
247
|
+
new Error(`Grok.build emitted no event for ${durationMs(this.config.idleTimeout)}ms`),
|
|
247
248
|
"idle-timeout",
|
|
248
249
|
),
|
|
249
|
-
this.config.
|
|
250
|
+
durationMs(this.config.idleTimeout),
|
|
250
251
|
);
|
|
251
252
|
}
|
|
252
253
|
|
package/src/drivers/mcp/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
2
|
import { getDefaultEnvironment } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { DurationSchema, durationMs as parseDuration } from "../../core/duration.js";
|
|
4
5
|
import {
|
|
5
6
|
type AgentDriver,
|
|
6
7
|
type Answer,
|
|
@@ -72,9 +73,9 @@ export const McpProbeDriverConfigSchema = z
|
|
|
72
73
|
/** The steps to run. Defaults to a single `tools/list` capture. */
|
|
73
74
|
probe: z.array(ProbeStepSchema).default([{ op: "list-tools" }]),
|
|
74
75
|
/** Timeout for the initialize handshake. */
|
|
75
|
-
|
|
76
|
+
startupTimeout: DurationSchema.default("30 seconds"),
|
|
76
77
|
/** Timeout for each `tools/list` / `tools/call` request. */
|
|
77
|
-
|
|
78
|
+
stepTimeout: DurationSchema.default("1 minute"),
|
|
78
79
|
/** Safety cap for a paginated `tools/list` operation. */
|
|
79
80
|
maxListPages: z.number().int().positive().default(100),
|
|
80
81
|
})
|
|
@@ -211,8 +212,8 @@ class McpProbeDriverImpl implements AgentDriver {
|
|
|
211
212
|
|
|
212
213
|
try {
|
|
213
214
|
await client.connect(transport, {
|
|
214
|
-
timeout: this.config.
|
|
215
|
-
maxTotalTimeout: this.config.
|
|
215
|
+
timeout: parseDuration(this.config.startupTimeout),
|
|
216
|
+
maxTotalTimeout: parseDuration(this.config.startupTimeout),
|
|
216
217
|
signal: ctx.abortSignal,
|
|
217
218
|
});
|
|
218
219
|
} catch (err) {
|
|
@@ -261,8 +262,8 @@ class McpProbeDriverImpl implements AgentDriver {
|
|
|
261
262
|
throw new Error(`tools/list exceeded ${this.config.maxListPages} pages`);
|
|
262
263
|
}
|
|
263
264
|
const result = await client.listTools(cursor ? { cursor } : undefined, {
|
|
264
|
-
timeout: this.config.
|
|
265
|
-
maxTotalTimeout: this.config.
|
|
265
|
+
timeout: parseDuration(this.config.stepTimeout),
|
|
266
|
+
maxTotalTimeout: parseDuration(this.config.stepTimeout),
|
|
266
267
|
...(this.abortSignal ? { signal: this.abortSignal } : {}),
|
|
267
268
|
});
|
|
268
269
|
tools.push(...(result.tools as ListedTool[]));
|
|
@@ -285,8 +286,8 @@ class McpProbeDriverImpl implements AgentDriver {
|
|
|
285
286
|
{ name: step.tool, arguments: step.args },
|
|
286
287
|
undefined,
|
|
287
288
|
{
|
|
288
|
-
timeout: this.config.
|
|
289
|
-
maxTotalTimeout: this.config.
|
|
289
|
+
timeout: parseDuration(this.config.stepTimeout),
|
|
290
|
+
maxTotalTimeout: parseDuration(this.config.stepTimeout),
|
|
290
291
|
...(this.abortSignal ? { signal: this.abortSignal } : {}),
|
|
291
292
|
},
|
|
292
293
|
);
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
readArtifactSnapshotManifest,
|
|
7
7
|
} from "../../core/index.js";
|
|
8
8
|
|
|
9
|
-
const IGNORED_DIRS = new Set(["node_modules", "
|
|
9
|
+
const IGNORED_DIRS = new Set(["node_modules", "dist"]);
|
|
10
10
|
|
|
11
11
|
/** Enumerate agent-authored files without following symlinks or build/dependency trees. */
|
|
12
12
|
export const walkArtifacts = async (root: string, max = 500): Promise<Artifact[]> => {
|
|
@@ -71,7 +71,11 @@ export const walkArtifacts = async (root: string, max = 500): Promise<Artifact[]
|
|
|
71
71
|
const full = join(dir, entry.name);
|
|
72
72
|
if (entry.isDirectory()) {
|
|
73
73
|
if (await collectSnapshot(full)) continue;
|
|
74
|
-
if (
|
|
74
|
+
if (
|
|
75
|
+
(entry.name.startsWith(".") && entry.name !== ".spectral") ||
|
|
76
|
+
IGNORED_DIRS.has(entry.name)
|
|
77
|
+
)
|
|
78
|
+
continue;
|
|
75
79
|
await walk(full);
|
|
76
80
|
} else if (entry.isFile()) {
|
|
77
81
|
const metadata = await lstat(full);
|
|
@@ -2,6 +2,7 @@ import type { ChildProcessWithoutNullStreams } from "node:child_process";
|
|
|
2
2
|
import { createInterface } from "node:readline";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
+
import { DurationSchema, durationMs } from "../../core/duration.js";
|
|
5
6
|
import {
|
|
6
7
|
type AgentDriver,
|
|
7
8
|
type Answer,
|
|
@@ -36,7 +37,7 @@ export const SubprocessDriverConfigSchema = z
|
|
|
36
37
|
/** Inherit the host environment. Experiment mode always forces this off. */
|
|
37
38
|
inheritEnv: z.boolean().optional(),
|
|
38
39
|
protocol: z.enum(["lux-jsonl", "custom"]).default("lux-jsonl"),
|
|
39
|
-
|
|
40
|
+
idleTimeout: DurationSchema.default("2 minutes"),
|
|
40
41
|
maxInterrupts: z.number().positive().default(20),
|
|
41
42
|
/**
|
|
42
43
|
* Maximum files inventoried from LUX_ARTIFACTS_DIR. Keep the conservative
|
|
@@ -485,7 +486,7 @@ class SubprocessDriverImpl implements AgentDriver {
|
|
|
485
486
|
private bumpIdleTimer(): void {
|
|
486
487
|
this.clearIdleTimer();
|
|
487
488
|
this.idleTimer = setTimeout(() => {
|
|
488
|
-
const reason = `no event for ${this.config.
|
|
489
|
+
const reason = `no event for ${durationMs(this.config.idleTimeout)}ms`;
|
|
489
490
|
// Idle before ready means start() is still pending; reject it (and kill
|
|
490
491
|
// the child) or the orchestrator waits forever.
|
|
491
492
|
const preReady = this.readyRejected !== null;
|
|
@@ -497,7 +498,7 @@ class SubprocessDriverImpl implements AgentDriver {
|
|
|
497
498
|
// Kill immediately: the run is lost and the child would keep doing
|
|
498
499
|
// billable work until close().
|
|
499
500
|
this.terminate();
|
|
500
|
-
}, this.config.
|
|
501
|
+
}, durationMs(this.config.idleTimeout));
|
|
501
502
|
}
|
|
502
503
|
|
|
503
504
|
private clearIdleTimer(): void {
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { DurationSchema, durationMs } from "./core/duration.js";
|
|
1
2
|
// Public surface of @prismatic-io/lux. The package root exposes authoring
|
|
2
3
|
// contracts, extension points, built-ins, and supported programmatic
|
|
3
4
|
// lifecycles. Explicit exports keep implementation and test helpers private.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { DurationSchema, durationMs } from "../core/duration.js";
|
|
2
3
|
import {
|
|
3
4
|
type CandidateEvaluation,
|
|
4
5
|
type CandidateProposal,
|
|
@@ -16,7 +17,7 @@ export const ReflectiveOptimizerConfigSchema = z
|
|
|
16
17
|
model: z.string().optional(),
|
|
17
18
|
command: z.string().optional(),
|
|
18
19
|
reasoningEffort: ReasoningEffortSchema.optional(),
|
|
19
|
-
|
|
20
|
+
timeout: DurationSchema.default("3 minutes"),
|
|
20
21
|
maxComponentChars: z.number().int().positive().default(80_000),
|
|
21
22
|
maxAlternativeChars: z.number().int().positive().default(40_000),
|
|
22
23
|
maxFeedbackChars: z.number().int().positive().default(50_000),
|
|
@@ -273,7 +274,7 @@ const reflectiveOptimizer = (config: ReflectiveOptimizerConfig): Optimizer => ({
|
|
|
273
274
|
model,
|
|
274
275
|
command: config.command,
|
|
275
276
|
reasoningEffort: config.reasoningEffort,
|
|
276
|
-
timeoutMs: config.
|
|
277
|
+
timeoutMs: durationMs(config.timeout),
|
|
277
278
|
system: systemPrompt(input.campaign.evaluation.kind),
|
|
278
279
|
signal: input.abortSignal,
|
|
279
280
|
prompt: builtPrompt.prompt,
|
|
@@ -5,6 +5,7 @@ import { basename, dirname, isAbsolute, join, normalize, relative, resolve, sep
|
|
|
5
5
|
import { temporaryDirectory } from "tempy";
|
|
6
6
|
import { glob } from "tinyglobby";
|
|
7
7
|
import { z } from "zod";
|
|
8
|
+
import { durationMs } from "../core/duration.js";
|
|
8
9
|
import { exec } from "../core/exec.js";
|
|
9
10
|
import {
|
|
10
11
|
type Candidate,
|
|
@@ -226,7 +227,7 @@ export const validateCandidate = async (
|
|
|
226
227
|
try {
|
|
227
228
|
return await exec(validation.command, validation.args, {
|
|
228
229
|
cwd: materializedRoot,
|
|
229
|
-
timeoutMs: validation.
|
|
230
|
+
timeoutMs: durationMs(validation.timeout),
|
|
230
231
|
env,
|
|
231
232
|
...(signal ? { signal } : {}),
|
|
232
233
|
});
|
|
@@ -236,7 +237,7 @@ export const validateCandidate = async (
|
|
|
236
237
|
})().finally(() => rm(validationHome, { recursive: true, force: true }));
|
|
237
238
|
if (result.timedOut || result.exitCode !== 0) {
|
|
238
239
|
const reason = result.timedOut
|
|
239
|
-
? `timed out after ${validation.
|
|
240
|
+
? `timed out after ${durationMs(validation.timeout)}ms`
|
|
240
241
|
: `exited ${result.exitCode}`;
|
|
241
242
|
throw new Error(
|
|
242
243
|
`candidate validation '${validation.command}' ${reason}: ${result.stderr.slice(0, 500)}`,
|
|
@@ -2,10 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { rm } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import {
|
|
6
|
-
createRubricAssertion,
|
|
7
|
-
RubricModelAccountingDetailSchema,
|
|
8
|
-
} from "../assertions/rubric/index.js";
|
|
5
|
+
import { RubricModelAccountingDetailSchema } from "../assertions/rubric/index.js";
|
|
9
6
|
import {
|
|
10
7
|
addUsage,
|
|
11
8
|
type Candidate,
|
|
@@ -26,6 +23,7 @@ import { profileOrThrow } from "./experiment-context.js";
|
|
|
26
23
|
import type { ExperimentEvaluation, OpenedExperimentRun } from "./experiment-runs.js";
|
|
27
24
|
import { average } from "./experiment-selection.js";
|
|
28
25
|
import { evaluateGraderCandidate } from "./grader-experiment.js";
|
|
26
|
+
import { registryWithHarness } from "./harness-registry.js";
|
|
29
27
|
import { loadEvalCase } from "./loader.js";
|
|
30
28
|
import { Orchestrator, type SuiteCaseResult, type SuiteItem } from "./orchestrator.js";
|
|
31
29
|
import { clusterCaseSamples, groupedCaseMetricSamples } from "./paired-effects.js";
|
|
@@ -496,7 +494,7 @@ export const evaluateAgentCandidate = async (options: {
|
|
|
496
494
|
const profile = profileOrThrow(execution.config, profileId);
|
|
497
495
|
const harness = profile.harness ?? execution.config.harness;
|
|
498
496
|
const defaultDriver = profile.driver ?? execution.config.defaultDriver;
|
|
499
|
-
const registry = execution.registry.
|
|
497
|
+
const registry = registryWithHarness(execution.registry, execution.config, harness);
|
|
500
498
|
const orchestrator = new Orchestrator({
|
|
501
499
|
environment: profile.environment ?? execution.config.environment,
|
|
502
500
|
registry,
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { join, relative, resolve, sep } from "node:path";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
import {
|
|
5
|
-
createRubricAssertion,
|
|
6
|
-
RubricModelAccountingDetailSchema,
|
|
7
|
-
} from "../assertions/rubric/index.js";
|
|
4
|
+
import { RubricModelAccountingDetailSchema } from "../assertions/rubric/index.js";
|
|
8
5
|
import {
|
|
9
6
|
type Candidate,
|
|
10
7
|
type CandidateEvaluation,
|
|
@@ -711,7 +708,7 @@ export const evaluateGraderCandidate = async (options: {
|
|
|
711
708
|
const registry = buildRegistryFromConfig({
|
|
712
709
|
...execution.config,
|
|
713
710
|
...(harness ? { harness } : {}),
|
|
714
|
-
})
|
|
711
|
+
});
|
|
715
712
|
const items: GraderEvidenceItem[] = [];
|
|
716
713
|
for (const annotation of selected) {
|
|
717
714
|
const rubric = await loadRubricDefinition(
|
|
@@ -213,7 +213,7 @@ export const gradeRun = async (
|
|
|
213
213
|
if (validatedConfigs && index >= validatedConfigs.length) {
|
|
214
214
|
throw new Error(`validated assertion plan is missing assertions[${index}]`);
|
|
215
215
|
}
|
|
216
|
-
// Pass the validated config so schema defaults (e.g.
|
|
216
|
+
// Pass the validated config so schema defaults (e.g. timeout)
|
|
217
217
|
// reach evaluate(); the raw assertion object has none applied.
|
|
218
218
|
const result = AssertionResultSchema.parse(
|
|
219
219
|
await impl.evaluate(validated as typeof a, run, {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createRubricAssertion } from "../assertions/rubric/index.js";
|
|
2
|
+
import type { HarnessModelConfig, Registry } from "../core/index.js";
|
|
3
|
+
import type { ResolvedLuxConfig } from "./config.js";
|
|
4
|
+
|
|
5
|
+
export const registryWithHarness = (
|
|
6
|
+
registry: Registry,
|
|
7
|
+
config: Pick<ResolvedLuxConfig, "assertions">,
|
|
8
|
+
harness: HarnessModelConfig | undefined,
|
|
9
|
+
): Registry =>
|
|
10
|
+
config.assertions?.some((assertion) => assertion.type === "rubric")
|
|
11
|
+
? registry
|
|
12
|
+
: registry.withAssertion(createRubricAssertion(harness));
|