nexus-agents 8.23.3 → 8.23.4

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.
@@ -23,10 +23,10 @@ import {
23
23
  toolSuccessStructured,
24
24
  withProgressHeartbeat,
25
25
  wrapToolWithTimeout
26
- } from "./chunk-FAI5Z3TK.js";
26
+ } from "./chunk-NUYJ4VW5.js";
27
27
  import {
28
28
  VERSION
29
- } from "./chunk-DP2H62OR.js";
29
+ } from "./chunk-FKCE4X4F.js";
30
30
  import {
31
31
  assessPanelIndependence,
32
32
  countDistinctModels,
@@ -81,7 +81,7 @@ import {
81
81
  } from "./chunk-J7QCZRVK.js";
82
82
 
83
83
  // src/mcp/tools/consensus-vote.ts
84
- import { z as z10 } from "zod";
84
+ import { z as z11 } from "zod";
85
85
 
86
86
  // src/utils/bounded-artifact.ts
87
87
  function boundArtifactForReview(text, budget, label) {
@@ -99,7 +99,7 @@ function boundArtifactForReview(text, budget, label) {
99
99
  function voterModelOverrideEnvKey(role) {
100
100
  return `NEXUS_VOTER_MODEL_${role.toUpperCase()}`;
101
101
  }
102
- function resolveVoterModelOverrides(roles, gatewayAdapters, logger10) {
102
+ function resolveVoterModelOverrides(roles, gatewayAdapters, logger11) {
103
103
  const overrides = /* @__PURE__ */ new Map();
104
104
  if (gatewayAdapters.length === 0) return overrides;
105
105
  const byId = /* @__PURE__ */ new Map();
@@ -111,7 +111,7 @@ function resolveVoterModelOverrides(roles, gatewayAdapters, logger10) {
111
111
  const requested = raw.trim();
112
112
  const adapter = byId.get(requested) ?? gatewayAdapters.find((a) => a.modelId.toLowerCase() === requested.toLowerCase());
113
113
  if (adapter === void 0) {
114
- logger10.warn(
114
+ logger11.warn(
115
115
  `Voter model override ${envKey}="${requested}" is not a discovered gateway model \u2014 falling back to round-robin for role "${role}".`,
116
116
  { role, requested, available: [...byId.keys()] }
117
117
  );
@@ -120,7 +120,7 @@ function resolveVoterModelOverrides(roles, gatewayAdapters, logger10) {
120
120
  overrides.set(role, adapter);
121
121
  }
122
122
  if (overrides.size > 0) {
123
- logger10.info("Applied per-role voter model overrides (#4055)", {
123
+ logger11.info("Applied per-role voter model overrides (#4055)", {
124
124
  overrides: Object.fromEntries([...overrides].map(([r, a]) => [r, a.modelId]))
125
125
  });
126
126
  }
@@ -146,28 +146,28 @@ function checkCodexConcurrency(codexBoundConcurrency) {
146
146
  }
147
147
 
148
148
  // src/cli/panel-independence.ts
149
- function reportPanelIndependence(adapters, roleCount, phase, logger10) {
149
+ function reportPanelIndependence(adapters, roleCount, phase, logger11) {
150
150
  reportPanelModelIndependence(
151
151
  adapters.map((adapter) => adapter.modelId),
152
152
  roleCount,
153
153
  phase,
154
- logger10
154
+ logger11
155
155
  );
156
156
  }
157
- function reportVoteIndependence(results, logger10) {
157
+ function reportVoteIndependence(results, logger11) {
158
158
  const successful = results.filter((result) => result.source === "llm");
159
159
  reportPanelModelIndependence(
160
160
  successful.map((result) => result.model),
161
161
  successful.length,
162
162
  "post-vote",
163
- logger10
163
+ logger11
164
164
  );
165
165
  }
166
- function reportPanelModelIndependence(modelIds, roleCount, phase, logger10) {
166
+ function reportPanelModelIndependence(modelIds, roleCount, phase, logger11) {
167
167
  if (roleCount <= 1) return;
168
168
  const verdict = assessPanelIndependence(modelIds);
169
169
  if (verdict.kind === "collapsed") {
170
- logger10.warn("Consensus panel ran on ONE model \u2014 votes may correlate", {
170
+ logger11.warn("Consensus panel ran on ONE model \u2014 votes may correlate", {
171
171
  model: verdict.model,
172
172
  roleCount,
173
173
  phase
@@ -175,7 +175,7 @@ function reportPanelModelIndependence(modelIds, roleCount, phase, logger10) {
175
175
  return;
176
176
  }
177
177
  if (verdict.kind === "diverse") {
178
- logger10.debug("Consensus panel spans distinct models", {
178
+ logger11.debug("Consensus panel spans distinct models", {
179
179
  distinctModels: verdict.distinct,
180
180
  roleCount,
181
181
  phase
@@ -184,13 +184,13 @@ function reportPanelModelIndependence(modelIds, roleCount, phase, logger10) {
184
184
  }
185
185
  const context = { unresolved: verdict.unresolved, total: verdict.total, roleCount };
186
186
  if (phase === "post-vote") {
187
- logger10.warn(
187
+ logger11.warn(
188
188
  "Panel independence UNMEASURED after voting \u2014 cannot say whether votes correlate",
189
189
  context
190
190
  );
191
191
  return;
192
192
  }
193
- logger10.debug(
193
+ logger11.debug(
194
194
  "Panel independence not yet measurable (adapters have not detected their model)",
195
195
  context
196
196
  );
@@ -979,29 +979,29 @@ async function executeSingleVoteAttempt(role, proposal, adapter, timeoutMs, opti
979
979
  throw error;
980
980
  }
981
981
  }
982
- function logAbandonedRetries(logger10, role, attempt, maxRetries) {
983
- logger10.warn("Durable capacity cap \u2014 abandoning retries for this voter", {
982
+ function logAbandonedRetries(logger11, role, attempt, maxRetries) {
983
+ logger11.warn("Durable capacity cap \u2014 abandoning retries for this voter", {
984
984
  role,
985
985
  attempt: attempt + 1,
986
986
  remainingAttemptsSkipped: maxRetries - attempt
987
987
  });
988
988
  }
989
989
  async function executeWithRetries(opts) {
990
- const { role, proposal, adapter, logger: logger10, timeoutMs, maxRetries, options } = opts;
990
+ const { role, proposal, adapter, logger: logger11, timeoutMs, maxRetries, options } = opts;
991
991
  let lastError = "";
992
992
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
993
993
  if (attempt > 0) {
994
994
  const isRateLimit = isRateLimitError(lastError);
995
995
  const baseDelay = isRateLimit ? RATE_LIMIT_RETRY_DELAY_MS : INITIAL_RETRY_DELAY_MS;
996
996
  const delayMs = baseDelay * Math.pow(2, attempt - 1);
997
- logger10.debug("Retrying vote execution", { role, attempt, delayMs, isRateLimit });
997
+ logger11.debug("Retrying vote execution", { role, attempt, delayMs, isRateLimit });
998
998
  await delay(delayMs);
999
999
  }
1000
1000
  const attemptStart = Date.now();
1001
1001
  const result = await executeSingleVoteAttempt(role, proposal, adapter, timeoutMs, options);
1002
1002
  const attemptMs = Date.now() - attemptStart;
1003
1003
  if (result.ok) {
1004
- logger10.info("Vote attempt timing", {
1004
+ logger11.info("Vote attempt timing", {
1005
1005
  role,
1006
1006
  attempt: attempt + 1,
1007
1007
  attemptMs,
@@ -1012,14 +1012,14 @@ async function executeWithRetries(opts) {
1012
1012
  lastError = result.error;
1013
1013
  const rateLimited = isRateLimitError(lastError);
1014
1014
  const durableCap = isDurableCapacityText(lastError);
1015
- logger10.info("Vote attempt timing", {
1015
+ logger11.info("Vote attempt timing", {
1016
1016
  role,
1017
1017
  attempt: attempt + 1,
1018
1018
  attemptMs,
1019
1019
  succeeded: false,
1020
1020
  rateLimited
1021
1021
  });
1022
- logger10.warn("Vote attempt failed", {
1022
+ logger11.warn("Vote attempt failed", {
1023
1023
  role,
1024
1024
  attempt: attempt + 1,
1025
1025
  maxRetries: maxRetries + 1,
@@ -1028,7 +1028,7 @@ async function executeWithRetries(opts) {
1028
1028
  ...durableCap ? { durableCap: true } : {}
1029
1029
  });
1030
1030
  if (durableCap) {
1031
- logAbandonedRetries(logger10, role, attempt, maxRetries);
1031
+ logAbandonedRetries(logger11, role, attempt, maxRetries);
1032
1032
  break;
1033
1033
  }
1034
1034
  }
@@ -1064,9 +1064,9 @@ function createKeyedSerializer() {
1064
1064
  }
1065
1065
  function raceWithDeadline(p, role, deadlineMs) {
1066
1066
  let timer;
1067
- const timeoutP = new Promise((resolve2) => {
1067
+ const timeoutP = new Promise((resolve3) => {
1068
1068
  timer = setTimeout(() => {
1069
- resolve2(createErrorVoteResult(role, DEADLINE_MESSAGE, deadlineMs));
1069
+ resolve3(createErrorVoteResult(role, DEADLINE_MESSAGE, deadlineMs));
1070
1070
  }, deadlineMs);
1071
1071
  });
1072
1072
  return Promise.race([p, timeoutP]).finally(() => {
@@ -1097,7 +1097,7 @@ async function launchRoleVote(role, index, input, voteOnAdapter) {
1097
1097
  return withPinnedModel(await voteOnAdapter(role, input.fallbackAdapter), pinnedModel);
1098
1098
  }
1099
1099
  async function launchVotesWithOverallDeadline(input) {
1100
- const { roles, proposal, logger: logger10, voteOptions, overallDeadlineMs, voteFn } = input;
1100
+ const { roles, proposal, logger: logger11, voteOptions, overallDeadlineMs, voteFn } = input;
1101
1101
  const startedAt = Date.now();
1102
1102
  const serialize = createKeyedSerializer();
1103
1103
  const voteOnAdapter = (role, adapter) => (
@@ -1107,7 +1107,7 @@ async function launchVotesWithOverallDeadline(input) {
1107
1107
  serialize(adapterCliKey(adapter), () => {
1108
1108
  const remaining = Math.max(1, overallDeadlineMs - (Date.now() - startedAt));
1109
1109
  return raceWithDeadline(
1110
- voteFn(role, proposal, adapter, logger10, voteOptions),
1110
+ voteFn(role, proposal, adapter, logger11, voteOptions),
1111
1111
  role,
1112
1112
  remaining
1113
1113
  );
@@ -1117,7 +1117,7 @@ async function launchVotesWithOverallDeadline(input) {
1117
1117
  const results = await Promise.all(wrapped);
1118
1118
  const expired = results.filter((r) => r.source === "error" && r.error === DEADLINE_MESSAGE);
1119
1119
  if (expired.length > 0) {
1120
- logger10.warn("Consensus overall deadline reached; returning partial results", {
1120
+ logger11.warn("Consensus overall deadline reached; returning partial results", {
1121
1121
  totalRoles: roles.length,
1122
1122
  expiredRoles: expired.map((r) => r.role),
1123
1123
  overallDeadlineMs
@@ -1160,31 +1160,31 @@ function resolveVoteExecution(options) {
1160
1160
  declaredOptions: options?.declaredOptions
1161
1161
  };
1162
1162
  }
1163
- async function executeAgentVote(role, proposal, adapter, logger10, options) {
1163
+ async function executeAgentVote(role, proposal, adapter, logger11, options) {
1164
1164
  const start = getTimeProvider().now();
1165
1165
  const { timeoutMs, maxRetries, allowSimulation, declaredOptions } = resolveVoteExecution(options);
1166
- logger10.info("Executing vote", { role, model: adapter.modelId, provider: adapter.providerId });
1166
+ logger11.info("Executing vote", { role, model: adapter.modelId, provider: adapter.providerId });
1167
1167
  const result = await executeWithRetries({
1168
1168
  role,
1169
1169
  proposal,
1170
1170
  adapter,
1171
- logger: logger10,
1171
+ logger: logger11,
1172
1172
  timeoutMs,
1173
1173
  maxRetries,
1174
1174
  options: declaredOptions
1175
1175
  });
1176
1176
  const processingTimeMs = getTimeProvider().now() - start;
1177
1177
  if (result.ok) {
1178
- logger10.info("Vote completed", { role, model: adapter.modelId, decision: result.vote.decision });
1178
+ logger11.info("Vote completed", { role, model: adapter.modelId, decision: result.vote.decision });
1179
1179
  return buildLlmVoteResult(role, result.vote, result.usage, adapter, processingTimeMs);
1180
1180
  }
1181
- logger10.error("Vote execution failed after all retries", void 0, {
1181
+ logger11.error("Vote execution failed after all retries", void 0, {
1182
1182
  role,
1183
1183
  model: adapter.modelId,
1184
1184
  errorMessage: result.error
1185
1185
  });
1186
1186
  if (allowSimulation) {
1187
- logger10.warn("Falling back to simulation (allowSimulation=true)", { role });
1187
+ logger11.warn("Falling back to simulation (allowSimulation=true)", { role });
1188
1188
  return createSimulationVoteResult(role, proposal, processingTimeMs, result.error);
1189
1189
  }
1190
1190
  const remediation = authRemediation(result.error, adapter.providerId);
@@ -1199,26 +1199,26 @@ var NoAdapterError = class extends Error {
1199
1199
  this.name = "NoAdapterError";
1200
1200
  }
1201
1201
  };
1202
- function resolveAdapter(options, logger10) {
1202
+ function resolveAdapter(options, logger11) {
1203
1203
  try {
1204
1204
  if (options.adapter !== void 0) return { adapter: options.adapter };
1205
1205
  const gateway = options.gatewayAdapters;
1206
1206
  if (gateway !== void 0 && gateway.length > 0 && gateway[0] !== void 0) {
1207
1207
  return { adapter: gateway[0] };
1208
1208
  }
1209
- const registry = getGlobalRegistry({ logger: logger10 });
1209
+ const registry = getGlobalRegistry({ logger: logger11 });
1210
1210
  return { adapter: registry.getDefault() };
1211
1211
  } catch (error) {
1212
1212
  return { error: getErrorMessage(error) };
1213
1213
  }
1214
1214
  }
1215
- function warnIfCodexConcurrencyExceeded(roleAdapters, logger10) {
1215
+ function warnIfCodexConcurrencyExceeded(roleAdapters, logger11) {
1216
1216
  const codexBound = [...roleAdapters.values()].filter(
1217
1217
  (a) => a.name === "codex"
1218
1218
  ).length;
1219
1219
  const warning = checkCodexConcurrency(codexBound);
1220
1220
  if (warning !== null) {
1221
- logger10.warn("Codex concurrency limit may be exceeded", { detail: warning });
1221
+ logger11.warn("Codex concurrency limit may be exceeded", { detail: warning });
1222
1222
  }
1223
1223
  }
1224
1224
  function assignUniformAdapter(roles, adapter) {
@@ -1226,15 +1226,15 @@ function assignUniformAdapter(roles, adapter) {
1226
1226
  for (const role of roles) adapters.set(role, adapter);
1227
1227
  return adapters;
1228
1228
  }
1229
- function createCliAdapterMap(clis, logger10) {
1230
- const registry = getGlobalRegistry({ logger: logger10 });
1229
+ function createCliAdapterMap(clis, logger11) {
1230
+ const registry = getGlobalRegistry({ logger: logger11 });
1231
1231
  const result = /* @__PURE__ */ new Map();
1232
1232
  for (const cli of clis) {
1233
1233
  result.set(cli, registry.getAdapterForCli(cli));
1234
1234
  }
1235
1235
  return result;
1236
1236
  }
1237
- function assignRoundRobinAdapters(roles, entries, logger10, source) {
1237
+ function assignRoundRobinAdapters(roles, entries, logger11, source) {
1238
1238
  const adapters = /* @__PURE__ */ new Map();
1239
1239
  const assignments = {};
1240
1240
  for (let i = 0; i < roles.length; i++) {
@@ -1244,70 +1244,70 @@ function assignRoundRobinAdapters(roles, entries, logger10, source) {
1244
1244
  adapters.set(role, entry.adapter);
1245
1245
  assignments[role] = entry.label;
1246
1246
  }
1247
- logger10.info("Diverse adapters assigned", {
1247
+ logger11.info("Diverse adapters assigned", {
1248
1248
  source,
1249
1249
  count: entries.length,
1250
1250
  roleAssignments: assignments
1251
1251
  });
1252
1252
  return adapters;
1253
1253
  }
1254
- function resolveGatewayRoleAdapters(roles, gatewayAdapters, fallbackAdapter, logger10) {
1254
+ function resolveGatewayRoleAdapters(roles, gatewayAdapters, fallbackAdapter, logger11) {
1255
1255
  if (gatewayAdapters.length === 1) {
1256
1256
  if (roles.length > 1) {
1257
- logger10.warn("Consensus panel collapsed to a single gateway model \u2014 votes may correlate", {
1257
+ logger11.warn("Consensus panel collapsed to a single gateway model \u2014 votes may correlate", {
1258
1258
  model: gatewayAdapters[0]?.modelId,
1259
1259
  roleCount: roles.length
1260
1260
  });
1261
1261
  }
1262
1262
  return assignUniformAdapter(roles, gatewayAdapters[0] ?? fallbackAdapter);
1263
1263
  }
1264
- const overrides = resolveVoterModelOverrides(roles, gatewayAdapters, logger10);
1264
+ const overrides = resolveVoterModelOverrides(roles, gatewayAdapters, logger11);
1265
1265
  const roundRobinRoles = roles.filter((r) => !overrides.has(r));
1266
1266
  const assigned = assignRoundRobinAdapters(
1267
1267
  roundRobinRoles,
1268
1268
  gatewayAdapters.map((a) => ({ label: a.modelId, adapter: a })),
1269
- logger10,
1269
+ logger11,
1270
1270
  "gateway"
1271
1271
  );
1272
1272
  for (const [role, adapter] of overrides) assigned.set(role, adapter);
1273
1273
  const assignedModels = [...assigned.values()].map((a) => a.modelId);
1274
1274
  if (roles.length > 1 && countDistinctModels(assignedModels) === 1) {
1275
- logger10.warn(
1275
+ logger11.warn(
1276
1276
  "Consensus panel collapsed to a single gateway model via overrides \u2014 votes may correlate",
1277
1277
  { model: assignedModels[0], roleCount: roles.length }
1278
1278
  );
1279
1279
  }
1280
1280
  return assigned;
1281
1281
  }
1282
- async function resolveDiverseAdapters(roles, logger10, fallbackAdapter, gatewayAdapters) {
1282
+ async function resolveDiverseAdapters(roles, logger11, fallbackAdapter, gatewayAdapters) {
1283
1283
  if (gatewayAdapters !== void 0 && gatewayAdapters.length > 0) {
1284
- return resolveGatewayRoleAdapters(roles, gatewayAdapters, fallbackAdapter, logger10);
1284
+ return resolveGatewayRoleAdapters(roles, gatewayAdapters, fallbackAdapter, logger11);
1285
1285
  }
1286
1286
  let availableClis;
1287
1287
  try {
1288
1288
  availableClis = await getAvailableClis();
1289
1289
  } catch (e) {
1290
- logger10.warn("Failed to resolve available CLIs; falling back to single adapter", {
1290
+ logger11.warn("Failed to resolve available CLIs; falling back to single adapter", {
1291
1291
  error: String(e)
1292
1292
  });
1293
1293
  availableClis = [];
1294
1294
  }
1295
1295
  if (availableClis.length <= 1) {
1296
- logger10.info("Using single adapter for all roles", { cliCount: availableClis.length });
1296
+ logger11.info("Using single adapter for all roles", { cliCount: availableClis.length });
1297
1297
  return assignUniformAdapter(roles, fallbackAdapter);
1298
1298
  }
1299
- const cliAdapters = createCliAdapterMap(availableClis, logger10);
1299
+ const cliAdapters = createCliAdapterMap(availableClis, logger11);
1300
1300
  if (cliAdapters.size <= 1) return assignUniformAdapter(roles, fallbackAdapter);
1301
- reportPanelIndependence([...cliAdapters.values()], roles.length, "assignment", logger10);
1301
+ reportPanelIndependence([...cliAdapters.values()], roles.length, "assignment", logger11);
1302
1302
  return assignRoundRobinAdapters(
1303
1303
  roles,
1304
1304
  [...cliAdapters.entries()].map(([cli, adapter]) => ({ label: cli, adapter })),
1305
- logger10,
1305
+ logger11,
1306
1306
  "cli"
1307
1307
  );
1308
1308
  }
1309
1309
  async function launchStaggeredVotes(input) {
1310
- const { roles, proposal, roleAdapters, fallbackAdapter, logger: logger10, voteOptions, interDelay } = input;
1310
+ const { roles, proposal, roleAdapters, fallbackAdapter, logger: logger11, voteOptions, interDelay } = input;
1311
1311
  const computedDeadlineMs = computeOverallConsensusDeadlineMs(
1312
1312
  voteOptions.timeoutMs,
1313
1313
  voteOptions.maxRetries,
@@ -1316,7 +1316,7 @@ async function launchStaggeredVotes(input) {
1316
1316
  );
1317
1317
  const overallDeadlineMs = getMcpSafeDeadlineMs(computedDeadlineMs, "consensus_vote");
1318
1318
  if (overallDeadlineMs < computedDeadlineMs) {
1319
- logger10.debug("Consensus deadline clamped to MCP wrapper timeout", {
1319
+ logger11.debug("Consensus deadline clamped to MCP wrapper timeout", {
1320
1320
  computedDeadlineMs,
1321
1321
  overallDeadlineMs
1322
1322
  });
@@ -1326,7 +1326,7 @@ async function launchStaggeredVotes(input) {
1326
1326
  proposal,
1327
1327
  roleAdapters,
1328
1328
  fallbackAdapter,
1329
- logger: logger10,
1329
+ logger: logger11,
1330
1330
  voteOptions,
1331
1331
  interDelay,
1332
1332
  overallDeadlineMs,
@@ -1335,27 +1335,27 @@ async function launchStaggeredVotes(input) {
1335
1335
  });
1336
1336
  }
1337
1337
  async function collectRealVotes(options) {
1338
- const logger10 = options.logger ?? defaultLogger;
1338
+ const logger11 = options.logger ?? defaultLogger;
1339
1339
  const { roles, proposal, simulate, allowSimulation } = options;
1340
1340
  const timeoutMs = options.timeoutMs ?? resolveVoteTimeout();
1341
1341
  const maxRetries = options.maxRetries ?? VOTE_TIMEOUTS.maxRetries;
1342
1342
  if (simulate === true) {
1343
- logger10.info("Using simulation mode (explicitly requested)");
1343
+ logger11.info("Using simulation mode (explicitly requested)");
1344
1344
  return createSimulatedVotes(roles, proposal);
1345
1345
  }
1346
- const adapterResult = resolveAdapter(options, logger10);
1346
+ const adapterResult = resolveAdapter(options, logger11);
1347
1347
  if ("error" in adapterResult) {
1348
- logger10.error("No adapter available for voting", void 0, { error: adapterResult.error });
1348
+ logger11.error("No adapter available for voting", void 0, { error: adapterResult.error });
1349
1349
  if (allowSimulation === true) {
1350
- logger10.warn("Falling back to simulation (allowSimulation=true)");
1350
+ logger11.warn("Falling back to simulation (allowSimulation=true)");
1351
1351
  return createSimulatedVotes(roles, proposal, "No adapter available");
1352
1352
  }
1353
1353
  throw new NoAdapterError(
1354
1354
  `No adapter available for voting: ${adapterResult.error}. Install a CLI (claude/gemini/codex) or set ANTHROPIC_API_KEY.`
1355
1355
  );
1356
1356
  }
1357
- const roleAdapters = options.adapter !== void 0 ? assignUniformAdapter(roles, adapterResult.adapter) : await resolveDiverseAdapters(roles, logger10, adapterResult.adapter, options.gatewayAdapters);
1358
- warnIfCodexConcurrencyExceeded(roleAdapters, logger10);
1357
+ const roleAdapters = options.adapter !== void 0 ? assignUniformAdapter(roles, adapterResult.adapter) : await resolveDiverseAdapters(roles, logger11, adapterResult.adapter, options.gatewayAdapters);
1358
+ warnIfCodexConcurrencyExceeded(roleAdapters, logger11);
1359
1359
  const voteOptions = {
1360
1360
  timeoutMs,
1361
1361
  maxRetries,
@@ -1370,12 +1370,12 @@ async function collectRealVotes(options) {
1370
1370
  proposal,
1371
1371
  roleAdapters,
1372
1372
  fallbackAdapter: adapterResult.adapter,
1373
- logger: logger10,
1373
+ logger: logger11,
1374
1374
  voteOptions,
1375
1375
  interDelay,
1376
1376
  signal: options.signal
1377
1377
  });
1378
- reportVoteIndependence(results, logger10);
1378
+ reportVoteIndependence(results, logger11);
1379
1379
  return results;
1380
1380
  }
1381
1381
 
@@ -2312,11 +2312,11 @@ var ConsensusEngine = class {
2312
2312
  logger;
2313
2313
  metrics;
2314
2314
  voterExpansionCallback;
2315
- constructor(config, logger10) {
2315
+ constructor(config, logger11) {
2316
2316
  this.config = { ...DEFAULT_CONSENSUS_CONFIG, ...config };
2317
2317
  this.cacheConfig = { ...DEFAULT_PROPOSAL_CACHE_CONFIG, ...config?.proposalCache };
2318
2318
  this.quorumConfig = { ...DEFAULT_INCREMENTAL_QUORUM_CONFIG, ...config?.incrementalQuorum };
2319
- this.logger = logger10 ?? createLogger({ component: "ConsensusEngine" });
2319
+ this.logger = logger11 ?? createLogger({ component: "ConsensusEngine" });
2320
2320
  this.strategyFactory = new VotingStrategyFactory();
2321
2321
  this.metrics = this.createInitialMetrics();
2322
2322
  }
@@ -2760,15 +2760,15 @@ var ConsensusEngine = class {
2760
2760
  this.logger.debug("Proposal cache cleared");
2761
2761
  }
2762
2762
  };
2763
- function createConsensusEngine(config, logger10) {
2764
- return new ConsensusEngine(config, logger10);
2763
+ function createConsensusEngine(config, logger11) {
2764
+ return new ConsensusEngine(config, logger11);
2765
2765
  }
2766
2766
 
2767
2767
  // src/consensus/quorum-validator.ts
2768
2768
  var QuorumValidator = class {
2769
2769
  logger;
2770
- constructor(logger10) {
2771
- this.logger = logger10 ?? createLogger({ component: "QuorumValidator" });
2770
+ constructor(logger11) {
2771
+ this.logger = logger11 ?? createLogger({ component: "QuorumValidator" });
2772
2772
  }
2773
2773
  validateQuorum(input) {
2774
2774
  const { votes, config } = input;
@@ -2971,8 +2971,8 @@ var QuorumValidator = class {
2971
2971
  };
2972
2972
  }
2973
2973
  };
2974
- function createQuorumValidator(logger10) {
2975
- return new QuorumValidator(logger10);
2974
+ function createQuorumValidator(logger11) {
2975
+ return new QuorumValidator(logger11);
2976
2976
  }
2977
2977
 
2978
2978
  // src/consensus/voting-protocol-helpers.ts
@@ -4060,9 +4060,9 @@ function mergeHistory(target, source) {
4060
4060
  return target;
4061
4061
  }
4062
4062
  var CorrelationModelPartitions = class {
4063
- constructor(maxTrackedPairs, logger10) {
4063
+ constructor(maxTrackedPairs, logger11) {
4064
4064
  this.maxTrackedPairs = maxTrackedPairs;
4065
- this.logger = logger10;
4065
+ this.logger = logger11;
4066
4066
  }
4067
4067
  maxTrackedPairs;
4068
4068
  logger;
@@ -5238,8 +5238,8 @@ var VOTE_RECORDS_DATA_CATEGORY = "governance";
5238
5238
  var VOTE_RECORDS_FILENAME = "vote-records.jsonl";
5239
5239
  var VOTE_RECORDS_PATH_ENV = "NEXUS_VOTE_RECORDS_PATH";
5240
5240
  var MAX_PROPOSAL_RECORD_CHARS = 500;
5241
- function voteRecordWriteFailedMessage(path) {
5242
- return `Authentic vote record NOT persisted: the resolved data directory is not writable (${path}). Check filesystem permissions on the .nexus-agents data dir, or set ${VOTE_RECORDS_PATH_ENV} to a writable absolute file path. See server logs for the underlying filesystem error.`;
5241
+ function voteRecordWriteFailedMessage(path2) {
5242
+ return `Authentic vote record NOT persisted: the resolved data directory is not writable (${path2}). Check filesystem permissions on the .nexus-agents data dir, or set ${VOTE_RECORDS_PATH_ENV} to a writable absolute file path. See server logs for the underlying filesystem error.`;
5243
5243
  }
5244
5244
  function outcomeToDecision(result, votes, errorVoided) {
5245
5245
  const errorCount = votes.filter((v) => v.source === "error").length;
@@ -5319,7 +5319,7 @@ function buildVoteRecord(input) {
5319
5319
  };
5320
5320
  return { ...payload, hash: computeVoteRecordHash(payload) };
5321
5321
  }
5322
- function readLedgerTip(filePath, logger10) {
5322
+ function readLedgerTip(filePath, logger11) {
5323
5323
  if (!existsSync2(filePath)) return { maxSequence: -1, lastHash: void 0 };
5324
5324
  try {
5325
5325
  const { records } = readVoteRecords(filePath);
@@ -5331,7 +5331,7 @@ function readLedgerTip(filePath, logger10) {
5331
5331
  const last = records[records.length - 1];
5332
5332
  return { maxSequence, lastHash: last?.hash };
5333
5333
  } catch (error) {
5334
- logger10.warn("Failed to read vote-record ledger tip", { error: getErrorMessage(error) });
5334
+ logger11.warn("Failed to read vote-record ledger tip", { error: getErrorMessage(error) });
5335
5335
  return { maxSequence: -1, lastHash: void 0 };
5336
5336
  }
5337
5337
  }
@@ -5363,29 +5363,29 @@ function resolveVoteRecordsPath() {
5363
5363
  return resolved;
5364
5364
  }
5365
5365
  function persistVoteRecord(opts) {
5366
- const logger10 = opts.logger ?? createLogger({ component: "vote-record-store" });
5366
+ const logger11 = opts.logger ?? createLogger({ component: "vote-record-store" });
5367
5367
  const filePath = opts.filePath ?? resolveVoteRecordsPath();
5368
5368
  if (filePath === void 0) {
5369
- logger10.warn(voteRecordWriteFailedMessage("<unresolved>"), { id: opts.id });
5369
+ logger11.warn(voteRecordWriteFailedMessage("<unresolved>"), { id: opts.id });
5370
5370
  return void 0;
5371
5371
  }
5372
5372
  try {
5373
5373
  mkdirSync2(dirname(filePath), { recursive: true });
5374
- const { maxSequence, lastHash } = readLedgerTip(filePath, logger10);
5374
+ const { maxSequence, lastHash } = readLedgerTip(filePath, logger11);
5375
5375
  const record = buildVoteRecord({
5376
5376
  ...opts,
5377
5377
  sequence: maxSequence + 1,
5378
5378
  previousHash: lastHash
5379
5379
  });
5380
5380
  appendFileSync2(filePath, JSON.stringify(record) + "\n", "utf-8");
5381
- logger10.info("Persisted authentic vote record", {
5381
+ logger11.info("Persisted authentic vote record", {
5382
5382
  id: record.id,
5383
5383
  decision: record.decision,
5384
5384
  path: filePath
5385
5385
  });
5386
5386
  return record;
5387
5387
  } catch (error) {
5388
- logger10.warn("Failed to persist authentic vote record", {
5388
+ logger11.warn("Failed to persist authentic vote record", {
5389
5389
  error: getErrorMessage(error),
5390
5390
  path: filePath
5391
5391
  });
@@ -5417,10 +5417,10 @@ import { appendFileSync as appendFileSync3, readFileSync as readFileSync3, write
5417
5417
  var PersistentOutcomeStore = class extends OutcomeStore {
5418
5418
  filePath;
5419
5419
  logger;
5420
- constructor(config, logger10) {
5420
+ constructor(config, logger11) {
5421
5421
  super(config);
5422
5422
  this.filePath = config?.filePath ?? getOutcomesFile();
5423
- this.logger = logger10 ?? createLogger({ component: "PersistentOutcomeStore" });
5423
+ this.logger = logger11 ?? createLogger({ component: "PersistentOutcomeStore" });
5424
5424
  const dataDir = config?.dataDir;
5425
5425
  ensureLearningDir(dataDir);
5426
5426
  this.hydrate();
@@ -5720,7 +5720,7 @@ function recordDecisionCost(options) {
5720
5720
  const billingMode = options.billingMode ?? resolveBillingMode();
5721
5721
  const voters = votesToCostInputs(options.votes);
5722
5722
  const store = options.store ?? new DecisionCostStore();
5723
- const logger10 = options.logger ?? defaultLogger2;
5723
+ const logger11 = options.logger ?? defaultLogger2;
5724
5724
  const timestamp = new Date(getTimeProvider().now()).toISOString();
5725
5725
  const { record, persisted } = store.record({
5726
5726
  decisionId: options.decisionId,
@@ -5734,7 +5734,7 @@ function recordDecisionCost(options) {
5734
5734
  if (shouldWarnForDrop(droppedCostRecordCount)) {
5735
5735
  const suppressedSinceLastWarn = droppedCostRecordCount - warnCountSinceReset - 1;
5736
5736
  warnCountSinceReset += 1;
5737
- logger10.warn("Decision-cost rollup dropped (failed to persist) \u2014 billing telemetry lost", {
5737
+ logger11.warn("Decision-cost rollup dropped (failed to persist) \u2014 billing telemetry lost", {
5738
5738
  decisionId: options.decisionId,
5739
5739
  gate: options.gate,
5740
5740
  totalCostUsd: record.summary.totalCostUsd,
@@ -5757,7 +5757,7 @@ function rejectionRulesFrom(result) {
5757
5757
  }
5758
5758
  return rules.size > 0 ? [...rules] : void 0;
5759
5759
  }
5760
- function emitVoteRejectedSignal(result, bus, logger10) {
5760
+ function emitVoteRejectedSignal(result, bus, logger11) {
5761
5761
  if (result.outcome !== "rejected") return;
5762
5762
  try {
5763
5763
  const rejectionRules = rejectionRulesFrom(result);
@@ -5769,7 +5769,7 @@ function emitVoteRejectedSignal(result, bus, logger10) {
5769
5769
  ...rejectionRules !== void 0 ? { rejectionRules } : {}
5770
5770
  });
5771
5771
  } catch (error) {
5772
- logger10.warn("Failed to emit signal.vote_rejected", { error: getErrorMessage(error) });
5772
+ logger11.warn("Failed to emit signal.vote_rejected", { error: getErrorMessage(error) });
5773
5773
  }
5774
5774
  }
5775
5775
 
@@ -5779,10 +5779,10 @@ var ALLOW_SIMULATE_ENV = "NEXUS_ALLOW_SIMULATE";
5779
5779
  function isTestRunner() {
5780
5780
  return process.env.VITEST === "true" || process.env.NODE_ENV === "test";
5781
5781
  }
5782
- function checkSimulationAllowed(toolName, logger10) {
5782
+ function checkSimulationAllowed(toolName, logger11) {
5783
5783
  if (isTestRunner()) return { allowed: true, optedIn: false };
5784
5784
  if (process.env[ALLOW_SIMULATE_ENV] === "1") {
5785
- warnOnce(toolName, logger10);
5785
+ warnOnce(toolName, logger11);
5786
5786
  return { allowed: true, optedIn: true };
5787
5787
  }
5788
5788
  return {
@@ -5797,10 +5797,10 @@ function simulationDeniedResult(reason) {
5797
5797
  detail: { optIn: `${ALLOW_SIMULATE_ENV}=1` }
5798
5798
  });
5799
5799
  }
5800
- function warnOnce(toolName, logger10) {
5800
+ function warnOnce(toolName, logger11) {
5801
5801
  if (WARNED.has(toolName)) return;
5802
5802
  WARNED.add(toolName);
5803
- logger10.warn(
5803
+ logger11.warn(
5804
5804
  `[${toolName}] simulateVotes=true: output is RANDOM and reserved for tests/demos. Do not treat the result as a real decision.`
5805
5805
  );
5806
5806
  }
@@ -5881,13 +5881,13 @@ function isAbandonedJob(record, nowMs) {
5881
5881
  function jobResultPath(jobId) {
5882
5882
  return nexusDataPathEnsure("jobs", `result-${jobId}.json`);
5883
5883
  }
5884
- function persistJobRecord(path, record) {
5885
- writeFileSync3(path, JSON.stringify(record, null, 2), { mode: 384 });
5886
- chmodSync(path, 384);
5884
+ function persistJobRecord(path2, record) {
5885
+ writeFileSync3(path2, JSON.stringify(record, null, 2), { mode: 384 });
5886
+ chmodSync(path2, 384);
5887
5887
  }
5888
5888
  function writeJobPending(jobId, toolName, signalAccepted, producerVersion = VERSION) {
5889
- const path = jobResultPath(jobId);
5890
- if (existsSync4(path)) {
5889
+ const path2 = jobResultPath(jobId);
5890
+ if (existsSync4(path2)) {
5891
5891
  logger7.debug("Job result file already exists \u2014 leaving in place", { jobId });
5892
5892
  return;
5893
5893
  }
@@ -5900,7 +5900,7 @@ function writeJobPending(jobId, toolName, signalAccepted, producerVersion = VERS
5900
5900
  ...signalAccepted !== void 0 ? { signalAccepted } : {},
5901
5901
  producerVersion
5902
5902
  };
5903
- persistJobRecord(path, record);
5903
+ persistJobRecord(path2, record);
5904
5904
  logger7.debug("Wrote pending job record", { jobId, toolName, signalAccepted });
5905
5905
  }
5906
5906
  function writeJobComplete(jobId, toolName, result, producerVersion = VERSION) {
@@ -5962,20 +5962,20 @@ function writeJobCancelled(jobId, toolName, reason, producerVersion = VERSION) {
5962
5962
  logger7.debug("Wrote cancelled job record", { jobId, toolName, reason });
5963
5963
  }
5964
5964
  function readJobResult(jobId) {
5965
- const path = nexusDataPath("jobs", `result-${jobId}.json`);
5966
- if (!existsSync4(path)) return null;
5965
+ const path2 = nexusDataPath("jobs", `result-${jobId}.json`);
5966
+ if (!existsSync4(path2)) return null;
5967
5967
  try {
5968
- const raw = JSON.parse(readFileSync4(path, "utf-8"));
5968
+ const raw = JSON.parse(readFileSync4(path2, "utf-8"));
5969
5969
  const parsed = JobResultSchema.safeParse(raw);
5970
5970
  if (!parsed.success) {
5971
- logger7.warn("Job result file failed schema check", { jobId, path });
5971
+ logger7.warn("Job result file failed schema check", { jobId, path: path2 });
5972
5972
  return null;
5973
5973
  }
5974
5974
  return parsed.data;
5975
5975
  } catch (err2) {
5976
5976
  logger7.warn("Job result file unreadable", {
5977
5977
  jobId,
5978
- path,
5978
+ path: path2,
5979
5979
  error: err2 instanceof Error ? err2.message : String(err2)
5980
5980
  });
5981
5981
  return null;
@@ -6078,9 +6078,9 @@ function resolveIdempotency(tool, idempotencyKey, inputs, randomFallback = rando
6078
6078
  return { kind: "fresh", jobId: randomFallback() };
6079
6079
  }
6080
6080
  const incomingInputsHash = computeInputsHash(inputs);
6081
- const path = indexFilePathReadOnly(tool, idempotencyKey);
6082
- if (existsSync5(path)) {
6083
- const entry = readIndexEntry(path);
6081
+ const path2 = indexFilePathReadOnly(tool, idempotencyKey);
6082
+ if (existsSync5(path2)) {
6083
+ const entry = readIndexEntry(path2);
6084
6084
  if (entry !== null) {
6085
6085
  if (entry.inputsHash === incomingInputsHash) {
6086
6086
  return { kind: "replay", jobId: entry.jobId, entry };
@@ -6092,14 +6092,14 @@ function resolveIdempotency(tool, idempotencyKey, inputs, randomFallback = rando
6092
6092
  existingJobId: entry.jobId
6093
6093
  };
6094
6094
  }
6095
- logger8.warn("Idempotency index file unreadable; treating as fresh dispatch", { tool, path });
6095
+ logger8.warn("Idempotency index file unreadable; treating as fresh dispatch", { tool, path: path2 });
6096
6096
  }
6097
6097
  const jobId = `job-${tool}-${sha256Hex(`${tool}:${idempotencyKey}:${incomingInputsHash}`).slice(0, 16)}`;
6098
6098
  return { kind: "fresh", jobId };
6099
6099
  }
6100
6100
  function registerIdempotentJob(params) {
6101
- const path = indexFilePath(params.tool, params.idempotencyKey);
6102
- if (existsSync5(path)) {
6101
+ const path2 = indexFilePath(params.tool, params.idempotencyKey);
6102
+ if (existsSync5(path2)) {
6103
6103
  logger8.debug("Idempotency index entry already present; skipping write", {
6104
6104
  tool: params.tool,
6105
6105
  jobId: params.jobId
@@ -6114,7 +6114,7 @@ function registerIdempotentJob(params) {
6114
6114
  jobId: params.jobId,
6115
6115
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
6116
6116
  };
6117
- writeFileSync4(path, JSON.stringify(entry, null, 2));
6117
+ writeFileSync4(path2, JSON.stringify(entry, null, 2));
6118
6118
  logger8.debug("Wrote idempotency index entry", { tool: params.tool, jobId: params.jobId });
6119
6119
  }
6120
6120
  function shortCircuitOrFreshJobId(params) {
@@ -6132,18 +6132,18 @@ function shortCircuitOrFreshJobId(params) {
6132
6132
  }
6133
6133
  return { kind: "continue", jobId: r.jobId };
6134
6134
  }
6135
- function readIndexEntry(path) {
6135
+ function readIndexEntry(path2) {
6136
6136
  try {
6137
- const raw = JSON.parse(readFileSync5(path, "utf-8"));
6137
+ const raw = JSON.parse(readFileSync5(path2, "utf-8"));
6138
6138
  const parsed = IdempotencyIndexEntrySchema.safeParse(raw);
6139
6139
  if (!parsed.success) {
6140
- logger8.warn("Idempotency index file failed schema check", { path });
6140
+ logger8.warn("Idempotency index file failed schema check", { path: path2 });
6141
6141
  return null;
6142
6142
  }
6143
6143
  return parsed.data;
6144
6144
  } catch (err2) {
6145
6145
  logger8.warn("Idempotency index file read failed", {
6146
- path,
6146
+ path: path2,
6147
6147
  error: err2 instanceof Error ? err2.message : String(err2)
6148
6148
  });
6149
6149
  return null;
@@ -6244,17 +6244,486 @@ function suggestRetryAfterMs(toolName) {
6244
6244
  return Math.min(6e4, Math.max(5e3, base));
6245
6245
  }
6246
6246
 
6247
+ // src/context/structured-task-state.ts
6248
+ import * as fs2 from "node:fs";
6249
+ import * as path from "node:path";
6250
+ import { AsyncLocalStorage } from "node:async_hooks";
6251
+
6252
+ // src/context/structured-task-state-types.ts
6253
+ import { z as z10 } from "zod";
6254
+ var TaskStageSchema = z10.enum([
6255
+ "planning",
6256
+ "executing",
6257
+ "verifying",
6258
+ "complete",
6259
+ "blocked",
6260
+ // #3091 / epic #2631: terminal failure stage. Distinct from `blocked`
6261
+ // (recoverable, still in-flight) — `failed` is terminal and maps to the
6262
+ // job-result `failed` status. Added so async-mode writers can record a
6263
+ // failed run in StructuredTaskState instead of the Stage-1 sidecar.
6264
+ "failed"
6265
+ ]);
6266
+ var TaskDecisionSchema = z10.object({
6267
+ ts: z10.iso.datetime(),
6268
+ decision: z10.string().min(1),
6269
+ rationale: z10.string().min(1)
6270
+ });
6271
+ var TaskBlockerSchema = z10.object({
6272
+ ts: z10.iso.datetime(),
6273
+ blocker: z10.string().min(1),
6274
+ resolved: z10.iso.datetime().optional()
6275
+ });
6276
+ var TaskPositionSchema = z10.object({
6277
+ currentStep: z10.string().min(1),
6278
+ nextStep: z10.string().optional()
6279
+ });
6280
+ var TaskLedgerSchema = z10.object({
6281
+ /** Verifiable observations: what we have observed/measured/confirmed. */
6282
+ facts: z10.array(z10.string()),
6283
+ /** Working assumptions: useful guesses we proceed under, marked separately. */
6284
+ guesses: z10.array(z10.string()),
6285
+ /** Things we still need to figure out before the plan is sound. */
6286
+ openQuestions: z10.array(z10.string()),
6287
+ updatedAt: z10.iso.datetime()
6288
+ });
6289
+ var ReflectActionSchema = z10.enum([
6290
+ "continue",
6291
+ "revise_plan",
6292
+ "escalate_to_human",
6293
+ "abort"
6294
+ ]);
6295
+ var ProgressLedgerEntrySchema = z10.object({
6296
+ ts: z10.iso.datetime(),
6297
+ /** What just happened (the step we are reflecting on). */
6298
+ step: z10.string().min(1),
6299
+ /** Is the outer Task Ledger plan still right after this step? */
6300
+ planStillValid: z10.boolean(),
6301
+ /** Are we making progress, or have we stalled? */
6302
+ stuck: z10.boolean(),
6303
+ /** What the orchestrator should do next based on this reflection. */
6304
+ suggestedAction: ReflectActionSchema,
6305
+ /** Why this action was chosen — required so future readers can audit the call. */
6306
+ rationale: z10.string().min(1)
6307
+ });
6308
+ var TaskCancellationSchema = z10.object({
6309
+ requestedAt: z10.iso.datetime(),
6310
+ /** Optional human-readable note carried back to the caller. */
6311
+ reason: z10.string().max(1e3).optional()
6312
+ });
6313
+ var TASK_RESULT_MAX_BYTES = 1048576;
6314
+ var StructuredTaskStateSchema = z10.object({
6315
+ taskId: z10.string().min(1),
6316
+ /**
6317
+ * Marks state created by the shared async-job dispatcher (#5622).
6318
+ * Optional for backward compatibility; absence does not prove async dispatch.
6319
+ */
6320
+ dispatch: z10.literal("async").optional(),
6321
+ stage: TaskStageSchema,
6322
+ decisions: z10.array(TaskDecisionSchema),
6323
+ blockers: z10.array(TaskBlockerSchema),
6324
+ position: TaskPositionSchema,
6325
+ /**
6326
+ * Magentic-One Task Ledger (#2278). Mutable single-object outer-loop state:
6327
+ * facts/guesses/openQuestions revised together when the plan is replanned.
6328
+ * Optional so the field can be added later without breaking existing logs.
6329
+ */
6330
+ taskLedger: TaskLedgerSchema.optional(),
6331
+ /**
6332
+ * Magentic-One Progress Ledger (#2278). Append-only inner-loop reflections.
6333
+ * Most recent entry's `suggestedAction` is what `reflect()` returns. Optional
6334
+ * for the same backward-compat reason as `taskLedger`.
6335
+ */
6336
+ progressLedger: z10.array(ProgressLedgerEntrySchema).optional(),
6337
+ /**
6338
+ * Monotonic version counter (#3043 / epic #2631 Stage 2). Increments by
6339
+ * 1 on every write; polling clients use this to detect "I missed a
6340
+ * transition" and resync rather than silently observe a stale snapshot.
6341
+ *
6342
+ * Optional + defaulting-to-0 in the reducer for backward-compat — old
6343
+ * state logs (pre-Stage-2) don't carry it; the reducer treats their
6344
+ * baseline as v0 and starts counting from there.
6345
+ */
6346
+ version: z10.number().int().nonnegative().optional(),
6347
+ /**
6348
+ * Tool result payload (#3043 / epic #2631 Stage 2). Set atomically
6349
+ * via the `result` log event when `stage === 'complete'`. Carries the
6350
+ * same shape the synchronous mode would have returned inline.
6351
+ *
6352
+ * Capped at `TASK_RESULT_MAX_BYTES` at write time; over-cap payloads
6353
+ * are replaced with `{ truncated: true, originalBytes }` so the
6354
+ * cap is observable rather than silent.
6355
+ *
6356
+ * Once Stage 2 (this) ships, Stage 3+ (#3044 / #3045) migrate the
6357
+ * orchestrate / run_workflow / consensus_vote async-mode writers
6358
+ * from the Stage-1 sidecar (`mcp/jobs/job-result-store.ts`) to this
6359
+ * field, then the sidecar files become legacy that the next cleanup
6360
+ * sweep can remove.
6361
+ */
6362
+ result: z10.unknown().optional(),
6363
+ /**
6364
+ * Cancellation marker (#3043 / epic #2631 Stage 2). Set by `cancel_job`
6365
+ * — the running tool checks for this at safe-point boundaries (between
6366
+ * steps, between waves) and aborts via the AbortSignal plumbing from
6367
+ * #3035 / #3038. Append-only by construction (the reducer ignores a
6368
+ * second cancellation event).
6369
+ */
6370
+ cancellation: TaskCancellationSchema.optional(),
6371
+ /**
6372
+ * Creation timestamp (#3090 / epic #2631). Set by the reducer to the
6373
+ * `init` entry's `ts` and never mutated thereafter — `updatedAt` advances
6374
+ * with each write, but `createdAt` is fixed. Job-result readers need the
6375
+ * original creation time; `updatedAt` alone can't supply it once any
6376
+ * transition has been recorded. Optional for backward-compat with
6377
+ * pre-#3090 logs (the reducer backfills it from the init entry).
6378
+ */
6379
+ createdAt: z10.iso.datetime().optional(),
6380
+ updatedAt: z10.iso.datetime()
6381
+ });
6382
+ var StructuredTaskLogEntrySchema = z10.discriminatedUnion("event", [
6383
+ z10.object({
6384
+ event: z10.literal("init"),
6385
+ ts: z10.iso.datetime(),
6386
+ state: StructuredTaskStateSchema
6387
+ }),
6388
+ z10.object({
6389
+ event: z10.literal("decision"),
6390
+ ts: z10.iso.datetime(),
6391
+ decision: TaskDecisionSchema
6392
+ }),
6393
+ z10.object({
6394
+ event: z10.literal("blocker"),
6395
+ ts: z10.iso.datetime(),
6396
+ blocker: TaskBlockerSchema
6397
+ }),
6398
+ z10.object({
6399
+ event: z10.literal("blocker_resolved"),
6400
+ ts: z10.iso.datetime(),
6401
+ /** Index of the blocker in the state's blockers[] array. */
6402
+ blockerIndex: z10.number().int().nonnegative(),
6403
+ resolvedAt: z10.iso.datetime()
6404
+ }),
6405
+ z10.object({
6406
+ event: z10.literal("stage"),
6407
+ ts: z10.iso.datetime(),
6408
+ stage: TaskStageSchema
6409
+ }),
6410
+ z10.object({
6411
+ event: z10.literal("position"),
6412
+ ts: z10.iso.datetime(),
6413
+ position: TaskPositionSchema
6414
+ }),
6415
+ // Magentic-One Task Ledger replacement event — the outer loop revises the
6416
+ // entire ledger atomically when replanning. Always replaces, never partial.
6417
+ z10.object({
6418
+ event: z10.literal("task_ledger"),
6419
+ ts: z10.iso.datetime(),
6420
+ ledger: TaskLedgerSchema
6421
+ }),
6422
+ // Magentic-One Progress Ledger append event — one self-reflection per step.
6423
+ z10.object({
6424
+ event: z10.literal("progress_ledger"),
6425
+ ts: z10.iso.datetime(),
6426
+ entry: ProgressLedgerEntrySchema
6427
+ }),
6428
+ // #3043 / epic #2631 Stage 2 — tool result payload set when stage flips
6429
+ // to 'complete'. Written by appendResult; replayed into state.result.
6430
+ // The payload itself is `unknown` because each tool's result shape is
6431
+ // its own; readers cast after a status check.
6432
+ z10.object({
6433
+ event: z10.literal("result"),
6434
+ ts: z10.iso.datetime(),
6435
+ result: z10.unknown()
6436
+ }),
6437
+ // #3043 / epic #2631 Stage 2 — cancellation marker. Append-only: the
6438
+ // reducer ignores a second cancellation event so a malicious or buggy
6439
+ // double-cancel can't rewrite the requestedAt timestamp.
6440
+ z10.object({
6441
+ event: z10.literal("cancellation"),
6442
+ ts: z10.iso.datetime(),
6443
+ cancellation: TaskCancellationSchema
6444
+ })
6445
+ ]);
6446
+
6447
+ // src/context/structured-task-state.ts
6448
+ var logger10 = createLogger({ component: "structured-task-state" });
6449
+ var TASKS_SUBDIR = "tasks";
6450
+ var FILE_MODE2 = 384;
6451
+ var DIR_MODE2 = 448;
6452
+ var asyncTaskStateJob = new AsyncLocalStorage();
6453
+ function withAsyncTaskStateDispatch(jobId, operation) {
6454
+ return asyncTaskStateJob.run(jobId, operation);
6455
+ }
6456
+ function getTasksDir(customDir) {
6457
+ if (customDir !== void 0) return path.resolve(customDir);
6458
+ return nexusDataPath(TASKS_SUBDIR);
6459
+ }
6460
+ function getLogPath(taskId, customDir) {
6461
+ return path.join(getTasksDir(customDir), `state-${taskId}.jsonl`);
6462
+ }
6463
+ function listTaskStateIds(customDir) {
6464
+ const dir = getTasksDir(customDir);
6465
+ if (!fs2.existsSync(dir)) return [];
6466
+ let entries;
6467
+ try {
6468
+ entries = fs2.readdirSync(dir);
6469
+ } catch (cause) {
6470
+ logger10.warn("tasks directory unreadable", {
6471
+ dir,
6472
+ error: cause instanceof Error ? cause.message : String(cause)
6473
+ });
6474
+ return [];
6475
+ }
6476
+ const ids = [];
6477
+ for (const entry of entries) {
6478
+ const match = /^state-(.+)\.jsonl$/.exec(entry);
6479
+ if (match?.[1] !== void 0) ids.push(match[1]);
6480
+ }
6481
+ return ids;
6482
+ }
6483
+ function validateTaskId(taskId) {
6484
+ if (taskId.includes("..") || taskId.includes("/") || taskId.includes("\\")) {
6485
+ return err(new Error("Invalid task ID: contains path traversal characters"));
6486
+ }
6487
+ if (taskId.length === 0 || taskId.length > 128) {
6488
+ return err(new Error("Invalid task ID: must be 1-128 characters"));
6489
+ }
6490
+ return ok(taskId);
6491
+ }
6492
+ function ensureTasksDir(customDir) {
6493
+ const dirPath = getTasksDir(customDir);
6494
+ try {
6495
+ fs2.mkdirSync(dirPath, { recursive: true, mode: DIR_MODE2 });
6496
+ return ok(dirPath);
6497
+ } catch (cause) {
6498
+ const e = cause instanceof Error ? cause : new Error(String(cause));
6499
+ return err(new Error(`Failed to create tasks directory at ${dirPath}: ${e.message}`));
6500
+ }
6501
+ }
6502
+ function appendLogEntry(taskId, entry, customDir) {
6503
+ const idCheck = validateTaskId(taskId);
6504
+ if (!idCheck.ok) return err(idCheck.error);
6505
+ const dirResult = ensureTasksDir(customDir);
6506
+ if (!dirResult.ok) return err(dirResult.error);
6507
+ const filePath = getLogPath(taskId, customDir);
6508
+ const line = JSON.stringify(entry) + "\n";
6509
+ try {
6510
+ fs2.appendFileSync(filePath, line, { mode: FILE_MODE2 });
6511
+ return ok(void 0);
6512
+ } catch (cause) {
6513
+ const e = cause instanceof Error ? cause : new Error(String(cause));
6514
+ return err(new Error(`Failed to write task state entry: ${e.message}`));
6515
+ }
6516
+ }
6517
+ function initTaskState(state, customDir) {
6518
+ const isAsyncJob = asyncTaskStateJob.getStore() === state.taskId;
6519
+ const persistedState = isAsyncJob ? { ...state, dispatch: "async" } : state;
6520
+ return appendLogEntry(
6521
+ state.taskId,
6522
+ { event: "init", ts: state.updatedAt, state: persistedState },
6523
+ customDir
6524
+ );
6525
+ }
6526
+ function appendBlocker(taskId, blocker, customDir) {
6527
+ return appendLogEntry(taskId, { event: "blocker", ts: blocker.ts, blocker }, customDir);
6528
+ }
6529
+ function updateStage(taskId, stage, ts, customDir) {
6530
+ return appendLogEntry(taskId, { event: "stage", ts, stage }, customDir);
6531
+ }
6532
+ function appendResult(taskId, result, ts, customDir) {
6533
+ let payload = result;
6534
+ let serialized;
6535
+ try {
6536
+ serialized = JSON.stringify(result ?? null);
6537
+ } catch (cause) {
6538
+ const e = cause instanceof Error ? cause : new Error(String(cause));
6539
+ return err(new Error(`Failed to serialize result for task ${taskId}: ${e.message}`));
6540
+ }
6541
+ const bytes = Buffer.byteLength(serialized, "utf-8");
6542
+ if (bytes > TASK_RESULT_MAX_BYTES) {
6543
+ payload = {
6544
+ truncated: true,
6545
+ originalBytes: bytes,
6546
+ maxBytes: TASK_RESULT_MAX_BYTES,
6547
+ note: "Result exceeded TASK_RESULT_MAX_BYTES \u2014 original dropped at write time."
6548
+ };
6549
+ logger10.warn("Task result truncated at write", {
6550
+ taskId,
6551
+ bytes,
6552
+ max: TASK_RESULT_MAX_BYTES
6553
+ });
6554
+ }
6555
+ return appendLogEntry(taskId, { event: "result", ts, result: payload }, customDir);
6556
+ }
6557
+ function appendCancellation(taskId, cancellation, customDir) {
6558
+ return appendLogEntry(
6559
+ taskId,
6560
+ { event: "cancellation", ts: cancellation.requestedAt, cancellation },
6561
+ customDir
6562
+ );
6563
+ }
6564
+ function readTaskState(taskId, customDir) {
6565
+ const idCheck = validateTaskId(taskId);
6566
+ if (!idCheck.ok) return err(idCheck.error);
6567
+ const filePath = getLogPath(taskId, customDir);
6568
+ if (!fs2.existsSync(filePath)) {
6569
+ return err(new Error(`No state log for task: ${taskId}`));
6570
+ }
6571
+ let content;
6572
+ try {
6573
+ content = fs2.readFileSync(filePath, "utf-8");
6574
+ } catch (cause) {
6575
+ const e = cause instanceof Error ? cause : new Error(String(cause));
6576
+ return err(new Error(`Failed to read state log: ${e.message}`));
6577
+ }
6578
+ const lines = content.split("\n").filter((l) => l.length > 0);
6579
+ const entries = [];
6580
+ for (const line of lines) {
6581
+ try {
6582
+ const parsed = JSON.parse(line);
6583
+ const validated = StructuredTaskLogEntrySchema.safeParse(parsed);
6584
+ if (validated.success) {
6585
+ entries.push(validated.data);
6586
+ } else {
6587
+ logger10.warn("Skipping malformed task-state log entry", {
6588
+ taskId,
6589
+ error: validated.error.message
6590
+ });
6591
+ }
6592
+ } catch (cause) {
6593
+ const msg = cause instanceof Error ? cause.message : String(cause);
6594
+ logger10.warn("Skipping unparseable task-state log entry", { taskId, error: msg });
6595
+ }
6596
+ }
6597
+ return reduceLogEntries(taskId, entries);
6598
+ }
6599
+ function reduceLogEntries(taskId, entries) {
6600
+ const init = entries.find((e) => e.event === "init");
6601
+ if (init === void 0) {
6602
+ return err(new Error(`No init entry found for task: ${taskId}`));
6603
+ }
6604
+ const initState = init.state;
6605
+ if (initState.taskId !== taskId) {
6606
+ return err(
6607
+ new Error(`Task ID mismatch: log contains state for ${initState.taskId}, expected ${taskId}`)
6608
+ );
6609
+ }
6610
+ let state = {
6611
+ ...initState,
6612
+ decisions: [...initState.decisions],
6613
+ blockers: initState.blockers.map((b) => ({ ...b })),
6614
+ version: initState.version ?? 0,
6615
+ // #3090: createdAt is fixed at the init entry's ts and never advances
6616
+ // (unlike updatedAt). Prefer an explicit createdAt on the init state,
6617
+ // else fall back to the init entry's ts.
6618
+ createdAt: initState.createdAt ?? init.ts
6619
+ };
6620
+ for (const entry of entries) {
6621
+ if (entry === init) continue;
6622
+ state = applyLogEntry(state, entry);
6623
+ }
6624
+ return ok(state);
6625
+ }
6626
+ function applyBlockerEvent(state, entry, nextVersion) {
6627
+ if (entry.event === "blocker") {
6628
+ return {
6629
+ ...state,
6630
+ blockers: [...state.blockers, entry.blocker],
6631
+ updatedAt: entry.ts,
6632
+ version: nextVersion
6633
+ };
6634
+ }
6635
+ return {
6636
+ ...state,
6637
+ blockers: state.blockers.map(
6638
+ (b, i) => i === entry.blockerIndex ? { ...b, resolved: entry.resolvedAt } : b
6639
+ ),
6640
+ updatedAt: entry.ts,
6641
+ version: nextVersion
6642
+ };
6643
+ }
6644
+ function applyReplacementEvent(state, entry, nextVersion) {
6645
+ switch (entry.event) {
6646
+ case "decision":
6647
+ return {
6648
+ ...state,
6649
+ decisions: [...state.decisions, entry.decision],
6650
+ updatedAt: entry.ts,
6651
+ version: nextVersion
6652
+ };
6653
+ case "stage":
6654
+ return { ...state, stage: entry.stage, updatedAt: entry.ts, version: nextVersion };
6655
+ case "position":
6656
+ return { ...state, position: entry.position, updatedAt: entry.ts, version: nextVersion };
6657
+ case "task_ledger":
6658
+ return { ...state, taskLedger: entry.ledger, updatedAt: entry.ts, version: nextVersion };
6659
+ case "progress_ledger":
6660
+ return {
6661
+ ...state,
6662
+ progressLedger: [...state.progressLedger ?? [], entry.entry],
6663
+ updatedAt: entry.ts,
6664
+ version: nextVersion
6665
+ };
6666
+ }
6667
+ }
6668
+ function applyTerminalEvent(state, entry, nextVersion) {
6669
+ if (entry.event === "result") {
6670
+ return { ...state, result: entry.result, updatedAt: entry.ts, version: nextVersion };
6671
+ }
6672
+ return {
6673
+ ...state,
6674
+ cancellation: state.cancellation ?? entry.cancellation,
6675
+ updatedAt: entry.ts,
6676
+ version: nextVersion
6677
+ };
6678
+ }
6679
+ var EVENT_CATEGORY = {
6680
+ init: "init",
6681
+ blocker: "blocker",
6682
+ blocker_resolved: "blocker",
6683
+ decision: "replace",
6684
+ stage: "replace",
6685
+ position: "replace",
6686
+ task_ledger: "replace",
6687
+ progress_ledger: "replace",
6688
+ result: "terminal",
6689
+ cancellation: "terminal"
6690
+ };
6691
+ function applyLogEntry(state, entry) {
6692
+ const category = EVENT_CATEGORY[entry.event];
6693
+ if (category === "init") return state;
6694
+ const nextVersion = (state.version ?? 0) + 1;
6695
+ if (category === "blocker") {
6696
+ return applyBlockerEvent(
6697
+ state,
6698
+ entry,
6699
+ nextVersion
6700
+ );
6701
+ }
6702
+ if (category === "terminal") {
6703
+ return applyTerminalEvent(
6704
+ state,
6705
+ entry,
6706
+ nextVersion
6707
+ );
6708
+ }
6709
+ return applyReplacementEvent(
6710
+ state,
6711
+ entry,
6712
+ nextVersion
6713
+ );
6714
+ }
6715
+
6247
6716
  // src/mcp/jobs/run-as-job.ts
6248
6717
  var ASYNC_JOB_BODY_GUARD_CLASS = "async-job-body";
6249
6718
  var ASYNC_JOB_BODY_NEAR_TIMEOUT_THRESHOLD = 0.5;
6250
6719
  var ASYNC_JOB_BODY_RUNAWAY_MESSAGE = "runaway guard exceeded";
6251
- function makeAsyncBodyGuard(jobId, toolName, guardMs, logger10) {
6720
+ function makeAsyncBodyGuard(jobId, toolName, guardMs, logger11) {
6252
6721
  let guardTimer;
6253
6722
  let warnTimer;
6254
6723
  const expired = new Promise((_resolve, reject) => {
6255
6724
  warnTimer = setTimeout(
6256
6725
  () => {
6257
- logger10?.warn(`Async ${toolName} job approaching runaway guard`, {
6726
+ logger11?.warn(`Async ${toolName} job approaching runaway guard`, {
6258
6727
  jobId,
6259
6728
  guardMs,
6260
6729
  thresholdFraction: ASYNC_JOB_BODY_NEAR_TIMEOUT_THRESHOLD
@@ -6373,10 +6842,11 @@ async function runJobInBackground(jobId, params) {
6373
6842
  const guard = makeAsyncBodyGuard(jobId, params.toolName, guardMs, params.logger);
6374
6843
  const controller = registerJobAbort(jobId);
6375
6844
  try {
6376
- const result = await Promise.race([
6377
- params.run(jobId, params.input, controller.signal),
6378
- guard.expired
6379
- ]);
6845
+ const body = withAsyncTaskStateDispatch(
6846
+ jobId,
6847
+ () => params.run(jobId, params.input, controller.signal)
6848
+ );
6849
+ const result = await Promise.race([body, guard.expired]);
6380
6850
  const failure = detectFailureShapedResult(result);
6381
6851
  if (failure !== null && params.allowFailureShapedResult === void 0) {
6382
6852
  writeJobFailed(jobId, params.toolName, describeFailureShape(failure), params.producerVersion);
@@ -6522,13 +6992,13 @@ async function processVotesThroughEngine(engineVotes, proposal, algorithm) {
6522
6992
  });
6523
6993
  return resultRes.value;
6524
6994
  }
6525
- function runHigherOrderVoting(strategy, voteMap, logger10, context) {
6995
+ function runHigherOrderVoting(strategy, voteMap, logger11, context) {
6526
6996
  if (!isHigherOrderStrategy(strategy)) return void 0;
6527
6997
  const hovStrategy = new HigherOrderVotingStrategy();
6528
6998
  const tracker = getOrCreateCorrelationTracker();
6529
6999
  tracker.setCurrentModelPins?.(context.modelPins);
6530
7000
  const result = hovStrategy.aggregate(voteMap, tracker);
6531
- logger10.info("Higher-Order Voting complete", {
7001
+ logger11.info("Higher-Order Voting complete", {
6532
7002
  method: result.method,
6533
7003
  decision: result.decision,
6534
7004
  posteriorApproval: result.posteriorApproval.toFixed(3)
@@ -6544,10 +7014,10 @@ function buildCorrelationContext(votes) {
6544
7014
  }
6545
7015
  return { modelPins, observedModels };
6546
7016
  }
6547
- function recordVotesToTracker(votes, outcome, logger10) {
7017
+ function recordVotesToTracker(votes, outcome, logger11) {
6548
7018
  const llmVotes = votes.filter((v) => v.source === "llm");
6549
7019
  if (llmVotes.length < votes.length) {
6550
- logger10.warn("Recording only LLM votes to correlation tracker; excluding non-LLM votes", {
7020
+ logger11.warn("Recording only LLM votes to correlation tracker; excluding non-LLM votes", {
6551
7021
  recorded: llmVotes.length,
6552
7022
  excluded: votes.length - llmVotes.length
6553
7023
  });
@@ -6559,16 +7029,16 @@ function recordVotesToTracker(votes, outcome, logger10) {
6559
7029
  const tracker = getOrCreateCorrelationTracker();
6560
7030
  const id = `consensus-${String(getTimeProvider().now())}-${getRandomProvider().random().toString(36).slice(2, 9)}`;
6561
7031
  tracker.recordProposalVotes(id, llmVoteMap, outcome, context);
6562
- logger10.debug("Recorded votes to tracker", { proposalId: id, outcome });
7032
+ logger11.debug("Recorded votes to tracker", { proposalId: id, outcome });
6563
7033
  try {
6564
7034
  const persisted = createPersistedProposal(id, llmVoteMap, outcome, context);
6565
7035
  const saveResult = saveCorrelationData([persisted]);
6566
7036
  if (!saveResult.ok) {
6567
- logger10.warn("Failed to persist correlation data", { error: saveResult.error.message });
7037
+ logger11.warn("Failed to persist correlation data", { error: saveResult.error.message });
6568
7038
  }
6569
7039
  } catch (error) {
6570
7040
  const message = getErrorMessage(error);
6571
- logger10.warn("Error persisting correlation data", { error: message });
7041
+ logger11.warn("Error persisting correlation data", { error: message });
6572
7042
  }
6573
7043
  }
6574
7044
  async function processVotesWithCascade(engineVotes, opts) {
@@ -6664,37 +7134,37 @@ function buildPolicyShortCircuitResult(args) {
6664
7134
  policyReason: args.reason
6665
7135
  };
6666
7136
  }
6667
- async function maybeEscalateContrarian(input, outcome, ctx, logger10, opts) {
7137
+ async function maybeEscalateContrarian(input, outcome, ctx, logger11, opts) {
6668
7138
  if (!input.quickMode || outcome !== "approved" || input.simulateVotes) return {};
6669
7139
  if (shouldEscalateLowPosterior(ctx.strategy, outcome, input.quickMode, ctx.posteriorApproval)) {
6670
- logger10.warn("Posterior-confidence escalation: re-running with full vote (#3174)", {
7140
+ logger11.warn("Posterior-confidence escalation: re-running with full vote (#3174)", {
6671
7141
  strategy: ctx.strategy,
6672
7142
  posteriorApproval: ctx.posteriorApproval
6673
7143
  });
6674
- return { escalated: await executeVoting({ ...input, quickMode: false }, logger10, opts) };
7144
+ return { escalated: await executeVoting({ ...input, quickMode: false }, logger11, opts) };
6675
7145
  }
6676
- const escalation = await runContrarianCheck(input.proposal, logger10);
7146
+ const escalation = await runContrarianCheck(input.proposal, logger11);
6677
7147
  if (escalation.errored && input.errorPolicy === "absolute_quorum") {
6678
- logger10.warn("Contrarian check errored under absolute_quorum \u2014 degrading to no_quorum (#4132)");
7148
+ logger11.warn("Contrarian check errored under absolute_quorum \u2014 degrading to no_quorum (#4132)");
6679
7149
  return {
6680
7150
  degradeReason: "no_quorum: re-run \u2014 contrarian check errored (absolute_quorum quick-mode)"
6681
7151
  };
6682
7152
  }
6683
7153
  if (!escalation.shouldEscalate) return {};
6684
- logger10.warn("Contrarian escalation: re-running with full vote", {
7154
+ logger11.warn("Contrarian escalation: re-running with full vote", {
6685
7155
  reason: escalation.reason,
6686
7156
  confidence: escalation.confidence
6687
7157
  });
6688
- return { escalated: await executeVoting({ ...input, quickMode: false }, logger10, opts) };
7158
+ return { escalated: await executeVoting({ ...input, quickMode: false }, logger11, opts) };
6689
7159
  }
6690
- async function executeVoting(input, logger10, opts) {
6691
- const result = await executeVotingInner(input, logger10, opts ?? {});
7160
+ async function executeVoting(input, logger11, opts) {
7161
+ const result = await executeVotingInner(input, logger11, opts ?? {});
6692
7162
  const correlationAlreadyRecorded = result.decision !== void 0;
6693
7163
  const errorCount = result.votes.filter((v) => v.source === "error").length;
6694
7164
  applyOptionGate(input, result);
6695
7165
  result.decision = resolveVoteDecision(input, result, errorCount).decision;
6696
7166
  if (!correlationAlreadyRecorded && (result.decision === "approved" || result.decision === "rejected")) {
6697
- recordVotesToTracker(result.votes, result.decision, logger10);
7167
+ recordVotesToTracker(result.votes, result.decision, logger11);
6698
7168
  }
6699
7169
  return result;
6700
7170
  }
@@ -6714,13 +7184,13 @@ function applyOptionGate(input, result) {
6714
7184
  result.result.outcome = "rejected";
6715
7185
  result.optionGate = outcome.reason !== void 0 ? { ...outcome.verdict, reason: outcome.reason } : outcome.verdict;
6716
7186
  }
6717
- async function executeVotingInner(input, logger10, opts) {
7187
+ async function executeVotingInner(input, logger11, opts) {
6718
7188
  const strategy = resolveStrategy(input);
6719
7189
  const algorithm = strategyToAlgorithm(strategy);
6720
7190
  const roles = getVoterRoles(input.quickMode);
6721
7191
  const startTime = getTimeProvider().now();
6722
7192
  const errorPolicy = input.errorPolicy ?? getDefaultErrorPolicy(strategy);
6723
- logger10.info("Starting consensus vote", {
7193
+ logger11.info("Starting consensus vote", {
6724
7194
  strategy,
6725
7195
  algorithm,
6726
7196
  roleCount: roles.length,
@@ -6746,7 +7216,7 @@ async function executeVotingInner(input, logger10, opts) {
6746
7216
  errorPolicy,
6747
7217
  reason: policyDecision.reason ?? "error policy short-circuit",
6748
7218
  startTime,
6749
- logger: logger10
7219
+ logger: logger11
6750
7220
  });
6751
7221
  }
6752
7222
  const { engineResult, higherOrderResult, outcome, cascaded } = await processVotesWithCascade(
@@ -6756,14 +7226,14 @@ async function executeVotingInner(input, logger10, opts) {
6756
7226
  proposal: input.proposal,
6757
7227
  algorithm,
6758
7228
  strategy,
6759
- log: logger10
7229
+ log: logger11
6760
7230
  }
6761
7231
  );
6762
7232
  const escalation = await maybeEscalateContrarian(
6763
7233
  input,
6764
7234
  outcome,
6765
7235
  { strategy, posteriorApproval: higherOrderResult?.posteriorApproval },
6766
- logger10,
7236
+ logger11,
6767
7237
  opts
6768
7238
  );
6769
7239
  if (escalation.escalated !== void 0) return escalation.escalated;
@@ -6778,7 +7248,7 @@ async function executeVotingInner(input, logger10, opts) {
6778
7248
  outcome,
6779
7249
  cascaded,
6780
7250
  startTime,
6781
- logger: logger10
7251
+ logger: logger11
6782
7252
  });
6783
7253
  return applyContrarianDegrade(finalized, escalation.degradeReason);
6784
7254
  }
@@ -6786,8 +7256,8 @@ function applyContrarianDegrade(result, degradeReason) {
6786
7256
  if (degradeReason === void 0 || result.policyReason !== void 0) return result;
6787
7257
  return { ...result, policyReason: degradeReason };
6788
7258
  }
6789
- async function runConsensusForGoal(goal, logger10 = createLogger({ tool: "consensus_vote" }), gatewayAdapters) {
6790
- return executeVoting(ConsensusVoteInputSchema.parse({ proposal: goal }), logger10, {
7259
+ async function runConsensusForGoal(goal, logger11 = createLogger({ tool: "consensus_vote" }), gatewayAdapters) {
7260
+ return executeVoting(ConsensusVoteInputSchema.parse({ proposal: goal }), logger11, {
6791
7261
  ...gatewayAdapters !== void 0 && { gatewayAdapters }
6792
7262
  });
6793
7263
  }
@@ -6814,7 +7284,7 @@ function finalizeVotingResult(args) {
6814
7284
  if (args.higherOrderResult !== void 0) result.higherOrderResult = args.higherOrderResult;
6815
7285
  return result;
6816
7286
  }
6817
- function recordVoteSideEffects(proposal, strategy, result, logger10, ratifies) {
7287
+ function recordVoteSideEffects(proposal, strategy, result, logger11, ratifies) {
6818
7288
  const decisionId = `consensus-${String(getTimeProvider().now())}-${randomUUID2().slice(0, 8)}`;
6819
7289
  const voteRecord = recordAuthenticVote({
6820
7290
  proposal,
@@ -6837,7 +7307,7 @@ function recordVoteSideEffects(proposal, strategy, result, logger10, ratifies) {
6837
7307
  try {
6838
7308
  costSummary = recordDecisionCost({ decisionId, gate: "consensus_vote", votes: result.votes });
6839
7309
  } catch (costError) {
6840
- logger10.warn("Per-decision cost rollup failed (non-fatal)", {
7310
+ logger11.warn("Per-decision cost rollup failed (non-fatal)", {
6841
7311
  error: getErrorMessage(costError)
6842
7312
  });
6843
7313
  costSummary = void 0;
@@ -6845,16 +7315,16 @@ function recordVoteSideEffects(proposal, strategy, result, logger10, ratifies) {
6845
7315
  return { costSummary, voteRecord };
6846
7316
  }
6847
7317
  async function handleConsensusVote(deps, args, signal) {
6848
- const logger10 = deps.logger ?? createLogger({ tool: "consensus_vote" });
7318
+ const logger11 = deps.logger ?? createLogger({ tool: "consensus_vote" });
6849
7319
  try {
6850
- const result = await executeVoting(args, logger10, {
7320
+ const result = await executeVoting(args, logger11, {
6851
7321
  ...deps.gatewayAdapters !== void 0 && { gatewayAdapters: deps.gatewayAdapters },
6852
7322
  signal
6853
7323
  });
6854
7324
  const errorVotes = result.votes.filter((v) => v.source === "error");
6855
7325
  if (errorVotes.length === result.votes.length && result.votes.length > 0) {
6856
7326
  const failures = errorVotes.map((v) => `${v.role}: ${v.error ?? "unknown error"}`).join("; ");
6857
- logger10.warn("All voters failed", { failureCount: errorVotes.length, failures });
7327
+ logger11.warn("All voters failed", { failureCount: errorVotes.length, failures });
6858
7328
  recordVoteError(args.proposal, `All ${String(errorVotes.length)} voters failed: ${failures}`);
6859
7329
  return {
6860
7330
  ok: false,
@@ -6876,15 +7346,15 @@ async function handleConsensusVote(deps, args, signal) {
6876
7346
  args.proposal,
6877
7347
  result.strategy,
6878
7348
  result,
6879
- logger10,
7349
+ logger11,
6880
7350
  args.ratifies
6881
7351
  );
6882
- emitVoteRejectedSignal(result.result, getPipelineEventBus(), logger10);
7352
+ emitVoteRejectedSignal(result.result, getPipelineEventBus(), logger11);
6883
7353
  return { ok: true, value: buildResponse(args, result, costSummary, voteRecord) };
6884
7354
  } catch (error) {
6885
7355
  const message = getErrorMessage(error);
6886
7356
  const cause = error instanceof Error ? error : new Error(message);
6887
- logger10.error("Consensus vote failed", cause);
7357
+ logger11.error("Consensus vote failed", cause);
6888
7358
  recordVoteError(args.proposal, message);
6889
7359
  return { ok: false, error: `Voting failed: ${message}` };
6890
7360
  }
@@ -7002,35 +7472,35 @@ var ASYNC_ENVELOPES = {
7002
7472
  };
7003
7473
  var CONSENSUS_VOTE_OUTPUT_SCHEMA = {
7004
7474
  /** Async-dispatch envelope discriminator — absent on a completed vote. */
7005
- status: z10.enum(["pending", "busy", "replay"]).optional(),
7006
- jobId: z10.string().max(200).optional(),
7007
- pollTool: z10.literal("get_job_result").optional(),
7008
- note: z10.string().max(500).optional(),
7009
- retryAfterMs: z10.number().optional(),
7010
- proposal: z10.string().optional(),
7475
+ status: z11.enum(["pending", "busy", "replay"]).optional(),
7476
+ jobId: z11.string().max(200).optional(),
7477
+ pollTool: z11.literal("get_job_result").optional(),
7478
+ note: z11.string().max(500).optional(),
7479
+ retryAfterMs: z11.number().optional(),
7480
+ proposal: z11.string().optional(),
7011
7481
  strategy: VotingStrategySchema.optional(),
7012
7482
  // Reuses the canonical VoteDecisionStatusSchema (single source) — a hand-listed
7013
7483
  // subset here (was ['approved','rejected','no_quorum']) omitted the reachable
7014
7484
  // 'timeout'/'pending' outcomes and made strict clients reject those votes (#4032).
7015
7485
  decision: VoteDecisionStatusSchema.optional(),
7016
- approvalPercentage: z10.number().optional(),
7017
- voteCounts: z10.object({
7018
- approve: z10.number(),
7019
- reject: z10.number(),
7020
- abstain: z10.number(),
7021
- error: z10.number()
7486
+ approvalPercentage: z11.number().optional(),
7487
+ voteCounts: z11.object({
7488
+ approve: z11.number(),
7489
+ reject: z11.number(),
7490
+ abstain: z11.number(),
7491
+ error: z11.number()
7022
7492
  }).optional(),
7023
- votes: z10.array(
7024
- z10.object({
7025
- role: z10.string().max(100),
7026
- decision: z10.enum(["approve", "reject", "abstain"]),
7027
- confidence: z10.number(),
7028
- reasoning: z10.string().max(4e3),
7029
- simulated: z10.boolean(),
7030
- error: z10.boolean(),
7031
- modelUsed: z10.string().max(100).optional(),
7032
- rejectionCategories: z10.array(
7033
- z10.enum([
7493
+ votes: z11.array(
7494
+ z11.object({
7495
+ role: z11.string().max(100),
7496
+ decision: z11.enum(["approve", "reject", "abstain"]),
7497
+ confidence: z11.number(),
7498
+ reasoning: z11.string().max(4e3),
7499
+ simulated: z11.boolean(),
7500
+ error: z11.boolean(),
7501
+ modelUsed: z11.string().max(100).optional(),
7502
+ rejectionCategories: z11.array(
7503
+ z11.enum([
7034
7504
  "YAGNI",
7035
7505
  "DRY_VIOLATION",
7036
7506
  "OVER_ENGINEERING",
@@ -7043,33 +7513,33 @@ var CONSENSUS_VOTE_OUTPUT_SCHEMA = {
7043
7513
  })
7044
7514
  ).optional(),
7045
7515
  threshold: VoteThresholdSchema.optional(),
7046
- durationMs: z10.number().optional(),
7047
- simulateVotes: z10.boolean().optional(),
7048
- higherOrderMetadata: z10.object({
7049
- posteriorApproval: z10.number(),
7050
- posteriorRejection: z10.number(),
7051
- effectiveVoteCount: z10.number(),
7052
- method: z10.enum(["ow", "isp", "simple"]),
7053
- usedCorrelationData: z10.boolean(),
7054
- improvementOverBaseline: z10.number(),
7055
- downweightedAgents: z10.array(z10.string().max(100)).max(10),
7056
- reasoning: z10.string().max(2e3)
7516
+ durationMs: z11.number().optional(),
7517
+ simulateVotes: z11.boolean().optional(),
7518
+ higherOrderMetadata: z11.object({
7519
+ posteriorApproval: z11.number(),
7520
+ posteriorRejection: z11.number(),
7521
+ effectiveVoteCount: z11.number(),
7522
+ method: z11.enum(["ow", "isp", "simple"]),
7523
+ usedCorrelationData: z11.boolean(),
7524
+ improvementOverBaseline: z11.number(),
7525
+ downweightedAgents: z11.array(z11.string().max(100)).max(10),
7526
+ reasoning: z11.string().max(2e3)
7057
7527
  }).optional(),
7058
7528
  // #3124: explains a `rejected` decision that coexists with a high
7059
7529
  // approvalPercentage (an error-policy short-circuit, e.g. fail_closed).
7060
- policyReason: z10.string().max(200).optional(),
7530
+ policyReason: z11.string().max(200).optional(),
7061
7531
  // #3991: whether the authentic vote record was persisted at vote time. Post-
7062
7532
  // #3991 it routes through nexusDataPath under governance/, so true is the
7063
7533
  // normal case; false means all-simulated (skipped by design) or write-failed
7064
7534
  // (data dir unwritable) — voteRecordNote carries the actionable reason. Makes
7065
7535
  // a previously WARN-only skip visible to MCP callers.
7066
- voteRecordPersisted: z10.boolean().optional(),
7067
- voteRecordNote: z10.string().max(500).optional(),
7536
+ voteRecordPersisted: z11.boolean().optional(),
7537
+ voteRecordNote: z11.string().max(500).optional(),
7068
7538
  // #3587: set when the panel DEGRADED (some voters errored), so the decision
7069
7539
  // rests on fewer voters than requested. Part of the response since #3587 but
7070
7540
  // omitted from this schema until #4032 — its absence made a strict MCP client
7071
7541
  // reject any degraded-panel vote (`-32602 additional properties`).
7072
- panelWarning: z10.string().optional(),
7542
+ panelWarning: z11.string().optional(),
7073
7543
  // #3855: per-decision cost rollup. Same omission as panelWarning (#4032) — it
7074
7544
  // is present on the response whenever cost recording succeeds (common in `api`
7075
7545
  // billing mode). Shared schema lives with the type (single source of truth).
@@ -7077,35 +7547,35 @@ var CONSENSUS_VOTE_OUTPUT_SCHEMA = {
7077
7547
  // #4472: declared-option outcome. Present whenever the proposal declared
7078
7548
  // `options`. `unattributedApprovals` is part of the contract, not telemetry:
7079
7549
  // without it a caller cannot tell a real split from unreadable responses.
7080
- optionOutcome: z10.object({
7081
- tally: z10.array(z10.object({ option: z10.string(), count: z10.number().int().nonnegative() })),
7082
- leadingOption: z10.string().optional(),
7083
- leadingShare: z10.number().min(0).max(1),
7084
- approverCount: z10.number().int().nonnegative(),
7085
- selectedCount: z10.number().int().nonnegative(),
7086
- unattributedApprovals: z10.number().int().nonnegative(),
7087
- thresholdMet: z10.boolean(),
7550
+ optionOutcome: z11.object({
7551
+ tally: z11.array(z11.object({ option: z11.string(), count: z11.number().int().nonnegative() })),
7552
+ leadingOption: z11.string().optional(),
7553
+ leadingShare: z11.number().min(0).max(1),
7554
+ approverCount: z11.number().int().nonnegative(),
7555
+ selectedCount: z11.number().int().nonnegative(),
7556
+ unattributedApprovals: z11.number().int().nonnegative(),
7557
+ thresholdMet: z11.boolean(),
7088
7558
  // #4529: present only on a veto. Declared here because a strict MCP
7089
7559
  // client rejects any property the advertised schema omits — the same
7090
7560
  // drift that made degraded-panel votes unusable before #4032.
7091
- vetoReason: z10.string().max(400).optional()
7561
+ vetoReason: z11.string().max(400).optional()
7092
7562
  }).optional()
7093
7563
  };
7094
7564
  var CONSENSUS_VOTE_TOOL_SCHEMA = ConsensusVoteInputSchema.shape;
7095
7565
  var CONSENSUS_VOTE_DESCRIPTION = "Execute multi-model consensus voting on a proposal. Uses 7 roles by default (architect, security, devex, ai_ml, pm, catfish, scope_steward) or 3 with quickMode (architect, security, scope_steward), voting with configurable strategies. higher_order does NOT decide the verdict by correlation-aware aggregation (#4701): approve/reject is a simple tally of the panel, so correlated voters each carry full independent weight. The Bayesian correlation analysis is computed and feeds contrarian escalation only. Choose it for the escalation behaviour, not for a weighted verdict. Supports async mode (mode: 'async') \u2014 returns a jobId to poll via get_job_result. Pass ratifies=<subject> to bind an authority-ladder ratification vote into its authentic record. If your proposal asks voters to choose among named alternatives, you MUST pass them in `options` (#4472) \u2014 the threshold is then measured over WHICH option won, and the record carries the per-option tally plus selection coverage. WITHOUT `options` the tally is approve/reject/abstain only, so every voter who engages returns `approve` and a 6-1 split on which option persists as 7-0, 100% (#4452).";
7096
7566
  function registerConsensusVoteTool(server, deps) {
7097
- const logger10 = deps.logger ?? createLogger({ tool: "consensus_vote" });
7567
+ const logger11 = deps.logger ?? createLogger({ tool: "consensus_vote" });
7098
7568
  const notifier = deps.notifier ?? createMcpNotifier(server);
7099
7569
  const depsWithNotifier = { ...deps, notifier };
7100
7570
  const secureHandler = createSecureHandler(createConsensusVoteHandler(depsWithNotifier), {
7101
7571
  toolName: "consensus_vote",
7102
7572
  rateLimiter: deps.rateLimiter,
7103
- logger: logger10
7573
+ logger: logger11
7104
7574
  });
7105
7575
  const timeoutMs = getToolTimeout("consensus_vote", deps.security);
7106
7576
  const wrappedHandler = wrapToolWithTimeout("consensus_vote", secureHandler, {
7107
7577
  timeoutMs,
7108
- logger: logger10
7578
+ logger: logger11
7109
7579
  });
7110
7580
  server.registerTool(
7111
7581
  "consensus_vote",
@@ -7115,9 +7585,9 @@ function registerConsensusVoteTool(server, deps) {
7115
7585
  outputSchema: CONSENSUS_VOTE_OUTPUT_SCHEMA,
7116
7586
  annotations: getToolAnnotations("consensus_vote")
7117
7587
  },
7118
- toSdkCallbackWithBudgetCheck(wrappedHandler, "consensus_vote", timeoutMs, logger10)
7588
+ toSdkCallbackWithBudgetCheck(wrappedHandler, "consensus_vote", timeoutMs, logger11)
7119
7589
  );
7120
- logger10.info("Registered consensus_vote tool with secure handler and timeout protection");
7590
+ logger11.info("Registered consensus_vote tool with secure handler and timeout protection");
7121
7591
  }
7122
7592
 
7123
7593
  export {
@@ -7132,6 +7602,13 @@ export {
7132
7602
  abortJob,
7133
7603
  resolveIdempotency,
7134
7604
  registerIdempotentJob,
7605
+ listTaskStateIds,
7606
+ initTaskState,
7607
+ appendBlocker,
7608
+ updateStage,
7609
+ appendResult,
7610
+ appendCancellation,
7611
+ readTaskState,
7135
7612
  defaultPendingEnvelope,
7136
7613
  defaultBusyEnvelope,
7137
7614
  defaultReplayEnvelope,
@@ -7205,4 +7682,4 @@ export {
7205
7682
  CONSENSUS_VOTE_TOOL_SCHEMA,
7206
7683
  registerConsensusVoteTool
7207
7684
  };
7208
- //# sourceMappingURL=chunk-MEZUIN3R.js.map
7685
+ //# sourceMappingURL=chunk-DEVL62JD.js.map