patchwork-os 1.2.0-beta.2.canary.836 → 1.2.0-beta.2.canary.838
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/recipes/chainedRunner.d.ts +11 -0
- package/dist/recipes/chainedRunner.js +14 -1
- package/dist/recipes/chainedRunner.js.map +1 -1
- package/dist/recipes/replayBoundary.d.ts +21 -0
- package/dist/recipes/replayBoundary.js +15 -0
- package/dist/recipes/replayBoundary.js.map +1 -1
- package/dist/recipes/replayRun.d.ts +3 -0
- package/dist/recipes/replayRun.js +53 -7
- package/dist/recipes/replayRun.js.map +1 -1
- package/dist/recipes/yamlRunner.d.ts +10 -1
- package/dist/recipes/yamlRunner.js +33 -8
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/package.json +1 -1
|
@@ -67,7 +67,7 @@ import { resolveLocalEndpoint, resolveLocalModel } from "./localSettings.js";
|
|
|
67
67
|
import { defaultDeprecationWarn, normalizeRecipeForRuntime, } from "./migrations/index.js";
|
|
68
68
|
import { costRouter } from "./pricing/costRouter.js";
|
|
69
69
|
import { loadPriceTable, costUsd as priceCostUsd, } from "./pricing/priceTable.js";
|
|
70
|
-
import { ReplayIncompleteError } from "./replayBoundary.js";
|
|
70
|
+
import { ReplayIncompleteError, } from "./replayBoundary.js";
|
|
71
71
|
import { resolveRecipePath } from "./resolveRecipePath.js";
|
|
72
72
|
import { RunBudget } from "./runBudget.js";
|
|
73
73
|
import { recordAttemptRun } from "./runLedgers.js";
|
|
@@ -961,6 +961,9 @@ export async function runYamlRecipe(recipe, deps = {}, seedContext = {}) {
|
|
|
961
961
|
// agent step would. It returns `{ value, ok }`; `ok: false` signals a
|
|
962
962
|
// failed / silent-fail / empty agent response — the caller stops the loop
|
|
963
963
|
// and treats it as exhausted (we don't re-judge a non-result).
|
|
964
|
+
// The agent step currently executing, for replay refusals raised from the
|
|
965
|
+
// refine-loop / nested-agent helpers below (they do not take a step id).
|
|
966
|
+
let currentAgentStepId;
|
|
964
967
|
const runAgentText = async (prompt, driver, model, mcpAccess, downshift, providerOptions,
|
|
965
968
|
// P0-5: carry the reviewed/judge step's opt-in tool sandbox into refine-loop
|
|
966
969
|
// re-runs so a sandboxed step STAYS sandboxed across revisions/re-judges.
|
|
@@ -995,7 +998,7 @@ export async function runYamlRecipe(recipe, deps = {}, seedContext = {}) {
|
|
|
995
998
|
...(deps.agentDisallowedTools?.length && { enforceSandbox: true }),
|
|
996
999
|
...(providerOptions && { providerOptions }),
|
|
997
1000
|
...(dataPolicy !== undefined && { boundary: { dataPolicy } }),
|
|
998
|
-
}, buildAgentExecutorDeps(stepDeps, deps, undefined, runTaskId));
|
|
1001
|
+
}, buildAgentExecutorDeps(stepDeps, deps, undefined, runTaskId, currentAgentStepId));
|
|
999
1002
|
runBudget.reconcile(
|
|
1000
1003
|
// Prefer the driver executeAgent actually resolved+ran; fall back to
|
|
1001
1004
|
// the routed value only when servedBy is absent (non-executeAgent
|
|
@@ -1076,7 +1079,7 @@ export async function runYamlRecipe(recipe, deps = {}, seedContext = {}) {
|
|
|
1076
1079
|
...(input.dataPolicy !== undefined && {
|
|
1077
1080
|
boundary: { dataPolicy: input.dataPolicy },
|
|
1078
1081
|
}),
|
|
1079
|
-
}, buildAgentExecutorDeps(stepDeps, deps, undefined, runTaskId));
|
|
1082
|
+
}, buildAgentExecutorDeps(stepDeps, deps, undefined, runTaskId, currentAgentStepId));
|
|
1080
1083
|
runBudget.reconcile(agentReturn.servedBy?.driver ?? input.driver ?? "auto", agentReturn.usage, agentReturn.servedBy?.model, {
|
|
1081
1084
|
inputChars: input.prompt.length,
|
|
1082
1085
|
outputChars: agentReturn.text.length,
|
|
@@ -1317,6 +1320,7 @@ export async function runYamlRecipe(recipe, deps = {}, seedContext = {}) {
|
|
|
1317
1320
|
// cap is set; never disturbs injected (unit-test) price tables.
|
|
1318
1321
|
runBudget.refreshPrices();
|
|
1319
1322
|
const stepIdForEmit = step.into ?? step.agent?.into ?? `step_${stepsRun}`;
|
|
1323
|
+
currentAgentStepId = stepIdForEmit;
|
|
1320
1324
|
const stepTs = Date.now();
|
|
1321
1325
|
stepStartTs.set(stepIdForEmit, stepTs);
|
|
1322
1326
|
emit("recipe_step_start", {
|
|
@@ -1714,6 +1718,12 @@ export async function runYamlRecipe(recipe, deps = {}, seedContext = {}) {
|
|
|
1714
1718
|
// capture no `output`, so under replay there is never a mock for
|
|
1715
1719
|
// one — refuse here rather than let the catch below be the first
|
|
1716
1720
|
// to hear about it from the seam.
|
|
1721
|
+
// A recorded agent failure replays as that failure (thrown so the
|
|
1722
|
+
// catch below records it exactly as the original halt did).
|
|
1723
|
+
const replayedAgentFailure = deps.mockedFailures?.get(stepId);
|
|
1724
|
+
if (replayedAgentFailure !== undefined) {
|
|
1725
|
+
throw new Error(replayedAgentFailure.error);
|
|
1726
|
+
}
|
|
1717
1727
|
if (deps.replayOnly === true) {
|
|
1718
1728
|
throw new ReplayIncompleteError([stepId], "agent step");
|
|
1719
1729
|
}
|
|
@@ -1764,7 +1774,7 @@ export async function runYamlRecipe(recipe, deps = {}, seedContext = {}) {
|
|
|
1764
1774
|
...(agentCfg.data_policy !== undefined && {
|
|
1765
1775
|
boundary: { dataPolicy: agentCfg.data_policy },
|
|
1766
1776
|
}),
|
|
1767
|
-
}, buildAgentExecutorDeps(stepDeps, deps, undefined, runTaskId));
|
|
1777
|
+
}, buildAgentExecutorDeps(stepDeps, deps, undefined, runTaskId, stepId));
|
|
1768
1778
|
agentResult = agentReturn.text;
|
|
1769
1779
|
runBudget.reconcile(
|
|
1770
1780
|
// Prefer the driver executeAgent actually resolved+ran; the routed
|
|
@@ -2007,7 +2017,16 @@ export async function runYamlRecipe(recipe, deps = {}, seedContext = {}) {
|
|
|
2007
2017
|
// below (driven by `result`), so a replay shows how the recipe's
|
|
2008
2018
|
// wiring behaves against captured evidence — only the tool call
|
|
2009
2019
|
// itself is skipped. See RunnerDeps.mockedOutputs's doc comment.
|
|
2010
|
-
|
|
2020
|
+
const replayedFailure = deps.mockedFailures?.get(stepId);
|
|
2021
|
+
if (replayedFailure !== undefined) {
|
|
2022
|
+
// The original run recorded this step as FAILED with no output. That
|
|
2023
|
+
// record is the evidence: fail the same way, dispatch nothing, and do
|
|
2024
|
+
// not retry — there is nothing to retry against.
|
|
2025
|
+
thrownError = replayedFailure.error;
|
|
2026
|
+
thrownErrorCode = replayedFailure.errorCode;
|
|
2027
|
+
result = null;
|
|
2028
|
+
}
|
|
2029
|
+
else if (deps.mockedOutputs?.has(stepId)) {
|
|
2011
2030
|
result = deps.mockedOutputs.get(stepId) ?? null;
|
|
2012
2031
|
// A replayed http.post response is interpreted exactly as a live one,
|
|
2013
2032
|
// including a response captured before httpOutcome existed: it reads
|
|
@@ -3121,12 +3140,17 @@ function buildAgentExecutorDeps(stepDeps, runnerDeps, claudeCodeFnOverride,
|
|
|
3121
3140
|
* the `runTaskIdRef` cell on its own deps at dispatch time, by which point
|
|
3122
3141
|
* the run has started; the flat caller passes its local const directly.
|
|
3123
3142
|
*/
|
|
3124
|
-
runTaskId
|
|
3143
|
+
runTaskId,
|
|
3144
|
+
/**
|
|
3145
|
+
* The step this dispatch belongs to, so a replay refusal names it. Falls
|
|
3146
|
+
* back to "agent" only when a caller genuinely does not know.
|
|
3147
|
+
*/
|
|
3148
|
+
stepId) {
|
|
3125
3149
|
// Replay boundary (replayBoundary.ts, layer 3) — the single place agent
|
|
3126
3150
|
// executor deps are built for every dispatch site in this runner, so a
|
|
3127
3151
|
// replay's StepDeps can never hand a driver to an agent step.
|
|
3128
3152
|
if (stepDeps.replayOnly === true) {
|
|
3129
|
-
throw new ReplayIncompleteError(["agent"], "agent step");
|
|
3153
|
+
throw new ReplayIncompleteError([stepId ?? "agent"], "agent step");
|
|
3130
3154
|
}
|
|
3131
3155
|
const claudeCliFn = claudeCodeFnOverride ?? stepDeps.claudeCodeFn;
|
|
3132
3156
|
return {
|
|
@@ -3820,7 +3844,7 @@ recipeName) {
|
|
|
3820
3844
|
}, buildAgentExecutorDeps(stepDeps, runnerDeps, claudeCodeFnOverride,
|
|
3821
3845
|
// Read at DISPATCH time, not build time — by now `runChainedRecipe` has
|
|
3822
3846
|
// computed and published the run's `taskId`.
|
|
3823
|
-
runTaskIdRef.current));
|
|
3847
|
+
runTaskIdRef.current, opts?.stepId));
|
|
3824
3848
|
};
|
|
3825
3849
|
// ---------------------------------------------------------------------
|
|
3826
3850
|
// BEGIN A-PR2 EDIT BLOCK — `loadNestedRecipe` jail (dogfood F-04).
|
|
@@ -4004,6 +4028,7 @@ export async function dispatchRecipe(recipe, deps, seedContext = {}) {
|
|
|
4004
4028
|
runLog: deps.chainedOptions?.runLog,
|
|
4005
4029
|
activityLog: deps.chainedOptions?.activityLog,
|
|
4006
4030
|
mockedOutputs: deps.chainedOptions?.mockedOutputs,
|
|
4031
|
+
mockedFailures: deps.chainedOptions?.mockedFailures,
|
|
4007
4032
|
...((deps.replayOnly === true ||
|
|
4008
4033
|
deps.chainedOptions?.replayOnly === true) && { replayOnly: true }),
|
|
4009
4034
|
taskIdPrefix: deps.chainedOptions?.taskIdPrefix,
|