@tangle-network/agent-runtime 0.339.0 → 0.342.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{activation-CVSFxis9.js → activation-CWPmt0Do.js} +4 -4
- package/dist/{activation-CVSFxis9.js.map → activation-CWPmt0Do.js.map} +1 -1
- package/dist/{activation-CJIIl_Ey.d.ts → activation-CXqtijue.d.ts} +2 -2
- package/dist/agent.d.ts +4 -18
- package/dist/agent.js +3 -21
- package/dist/agent.js.map +1 -1
- package/dist/analyst-loop.d.ts +2 -2
- package/dist/{bundle-DVOhBTic.js → bundle-Cwpit6Tg.js} +2 -2
- package/dist/{bundle-DVOhBTic.js.map → bundle-Cwpit6Tg.js.map} +1 -1
- package/dist/candidate-execution/index.d.ts +2 -40
- package/dist/candidate-execution/index.js +9 -255
- package/dist/candidate-execution/index.js.map +1 -1
- package/dist/{driver-control-acknowledgers-C53ggdJ6.js → coordination-manager-B5JsolDR.js} +4852 -4539
- package/dist/coordination-manager-B5JsolDR.js.map +1 -0
- package/dist/{delegate-CCWE_AkU.js → delegate-Rl-5paLJ.js} +2 -2
- package/dist/{delegate-CCWE_AkU.js.map → delegate-Rl-5paLJ.js.map} +1 -1
- package/dist/durable.d.ts +1 -1
- package/dist/durable.js +451 -358
- package/dist/durable.js.map +1 -1
- package/dist/{graph-CI9JXKqO.js → graph-Ce-59ZXn.js} +5 -5
- package/dist/{graph-CI9JXKqO.js.map → graph-Ce-59ZXn.js.map} +1 -1
- package/dist/{improve-BOXTLWJ3.js → improve-BZXt2qM0.js} +837 -704
- package/dist/improve-BZXt2qM0.js.map +1 -0
- package/dist/{improvement-adapter-HUt_-cWA.d.ts → improvement-adapter-sIthWkcN.d.ts} +2 -2
- package/dist/index.d.ts +6 -14
- package/dist/index.js +10 -10
- package/dist/intelligence.d.ts +4 -4
- package/dist/intelligence.js +205 -191
- package/dist/intelligence.js.map +1 -1
- package/dist/kernel.d.ts +3 -3
- package/dist/kernel.js +10 -10
- package/dist/{loop-runner-pmPIHFVY.js → loop-runner-B0MV1-CD.js} +2 -2
- package/dist/{loop-runner-pmPIHFVY.js.map → loop-runner-B0MV1-CD.js.map} +1 -1
- package/dist/{loop-runner-CWzG1bH4.d.ts → loop-runner-CuhbgVGo.d.ts} +3 -3
- package/dist/loop-runner-bin.d.ts +1 -1
- package/dist/loop-runner-bin.js +1 -1
- package/dist/mcp/bin.js +3 -3
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +5 -5
- package/dist/placement.d.ts +2 -26
- package/dist/placement.js +1 -35
- package/dist/placement.js.map +1 -1
- package/dist/{prepare-bXkvPMJA.js → prepare-C-cWCyt3.js} +988 -735
- package/dist/prepare-C-cWCyt3.js.map +1 -0
- package/dist/{profile-Dpei_Sq0.js → profile-CbMw5hAn.js} +2 -2
- package/dist/{profile-Dpei_Sq0.js.map → profile-CbMw5hAn.js.map} +1 -1
- package/dist/profile-materialization-bPm0gGLO.d.ts +49 -0
- package/dist/profiles.d.ts +1 -1
- package/dist/{protected-model-port-BGgpy2r9.d.ts → protected-model-port-DVVh-hEk.d.ts} +2 -6
- package/dist/{provision-supervisor-CJ6Zz6dz.js → provision-supervisor-DL6gEMQp.js} +444 -419
- package/dist/provision-supervisor-DL6gEMQp.js.map +1 -0
- package/dist/{runtime-B2fjL9Oi.js → runtime-eghmj6W4.js} +1245 -1028
- package/dist/runtime-eghmj6W4.js.map +1 -0
- package/dist/{sandbox-profile-compat-BzVBFqrz.js → sandbox-profile-compat-FN2kab2-.js} +72 -72
- package/dist/{sandbox-profile-compat-BzVBFqrz.js.map → sandbox-profile-compat-FN2kab2-.js.map} +1 -1
- package/dist/{search-executor-zMumiak_.js → search-executor-rbjdZ3OD.js} +3 -3
- package/dist/{search-executor-zMumiak_.js.map → search-executor-rbjdZ3OD.js.map} +1 -1
- package/dist/{server-_4voDNrl.js → server-BiK1Kcno.js} +4 -4
- package/dist/{server-_4voDNrl.js.map → server-BiK1Kcno.js.map} +1 -1
- package/dist/{structural-rollout-DpLCXzaL.js → structural-rollout-BD9IN7K_.js} +3 -3
- package/dist/{structural-rollout-DpLCXzaL.js.map → structural-rollout-BD9IN7K_.js.map} +1 -1
- package/dist/{supervise-qAwXmPtD.js → supervise-DmOi7gll.js} +6525 -5562
- package/dist/supervise-DmOi7gll.js.map +1 -0
- package/dist/{supervisor-DHrUJhEZ.js → supervisor-DUWcecAd.js} +13717 -12778
- package/dist/supervisor-DUWcecAd.js.map +1 -0
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +13 -13
- package/dist/tui/index.d.ts +1 -1
- package/dist/tui/index.js +1 -1
- package/dist/{types-CaOXqRTq.d.ts → types-Cgs89PQd.d.ts} +315 -409
- package/dist/{types-zWfqDjeL.d.ts → types-Cwrea-bU.d.ts} +2 -17
- package/dist/workspace-store/index.d.ts +1 -82
- package/dist/workspace-store/index.js +274 -680
- package/dist/workspace-store/index.js.map +1 -1
- package/package.json +8 -8
- package/dist/driver-control-acknowledgers-C53ggdJ6.js.map +0 -1
- package/dist/improve-BOXTLWJ3.js.map +0 -1
- package/dist/prepare-bXkvPMJA.js.map +0 -1
- package/dist/profile-materialization-B1wm2SPT.d.ts +0 -94
- package/dist/provision-supervisor-CJ6Zz6dz.js.map +0 -1
- package/dist/runtime-B2fjL9Oi.js.map +0 -1
- package/dist/supervise-qAwXmPtD.js.map +0 -1
- package/dist/supervisor-DHrUJhEZ.js.map +0 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { a as syncDurableDirectory, i as publishExclusiveDurableFile } from "./durable-file-gNI9ILAn.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Tr as terminateProcessTreeAndConfirm, _r as runAbortable, gr as linkAbort, mt as createExecutor, xi as detachedSnapshot, xr as runSettledCommand } from "./supervisor-DUWcecAd.js";
|
|
3
3
|
import { i as ConfigError } from "./errors-DodWX-cb.js";
|
|
4
|
-
import { F as collectAgentTurn, I as streamAgentTurn } from "./structural-rollout-
|
|
5
|
-
import {
|
|
4
|
+
import { F as collectAgentTurn, I as streamAgentTurn } from "./structural-rollout-BD9IN7K_.js";
|
|
5
|
+
import { B as sha256Bytes$1, Ct as armDeadlineTimer, P as canonicalCandidateDigest$1, R as immutableCandidateValue } from "./sandbox-profile-compat-FN2kab2-.js";
|
|
6
6
|
import { a as concreteProfileModel, t as assertExecutableAgentProfile } from "./model-policy-CyCUwHed.js";
|
|
7
7
|
import { t as sha256 } from "./content-digest-sBTLujlK.js";
|
|
8
|
-
import { C as serializeRolloutPolicy, S as normalizeRolloutPolicy, w as structuralRolloutPolicyFromProfile, x as applyRolloutPolicyToProfile } from "./activation-
|
|
9
|
-
import { a as reconcileInterruptedSearchCalls, b as improveSearchCost, c as searchExecutor, d as taggedLedger, i as isSearchEnvironmentFault, n as assertSearchLanes, s as searchCallTags, v as decideClosedSearch } from "./search-executor-
|
|
8
|
+
import { C as serializeRolloutPolicy, S as normalizeRolloutPolicy, w as structuralRolloutPolicyFromProfile, x as applyRolloutPolicyToProfile } from "./activation-CWPmt0Do.js";
|
|
9
|
+
import { a as reconcileInterruptedSearchCalls, b as improveSearchCost, c as searchExecutor, d as taggedLedger, i as isSearchEnvironmentFault, n as assertSearchLanes, s as searchCallTags, v as decideClosedSearch } from "./search-executor-rbjdZ3OD.js";
|
|
10
10
|
import { agentProfileEnvironmentSchema, agentProfileSchema, agentProfileTrainingSchema, agentTrainingDatasetIdentitySchema, agentTrainingParametersSchema, agentTrainingReceiptSchema, agentTrainingTaskKey, agentTrainingTaskSchema, applyAgentProfileDiff, canonicalAgentProfileDigest, canonicalCandidateBytes, diffAgentProfiles, sha256DigestSchema, snapshotAgentProfile, trainedModelIdForArtifact } from "@tangle-network/agent-interface";
|
|
11
11
|
import { canonicalJson, makeProposalFinding } from "@tangle-network/agent-eval";
|
|
12
12
|
import { redact } from "@tangle-network/agent-eval/traces";
|
|
@@ -50,6 +50,108 @@ function addRuntimeUsage(totals, event) {
|
|
|
50
50
|
if (isUsageAmount(event.estimatedCostUsd)) totals.estimatedCostUsd = (totals.estimatedCostUsd ?? 0) + event.estimatedCostUsd;
|
|
51
51
|
}
|
|
52
52
|
//#endregion
|
|
53
|
+
//#region src/improvement/agentic-shot-evidence.ts
|
|
54
|
+
async function emitShotReceipt(callback, receipt, execution, primaryError) {
|
|
55
|
+
try {
|
|
56
|
+
await callback?.(receipt, execution);
|
|
57
|
+
} catch (callbackError) {
|
|
58
|
+
if (primaryError !== null) throw new AggregateError([primaryError, callbackError], "agenticGenerator: author shot failed and its receipt could not be persisted");
|
|
59
|
+
throw callbackError;
|
|
60
|
+
}
|
|
61
|
+
if (primaryError !== null) throw primaryError;
|
|
62
|
+
}
|
|
63
|
+
async function emitShotDisposition(callback, receipt, disposition) {
|
|
64
|
+
await callback?.(receipt, disposition);
|
|
65
|
+
}
|
|
66
|
+
async function rethrowShotSetupError(callback, receipt, worktreePath, stage, cause) {
|
|
67
|
+
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
68
|
+
try {
|
|
69
|
+
await emitShotDisposition(callback, receipt, {
|
|
70
|
+
kind: "setup-error",
|
|
71
|
+
worktreePath,
|
|
72
|
+
stage,
|
|
73
|
+
error: {
|
|
74
|
+
name: error.name,
|
|
75
|
+
message: error.message
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
} catch (callbackError) {
|
|
79
|
+
throw new AggregateError([cause, callbackError], "agenticGenerator: shot processing failed and its worktree disposition could not be persisted");
|
|
80
|
+
}
|
|
81
|
+
throw cause;
|
|
82
|
+
}
|
|
83
|
+
function shotReceipt(input) {
|
|
84
|
+
const error = input.error ? {
|
|
85
|
+
name: input.error instanceof Error ? input.error.name : "Error",
|
|
86
|
+
message: input.error instanceof Error ? input.error.message : String(input.error)
|
|
87
|
+
} : null;
|
|
88
|
+
const result = input.result;
|
|
89
|
+
const costBasis = costBasisFor(input.costReceipt, result);
|
|
90
|
+
const costUsd = input.costReceipt?.costUsd ?? result?.usage.costUsd ?? result?.usage.estimatedCostUsd ?? null;
|
|
91
|
+
return {
|
|
92
|
+
generation: input.generation ?? null,
|
|
93
|
+
candidateIndex: input.candidateIndex ?? null,
|
|
94
|
+
shot: input.shot + 1,
|
|
95
|
+
maxShots: input.maxShots,
|
|
96
|
+
profileDigest: input.profileDigest,
|
|
97
|
+
harness: input.harness,
|
|
98
|
+
provider: input.provider,
|
|
99
|
+
model: input.model,
|
|
100
|
+
reasoningEffort: input.profile.model?.reasoningEffort ?? null,
|
|
101
|
+
promptSha256: `sha256:${sha256(input.prompt)}`,
|
|
102
|
+
startedAt: input.startedAt.toISOString(),
|
|
103
|
+
completedAt: input.completedAt.toISOString(),
|
|
104
|
+
durationMs: input.completedAt.getTime() - input.startedAt.getTime(),
|
|
105
|
+
status: result?.status ?? null,
|
|
106
|
+
usage: result ? { ...result.usage } : null,
|
|
107
|
+
transportAttempts: result?.transportAttempts ?? null,
|
|
108
|
+
costCallId: input.costCallId,
|
|
109
|
+
costBasis,
|
|
110
|
+
costUsd: costBasis === "unknown" ? null : costUsd,
|
|
111
|
+
costUsdKnown: costBasis === "provider-reported",
|
|
112
|
+
error
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function costBasisFor(receipt, turn) {
|
|
116
|
+
if (receipt) {
|
|
117
|
+
if (receipt.costUnknown) return "unknown";
|
|
118
|
+
return receipt.actualCostUsd === void 0 ? "estimated-pricing" : "provider-reported";
|
|
119
|
+
}
|
|
120
|
+
if (turn?.usage.usdKnown !== false && turn?.usage.costUsd !== void 0) return "provider-reported";
|
|
121
|
+
return turn?.usage.estimatedCostUsd !== void 0 ? "estimated-pricing" : "unknown";
|
|
122
|
+
}
|
|
123
|
+
function shotFailure(result) {
|
|
124
|
+
if (result.status === "completed") return null;
|
|
125
|
+
if (result.status === "aborted") return /* @__PURE__ */ new Error("agenticGenerator: author shot was cancelled by the caller");
|
|
126
|
+
return /* @__PURE__ */ new Error(`agenticGenerator: author shot failed${result.error?.message ? `: ${result.error.message}` : ""}`);
|
|
127
|
+
}
|
|
128
|
+
function costReceiptFromTurn(result, model) {
|
|
129
|
+
const tokensKnown = result.usage.tokensKnown !== false;
|
|
130
|
+
const actualCostUsd = result.usage.usdKnown === false ? void 0 : result.usage.costUsd;
|
|
131
|
+
const cachedTokens = promptCacheReadTokens(result.usage);
|
|
132
|
+
return {
|
|
133
|
+
model,
|
|
134
|
+
inputTokens: tokensKnown ? Math.max(0, result.usage.input - (cachedTokens ?? 0)) : 0,
|
|
135
|
+
outputTokens: tokensKnown ? result.usage.output : 0,
|
|
136
|
+
...tokensKnown ? {} : { usageUnknown: true },
|
|
137
|
+
...cachedTokens !== void 0 ? { cachedTokens } : {},
|
|
138
|
+
...result.usage.reasoningTokens !== void 0 ? { reasoningTokens: result.usage.reasoningTokens } : {},
|
|
139
|
+
...actualCostUsd !== void 0 ? { actualCostUsd } : result.usage.estimatedCostUsd !== void 0 ? { estimatedCostUsd: result.usage.estimatedCostUsd } : { costUnknown: true }
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function promptCacheReadTokens(usage) {
|
|
143
|
+
const cache = usage.promptCache;
|
|
144
|
+
if (!cache) return void 0;
|
|
145
|
+
for (const field of [
|
|
146
|
+
"readTokens",
|
|
147
|
+
"cachedInputTokens",
|
|
148
|
+
"cacheReadInputTokens"
|
|
149
|
+
]) {
|
|
150
|
+
const value = cache[field];
|
|
151
|
+
if (typeof value === "number" && Number.isFinite(value) && value >= 0) return value;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
53
155
|
//#region src/improvement/worktree-tree.ts
|
|
54
156
|
/**
|
|
55
157
|
* The exact content of a candidate worktree, as a Git tree object.
|
|
@@ -192,229 +294,275 @@ function agenticGenerator(opts) {
|
|
|
192
294
|
const profile = detachedSnapshot(agentProfileSchema.parse(opts.profile), "agenticGenerator profile");
|
|
193
295
|
assertExecutableAgentProfile(profile, "agenticGenerator");
|
|
194
296
|
const harness = profile.harness;
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
297
|
+
const author = {
|
|
298
|
+
opts,
|
|
299
|
+
profile,
|
|
300
|
+
harness,
|
|
301
|
+
provider: profile.model.provider.trim(),
|
|
302
|
+
model: concreteProfileModel(profile),
|
|
303
|
+
profileDigest: canonicalAgentProfileDigest(profile),
|
|
304
|
+
dirty: opts.isDirty ?? worktreeDirty
|
|
305
|
+
};
|
|
200
306
|
return {
|
|
201
307
|
kind: `agentic:${harness}`,
|
|
202
308
|
proposesWithoutFindings: true,
|
|
203
|
-
|
|
309
|
+
generate: (request) => generateCandidate(author, request)
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
async function generateCandidate(author, request) {
|
|
313
|
+
const { opts, harness, provider, model, profile, profileDigest } = author;
|
|
314
|
+
const { findings, maxShots, signal, generation, candidateIndex } = request;
|
|
315
|
+
signal.throwIfAborted();
|
|
316
|
+
const { basePrompt, factory } = prepareAuthoring(author, request);
|
|
317
|
+
const needsRawTraceEvidence = requiresRawTraceEvidence(findings);
|
|
318
|
+
const shots = Math.max(1, maxShots);
|
|
319
|
+
const state = {
|
|
320
|
+
attemptNote: "",
|
|
321
|
+
best: null,
|
|
322
|
+
scored: null,
|
|
323
|
+
lastReceipt: null
|
|
324
|
+
};
|
|
325
|
+
for (let shot = 0; shot < shots; shot++) {
|
|
326
|
+
signal.throwIfAborted();
|
|
327
|
+
if (state.best) state.best.onDisk = false;
|
|
328
|
+
const taskPrompt = state.attemptNote ? `${basePrompt}\n\n${state.attemptNote}` : basePrompt;
|
|
329
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
330
|
+
const ran = await runAuthorShot(author, request, factory, taskPrompt, shot);
|
|
331
|
+
const execution = ran.turn ? detachedSnapshot(ran.turn, "agenticGenerator shot execution") : null;
|
|
332
|
+
const receipt = shotReceipt({
|
|
333
|
+
generation,
|
|
334
|
+
candidateIndex,
|
|
335
|
+
shot,
|
|
336
|
+
maxShots: shots,
|
|
337
|
+
harness,
|
|
338
|
+
provider,
|
|
339
|
+
model,
|
|
340
|
+
profile,
|
|
341
|
+
profileDigest,
|
|
342
|
+
prompt: taskPrompt,
|
|
343
|
+
startedAt,
|
|
344
|
+
completedAt: /* @__PURE__ */ new Date(),
|
|
345
|
+
result: execution,
|
|
346
|
+
costCallId: ran.costCallId,
|
|
347
|
+
costReceipt: ran.costReceipt,
|
|
348
|
+
error: ran.shotError
|
|
349
|
+
});
|
|
350
|
+
state.lastReceipt = receipt;
|
|
351
|
+
await emitShotReceipt(opts.onShotCompleted, receipt, execution, ran.shotError);
|
|
352
|
+
signal.throwIfAborted();
|
|
353
|
+
if (!execution) throw new Error("agenticGenerator: author shot completed without a Runtime turn");
|
|
354
|
+
const step = await settleShot(author, request, state, receipt, {
|
|
355
|
+
shot,
|
|
356
|
+
shots,
|
|
357
|
+
needsRawTraceEvidence
|
|
358
|
+
});
|
|
359
|
+
if ("candidate" in step) return step.candidate;
|
|
360
|
+
state.attemptNote = step.note;
|
|
361
|
+
}
|
|
362
|
+
if (state.best !== null) {
|
|
363
|
+
if (!state.lastReceipt) throw new Error("agenticGenerator: a tree was banked without a shot receipt");
|
|
364
|
+
return await shipBankedTree(author, request, state.lastReceipt, state.best);
|
|
365
|
+
}
|
|
366
|
+
return {
|
|
367
|
+
applied: false,
|
|
368
|
+
summary: ""
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
/** Check the request and build the author's prompt and executor, before any shot spends. */
|
|
372
|
+
function prepareAuthoring(author, request) {
|
|
373
|
+
const { opts } = author;
|
|
374
|
+
const { worktreePath, findings, costLedger } = request;
|
|
375
|
+
if (opts.maximumCharge && !costLedger) throw new Error("agenticGenerator: maximumCharge requires the run-wide CostLedger supplied by agent-eval");
|
|
376
|
+
const basePrompt = opts.buildPrompt({ findings });
|
|
377
|
+
if (typeof basePrompt !== "string" || basePrompt.trim().length === 0) throw new Error("agenticGenerator: buildPrompt must return a non-empty string");
|
|
378
|
+
const executorConfig = opts.executorForWorktree(worktreePath);
|
|
379
|
+
if (executorConfig.backend === "bridge" && !samePath(executorConfig.cwd, worktreePath)) throw new Error("agenticGenerator: bridge executor cwd must equal the candidate worktree path");
|
|
380
|
+
if (executorConfig.backend === "cli-in-place" && !samePath(executorConfig.workspacePath, worktreePath)) throw new Error("agenticGenerator: cli-in-place executor workspacePath must equal the candidate worktree path");
|
|
381
|
+
return {
|
|
382
|
+
basePrompt,
|
|
383
|
+
factory: createExecutor(executorConfig)
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
/** Run one author shot through the run-wide ledger when there is one. A failure is returned, not thrown. */
|
|
387
|
+
async function runAuthorShot(author, request, factory, taskPrompt, shot) {
|
|
388
|
+
const { opts, profile, harness, model } = author;
|
|
389
|
+
const { signal, generation, candidateIndex, costLedger, costPhase } = request;
|
|
390
|
+
let turn = null;
|
|
391
|
+
let costReceipt = null;
|
|
392
|
+
let costCallId = null;
|
|
393
|
+
let shotError = null;
|
|
394
|
+
try {
|
|
395
|
+
const execute = async (executionSignal, callId) => {
|
|
396
|
+
turn = await collectAgentTurn(streamAgentTurn({
|
|
397
|
+
kind: "executor",
|
|
398
|
+
profile,
|
|
399
|
+
factory
|
|
400
|
+
}, { prompt: taskPrompt }, {
|
|
401
|
+
signal: executionSignal,
|
|
402
|
+
...opts.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {},
|
|
403
|
+
...callId ? { callId } : {}
|
|
404
|
+
}));
|
|
405
|
+
const failure = shotFailure(turn);
|
|
406
|
+
if (failure) throw failure;
|
|
407
|
+
return turn;
|
|
408
|
+
};
|
|
409
|
+
if (costLedger) {
|
|
410
|
+
const paid = await costLedger.runPaidCall({
|
|
411
|
+
channel: "driver",
|
|
412
|
+
phase: costPhase ?? "search.proposal",
|
|
413
|
+
actor: `agentic-generator:${harness}`,
|
|
414
|
+
model,
|
|
415
|
+
tags: {
|
|
416
|
+
generation: String(generation ?? -1),
|
|
417
|
+
candidateIndex: String(candidateIndex ?? -1),
|
|
418
|
+
shot: String(shot + 1)
|
|
419
|
+
},
|
|
420
|
+
signal,
|
|
421
|
+
...opts.maximumCharge ? { maximumCharge: opts.maximumCharge } : {},
|
|
422
|
+
execute: (executionSignal, callId) => execute(executionSignal, callId),
|
|
423
|
+
receipt: (result) => costReceiptFromTurn(result, model),
|
|
424
|
+
receiptFromError: () => turn ? costReceiptFromTurn(turn, model) : void 0
|
|
425
|
+
});
|
|
426
|
+
costCallId = paid.callId ?? null;
|
|
427
|
+
costReceipt = paid.receipt ?? null;
|
|
428
|
+
if (!paid.succeeded) throw paid.error;
|
|
429
|
+
turn = paid.value;
|
|
430
|
+
} else turn = await execute(signal);
|
|
431
|
+
} catch (cause) {
|
|
432
|
+
shotError = cause instanceof Error ? cause : new Error(String(cause));
|
|
433
|
+
}
|
|
434
|
+
return {
|
|
435
|
+
turn,
|
|
436
|
+
costReceipt,
|
|
437
|
+
costCallId,
|
|
438
|
+
shotError
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
/** Decide what a completed shot's worktree means: ship it, or the note the next shot starts from. */
|
|
442
|
+
async function settleShot(author, request, state, receipt, position) {
|
|
443
|
+
const { opts, dirty } = author;
|
|
444
|
+
const { worktreePath, findings, signal } = request;
|
|
445
|
+
let worktreeChanged;
|
|
446
|
+
try {
|
|
447
|
+
worktreeChanged = dirty(worktreePath);
|
|
448
|
+
} catch (cause) {
|
|
449
|
+
signal.throwIfAborted();
|
|
450
|
+
return rethrowShotSetupError(opts.onShotDisposition, receipt, worktreePath, "worktree-inspection", cause);
|
|
451
|
+
}
|
|
452
|
+
if (!worktreeChanged) {
|
|
453
|
+
signal.throwIfAborted();
|
|
454
|
+
await emitShotDisposition(opts.onShotDisposition, receipt, {
|
|
455
|
+
kind: "clean",
|
|
456
|
+
worktreePath
|
|
457
|
+
});
|
|
458
|
+
signal.throwIfAborted();
|
|
459
|
+
return { note: EMPTY_TREE_NOTE };
|
|
460
|
+
}
|
|
461
|
+
if (position.needsRawTraceEvidence) {
|
|
462
|
+
let problem;
|
|
463
|
+
try {
|
|
464
|
+
problem = rawTraceEvidenceProblem(worktreePath, findings);
|
|
465
|
+
} catch (cause) {
|
|
204
466
|
signal.throwIfAborted();
|
|
205
|
-
|
|
206
|
-
const basePrompt = opts.buildPrompt({ findings });
|
|
207
|
-
if (typeof basePrompt !== "string" || basePrompt.trim().length === 0) throw new Error("agenticGenerator: buildPrompt must return a non-empty string");
|
|
208
|
-
const executorConfig = opts.executorForWorktree(worktreePath);
|
|
209
|
-
if (executorConfig.backend === "bridge" && !samePath(executorConfig.cwd, worktreePath)) throw new Error("agenticGenerator: bridge executor cwd must equal the candidate worktree path");
|
|
210
|
-
if (executorConfig.backend === "cli-in-place" && !samePath(executorConfig.workspacePath, worktreePath)) throw new Error("agenticGenerator: cli-in-place executor workspacePath must equal the candidate worktree path");
|
|
211
|
-
const factory = createExecutor(executorConfig);
|
|
212
|
-
const needsRawTraceEvidence = requiresRawTraceEvidence(findings);
|
|
213
|
-
const shots = Math.max(1, maxShots);
|
|
214
|
-
let attemptNote = "";
|
|
215
|
-
let best = null;
|
|
216
|
-
let scored = null;
|
|
217
|
-
let lastReceipt = null;
|
|
218
|
-
/** Ship the best tree this candidate produced, restoring it when a later
|
|
219
|
-
* shot wrote over it. */
|
|
220
|
-
const shipBankedTree = async (receipt, banked) => {
|
|
221
|
-
const restoredFromShot = banked.onDisk ? null : banked.shot;
|
|
222
|
-
if (!banked.onDisk) {
|
|
223
|
-
if (banked.tree === null) throw new Error(`agenticGenerator: shot ${banked.shot} produced the best tree but it was never snapshotted`);
|
|
224
|
-
restoreWorktreeTree(worktreePath, banked.tree);
|
|
225
|
-
banked.onDisk = true;
|
|
226
|
-
}
|
|
227
|
-
signal.throwIfAborted();
|
|
228
|
-
await emitShotDisposition(opts.onShotDisposition, receipt, {
|
|
229
|
-
kind: "accepted",
|
|
230
|
-
worktreePath,
|
|
231
|
-
verified: true,
|
|
232
|
-
restoredFromShot
|
|
233
|
-
});
|
|
234
|
-
signal.throwIfAborted();
|
|
235
|
-
return acceptedCandidate(findings);
|
|
236
|
-
};
|
|
237
|
-
for (let shot = 0; shot < shots; shot++) {
|
|
238
|
-
signal.throwIfAborted();
|
|
239
|
-
if (best) best.onDisk = false;
|
|
240
|
-
const taskPrompt = attemptNote ? `${basePrompt}\n\n${attemptNote}` : basePrompt;
|
|
241
|
-
const startedAt = /* @__PURE__ */ new Date();
|
|
242
|
-
let turn = null;
|
|
243
|
-
let costReceipt = null;
|
|
244
|
-
let costCallId = null;
|
|
245
|
-
let shotError = null;
|
|
246
|
-
try {
|
|
247
|
-
const execute = async (executionSignal, callId) => {
|
|
248
|
-
turn = await collectAgentTurn(streamAgentTurn({
|
|
249
|
-
kind: "executor",
|
|
250
|
-
profile,
|
|
251
|
-
factory
|
|
252
|
-
}, { prompt: taskPrompt }, {
|
|
253
|
-
signal: executionSignal,
|
|
254
|
-
...opts.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {},
|
|
255
|
-
...callId ? { callId } : {}
|
|
256
|
-
}));
|
|
257
|
-
const failure = shotFailure(turn);
|
|
258
|
-
if (failure) throw failure;
|
|
259
|
-
return turn;
|
|
260
|
-
};
|
|
261
|
-
if (costLedger) {
|
|
262
|
-
const paid = await costLedger.runPaidCall({
|
|
263
|
-
channel: "driver",
|
|
264
|
-
phase: costPhase ?? "search.proposal",
|
|
265
|
-
actor: `agentic-generator:${harness}`,
|
|
266
|
-
model,
|
|
267
|
-
tags: {
|
|
268
|
-
generation: String(generation ?? -1),
|
|
269
|
-
candidateIndex: String(candidateIndex ?? -1),
|
|
270
|
-
shot: String(shot + 1)
|
|
271
|
-
},
|
|
272
|
-
signal,
|
|
273
|
-
...opts.maximumCharge ? { maximumCharge: opts.maximumCharge } : {},
|
|
274
|
-
execute: (executionSignal, callId) => execute(executionSignal, callId),
|
|
275
|
-
receipt: (result) => costReceiptFromTurn(result, model),
|
|
276
|
-
receiptFromError: () => turn ? costReceiptFromTurn(turn, model) : void 0
|
|
277
|
-
});
|
|
278
|
-
costCallId = paid.callId ?? null;
|
|
279
|
-
costReceipt = paid.receipt ?? null;
|
|
280
|
-
if (!paid.succeeded) throw paid.error;
|
|
281
|
-
turn = paid.value;
|
|
282
|
-
} else turn = await execute(signal);
|
|
283
|
-
} catch (cause) {
|
|
284
|
-
shotError = cause instanceof Error ? cause : new Error(String(cause));
|
|
285
|
-
}
|
|
286
|
-
const execution = turn ? detachedSnapshot(turn, "agenticGenerator shot execution") : null;
|
|
287
|
-
const receipt = shotReceipt({
|
|
288
|
-
generation,
|
|
289
|
-
candidateIndex,
|
|
290
|
-
shot,
|
|
291
|
-
maxShots: shots,
|
|
292
|
-
harness,
|
|
293
|
-
provider,
|
|
294
|
-
model,
|
|
295
|
-
profile,
|
|
296
|
-
profileDigest,
|
|
297
|
-
prompt: taskPrompt,
|
|
298
|
-
startedAt,
|
|
299
|
-
completedAt: /* @__PURE__ */ new Date(),
|
|
300
|
-
result: execution,
|
|
301
|
-
costCallId,
|
|
302
|
-
costReceipt,
|
|
303
|
-
error: shotError
|
|
304
|
-
});
|
|
305
|
-
lastReceipt = receipt;
|
|
306
|
-
await emitShotReceipt(opts.onShotCompleted, receipt, execution, shotError);
|
|
307
|
-
signal.throwIfAborted();
|
|
308
|
-
if (!execution) throw new Error("agenticGenerator: author shot completed without a Runtime turn");
|
|
309
|
-
let worktreeChanged;
|
|
310
|
-
try {
|
|
311
|
-
worktreeChanged = dirty(worktreePath);
|
|
312
|
-
} catch (cause) {
|
|
313
|
-
signal.throwIfAborted();
|
|
314
|
-
return rethrowShotSetupError(opts.onShotDisposition, receipt, worktreePath, "worktree-inspection", cause);
|
|
315
|
-
}
|
|
316
|
-
if (!worktreeChanged) {
|
|
317
|
-
signal.throwIfAborted();
|
|
318
|
-
await emitShotDisposition(opts.onShotDisposition, receipt, {
|
|
319
|
-
kind: "clean",
|
|
320
|
-
worktreePath
|
|
321
|
-
});
|
|
322
|
-
signal.throwIfAborted();
|
|
323
|
-
attemptNote = EMPTY_TREE_NOTE;
|
|
324
|
-
continue;
|
|
325
|
-
}
|
|
326
|
-
if (needsRawTraceEvidence) {
|
|
327
|
-
let problem;
|
|
328
|
-
try {
|
|
329
|
-
problem = rawTraceEvidenceProblem(worktreePath, findings);
|
|
330
|
-
} catch (cause) {
|
|
331
|
-
signal.throwIfAborted();
|
|
332
|
-
return rethrowShotSetupError(opts.onShotDisposition, receipt, worktreePath, "raw-trace-evidence", cause);
|
|
333
|
-
}
|
|
334
|
-
if (problem) {
|
|
335
|
-
signal.throwIfAborted();
|
|
336
|
-
await emitShotDisposition(opts.onShotDisposition, receipt, {
|
|
337
|
-
kind: "rejected",
|
|
338
|
-
worktreePath,
|
|
339
|
-
stage: "raw-trace-evidence",
|
|
340
|
-
feedback: problem
|
|
341
|
-
});
|
|
342
|
-
signal.throwIfAborted();
|
|
343
|
-
attemptNote = problem;
|
|
344
|
-
continue;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
if (!verify) {
|
|
348
|
-
signal.throwIfAborted();
|
|
349
|
-
await emitShotDisposition(opts.onShotDisposition, receipt, {
|
|
350
|
-
kind: "accepted",
|
|
351
|
-
worktreePath,
|
|
352
|
-
verified: false,
|
|
353
|
-
restoredFromShot: null
|
|
354
|
-
});
|
|
355
|
-
signal.throwIfAborted();
|
|
356
|
-
return acceptedCandidate(findings);
|
|
357
|
-
}
|
|
358
|
-
let result;
|
|
359
|
-
try {
|
|
360
|
-
signal.throwIfAborted();
|
|
361
|
-
result = await verify(worktreePath, signal);
|
|
362
|
-
signal.throwIfAborted();
|
|
363
|
-
} catch (cause) {
|
|
364
|
-
signal.throwIfAborted();
|
|
365
|
-
return rethrowShotSetupError(opts.onShotDisposition, receipt, worktreePath, "verification", cause);
|
|
366
|
-
}
|
|
367
|
-
if (result.ok) {
|
|
368
|
-
const score = admittedScore(result, scored, shot);
|
|
369
|
-
scored = score !== null;
|
|
370
|
-
const previousBest = best;
|
|
371
|
-
let banked;
|
|
372
|
-
if (previousBest === null || (score ?? 0) >= (previousBest.score ?? 0)) banked = {
|
|
373
|
-
shot: shot + 1,
|
|
374
|
-
score,
|
|
375
|
-
tree: null,
|
|
376
|
-
onDisk: true
|
|
377
|
-
};
|
|
378
|
-
else banked = previousBest;
|
|
379
|
-
const becomesBest = banked !== previousBest;
|
|
380
|
-
best = banked;
|
|
381
|
-
if (result.keepGoing !== true) {
|
|
382
|
-
signal.throwIfAborted();
|
|
383
|
-
return await shipBankedTree(receipt, banked);
|
|
384
|
-
}
|
|
385
|
-
if (becomesBest && shot < shots - 1) banked.tree = snapshotWorktreeTree(worktreePath);
|
|
386
|
-
signal.throwIfAborted();
|
|
387
|
-
await emitShotDisposition(opts.onShotDisposition, receipt, {
|
|
388
|
-
kind: "kept",
|
|
389
|
-
worktreePath,
|
|
390
|
-
score,
|
|
391
|
-
best: becomesBest,
|
|
392
|
-
feedback: result.feedback ?? null
|
|
393
|
-
});
|
|
394
|
-
signal.throwIfAborted();
|
|
395
|
-
attemptNote = keptNote(result.feedback);
|
|
396
|
-
continue;
|
|
397
|
-
}
|
|
398
|
-
signal.throwIfAborted();
|
|
399
|
-
await emitShotDisposition(opts.onShotDisposition, receipt, {
|
|
400
|
-
kind: "rejected",
|
|
401
|
-
worktreePath,
|
|
402
|
-
stage: "verification",
|
|
403
|
-
feedback: result.feedback ?? null
|
|
404
|
-
});
|
|
405
|
-
signal.throwIfAborted();
|
|
406
|
-
attemptNote = failureNote(result.feedback);
|
|
407
|
-
}
|
|
408
|
-
if (best !== null) {
|
|
409
|
-
if (!lastReceipt) throw new Error("agenticGenerator: a tree was banked without a shot receipt");
|
|
410
|
-
return await shipBankedTree(lastReceipt, best);
|
|
411
|
-
}
|
|
412
|
-
return {
|
|
413
|
-
applied: false,
|
|
414
|
-
summary: ""
|
|
415
|
-
};
|
|
467
|
+
return rethrowShotSetupError(opts.onShotDisposition, receipt, worktreePath, "raw-trace-evidence", cause);
|
|
416
468
|
}
|
|
417
|
-
|
|
469
|
+
if (problem) {
|
|
470
|
+
signal.throwIfAborted();
|
|
471
|
+
await emitShotDisposition(opts.onShotDisposition, receipt, {
|
|
472
|
+
kind: "rejected",
|
|
473
|
+
worktreePath,
|
|
474
|
+
stage: "raw-trace-evidence",
|
|
475
|
+
feedback: problem
|
|
476
|
+
});
|
|
477
|
+
signal.throwIfAborted();
|
|
478
|
+
return { note: problem };
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if (!opts.verify) {
|
|
482
|
+
signal.throwIfAborted();
|
|
483
|
+
await emitShotDisposition(opts.onShotDisposition, receipt, {
|
|
484
|
+
kind: "accepted",
|
|
485
|
+
worktreePath,
|
|
486
|
+
verified: false,
|
|
487
|
+
restoredFromShot: null
|
|
488
|
+
});
|
|
489
|
+
signal.throwIfAborted();
|
|
490
|
+
return { candidate: acceptedCandidate(findings) };
|
|
491
|
+
}
|
|
492
|
+
return settleVerifiedShot(author, request, state, receipt, position, opts.verify);
|
|
493
|
+
}
|
|
494
|
+
/** Run the verifier on a dirty tree, then ship, bank or reject it. */
|
|
495
|
+
async function settleVerifiedShot(author, request, state, receipt, { shot, shots }, verify) {
|
|
496
|
+
const { opts } = author;
|
|
497
|
+
const { worktreePath, signal } = request;
|
|
498
|
+
let result;
|
|
499
|
+
try {
|
|
500
|
+
signal.throwIfAborted();
|
|
501
|
+
result = await verify(worktreePath, signal);
|
|
502
|
+
signal.throwIfAborted();
|
|
503
|
+
} catch (cause) {
|
|
504
|
+
signal.throwIfAborted();
|
|
505
|
+
return rethrowShotSetupError(opts.onShotDisposition, receipt, worktreePath, "verification", cause);
|
|
506
|
+
}
|
|
507
|
+
if (result.ok) {
|
|
508
|
+
const score = admittedScore(result, state.scored, shot);
|
|
509
|
+
state.scored = score !== null;
|
|
510
|
+
const previousBest = state.best;
|
|
511
|
+
let banked;
|
|
512
|
+
if (previousBest === null || (score ?? 0) >= (previousBest.score ?? 0)) banked = {
|
|
513
|
+
shot: shot + 1,
|
|
514
|
+
score,
|
|
515
|
+
tree: null,
|
|
516
|
+
onDisk: true
|
|
517
|
+
};
|
|
518
|
+
else banked = previousBest;
|
|
519
|
+
const becomesBest = banked !== previousBest;
|
|
520
|
+
state.best = banked;
|
|
521
|
+
if (result.keepGoing !== true) {
|
|
522
|
+
signal.throwIfAborted();
|
|
523
|
+
return { candidate: await shipBankedTree(author, request, receipt, banked) };
|
|
524
|
+
}
|
|
525
|
+
if (becomesBest && shot < shots - 1) banked.tree = snapshotWorktreeTree(worktreePath);
|
|
526
|
+
signal.throwIfAborted();
|
|
527
|
+
await emitShotDisposition(opts.onShotDisposition, receipt, {
|
|
528
|
+
kind: "kept",
|
|
529
|
+
worktreePath,
|
|
530
|
+
score,
|
|
531
|
+
best: becomesBest,
|
|
532
|
+
feedback: result.feedback ?? null
|
|
533
|
+
});
|
|
534
|
+
signal.throwIfAborted();
|
|
535
|
+
return { note: keptNote(result.feedback) };
|
|
536
|
+
}
|
|
537
|
+
signal.throwIfAborted();
|
|
538
|
+
await emitShotDisposition(opts.onShotDisposition, receipt, {
|
|
539
|
+
kind: "rejected",
|
|
540
|
+
worktreePath,
|
|
541
|
+
stage: "verification",
|
|
542
|
+
feedback: result.feedback ?? null
|
|
543
|
+
});
|
|
544
|
+
signal.throwIfAborted();
|
|
545
|
+
return { note: failureNote(result.feedback) };
|
|
546
|
+
}
|
|
547
|
+
/** Ship the best tree this candidate produced, restoring it when a later
|
|
548
|
+
* shot wrote over it. */
|
|
549
|
+
async function shipBankedTree(author, request, receipt, banked) {
|
|
550
|
+
const { worktreePath, findings, signal } = request;
|
|
551
|
+
const restoredFromShot = banked.onDisk ? null : banked.shot;
|
|
552
|
+
if (!banked.onDisk) {
|
|
553
|
+
if (banked.tree === null) throw new Error(`agenticGenerator: shot ${banked.shot} produced the best tree but it was never snapshotted`);
|
|
554
|
+
restoreWorktreeTree(worktreePath, banked.tree);
|
|
555
|
+
banked.onDisk = true;
|
|
556
|
+
}
|
|
557
|
+
signal.throwIfAborted();
|
|
558
|
+
await emitShotDisposition(author.opts.onShotDisposition, receipt, {
|
|
559
|
+
kind: "accepted",
|
|
560
|
+
worktreePath,
|
|
561
|
+
verified: true,
|
|
562
|
+
restoredFromShot
|
|
563
|
+
});
|
|
564
|
+
signal.throwIfAborted();
|
|
565
|
+
return acceptedCandidate(findings);
|
|
418
566
|
}
|
|
419
567
|
/** The rank a passing tree carries, refusing a set of trees that cannot be ordered. */
|
|
420
568
|
function admittedScore(result, scored, shot) {
|
|
@@ -424,129 +572,29 @@ function admittedScore(result, scored, shot) {
|
|
|
424
572
|
if (typeof result.score !== "number" || !Number.isFinite(result.score)) throw new Error(`agenticGenerator: verify returned a non-finite score (${String(result.score)}) for shot ${shot + 1}`);
|
|
425
573
|
return result.score;
|
|
426
574
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
575
|
+
const EMPTY_TREE_NOTE = "NOTE: your previous attempt left the working tree unchanged. Make the concrete file edits now.";
|
|
576
|
+
/** Next-shot feedback when the worktree is dirty but failed verification. The
|
|
577
|
+
* edits persist on disk, so the harness resumes atop them — tell it to fix in
|
|
578
|
+
* place, not start over. Verifier detail is truncated to keep the prompt bounded. */
|
|
579
|
+
function failureNote(feedback) {
|
|
580
|
+
const detail = feedback?.trim();
|
|
581
|
+
return [
|
|
582
|
+
"NOTE: your edits are in the working tree but verification FAILED.",
|
|
583
|
+
"Fix the problem in place — build on your existing edits, do not revert them.",
|
|
584
|
+
detail ? `Verifier output:\n${truncate$1(detail, 4e3)}` : "No verifier detail was captured."
|
|
585
|
+
].join("\n");
|
|
435
586
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
name: error.name,
|
|
448
|
-
message: error.message
|
|
449
|
-
}
|
|
450
|
-
});
|
|
451
|
-
} catch (callbackError) {
|
|
452
|
-
throw new AggregateError([cause, callbackError], "agenticGenerator: shot processing failed and its worktree disposition could not be persisted");
|
|
453
|
-
}
|
|
454
|
-
throw cause;
|
|
455
|
-
}
|
|
456
|
-
function shotReceipt(input) {
|
|
457
|
-
const error = input.error ? {
|
|
458
|
-
name: input.error instanceof Error ? input.error.name : "Error",
|
|
459
|
-
message: input.error instanceof Error ? input.error.message : String(input.error)
|
|
460
|
-
} : null;
|
|
461
|
-
const result = input.result;
|
|
462
|
-
const costBasis = costBasisFor(input.costReceipt, result);
|
|
463
|
-
const costUsd = input.costReceipt?.costUsd ?? result?.usage.costUsd ?? result?.usage.estimatedCostUsd ?? null;
|
|
464
|
-
return {
|
|
465
|
-
generation: input.generation ?? null,
|
|
466
|
-
candidateIndex: input.candidateIndex ?? null,
|
|
467
|
-
shot: input.shot + 1,
|
|
468
|
-
maxShots: input.maxShots,
|
|
469
|
-
profileDigest: input.profileDigest,
|
|
470
|
-
harness: input.harness,
|
|
471
|
-
provider: input.provider,
|
|
472
|
-
model: input.model,
|
|
473
|
-
reasoningEffort: input.profile.model?.reasoningEffort ?? null,
|
|
474
|
-
promptSha256: `sha256:${sha256(input.prompt)}`,
|
|
475
|
-
startedAt: input.startedAt.toISOString(),
|
|
476
|
-
completedAt: input.completedAt.toISOString(),
|
|
477
|
-
durationMs: input.completedAt.getTime() - input.startedAt.getTime(),
|
|
478
|
-
status: result?.status ?? null,
|
|
479
|
-
usage: result ? { ...result.usage } : null,
|
|
480
|
-
transportAttempts: result?.transportAttempts ?? null,
|
|
481
|
-
costCallId: input.costCallId,
|
|
482
|
-
costBasis,
|
|
483
|
-
costUsd: costBasis === "unknown" ? null : costUsd,
|
|
484
|
-
costUsdKnown: costBasis === "provider-reported",
|
|
485
|
-
error
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
|
-
function costBasisFor(receipt, turn) {
|
|
489
|
-
if (receipt) {
|
|
490
|
-
if (receipt.costUnknown) return "unknown";
|
|
491
|
-
return receipt.actualCostUsd === void 0 ? "estimated-pricing" : "provider-reported";
|
|
492
|
-
}
|
|
493
|
-
if (turn?.usage.usdKnown !== false && turn?.usage.costUsd !== void 0) return "provider-reported";
|
|
494
|
-
return turn?.usage.estimatedCostUsd !== void 0 ? "estimated-pricing" : "unknown";
|
|
495
|
-
}
|
|
496
|
-
function shotFailure(result) {
|
|
497
|
-
if (result.status === "completed") return null;
|
|
498
|
-
if (result.status === "aborted") return /* @__PURE__ */ new Error("agenticGenerator: author shot was cancelled by the caller");
|
|
499
|
-
return /* @__PURE__ */ new Error(`agenticGenerator: author shot failed${result.error?.message ? `: ${result.error.message}` : ""}`);
|
|
500
|
-
}
|
|
501
|
-
function costReceiptFromTurn(result, model) {
|
|
502
|
-
const tokensKnown = result.usage.tokensKnown !== false;
|
|
503
|
-
const actualCostUsd = result.usage.usdKnown === false ? void 0 : result.usage.costUsd;
|
|
504
|
-
const cachedTokens = promptCacheReadTokens(result.usage);
|
|
505
|
-
return {
|
|
506
|
-
model,
|
|
507
|
-
inputTokens: tokensKnown ? Math.max(0, result.usage.input - (cachedTokens ?? 0)) : 0,
|
|
508
|
-
outputTokens: tokensKnown ? result.usage.output : 0,
|
|
509
|
-
...tokensKnown ? {} : { usageUnknown: true },
|
|
510
|
-
...cachedTokens !== void 0 ? { cachedTokens } : {},
|
|
511
|
-
...result.usage.reasoningTokens !== void 0 ? { reasoningTokens: result.usage.reasoningTokens } : {},
|
|
512
|
-
...actualCostUsd !== void 0 ? { actualCostUsd } : result.usage.estimatedCostUsd !== void 0 ? { estimatedCostUsd: result.usage.estimatedCostUsd } : { costUnknown: true }
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
function promptCacheReadTokens(usage) {
|
|
516
|
-
const cache = usage.promptCache;
|
|
517
|
-
if (!cache) return void 0;
|
|
518
|
-
for (const field of [
|
|
519
|
-
"readTokens",
|
|
520
|
-
"cachedInputTokens",
|
|
521
|
-
"cacheReadInputTokens"
|
|
522
|
-
]) {
|
|
523
|
-
const value = cache[field];
|
|
524
|
-
if (typeof value === "number" && Number.isFinite(value) && value >= 0) return value;
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
const EMPTY_TREE_NOTE = "NOTE: your previous attempt left the working tree unchanged. Make the concrete file edits now.";
|
|
528
|
-
/** Next-shot feedback when the worktree is dirty but failed verification. The
|
|
529
|
-
* edits persist on disk, so the harness resumes atop them — tell it to fix in
|
|
530
|
-
* place, not start over. Verifier detail is truncated to keep the prompt bounded. */
|
|
531
|
-
function failureNote(feedback) {
|
|
532
|
-
const detail = feedback?.trim();
|
|
533
|
-
return [
|
|
534
|
-
"NOTE: your edits are in the working tree but verification FAILED.",
|
|
535
|
-
"Fix the problem in place — build on your existing edits, do not revert them.",
|
|
536
|
-
detail ? `Verifier output:\n${truncate$1(detail, 4e3)}` : "No verifier detail was captured."
|
|
537
|
-
].join("\n");
|
|
538
|
-
}
|
|
539
|
-
/** Next-shot feedback when the worktree PASSED and the verifier asked for
|
|
540
|
-
* another shot. The passing tree is banked, so the author is told to improve
|
|
541
|
-
* it rather than protect it — a worse tree cannot cost it the candidate. */
|
|
542
|
-
function keptNote(feedback) {
|
|
543
|
-
const detail = feedback?.trim();
|
|
544
|
-
return [
|
|
545
|
-
"NOTE: your edits are in the working tree and verification PASSED.",
|
|
546
|
-
"Shots remain in this budget — keep improving the change in place, do not revert it.",
|
|
547
|
-
"The best version you produce is the one that ships.",
|
|
548
|
-
detail ? `Verifier output:\n${truncate$1(detail, 4e3)}` : "No verifier detail was captured."
|
|
549
|
-
].join("\n");
|
|
587
|
+
/** Next-shot feedback when the worktree PASSED and the verifier asked for
|
|
588
|
+
* another shot. The passing tree is banked, so the author is told to improve
|
|
589
|
+
* it rather than protect it — a worse tree cannot cost it the candidate. */
|
|
590
|
+
function keptNote(feedback) {
|
|
591
|
+
const detail = feedback?.trim();
|
|
592
|
+
return [
|
|
593
|
+
"NOTE: your edits are in the working tree and verification PASSED.",
|
|
594
|
+
"Shots remain in this budget — keep improving the change in place, do not revert it.",
|
|
595
|
+
"The best version you produce is the one that ships.",
|
|
596
|
+
detail ? `Verifier output:\n${truncate$1(detail, 4e3)}` : "No verifier detail was captured."
|
|
597
|
+
].join("\n");
|
|
550
598
|
}
|
|
551
599
|
function rawTraceEvidenceProblem(worktreePath, findings) {
|
|
552
600
|
if (worktreeChangedPaths(worktreePath).filter((path) => path !== RAW_TRACE_DIAGNOSIS_PATH).length === 0) return [`NOTE: raw-trace mode requires a real code/config edit in addition to ${RAW_TRACE_DIAGNOSIS_PATH}.`, "Your previous attempt only changed the diagnosis artifact. Inspect the cited traces and make the causal code change."].join("\n");
|
|
@@ -1974,6 +2022,121 @@ async function runMethodImprovement(profile, opts) {
|
|
|
1974
2022
|
};
|
|
1975
2023
|
}
|
|
1976
2024
|
//#endregion
|
|
2025
|
+
//#region src/improvement/search-session.ts
|
|
2026
|
+
/** A refusal as the ledger stores it: redacted with the share profile. */
|
|
2027
|
+
function searchRefusalText(error) {
|
|
2028
|
+
return redact(error instanceof Error ? error.message : String(error), { profile: "share" }).value;
|
|
2029
|
+
}
|
|
2030
|
+
/** The node a candidate surface becomes: materialized, or refused with the reason. */
|
|
2031
|
+
function profileNodeOf(prepared, candidateSurface) {
|
|
2032
|
+
const surface = immutableCandidateValue(candidateSurface);
|
|
2033
|
+
try {
|
|
2034
|
+
return {
|
|
2035
|
+
surface,
|
|
2036
|
+
profile: prepared.materializeCandidate(surface),
|
|
2037
|
+
refusal: null
|
|
2038
|
+
};
|
|
2039
|
+
} catch (error) {
|
|
2040
|
+
return {
|
|
2041
|
+
surface,
|
|
2042
|
+
profile: null,
|
|
2043
|
+
refusal: searchRefusalText(error)
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
/**
|
|
2048
|
+
* The codec that also records each node's profile by node id. Placement reads a node's profile
|
|
2049
|
+
* to skip the lanes that refuse it, so every node the ledger holds, and every node this process
|
|
2050
|
+
* registers, is known before its cells are placed.
|
|
2051
|
+
*/
|
|
2052
|
+
function registeringProfileCodec(prepared, searchId, profiles) {
|
|
2053
|
+
const profiled = profileCodec(prepared);
|
|
2054
|
+
return {
|
|
2055
|
+
node(recorder, node) {
|
|
2056
|
+
const registered = profiled.node(recorder, node);
|
|
2057
|
+
profiles.set(searchNodeId(searchId, registered.artifactDigest), node.profile);
|
|
2058
|
+
return registered;
|
|
2059
|
+
},
|
|
2060
|
+
diff: profiled.diff,
|
|
2061
|
+
load(recorder, node) {
|
|
2062
|
+
const loaded = profiled.load(recorder, node);
|
|
2063
|
+
profiles.set(node.nodeId, loaded.profile);
|
|
2064
|
+
return loaded;
|
|
2065
|
+
}
|
|
2066
|
+
};
|
|
2067
|
+
}
|
|
2068
|
+
/** Profiles as search artifacts: nodes by profile digest, edges by profile diffs. */
|
|
2069
|
+
function profileCodec(prepared) {
|
|
2070
|
+
const surfaceId = prepared.surface;
|
|
2071
|
+
return {
|
|
2072
|
+
node(recorder, node) {
|
|
2073
|
+
if (node.profile) {
|
|
2074
|
+
const artifact = recorder.blob("agent-profile", {
|
|
2075
|
+
kind: "agent-profile",
|
|
2076
|
+
profile: node.profile
|
|
2077
|
+
});
|
|
2078
|
+
return {
|
|
2079
|
+
artifactDigest: canonicalAgentProfileDigest(node.profile),
|
|
2080
|
+
artifact,
|
|
2081
|
+
surfaces: [{
|
|
2082
|
+
surfaceId,
|
|
2083
|
+
kind: "agent-profile",
|
|
2084
|
+
artifact
|
|
2085
|
+
}]
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
2088
|
+
const artifact = recorder.blob("surface", {
|
|
2089
|
+
kind: "unmaterialized-surface",
|
|
2090
|
+
surface: node.surface,
|
|
2091
|
+
refusal: node.refusal
|
|
2092
|
+
});
|
|
2093
|
+
return {
|
|
2094
|
+
artifactDigest: canonicalCandidateDigest$1({
|
|
2095
|
+
kind: "unmaterialized-surface",
|
|
2096
|
+
surface: node.surface
|
|
2097
|
+
}),
|
|
2098
|
+
artifact,
|
|
2099
|
+
surfaces: [{
|
|
2100
|
+
surfaceId,
|
|
2101
|
+
kind: "agent-profile",
|
|
2102
|
+
artifact
|
|
2103
|
+
}]
|
|
2104
|
+
};
|
|
2105
|
+
},
|
|
2106
|
+
diff(recorder, parent, child) {
|
|
2107
|
+
if (!parent.profile || !child.profile) return { unknown: "a surface that does not materialize has no profile to diff" };
|
|
2108
|
+
const diffs = diffAgentProfiles(parent.profile, child.profile);
|
|
2109
|
+
const to = canonicalAgentProfileDigest(child.profile);
|
|
2110
|
+
if (canonicalAgentProfileDigest(diffs.reduce(applyAgentProfileDiff, parent.profile)) !== to) return { unknown: "the Interface profile diffs do not reproduce the child profile" };
|
|
2111
|
+
return recorder.blob("diff", {
|
|
2112
|
+
kind: "agent-profile-diff",
|
|
2113
|
+
from: canonicalAgentProfileDigest(parent.profile),
|
|
2114
|
+
to,
|
|
2115
|
+
diffs
|
|
2116
|
+
});
|
|
2117
|
+
},
|
|
2118
|
+
load(recorder, node) {
|
|
2119
|
+
const stored = recorder.readBlob(node.artifact);
|
|
2120
|
+
if (stored.kind === "agent-profile") {
|
|
2121
|
+
const parsed = agentProfileSchema.safeParse(stored.profile);
|
|
2122
|
+
if (!parsed.success) throw new Error(`improve(): node ${node.nodeId} holds an invalid AgentProfile`);
|
|
2123
|
+
const loaded = immutableCandidateValue(parsed.data);
|
|
2124
|
+
return {
|
|
2125
|
+
surface: prepared.surfaceOf(loaded),
|
|
2126
|
+
profile: loaded,
|
|
2127
|
+
refusal: null
|
|
2128
|
+
};
|
|
2129
|
+
}
|
|
2130
|
+
if (stored.kind === "unmaterialized-surface" && stored.surface !== void 0) return {
|
|
2131
|
+
surface: stored.surface,
|
|
2132
|
+
profile: null,
|
|
2133
|
+
refusal: stored.refusal ?? null
|
|
2134
|
+
};
|
|
2135
|
+
throw new Error(`improve(): node ${node.nodeId} holds no profile search artifact`);
|
|
2136
|
+
}
|
|
2137
|
+
};
|
|
2138
|
+
}
|
|
2139
|
+
//#endregion
|
|
1977
2140
|
//#region src/improvement/search-method.ts
|
|
1978
2141
|
/** Build Runtime's native search for `improve(profile, { method })`. */
|
|
1979
2142
|
function searchMethod(options) {
|
|
@@ -2025,14 +2188,12 @@ const SEARCH_METHOD_SOURCE = {
|
|
|
2025
2188
|
};
|
|
2026
2189
|
async function runSearchImprovement(profile, opts) {
|
|
2027
2190
|
const { method, claim: inputClaim, agent, executionRunId, recordCell, trainScenarios, selectionScenarios, testScenarios, judges: _judges, surface: _surface, executionRef: _executionRef, validateCandidate: _validateCandidate, findings: _findings, skills: _skills, profileComponents: _profileComponents, minimumLift: _minimumLift, subject: _subject, costCeiling, costLedger: inputCostLedger, seed = 42, signal, workerSlots, budgetPool, trace, ...campaignOptions } = opts;
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
["testScenarios", testScenarios]
|
|
2035
|
-
]) if (!Array.isArray(split) || split.length === 0) throw new ConfigError(`improve(): a search needs at least one of ${name}`);
|
|
2191
|
+
const splitScenarios = {
|
|
2192
|
+
trainScenarios,
|
|
2193
|
+
selectionScenarios,
|
|
2194
|
+
testScenarios
|
|
2195
|
+
};
|
|
2196
|
+
const claim = assertSearchRequest(method, inputClaim, splitScenarios);
|
|
2036
2197
|
const { allocation, policy, lanes } = method;
|
|
2037
2198
|
const reps = allocation.reps;
|
|
2038
2199
|
const concurrency = lanes.reduce((total, lane) => total + lane.capacity, 0);
|
|
@@ -2059,121 +2220,34 @@ async function runSearchImprovement(profile, opts) {
|
|
|
2059
2220
|
runDir: searchDir,
|
|
2060
2221
|
costCeilingUsd: costCeiling
|
|
2061
2222
|
});
|
|
2062
|
-
const
|
|
2063
|
-
const
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
};
|
|
2076
|
-
const
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
revision: canonicalCandidateDigest$1({
|
|
2083
|
-
development: prepared.identity.developmentSplitDigest,
|
|
2084
|
-
test: prepared.identity.finalTestSplitDigest
|
|
2085
|
-
})
|
|
2086
|
-
}
|
|
2087
|
-
};
|
|
2088
|
-
const reservedClaimUsd = Math.max(method.claimReserveUsd ?? 0, searchClaimReserveUsd({
|
|
2089
|
-
testTasks: splits.test.length,
|
|
2090
|
-
reps,
|
|
2091
|
-
cellUsd: Math.max(...lanes.map((lane) => lane.cellUsd))
|
|
2092
|
-
}));
|
|
2093
|
-
const recorder = await SearchRecorder.open({
|
|
2094
|
-
ledger: storage.kind === "filesystem" ? openSearchLedger({
|
|
2095
|
-
path: `${searchDir}/ledger.jsonl`,
|
|
2096
|
-
searchId
|
|
2097
|
-
}) : openSearchLedger({
|
|
2098
|
-
path: `${searchDir}/ledger.jsonl`,
|
|
2099
|
-
searchId,
|
|
2100
|
-
store: storage
|
|
2101
|
-
}),
|
|
2102
|
-
storage
|
|
2103
|
-
}, {
|
|
2104
|
-
subject: prepared.searchIdentity.subject,
|
|
2105
|
-
process: {
|
|
2106
|
-
name: method.name,
|
|
2107
|
-
executionRef: SEARCH_METHOD_SOURCE
|
|
2108
|
-
},
|
|
2109
|
-
artifactKind: "agent-profile",
|
|
2110
|
-
objective: {
|
|
2111
|
-
metric: "composite",
|
|
2112
|
-
direction: "maximize",
|
|
2113
|
-
judge: prepared.searchIdentity.judge,
|
|
2114
|
-
claim
|
|
2115
|
-
},
|
|
2116
|
-
splits: {
|
|
2117
|
-
...splits,
|
|
2118
|
-
heldOutUnits: splits.test.every((task) => !developmentUnits.has(task.unitId))
|
|
2119
|
-
},
|
|
2120
|
-
policy: {
|
|
2121
|
-
expansion: policy.name,
|
|
2122
|
-
allocation: allocation.name,
|
|
2123
|
-
seed
|
|
2124
|
-
},
|
|
2125
|
-
budget: {
|
|
2126
|
-
maxUsd: costCeiling ?? null,
|
|
2127
|
-
maxCells: null,
|
|
2128
|
-
maxNodes: 1 + method.maxExpansions * method.childrenPerProposal,
|
|
2129
|
-
deadline: method.deadline,
|
|
2130
|
-
maxConcurrency: concurrency,
|
|
2131
|
-
reservedClaimUsd: costCeiling === void 0 ? 0 : reservedClaimUsd
|
|
2132
|
-
},
|
|
2133
|
-
containment: null,
|
|
2134
|
-
derivedFrom: null,
|
|
2135
|
-
identity: execution
|
|
2136
|
-
});
|
|
2137
|
-
const nodeOf = (candidateSurface) => {
|
|
2138
|
-
const surface = immutableCandidateValue(candidateSurface);
|
|
2139
|
-
try {
|
|
2140
|
-
return {
|
|
2141
|
-
surface,
|
|
2142
|
-
profile: prepared.materializeCandidate(surface),
|
|
2143
|
-
refusal: null
|
|
2144
|
-
};
|
|
2145
|
-
} catch (error) {
|
|
2146
|
-
return {
|
|
2147
|
-
surface,
|
|
2148
|
-
profile: null,
|
|
2149
|
-
refusal: refusalText(error)
|
|
2150
|
-
};
|
|
2151
|
-
}
|
|
2223
|
+
const execution = searchExecutionIdentity(prepared);
|
|
2224
|
+
const recorder = await openSearchRecorder({
|
|
2225
|
+
method,
|
|
2226
|
+
prepared,
|
|
2227
|
+
claim,
|
|
2228
|
+
splits: searchSplits(claim, splitScenarios),
|
|
2229
|
+
storage,
|
|
2230
|
+
searchId,
|
|
2231
|
+
searchDir,
|
|
2232
|
+
seed,
|
|
2233
|
+
costCeiling,
|
|
2234
|
+
concurrency,
|
|
2235
|
+
execution
|
|
2236
|
+
});
|
|
2237
|
+
const session = {
|
|
2238
|
+
method,
|
|
2239
|
+
prepared,
|
|
2240
|
+
searchId,
|
|
2241
|
+
costLedger,
|
|
2242
|
+
recorder
|
|
2152
2243
|
};
|
|
2153
2244
|
const profiles = /* @__PURE__ */ new Map();
|
|
2154
|
-
const
|
|
2155
|
-
const codec = {
|
|
2156
|
-
node(recorder, node) {
|
|
2157
|
-
const registered = profiled.node(recorder, node);
|
|
2158
|
-
profiles.set(searchNodeId(searchId, registered.artifactDigest), node.profile);
|
|
2159
|
-
return registered;
|
|
2160
|
-
},
|
|
2161
|
-
diff: profiled.diff,
|
|
2162
|
-
load(recorder, node) {
|
|
2163
|
-
const loaded = profiled.load(recorder, node);
|
|
2164
|
-
profiles.set(node.nodeId, loaded.profile);
|
|
2165
|
-
return loaded;
|
|
2166
|
-
}
|
|
2167
|
-
};
|
|
2245
|
+
const codec = registeringProfileCodec(prepared, searchId, profiles);
|
|
2168
2246
|
for (const node of (await recorder.state()).nodes()) codec.load(recorder, node);
|
|
2169
2247
|
await reconcileInterruptedSearchCalls(costLedger, searchId, lanes);
|
|
2170
|
-
const
|
|
2171
|
-
const refusals = lanes.map((lane) => `${lane.name}: ${lane.refusal(nodeProfile)}`);
|
|
2172
|
-
return lanes.some((lane) => lane.refusal(nodeProfile) === void 0) ? null : `no lane can run the profile (${refusals.join("; ")})`;
|
|
2173
|
-
};
|
|
2174
|
-
const root = nodeOf(prepared.baselineSurface);
|
|
2248
|
+
const root = profileNodeOf(prepared, prepared.baselineSurface);
|
|
2175
2249
|
if (root.profile) {
|
|
2176
|
-
const refused = laneRefusal(root.profile);
|
|
2250
|
+
const refused = laneRefusal(lanes, root.profile);
|
|
2177
2251
|
if (refused) throw new ConfigError(`improve(): the baseline profile cannot run: ${refused}`);
|
|
2178
2252
|
}
|
|
2179
2253
|
const scenarios = [
|
|
@@ -2181,11 +2255,7 @@ async function runSearchImprovement(profile, opts) {
|
|
|
2181
2255
|
...selectionScenarios,
|
|
2182
2256
|
...testScenarios
|
|
2183
2257
|
];
|
|
2184
|
-
|
|
2185
|
-
for (const scenario of scenarios) {
|
|
2186
|
-
if (scenarioIds.has(scenario.id)) throw new ConfigError(`improve(): scenario '${scenario.id}' appears in more than one split`);
|
|
2187
|
-
scenarioIds.add(scenario.id);
|
|
2188
|
-
}
|
|
2258
|
+
assertDistinctScenarios(scenarios);
|
|
2189
2259
|
const executor = searchExecutor({
|
|
2190
2260
|
lanes,
|
|
2191
2261
|
profileOf(nodeId) {
|
|
@@ -2200,167 +2270,164 @@ async function runSearchImprovement(profile, opts) {
|
|
|
2200
2270
|
...workerSlots ? { workerSlots } : {},
|
|
2201
2271
|
...budgetPool ? { budgetPool } : {},
|
|
2202
2272
|
...trace ? { trace } : {},
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
return await judge.score(input);
|
|
2217
|
-
} catch (error) {
|
|
2218
|
-
if (isSearchEnvironmentFault(error)) fault = error;
|
|
2219
|
-
throw error;
|
|
2220
|
-
}
|
|
2221
|
-
}
|
|
2222
|
-
})),
|
|
2223
|
-
seed,
|
|
2224
|
-
reps,
|
|
2225
|
-
storage,
|
|
2226
|
-
runDir: `${searchDir}/nodes/${profileDigest.slice(7)}`,
|
|
2227
|
-
dispatchRef: `improve:${evaluationRef}:${profileDigest}`,
|
|
2228
|
-
async dispatch(scenario, ctx) {
|
|
2229
|
-
try {
|
|
2230
|
-
return await agent(nodeProfile, scenario, {
|
|
2231
|
-
...ctx,
|
|
2232
|
-
search: context
|
|
2233
|
-
});
|
|
2234
|
-
} catch (error) {
|
|
2235
|
-
if (isSearchEnvironmentFault(error)) fault = error;
|
|
2236
|
-
throw error;
|
|
2237
|
-
}
|
|
2238
|
-
},
|
|
2239
|
-
cellFilter: ({ scenario, rep }) => scenario.id === work.taskId && rep === work.rep,
|
|
2240
|
-
resumable: true,
|
|
2241
|
-
maxConcurrency: 1,
|
|
2242
|
-
costLedger: cellLedger,
|
|
2243
|
-
costPhase: `search.${work.stage}`,
|
|
2244
|
-
buildTraceWriter: () => ({
|
|
2245
|
-
span,
|
|
2246
|
-
flush: async () => {}
|
|
2247
|
-
}),
|
|
2248
|
-
signal: work.signal
|
|
2249
|
-
})).cells[0];
|
|
2250
|
-
if (!cell) throw new Error(`improve(): cell ${work.cellId} produced no campaign cell`);
|
|
2251
|
-
const result = campaignCellSearchResult(cell, {
|
|
2252
|
-
execution,
|
|
2253
|
-
lane: lane.name
|
|
2254
|
-
});
|
|
2255
|
-
const execRunId = cell.error ? null : executionRunId?.(cell.artifact) ?? null;
|
|
2256
|
-
const settled = faultResult(execRunId && context.trace ? {
|
|
2257
|
-
...result,
|
|
2258
|
-
traceRef: {
|
|
2259
|
-
traceId: context.trace.traceId,
|
|
2260
|
-
execRunId,
|
|
2261
|
-
spansWritten: null,
|
|
2262
|
-
spansDropped: null
|
|
2263
|
-
}
|
|
2264
|
-
} : result, fault);
|
|
2265
|
-
return recordCell && settled.outcome.status !== "errored" ? {
|
|
2266
|
-
...settled,
|
|
2267
|
-
recordCell: (finalResult) => recordCell({
|
|
2268
|
-
cell,
|
|
2269
|
-
search: context,
|
|
2270
|
-
result: finalResult
|
|
2271
|
-
})
|
|
2272
|
-
} : settled;
|
|
2273
|
-
}
|
|
2274
|
-
});
|
|
2275
|
-
const { proposer } = method;
|
|
2276
|
-
const proposerSource = {
|
|
2277
|
-
uri: `proposer:${proposer.kind}`,
|
|
2278
|
-
revision: canonicalCandidateDigest$1({
|
|
2279
|
-
kind: proposer.kind,
|
|
2280
|
-
propose: Function.prototype.toString.call(proposer.propose),
|
|
2281
|
-
decide: proposer.decide ? Function.prototype.toString.call(proposer.decide) : null
|
|
2273
|
+
runAttempt: searchCellRunner({
|
|
2274
|
+
campaignOptions,
|
|
2275
|
+
prepared,
|
|
2276
|
+
agent,
|
|
2277
|
+
executionRunId,
|
|
2278
|
+
recordCell,
|
|
2279
|
+
scenarios,
|
|
2280
|
+
seed,
|
|
2281
|
+
reps,
|
|
2282
|
+
storage,
|
|
2283
|
+
searchDir,
|
|
2284
|
+
evaluationRef,
|
|
2285
|
+
execution
|
|
2282
2286
|
})
|
|
2283
|
-
};
|
|
2284
|
-
const
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2287
|
+
});
|
|
2288
|
+
const startedAt = Date.now();
|
|
2289
|
+
return decideSearchResult({
|
|
2290
|
+
session,
|
|
2291
|
+
codec,
|
|
2292
|
+
result: await runSearch({
|
|
2293
|
+
recorder,
|
|
2294
|
+
root,
|
|
2295
|
+
codec,
|
|
2296
|
+
policy,
|
|
2297
|
+
allocation,
|
|
2298
|
+
proposer: searchProposerPort(session),
|
|
2299
|
+
executor,
|
|
2300
|
+
admit: (node) => admissionRefusal(session, node),
|
|
2301
|
+
maxExpansions: method.maxExpansions,
|
|
2302
|
+
maxAttempts: method.maxAttempts,
|
|
2303
|
+
...signal ? { signal } : {}
|
|
2304
|
+
}),
|
|
2305
|
+
costCeiling,
|
|
2306
|
+
startedAt
|
|
2307
|
+
});
|
|
2308
|
+
}
|
|
2309
|
+
/** Open the search's ledger: a fresh search records its opening, an interrupted one continues. */
|
|
2310
|
+
function openSearchRecorder(input) {
|
|
2311
|
+
const { method, prepared, claim, splits, storage, searchId, searchDir, seed, costCeiling } = input;
|
|
2312
|
+
const { policy, allocation, lanes } = method;
|
|
2313
|
+
const reservedClaimUsd = Math.max(method.claimReserveUsd ?? 0, searchClaimReserveUsd({
|
|
2314
|
+
testTasks: splits.test.length,
|
|
2315
|
+
reps: allocation.reps,
|
|
2316
|
+
cellUsd: Math.max(...lanes.map((lane) => lane.cellUsd))
|
|
2317
|
+
}));
|
|
2318
|
+
return SearchRecorder.open({
|
|
2319
|
+
ledger: storage.kind === "filesystem" ? openSearchLedger({
|
|
2320
|
+
path: `${searchDir}/ledger.jsonl`,
|
|
2321
|
+
searchId
|
|
2322
|
+
}) : openSearchLedger({
|
|
2323
|
+
path: `${searchDir}/ledger.jsonl`,
|
|
2324
|
+
searchId,
|
|
2325
|
+
store: storage
|
|
2326
|
+
}),
|
|
2327
|
+
storage
|
|
2328
|
+
}, {
|
|
2329
|
+
subject: prepared.searchIdentity.subject,
|
|
2330
|
+
process: {
|
|
2331
|
+
name: method.name,
|
|
2332
|
+
executionRef: SEARCH_METHOD_SOURCE
|
|
2292
2333
|
},
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2334
|
+
artifactKind: "agent-profile",
|
|
2335
|
+
objective: {
|
|
2336
|
+
metric: "composite",
|
|
2337
|
+
direction: "maximize",
|
|
2338
|
+
judge: prepared.searchIdentity.judge,
|
|
2339
|
+
claim
|
|
2340
|
+
},
|
|
2341
|
+
splits,
|
|
2342
|
+
policy: {
|
|
2343
|
+
expansion: policy.name,
|
|
2344
|
+
allocation: allocation.name,
|
|
2345
|
+
seed
|
|
2346
|
+
},
|
|
2347
|
+
budget: {
|
|
2348
|
+
maxUsd: costCeiling ?? null,
|
|
2349
|
+
maxCells: null,
|
|
2350
|
+
maxNodes: 1 + method.maxExpansions * method.childrenPerProposal,
|
|
2351
|
+
deadline: method.deadline,
|
|
2352
|
+
maxConcurrency: input.concurrency,
|
|
2353
|
+
reservedClaimUsd: costCeiling === void 0 ? 0 : reservedClaimUsd
|
|
2354
|
+
},
|
|
2355
|
+
containment: null,
|
|
2356
|
+
derivedFrom: null,
|
|
2357
|
+
identity: input.execution
|
|
2358
|
+
});
|
|
2359
|
+
}
|
|
2360
|
+
/** The request is a search with a claim that can be powered, and every split has scenarios. */
|
|
2361
|
+
function assertSearchRequest(method, inputClaim, splits) {
|
|
2362
|
+
if (!isImproveSearchMethod(method)) throw new ConfigError("improve(): a search needs method: searchMethod(...)");
|
|
2363
|
+
const claim = defineEvaluationClaim(inputClaim);
|
|
2364
|
+
if (claim.minimumEffect === void 0) throw new ConfigError("improve(): a search claim needs minimumEffect for its power check");
|
|
2365
|
+
for (const [name, split] of Object.entries(splits)) if (!Array.isArray(split) || split.length === 0) throw new ConfigError(`improve(): a search needs at least one of ${name}`);
|
|
2366
|
+
return claim;
|
|
2367
|
+
}
|
|
2368
|
+
function assertDistinctScenarios(scenarios) {
|
|
2369
|
+
const scenarioIds = /* @__PURE__ */ new Set();
|
|
2370
|
+
for (const scenario of scenarios) {
|
|
2371
|
+
if (scenarioIds.has(scenario.id)) throw new ConfigError(`improve(): scenario '${scenario.id}' appears in more than one split`);
|
|
2372
|
+
scenarioIds.add(scenario.id);
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
/** The search tasks of each split, and whether the test units are held out of development. */
|
|
2376
|
+
function searchSplits(claim, scenarios) {
|
|
2377
|
+
const unitOf = (scenario) => summarizeEvaluationUnits(claim, [scenario]).units[0].id;
|
|
2378
|
+
const tasks = (list) => list.map((scenario) => ({
|
|
2379
|
+
taskId: scenario.id,
|
|
2380
|
+
unitId: unitOf(scenario),
|
|
2381
|
+
source: {
|
|
2382
|
+
uri: `scenario://${scenario.id}`,
|
|
2383
|
+
revision: canonicalCandidateDigest$1(scenario)
|
|
2337
2384
|
}
|
|
2385
|
+
}));
|
|
2386
|
+
const splits = {
|
|
2387
|
+
train: tasks(scenarios.trainScenarios),
|
|
2388
|
+
selection: tasks(scenarios.selectionScenarios),
|
|
2389
|
+
test: tasks(scenarios.testScenarios)
|
|
2338
2390
|
};
|
|
2339
|
-
const
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2391
|
+
const developmentUnits = new Set([...splits.train, ...splits.selection].map((task) => task.unitId));
|
|
2392
|
+
return {
|
|
2393
|
+
...splits,
|
|
2394
|
+
heldOutUnits: splits.test.every((task) => !developmentUnits.has(task.unitId))
|
|
2395
|
+
};
|
|
2396
|
+
}
|
|
2397
|
+
function searchExecutionIdentity(prepared) {
|
|
2398
|
+
return {
|
|
2399
|
+
model: prepared.searchIdentity.model,
|
|
2400
|
+
agent: prepared.searchIdentity.agent,
|
|
2401
|
+
benchmark: {
|
|
2402
|
+
uri: "agent-runtime:improve-splits",
|
|
2403
|
+
revision: canonicalCandidateDigest$1({
|
|
2404
|
+
development: prepared.identity.developmentSplitDigest,
|
|
2405
|
+
test: prepared.identity.finalTestSplitDigest
|
|
2406
|
+
})
|
|
2345
2407
|
}
|
|
2346
|
-
const paths = privateValuePaths([node.surface]);
|
|
2347
|
-
if (paths.length > 0) return `the surface carries a credential or private value at ${paths.slice(0, 8).join(", ")}`;
|
|
2348
|
-
return laneRefusal(node.profile);
|
|
2349
2408
|
};
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
}
|
|
2409
|
+
}
|
|
2410
|
+
/** Why no lane can run the profile, or null when one can. */
|
|
2411
|
+
function laneRefusal(lanes, nodeProfile) {
|
|
2412
|
+
const refusals = lanes.map((lane) => `${lane.name}: ${lane.refusal(nodeProfile)}`);
|
|
2413
|
+
return lanes.some((lane) => lane.refusal(nodeProfile) === void 0) ? null : `no lane can run the profile (${refusals.join("; ")})`;
|
|
2414
|
+
}
|
|
2415
|
+
/** Why a node is refused admission to the search, or null when it is admitted. */
|
|
2416
|
+
function admissionRefusal({ prepared, method }, node) {
|
|
2417
|
+
if (node.refusal !== null || node.profile === null) return node.refusal;
|
|
2418
|
+
try {
|
|
2419
|
+
prepared.admitCandidate(node.profile, node.surface);
|
|
2420
|
+
} catch (error) {
|
|
2421
|
+
return searchRefusalText(error);
|
|
2422
|
+
}
|
|
2423
|
+
const paths = privateValuePaths([node.surface]);
|
|
2424
|
+
if (paths.length > 0) return `the surface carries a credential or private value at ${paths.slice(0, 8).join(", ")}`;
|
|
2425
|
+
return laneRefusal(method.lanes, node.profile);
|
|
2426
|
+
}
|
|
2427
|
+
/** Read the closed search back from its ledger and decide whether its leader ships. */
|
|
2428
|
+
async function decideSearchResult(input) {
|
|
2429
|
+
const { session, codec, result, costCeiling, startedAt } = input;
|
|
2430
|
+
const { method, prepared, searchId, costLedger, recorder } = session;
|
|
2364
2431
|
const { state } = result;
|
|
2365
2432
|
const claimResult = result.claim;
|
|
2366
2433
|
if (!claimResult || !result.claimVerification) throw new Error(`improve(): search ${searchId} closed without a claim`);
|
|
@@ -2411,77 +2478,6 @@ async function runSearchImprovement(profile, opts) {
|
|
|
2411
2478
|
async dispose() {}
|
|
2412
2479
|
};
|
|
2413
2480
|
}
|
|
2414
|
-
/** Profiles as search artifacts: nodes by profile digest, edges by profile diffs. */
|
|
2415
|
-
function profileCodec(prepared) {
|
|
2416
|
-
const surfaceId = prepared.surface;
|
|
2417
|
-
return {
|
|
2418
|
-
node(recorder, node) {
|
|
2419
|
-
if (node.profile) {
|
|
2420
|
-
const artifact = recorder.blob("agent-profile", {
|
|
2421
|
-
kind: "agent-profile",
|
|
2422
|
-
profile: node.profile
|
|
2423
|
-
});
|
|
2424
|
-
return {
|
|
2425
|
-
artifactDigest: canonicalAgentProfileDigest(node.profile),
|
|
2426
|
-
artifact,
|
|
2427
|
-
surfaces: [{
|
|
2428
|
-
surfaceId,
|
|
2429
|
-
kind: "agent-profile",
|
|
2430
|
-
artifact
|
|
2431
|
-
}]
|
|
2432
|
-
};
|
|
2433
|
-
}
|
|
2434
|
-
const artifact = recorder.blob("surface", {
|
|
2435
|
-
kind: "unmaterialized-surface",
|
|
2436
|
-
surface: node.surface,
|
|
2437
|
-
refusal: node.refusal
|
|
2438
|
-
});
|
|
2439
|
-
return {
|
|
2440
|
-
artifactDigest: canonicalCandidateDigest$1({
|
|
2441
|
-
kind: "unmaterialized-surface",
|
|
2442
|
-
surface: node.surface
|
|
2443
|
-
}),
|
|
2444
|
-
artifact,
|
|
2445
|
-
surfaces: [{
|
|
2446
|
-
surfaceId,
|
|
2447
|
-
kind: "agent-profile",
|
|
2448
|
-
artifact
|
|
2449
|
-
}]
|
|
2450
|
-
};
|
|
2451
|
-
},
|
|
2452
|
-
diff(recorder, parent, child) {
|
|
2453
|
-
if (!parent.profile || !child.profile) return { unknown: "a surface that does not materialize has no profile to diff" };
|
|
2454
|
-
const diffs = diffAgentProfiles(parent.profile, child.profile);
|
|
2455
|
-
const to = canonicalAgentProfileDigest(child.profile);
|
|
2456
|
-
if (canonicalAgentProfileDigest(diffs.reduce(applyAgentProfileDiff, parent.profile)) !== to) return { unknown: "the Interface profile diffs do not reproduce the child profile" };
|
|
2457
|
-
return recorder.blob("diff", {
|
|
2458
|
-
kind: "agent-profile-diff",
|
|
2459
|
-
from: canonicalAgentProfileDigest(parent.profile),
|
|
2460
|
-
to,
|
|
2461
|
-
diffs
|
|
2462
|
-
});
|
|
2463
|
-
},
|
|
2464
|
-
load(recorder, node) {
|
|
2465
|
-
const stored = recorder.readBlob(node.artifact);
|
|
2466
|
-
if (stored.kind === "agent-profile") {
|
|
2467
|
-
const parsed = agentProfileSchema.safeParse(stored.profile);
|
|
2468
|
-
if (!parsed.success) throw new Error(`improve(): node ${node.nodeId} holds an invalid AgentProfile`);
|
|
2469
|
-
const loaded = immutableCandidateValue(parsed.data);
|
|
2470
|
-
return {
|
|
2471
|
-
surface: prepared.surfaceOf(loaded),
|
|
2472
|
-
profile: loaded,
|
|
2473
|
-
refusal: null
|
|
2474
|
-
};
|
|
2475
|
-
}
|
|
2476
|
-
if (stored.kind === "unmaterialized-surface" && stored.surface !== void 0) return {
|
|
2477
|
-
surface: stored.surface,
|
|
2478
|
-
profile: null,
|
|
2479
|
-
refusal: stored.refusal ?? null
|
|
2480
|
-
};
|
|
2481
|
-
throw new Error(`improve(): node ${node.nodeId} holds no profile search artifact`);
|
|
2482
|
-
}
|
|
2483
|
-
};
|
|
2484
|
-
}
|
|
2485
2481
|
/** Everything that decides which search a call continues. */
|
|
2486
2482
|
function searchMethodDescriptor(method) {
|
|
2487
2483
|
return {
|
|
@@ -2504,6 +2500,148 @@ function searchMethodDescriptor(method) {
|
|
|
2504
2500
|
maxAttempts: method.maxAttempts
|
|
2505
2501
|
};
|
|
2506
2502
|
}
|
|
2503
|
+
const PROPOSAL_PHASE = "search.proposal";
|
|
2504
|
+
function searchProposerPort(session) {
|
|
2505
|
+
const { method, prepared, recorder, costLedger, searchId } = session;
|
|
2506
|
+
const { proposer } = method;
|
|
2507
|
+
const proposerSource = {
|
|
2508
|
+
uri: `proposer:${proposer.kind}`,
|
|
2509
|
+
revision: canonicalCandidateDigest$1({
|
|
2510
|
+
kind: proposer.kind,
|
|
2511
|
+
propose: Function.prototype.toString.call(proposer.propose),
|
|
2512
|
+
decide: proposer.decide ? Function.prototype.toString.call(proposer.decide) : null
|
|
2513
|
+
})
|
|
2514
|
+
};
|
|
2515
|
+
return {
|
|
2516
|
+
name: proposer.kind,
|
|
2517
|
+
kind: "optimizer",
|
|
2518
|
+
source: proposerSource,
|
|
2519
|
+
execution: {
|
|
2520
|
+
kind: "deterministic",
|
|
2521
|
+
source: proposerSource
|
|
2522
|
+
},
|
|
2523
|
+
childrenPerProposal: method.childrenPerProposal,
|
|
2524
|
+
async propose(request) {
|
|
2525
|
+
const tags = searchCallTags(searchId, { operation: request.operationId });
|
|
2526
|
+
const state = await recorder.state();
|
|
2527
|
+
const parents = request.parents.map(({ nodeId, artifact }) => ({
|
|
2528
|
+
nodeId,
|
|
2529
|
+
artifact: artifact.surface
|
|
2530
|
+
}));
|
|
2531
|
+
const context = Object.freeze({
|
|
2532
|
+
currentSurface: parents[0]?.artifact ?? prepared.baselineSurface,
|
|
2533
|
+
operator: request.operator,
|
|
2534
|
+
parents,
|
|
2535
|
+
train: searchProposerView(state),
|
|
2536
|
+
summary: renderSearchSummary(state, { split: "train" }),
|
|
2537
|
+
history: [],
|
|
2538
|
+
findings: prepared.findings,
|
|
2539
|
+
populationSize: method.childrenPerProposal,
|
|
2540
|
+
generation: request.expansion,
|
|
2541
|
+
signal: request.signal,
|
|
2542
|
+
costLedger: taggedLedger(costLedger, tags),
|
|
2543
|
+
costPhase: PROPOSAL_PHASE
|
|
2544
|
+
});
|
|
2545
|
+
const decision = proposer.decide?.({ history: [] });
|
|
2546
|
+
const proposed = decision?.stop ? [] : await proposer.propose(context);
|
|
2547
|
+
if (!Array.isArray(proposed)) throw new ConfigError("improve(): the search proposer must return an array");
|
|
2548
|
+
const fresh = costLedger.list({
|
|
2549
|
+
phase: PROPOSAL_PHASE,
|
|
2550
|
+
tags
|
|
2551
|
+
});
|
|
2552
|
+
return {
|
|
2553
|
+
children: proposed.slice(0, method.childrenPerProposal).map((child) => isProposedCandidate(child) ? {
|
|
2554
|
+
artifact: profileNodeOf(prepared, child.surface),
|
|
2555
|
+
label: child.label,
|
|
2556
|
+
rationale: child.rationale,
|
|
2557
|
+
...child.attribution ? { attribution: child.attribution } : {}
|
|
2558
|
+
} : {
|
|
2559
|
+
artifact: profileNodeOf(prepared, child),
|
|
2560
|
+
label: "",
|
|
2561
|
+
rationale: ""
|
|
2562
|
+
}),
|
|
2563
|
+
...decision?.stop ? { stop: decision.reason ?? "the proposer decided to stop" } : {},
|
|
2564
|
+
accounting: searchReceiptAccounting(fresh),
|
|
2565
|
+
execution: searchProposalExecution(fresh, prepared.searchIdentity.model.provider, proposerSource)
|
|
2566
|
+
};
|
|
2567
|
+
}
|
|
2568
|
+
};
|
|
2569
|
+
}
|
|
2570
|
+
/** The executor's cell runner for one search. */
|
|
2571
|
+
function searchCellRunner(env) {
|
|
2572
|
+
const { campaignOptions, prepared, executionRunId, recordCell, execution } = env;
|
|
2573
|
+
return async ({ work, lane, context, costLedger: cellLedger, span }) => {
|
|
2574
|
+
const nodeProfile = work.artifact.profile;
|
|
2575
|
+
if (!nodeProfile) throw new Error(`improve(): refused node ${work.nodeId} was given a cell`);
|
|
2576
|
+
const profileDigest = canonicalAgentProfileDigest(nodeProfile);
|
|
2577
|
+
let fault;
|
|
2578
|
+
const cell = (await runCampaign({
|
|
2579
|
+
...campaignOptions,
|
|
2580
|
+
...lane.kind === "subscription" && campaignOptions.expectUsage === void 0 ? { expectUsage: "off" } : {},
|
|
2581
|
+
scenarios: env.scenarios,
|
|
2582
|
+
judges: prepared.judges.map((judge) => ({
|
|
2583
|
+
...judge,
|
|
2584
|
+
async score(input) {
|
|
2585
|
+
try {
|
|
2586
|
+
return await judge.score(input);
|
|
2587
|
+
} catch (error) {
|
|
2588
|
+
if (isSearchEnvironmentFault(error)) fault = error;
|
|
2589
|
+
throw error;
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
})),
|
|
2593
|
+
seed: env.seed,
|
|
2594
|
+
reps: env.reps,
|
|
2595
|
+
storage: env.storage,
|
|
2596
|
+
runDir: `${env.searchDir}/nodes/${profileDigest.slice(7)}`,
|
|
2597
|
+
dispatchRef: `improve:${env.evaluationRef}:${profileDigest}`,
|
|
2598
|
+
async dispatch(scenario, ctx) {
|
|
2599
|
+
try {
|
|
2600
|
+
return await env.agent(nodeProfile, scenario, {
|
|
2601
|
+
...ctx,
|
|
2602
|
+
search: context
|
|
2603
|
+
});
|
|
2604
|
+
} catch (error) {
|
|
2605
|
+
if (isSearchEnvironmentFault(error)) fault = error;
|
|
2606
|
+
throw error;
|
|
2607
|
+
}
|
|
2608
|
+
},
|
|
2609
|
+
cellFilter: ({ scenario, rep }) => scenario.id === work.taskId && rep === work.rep,
|
|
2610
|
+
resumable: true,
|
|
2611
|
+
maxConcurrency: 1,
|
|
2612
|
+
costLedger: cellLedger,
|
|
2613
|
+
costPhase: `search.${work.stage}`,
|
|
2614
|
+
buildTraceWriter: () => ({
|
|
2615
|
+
span,
|
|
2616
|
+
flush: async () => {}
|
|
2617
|
+
}),
|
|
2618
|
+
signal: work.signal
|
|
2619
|
+
})).cells[0];
|
|
2620
|
+
if (!cell) throw new Error(`improve(): cell ${work.cellId} produced no campaign cell`);
|
|
2621
|
+
const result = campaignCellSearchResult(cell, {
|
|
2622
|
+
execution,
|
|
2623
|
+
lane: lane.name
|
|
2624
|
+
});
|
|
2625
|
+
const execRunId = cell.error ? null : executionRunId?.(cell.artifact) ?? null;
|
|
2626
|
+
const settled = faultResult(execRunId && context.trace ? {
|
|
2627
|
+
...result,
|
|
2628
|
+
traceRef: {
|
|
2629
|
+
traceId: context.trace.traceId,
|
|
2630
|
+
execRunId,
|
|
2631
|
+
spansWritten: null,
|
|
2632
|
+
spansDropped: null
|
|
2633
|
+
}
|
|
2634
|
+
} : result, fault);
|
|
2635
|
+
return recordCell && settled.outcome.status !== "errored" ? {
|
|
2636
|
+
...settled,
|
|
2637
|
+
recordCell: (finalResult) => recordCell({
|
|
2638
|
+
cell,
|
|
2639
|
+
search: context,
|
|
2640
|
+
result: finalResult
|
|
2641
|
+
})
|
|
2642
|
+
} : settled;
|
|
2643
|
+
};
|
|
2644
|
+
}
|
|
2507
2645
|
/**
|
|
2508
2646
|
* An environment fault the agent raised settles retryable. The campaign reports every error as
|
|
2509
2647
|
* final because it applies its own retry policy; here the kernel owns retries.
|
|
@@ -2516,16 +2654,12 @@ function faultResult(result, fault) {
|
|
|
2516
2654
|
...result.outcome,
|
|
2517
2655
|
error: {
|
|
2518
2656
|
code: "environment-fault",
|
|
2519
|
-
message:
|
|
2657
|
+
message: searchRefusalText(fault),
|
|
2520
2658
|
retryable: true
|
|
2521
2659
|
}
|
|
2522
2660
|
}
|
|
2523
2661
|
};
|
|
2524
2662
|
}
|
|
2525
|
-
/** A refusal as the ledger stores it: redacted with the share profile. */
|
|
2526
|
-
function refusalText(error) {
|
|
2527
|
-
return redact(error instanceof Error ? error.message : String(error), { profile: "share" }).value;
|
|
2528
|
-
}
|
|
2529
2663
|
//#endregion
|
|
2530
2664
|
//#region src/improvement/training.ts
|
|
2531
2665
|
function positiveLimit(value, label) {
|
|
@@ -2540,10 +2674,9 @@ async function hashFile(path, maximum, signal, capture = false) {
|
|
|
2540
2674
|
const hash = createHash("sha256");
|
|
2541
2675
|
const chunks = [];
|
|
2542
2676
|
let bytes = 0;
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
signal
|
|
2546
|
-
})) {
|
|
2677
|
+
signal.throwIfAborted();
|
|
2678
|
+
for await (const chunk of file.createReadStream({ autoClose: false })) {
|
|
2679
|
+
signal.throwIfAborted();
|
|
2547
2680
|
bytes += chunk.length;
|
|
2548
2681
|
if (bytes > maximum) throw new Error("artifact exceeded its byte limit");
|
|
2549
2682
|
if (bytes > before.size) throw new Error("artifact changed while being hashed");
|
|
@@ -2918,4 +3051,4 @@ async function improve(profileOrCode, opts) {
|
|
|
2918
3051
|
//#endregion
|
|
2919
3052
|
export { assertProfileTrainingIsHeldOut as a, withMethodRuntimeControls as c, commandVerifier as d, addRuntimeUsage as f, assertCandidateValidator as i, rethrowAfterCleanup as l, isUsageAmount as m, createCommandProfileTrainer as n, parseExecutionRef as o, createRuntimeUsageTotals as p, searchMethod as r, privateValuePaths as s, improve as t, agenticGenerator as u };
|
|
2920
3053
|
|
|
2921
|
-
//# sourceMappingURL=improve-
|
|
3054
|
+
//# sourceMappingURL=improve-BZXt2qM0.js.map
|