nexus-agents 2.125.36 → 2.125.38

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.
@@ -30,7 +30,7 @@ import {
30
30
  runConsensusForGoal,
31
31
  warnIfSimulatedOutsideTests,
32
32
  writeJobCancelled
33
- } from "./chunk-Y5SDY462.js";
33
+ } from "./chunk-PRFSN66J.js";
34
34
  import {
35
35
  normalizeTopicToCanonical,
36
36
  synthesizeResearch
@@ -122,7 +122,7 @@ import {
122
122
  DEFAULT_TASK_TTL_MS,
123
123
  DEFAULT_TOOL_RATE_LIMITS,
124
124
  clampTaskTtl
125
- } from "./chunk-4LYMLGHZ.js";
125
+ } from "./chunk-Q37HBFVE.js";
126
126
  import {
127
127
  resolveInsideRoot
128
128
  } from "./chunk-NUBSJGQZ.js";
@@ -37599,11 +37599,22 @@ function recordTriageOutcome(success, durationMs, errorMsg) {
37599
37599
 
37600
37600
  // src/mcp/tools/run-graph-workflow.ts
37601
37601
  import { z as z67 } from "zod";
37602
+ import { randomUUID as randomUUID11 } from "crypto";
37602
37603
  var RunGraphWorkflowInputSchema = z67.object({
37603
37604
  workflow: z67.string().min(1).max(100).describe("Name of the predefined graph workflow to execute"),
37604
37605
  inputs: z67.record(z67.string(), z67.unknown()).optional().default({}).describe("Input values for the workflow"),
37605
37606
  enableCheckpointing: z67.boolean().optional().default(true).describe("Enable checkpoint saving between steps"),
37606
- enableAuditTrail: z67.boolean().optional().default(false).describe("Enable audit trail event logging")
37607
+ enableAuditTrail: z67.boolean().optional().default(false).describe("Enable audit trail event logging"),
37608
+ /**
37609
+ * Dispatch mode (#3732). `sync` (default) runs the graph workflow inline and
37610
+ * returns the result — but a workflow of up to ~100 expert nodes can exceed
37611
+ * the MCP request timeout. `async` returns a `{ status: 'pending', jobId }`
37612
+ * envelope immediately and runs in the background; poll
37613
+ * `get_job_result({ jobId })` for the result. Ignored for the `list` sentinel.
37614
+ */
37615
+ dispatch: z67.enum(["sync", "async"]).optional().default("sync").describe(
37616
+ "Dispatch mode (#3732). 'sync' (default): run inline. 'async': return a jobId immediately + run in background (poll get_job_result)."
37617
+ )
37607
37618
  });
37608
37619
  function resolveGraph(workflow, startTime) {
37609
37620
  const registry = getGraphRegistry();
@@ -37688,8 +37699,24 @@ var GRAPH_WORKFLOW_SCHEMA = {
37688
37699
  ),
37689
37700
  inputs: z67.record(z67.string(), z67.unknown()).optional().describe("Input values for the workflow"),
37690
37701
  enableCheckpointing: z67.boolean().optional().describe("Enable checkpoint saving"),
37691
- enableAuditTrail: z67.boolean().optional().describe("Enable audit trail logging")
37702
+ enableAuditTrail: z67.boolean().optional().describe("Enable audit trail logging"),
37703
+ dispatch: z67.enum(["sync", "async"]).optional().describe(
37704
+ "Dispatch mode (#3732). 'sync' (default): run inline. 'async': return a jobId immediately + run in background (poll get_job_result)."
37705
+ )
37692
37706
  };
37707
+ async function executeGraphWorkflowBody(input, logger57, notifier) {
37708
+ const result = await handleRunGraphWorkflow(input, logger57);
37709
+ const succeeded = result.status === "completed";
37710
+ notifier.info("run_graph_workflow", {
37711
+ event: succeeded ? "graph_workflow_complete" : "graph_workflow_failed",
37712
+ workflow: result.workflow,
37713
+ nodeCount: result.nodesExecuted,
37714
+ durationMs: result.durationMs
37715
+ });
37716
+ recordGraphWorkflowResult(result);
37717
+ const text = JSON.stringify(result, null, 2);
37718
+ return succeeded ? toolSuccess(text) : toolStructuredError({ errorCategory: "internal", message: text });
37719
+ }
37693
37720
  function createGraphWorkflowHandler(logger57, notifier) {
37694
37721
  return async (args, _ctx) => {
37695
37722
  const parsed = RunGraphWorkflowInputSchema.safeParse(args);
@@ -37699,24 +37726,24 @@ function createGraphWorkflowHandler(logger57, notifier) {
37699
37726
  message: `Validation error: ${formatZodError(parsed.error)}`
37700
37727
  });
37701
37728
  }
37702
- if (parsed.data.workflow === "list") {
37729
+ const input = parsed.data;
37730
+ if (input.workflow === "list") {
37703
37731
  return toolSuccess(JSON.stringify(getGraphWorkflowList(), null, 2));
37704
37732
  }
37705
37733
  notifier.info("run_graph_workflow", {
37706
37734
  event: "graph_workflow_start",
37707
- workflow: parsed.data.workflow
37708
- });
37709
- const result = await handleRunGraphWorkflow(parsed.data, logger57);
37710
- const succeeded = result.status === "completed";
37711
- notifier.info("run_graph_workflow", {
37712
- event: succeeded ? "graph_workflow_complete" : "graph_workflow_failed",
37713
- workflow: result.workflow,
37714
- nodeCount: result.nodesExecuted,
37715
- durationMs: result.durationMs
37735
+ workflow: input.workflow
37716
37736
  });
37717
- recordGraphWorkflowResult(result);
37718
- const text = JSON.stringify(result, null, 2);
37719
- return succeeded ? toolSuccess(text) : toolStructuredError({ errorCategory: "internal", message: text });
37737
+ if (input.dispatch === "async") {
37738
+ return runAsJob({
37739
+ toolName: "run_graph_workflow",
37740
+ input,
37741
+ freshJobId: () => `gw-${randomUUID11()}`,
37742
+ run: () => executeGraphWorkflowBody(input, logger57, notifier),
37743
+ logger: logger57
37744
+ });
37745
+ }
37746
+ return executeGraphWorkflowBody(input, logger57, notifier);
37720
37747
  };
37721
37748
  }
37722
37749
  function registerRunGraphWorkflowTool(server, deps) {
@@ -38298,9 +38325,21 @@ function suggestImprovement(criterion) {
38298
38325
 
38299
38326
  // src/mcp/tools/execute-spec-tool.ts
38300
38327
  import { z as z68 } from "zod";
38328
+ import { randomUUID as randomUUID12 } from "crypto";
38301
38329
  var ExecuteSpecInputSchema = z68.object({
38302
38330
  spec: z68.string().min(1).max(5e4).describe("Markdown specification to execute"),
38303
- dryRun: z68.boolean().optional().default(false).describe("Parse and decompose only")
38331
+ dryRun: z68.boolean().optional().default(false).describe("Parse and decompose only"),
38332
+ /**
38333
+ * Dispatch mode (#3732). `sync` (default) runs the full DAG pipeline inline
38334
+ * and returns the result — but a real parse→decompose→compile→execute→
38335
+ * validate→analyze run can exceed the MCP request timeout. `async` returns a
38336
+ * `{ status: 'pending', jobId }` envelope immediately and runs in the
38337
+ * background; poll `get_job_result({ jobId })` for the result. Ignored when
38338
+ * `dryRun` is true (parse+decompose completes fast, so dry runs stay sync).
38339
+ */
38340
+ dispatch: z68.enum(["sync", "async"]).default("sync").describe(
38341
+ "Dispatch mode (#3732). 'sync' (default): run inline. 'async': return a jobId immediately + run in background (poll get_job_result). Ignored for dryRun."
38342
+ )
38304
38343
  });
38305
38344
  function createDryRunResponse(input, logger57) {
38306
38345
  const parseResult2 = parseSpec(input.spec);
@@ -38350,9 +38389,8 @@ async function createFullResponse(input, logger57) {
38350
38389
  };
38351
38390
  return toolSuccess(JSON.stringify(output2, null, 2));
38352
38391
  }
38353
- function registerExecuteSpecTool(server, deps) {
38354
- const logger57 = deps.logger ?? createLogger({ tool: "execute_spec" });
38355
- const handler3 = async (args, _ctx) => {
38392
+ function createExecuteSpecHandler(logger57) {
38393
+ return async (args, _ctx) => {
38356
38394
  const parsed = ExecuteSpecInputSchema.safeParse(args);
38357
38395
  if (!parsed.success) {
38358
38396
  return toolStructuredError({
@@ -38360,11 +38398,25 @@ function registerExecuteSpecTool(server, deps) {
38360
38398
  message: `Invalid input: ${formatZodError(parsed.error)}`
38361
38399
  });
38362
38400
  }
38363
- if (parsed.data.dryRun) {
38364
- return createDryRunResponse(parsed.data, logger57);
38401
+ const input = parsed.data;
38402
+ if (input.dryRun) {
38403
+ return createDryRunResponse(input, logger57);
38365
38404
  }
38366
- return createFullResponse(parsed.data, logger57);
38405
+ if (input.dispatch === "async") {
38406
+ return runAsJob({
38407
+ toolName: "execute_spec",
38408
+ input,
38409
+ freshJobId: () => `es-${randomUUID12()}`,
38410
+ run: () => createFullResponse(input, logger57),
38411
+ logger: logger57
38412
+ });
38413
+ }
38414
+ return createFullResponse(input, logger57);
38367
38415
  };
38416
+ }
38417
+ function registerExecuteSpecTool(server, deps) {
38418
+ const logger57 = deps.logger ?? createLogger({ tool: "execute_spec" });
38419
+ const handler3 = createExecuteSpecHandler(logger57);
38368
38420
  const secureHandler = createSecureHandler(handler3, {
38369
38421
  toolName: "execute_spec",
38370
38422
  rateLimiter: deps.rateLimiter,
@@ -38376,7 +38428,10 @@ function registerExecuteSpecTool(server, deps) {
38376
38428
  spec: z68.string().min(1).max(5e4).describe(
38377
38429
  'Markdown specification to execute. Must contain "## Requirements" and "## Acceptance Criteria" sections.'
38378
38430
  ),
38379
- dryRun: z68.boolean().optional().describe("Parse and decompose only (no execution)")
38431
+ dryRun: z68.boolean().optional().describe("Parse and decompose only (no execution)"),
38432
+ dispatch: z68.enum(["sync", "async"]).optional().describe(
38433
+ "Dispatch mode (#3732). 'sync' (default): run inline. 'async': return a jobId immediately + run in background (poll get_job_result). Ignored for dryRun."
38434
+ )
38380
38435
  };
38381
38436
  const description = "Execute a markdown specification through the full pipeline: parse, decompose into task DAG, compile to graph, execute, validate against acceptance criteria, and analyze failures.";
38382
38437
  server.registerTool(
@@ -39547,7 +39602,17 @@ var TOOL_NAME_BY_PREFIX = {
39547
39602
  // resolves those from the sidecar via toolName recorded at writeJobPending).
39548
39603
  dp: "run_dev_pipeline",
39549
39604
  // #3730: run_pipeline async jobs mint `rp-<uuid>` ids (no sessionId surface).
39550
- rp: "run_pipeline"
39605
+ rp: "run_pipeline",
39606
+ // #3731: pr_review async jobs mint `pr-<uuid>` ids (no sessionId surface).
39607
+ pr: "pr_review",
39608
+ // #3731: supply_chain_tradeoff_panel async jobs mint `sc-<uuid>` ids.
39609
+ sc: "supply_chain_tradeoff_panel",
39610
+ // #3732: execute_spec async jobs mint `es-<uuid>` ids (no sessionId surface).
39611
+ es: "execute_spec",
39612
+ // #3732: run_graph_workflow async jobs mint `gw-<uuid>` ids.
39613
+ gw: "run_graph_workflow",
39614
+ // #3732: run (execute:true) async jobs mint `rn-<uuid>` ids.
39615
+ rn: "run"
39551
39616
  };
39552
39617
  function toolNameFromJobId(jobId) {
39553
39618
  const dash = jobId.indexOf("-");
@@ -43058,7 +43123,7 @@ ${contextBlock}`;
43058
43123
  const strategy = config.votingStrategy ?? "higher_order";
43059
43124
  await postProgress(config, "Vote", `Running consensus with ${strategy} strategy...`);
43060
43125
  try {
43061
- const { executeVoting } = await import("./consensus-vote-4ZB7C5QG.js");
43126
+ const { executeVoting } = await import("./consensus-vote-CSKEO3LA.js");
43062
43127
  const votingResult = await executeVoting(
43063
43128
  {
43064
43129
  proposal: buildVoteProposal(plan, research),
@@ -43601,6 +43666,7 @@ function createAuditStageRegistry() {
43601
43666
 
43602
43667
  // src/mcp/tools/pr-review-tool.ts
43603
43668
  import { z as z90 } from "zod";
43669
+ import { randomUUID as randomUUID13 } from "crypto";
43604
43670
 
43605
43671
  // src/mcp/tools/pr-review-findings.ts
43606
43672
  import { parse as parseYaml2 } from "yaml";
@@ -43692,6 +43758,7 @@ var PR_REVIEW_ROLES = [
43692
43758
  ];
43693
43759
  var MAX_DIFF_LENGTH = 5e4;
43694
43760
  var MAX_DESCRIPTION_LENGTH = 1e4;
43761
+ var PR_REVIEW_ASYNC_HINT = "A pr_review run fans out to 5 live LLM voters and can exceed the synchronous MCP request timeout. Retry with `dispatch: 'async'` to get a jobId immediately, then poll get_job_result({ jobId }) for the result.";
43695
43762
  var PrReviewInputSchema = z90.object({
43696
43763
  prTitle: z90.string().min(1).max(500).describe("PR title"),
43697
43764
  prDescription: z90.string().max(MAX_DESCRIPTION_LENGTH).optional().describe("PR body / description"),
@@ -43699,7 +43766,17 @@ var PrReviewInputSchema = z90.object({
43699
43766
  repoContext: z90.string().max(2e3).optional().describe("Optional one-paragraph repo context (architecture, conventions)"),
43700
43767
  baseRef: z90.string().max(200).optional().describe("Base branch ref (e.g. main)"),
43701
43768
  headRef: z90.string().max(200).optional().describe("Head branch ref"),
43702
- simulate: z90.boolean().default(false).describe("Use simulated voters (testing only; never ship live with this true)")
43769
+ simulate: z90.boolean().default(false).describe("Use simulated voters (testing only; never ship live with this true)"),
43770
+ /**
43771
+ * Dispatch mode (#3731). `sync` (default) runs the 5-voter panel inline and
43772
+ * returns the result — but a live fan-out can exceed the MCP request timeout.
43773
+ * `async` returns a `{ status: 'pending', jobId }` envelope immediately and
43774
+ * runs the panel in the background; poll `get_job_result({ jobId })` for the
43775
+ * result.
43776
+ */
43777
+ dispatch: z90.enum(["sync", "async"]).default("sync").describe(
43778
+ "Dispatch mode (#3731). 'sync' (default): run inline. 'async': return a jobId immediately + run the panel in background (poll get_job_result)."
43779
+ )
43703
43780
  });
43704
43781
  function mapVoteDecisionToPrDecision(voteDecision) {
43705
43782
  if (voteDecision === "reject") return "request_changes";
@@ -43806,6 +43883,27 @@ function summarizeReviews(reviews) {
43806
43883
  errorCount: reviews.filter((r) => r.source === "error").length
43807
43884
  };
43808
43885
  }
43886
+ async function executePrReviewBody(input, logger57) {
43887
+ const start = Date.now();
43888
+ const proposal = buildPrReviewProposal(input);
43889
+ const voteResults = await collectRealVotes({
43890
+ roles: PR_REVIEW_ROLES,
43891
+ proposal,
43892
+ simulate: input.simulate,
43893
+ logger: logger57
43894
+ });
43895
+ const reviews = voteResults.map(toPrReviewVote);
43896
+ const counts = summarizeReviews(reviews);
43897
+ const aggregate = aggregatePrDecisions(reviews);
43898
+ const response = {
43899
+ summary: aggregate.decision,
43900
+ verified: aggregate.verified,
43901
+ ...counts,
43902
+ reviews,
43903
+ totalDurationMs: Date.now() - start
43904
+ };
43905
+ return toolSuccess(JSON.stringify(response, null, 2));
43906
+ }
43809
43907
  async function prReviewHandler(args, ctx) {
43810
43908
  const parsed = PrReviewInputSchema.safeParse(args);
43811
43909
  if (!parsed.success) {
@@ -43815,30 +43913,21 @@ async function prReviewHandler(args, ctx) {
43815
43913
  });
43816
43914
  }
43817
43915
  const input = parsed.data;
43818
- const start = Date.now();
43819
43916
  try {
43820
- const proposal = buildPrReviewProposal(input);
43821
- const voteResults = await collectRealVotes({
43822
- roles: PR_REVIEW_ROLES,
43823
- proposal,
43824
- simulate: input.simulate,
43825
- logger: ctx.logger
43826
- });
43827
- const reviews = voteResults.map(toPrReviewVote);
43828
- const counts = summarizeReviews(reviews);
43829
- const aggregate = aggregatePrDecisions(reviews);
43830
- const response = {
43831
- summary: aggregate.decision,
43832
- verified: aggregate.verified,
43833
- ...counts,
43834
- reviews,
43835
- totalDurationMs: Date.now() - start
43836
- };
43837
- return toolSuccess(JSON.stringify(response, null, 2));
43917
+ if (input.dispatch === "async") {
43918
+ return runAsJob({
43919
+ toolName: "pr_review",
43920
+ input,
43921
+ freshJobId: () => `pr-${randomUUID13()}`,
43922
+ run: () => executePrReviewBody(input, ctx.logger),
43923
+ logger: ctx.logger
43924
+ });
43925
+ }
43926
+ return await executePrReviewBody(input, ctx.logger);
43838
43927
  } catch (error) {
43839
43928
  return toolStructuredError({
43840
43929
  errorCategory: "internal",
43841
- message: `PR review failed: ${getErrorMessage(error)}`
43930
+ message: `${PR_REVIEW_ASYNC_HINT} PR review failed: ${getErrorMessage(error)}`
43842
43931
  });
43843
43932
  }
43844
43933
  }
@@ -45091,9 +45180,10 @@ function registerSuggestResearchTasksTool(server, deps) {
45091
45180
 
45092
45181
  // src/mcp/tools/run-tool.ts
45093
45182
  import { z as z103 } from "zod";
45183
+ import { randomUUID as randomUUID17 } from "crypto";
45094
45184
 
45095
45185
  // src/orchestration/meta-orchestrator.ts
45096
- import { randomUUID as randomUUID11 } from "crypto";
45186
+ import { randomUUID as randomUUID14 } from "crypto";
45097
45187
  function createAuditLogSink(logger57) {
45098
45188
  return {
45099
45189
  record(record) {
@@ -45266,7 +45356,7 @@ function createMetaOrchestrator(options) {
45266
45356
  const classification = classifyTask(input.goal);
45267
45357
  const forced = input.forceStrategy !== void 0;
45268
45358
  const base = input.forceStrategy !== void 0 ? buildForcedDecision(input.forceStrategy, routing, classification) : buildSelectedDecision(routing, classification);
45269
- const decision = { ...base, decisionId: randomUUID11() };
45359
+ const decision = { ...base, decisionId: randomUUID14() };
45270
45360
  const timestamp = new Date(getTimeProvider().now()).toISOString();
45271
45361
  sink.record(toRecord(decision, input.goal, forced, timestamp));
45272
45362
  if (shadowSelector !== void 0 && shadowSink !== void 0) {
@@ -45561,7 +45651,7 @@ function createMetaDispatcher(options) {
45561
45651
  import { z as z101 } from "zod";
45562
45652
  import * as fs11 from "fs";
45563
45653
  import * as path10 from "path";
45564
- import { randomUUID as randomUUID12 } from "crypto";
45654
+ import { randomUUID as randomUUID15 } from "crypto";
45565
45655
 
45566
45656
  // src/pipeline/task-tracker.ts
45567
45657
  import * as fs10 from "fs";
@@ -45883,7 +45973,7 @@ function dispatchAsyncDevPipeline(input, taskText, stages, pipelineOptions, logg
45883
45973
  return runAsJob({
45884
45974
  toolName: "run_dev_pipeline",
45885
45975
  input,
45886
- freshJobId: () => `dp-${randomUUID12()}`,
45976
+ freshJobId: () => `dp-${randomUUID15()}`,
45887
45977
  run,
45888
45978
  logger: logger57
45889
45979
  });
@@ -45934,7 +46024,7 @@ function registerDevPipelineTool(server, deps) {
45934
46024
  import { z as z102 } from "zod";
45935
46025
  import * as fs12 from "fs";
45936
46026
  import * as path11 from "path";
45937
- import { randomUUID as randomUUID13 } from "crypto";
46027
+ import { randomUUID as randomUUID16 } from "crypto";
45938
46028
  var PIPELINE_ASYNC_HINT = "A full run_pipeline run can exceed the synchronous MCP request timeout. Retry with `dispatch: 'async'` to get a jobId immediately, then poll get_job_result({ jobId }) for the result.";
45939
46029
  var PipelineInputSchema = z102.object({
45940
46030
  /** The task to execute. */
@@ -46083,7 +46173,7 @@ async function runPipelineHandler(args, logger57) {
46083
46173
  return runAsJob({
46084
46174
  toolName: "run_pipeline",
46085
46175
  input,
46086
- freshJobId: () => `rp-${randomUUID13()}`,
46176
+ freshJobId: () => `rp-${randomUUID16()}`,
46087
46177
  run: () => executePipelineBody(task, stages, input.template, input.dryRun),
46088
46178
  logger: logger57
46089
46179
  });
@@ -46147,6 +46237,17 @@ var RunInputSchema = z103.object({
46147
46237
  isNovel: z103.boolean().optional().describe("Hint: this kind of task has not been seen before."),
46148
46238
  execute: z103.boolean().optional().describe(
46149
46239
  "When true, actually run the selected strategy (if an executor is wired) and return its result; otherwise return the routing decision only (default false, read-only)."
46240
+ ),
46241
+ /**
46242
+ * Dispatch mode (#3732). Only meaningful with `execute: true` — `run`
46243
+ * dispatches the heaviest engines (dev-pipeline/pipeline), which can exceed
46244
+ * the MCP request timeout even with the 1800s class guard (#3734). `sync`
46245
+ * (default) runs inline; `async` returns a `{ status: 'pending', jobId }`
46246
+ * envelope immediately and runs in the background; poll
46247
+ * `get_job_result({ jobId })`. Ignored for read-only routing (execute:false).
46248
+ */
46249
+ dispatch: z103.enum(["sync", "async"]).optional().describe(
46250
+ "Dispatch mode (#3732). 'sync' (default): run inline. 'async' (only with execute:true): return a jobId immediately + run in background (poll get_job_result)."
46150
46251
  )
46151
46252
  });
46152
46253
  var NOTE = "Routing decision only (read-only). Invoke the recommendedTool to execute, or wait for inline execution (run execute: true) in a later release. The other pipeline tools remain available as advanced force-strategy paths.";
@@ -46229,6 +46330,26 @@ async function executeGoal(input, opts = {}) {
46229
46330
  result: dispatch.result
46230
46331
  };
46231
46332
  }
46333
+ async function executeRunBody(input, logger57, trustTier) {
46334
+ try {
46335
+ const exec2 = await executeGoal(input, {
46336
+ logger: logger57,
46337
+ ...trustTier !== void 0 ? { trustTier } : {}
46338
+ });
46339
+ logger57.info("run: executed goal", {
46340
+ decisionId: exec2.decisionId,
46341
+ strategy: exec2.strategy,
46342
+ durationMs: exec2.durationMs
46343
+ });
46344
+ return toolSuccess(JSON.stringify(exec2, null, 2));
46345
+ } catch (err2) {
46346
+ const noExecutor = err2 instanceof MetaDispatchError && err2.code === "no_executor";
46347
+ return toolStructuredError({
46348
+ errorCategory: noExecutor ? "business" : "internal",
46349
+ message: err2 instanceof Error ? err2.message : String(err2)
46350
+ });
46351
+ }
46352
+ }
46232
46353
  async function runHandler(args, logger57, trustTier) {
46233
46354
  const parsed = RunInputSchema.safeParse(args);
46234
46355
  if (!parsed.success) {
@@ -46238,24 +46359,17 @@ async function runHandler(args, logger57, trustTier) {
46238
46359
  });
46239
46360
  }
46240
46361
  if (parsed.data.execute === true) {
46241
- try {
46242
- const exec2 = await executeGoal(parsed.data, {
46243
- logger: logger57,
46244
- ...trustTier !== void 0 ? { trustTier } : {}
46245
- });
46246
- logger57.info("run: executed goal", {
46247
- decisionId: exec2.decisionId,
46248
- strategy: exec2.strategy,
46249
- durationMs: exec2.durationMs
46250
- });
46251
- return toolSuccess(JSON.stringify(exec2, null, 2));
46252
- } catch (err2) {
46253
- const noExecutor = err2 instanceof MetaDispatchError && err2.code === "no_executor";
46254
- return toolStructuredError({
46255
- errorCategory: noExecutor ? "business" : "internal",
46256
- message: err2 instanceof Error ? err2.message : String(err2)
46362
+ const input = parsed.data;
46363
+ if (input.dispatch === "async") {
46364
+ return runAsJob({
46365
+ toolName: "run",
46366
+ input,
46367
+ freshJobId: () => `rn-${randomUUID17()}`,
46368
+ run: () => executeRunBody(input, logger57, trustTier),
46369
+ logger: logger57
46257
46370
  });
46258
46371
  }
46372
+ return executeRunBody(input, logger57, trustTier);
46259
46373
  }
46260
46374
  const response = routeGoal(parsed.data, logger57);
46261
46375
  logger57.info("run: routed goal", {
@@ -46387,6 +46501,7 @@ function registerListAvailableModelsTool(server, deps) {
46387
46501
 
46388
46502
  // src/mcp/tools/supply-chain-tradeoff-panel.ts
46389
46503
  import { z as z105 } from "zod";
46504
+ import { randomUUID as randomUUID18 } from "crypto";
46390
46505
  var DEFAULT_AXES = [
46391
46506
  "build_time_determinism",
46392
46507
  "supply_chain_risk",
@@ -46396,6 +46511,7 @@ var MAX_AXES = 6;
46396
46511
  var MAX_AXIS_NAME_LENGTH = 64;
46397
46512
  var MAX_PROPOSAL_LENGTH = 4e3;
46398
46513
  var MAX_CONTEXT_LENGTH = 4e3;
46514
+ var TRADEOFF_PANEL_ASYNC_HINT = "A supply_chain_tradeoff_panel run fans out to up to 7 live LLM voters and can exceed the synchronous MCP request timeout. Retry with `dispatch: 'async'` to get a jobId immediately, then poll get_job_result({ jobId }) for the result.";
46399
46515
  var FULL_PANEL = [
46400
46516
  "architect",
46401
46517
  "security",
@@ -46415,7 +46531,17 @@ var SupplyChainTradeoffPanelInputSchema = z105.object({
46415
46531
  "Optional context: relevant repo state, dependency tree, vendor publishing patterns, etc."
46416
46532
  ),
46417
46533
  quickMode: z105.boolean().optional().default(false).describe("Use 3 voters (architect, security, scope_steward) instead of 7"),
46418
- simulate: z105.boolean().optional().default(false).describe("Use simulated voters (testing only)")
46534
+ simulate: z105.boolean().optional().default(false).describe("Use simulated voters (testing only)"),
46535
+ /**
46536
+ * Dispatch mode (#3731). `sync` (default) runs the panel inline and returns
46537
+ * the result — but a live fan-out (up to 7 voters) can exceed the MCP request
46538
+ * timeout. `async` returns a `{ status: 'pending', jobId }` envelope
46539
+ * immediately and runs the panel in the background; poll
46540
+ * `get_job_result({ jobId })` for the result.
46541
+ */
46542
+ dispatch: z105.enum(["sync", "async"]).default("sync").describe(
46543
+ "Dispatch mode (#3731). 'sync' (default): run inline. 'async': return a jobId immediately + run the panel in background (poll get_job_result)."
46544
+ )
46419
46545
  });
46420
46546
  function buildTradeoffProposal(input) {
46421
46547
  const axes = input.axes ?? DEFAULT_AXES;
@@ -46593,6 +46719,34 @@ function toPanelVote(result, axes) {
46593
46719
  ...result.error !== void 0 && { errorMessage: result.error }
46594
46720
  };
46595
46721
  }
46722
+ async function executeTradeoffPanelBody(input, logger57) {
46723
+ const axes = input.axes ?? DEFAULT_AXES;
46724
+ const roles = input.quickMode ? QUICK_PANEL : FULL_PANEL;
46725
+ const start = Date.now();
46726
+ const proposal = buildTradeoffProposal(input);
46727
+ const voteResults = await collectRealVotes({
46728
+ roles,
46729
+ proposal,
46730
+ simulate: input.simulate,
46731
+ logger: logger57
46732
+ });
46733
+ const votes = voteResults.map((r) => toPanelVote(r, axes));
46734
+ const axisVerdicts = axes.map((a) => aggregateAxis(a, votes));
46735
+ const decision = aggregatePanel(axisVerdicts);
46736
+ const recommendation = buildRecommendation(decision, axisVerdicts);
46737
+ const voterErrors = votes.filter((v) => v.source === "error").length;
46738
+ const response = {
46739
+ proposal: input.proposal,
46740
+ axes,
46741
+ decision,
46742
+ axisVerdicts,
46743
+ recommendation,
46744
+ votes,
46745
+ voterErrors,
46746
+ durationMs: Date.now() - start
46747
+ };
46748
+ return toolSuccess(JSON.stringify(response, null, 2));
46749
+ }
46596
46750
  async function tradeoffPanelHandler(args, ctx) {
46597
46751
  const parsed = SupplyChainTradeoffPanelInputSchema.safeParse(args);
46598
46752
  if (!parsed.success) {
@@ -46602,37 +46756,21 @@ async function tradeoffPanelHandler(args, ctx) {
46602
46756
  });
46603
46757
  }
46604
46758
  const input = parsed.data;
46605
- const axes = input.axes ?? DEFAULT_AXES;
46606
- const roles = input.quickMode ? QUICK_PANEL : FULL_PANEL;
46607
- const start = Date.now();
46608
46759
  try {
46609
- const proposal = buildTradeoffProposal(input);
46610
- const voteResults = await collectRealVotes({
46611
- roles,
46612
- proposal,
46613
- simulate: input.simulate,
46614
- logger: ctx.logger
46615
- });
46616
- const votes = voteResults.map((r) => toPanelVote(r, axes));
46617
- const axisVerdicts = axes.map((a) => aggregateAxis(a, votes));
46618
- const decision = aggregatePanel(axisVerdicts);
46619
- const recommendation = buildRecommendation(decision, axisVerdicts);
46620
- const voterErrors = votes.filter((v) => v.source === "error").length;
46621
- const response = {
46622
- proposal: input.proposal,
46623
- axes,
46624
- decision,
46625
- axisVerdicts,
46626
- recommendation,
46627
- votes,
46628
- voterErrors,
46629
- durationMs: Date.now() - start
46630
- };
46631
- return toolSuccess(JSON.stringify(response, null, 2));
46760
+ if (input.dispatch === "async") {
46761
+ return runAsJob({
46762
+ toolName: "supply_chain_tradeoff_panel",
46763
+ input,
46764
+ freshJobId: () => `sc-${randomUUID18()}`,
46765
+ run: () => executeTradeoffPanelBody(input, ctx.logger),
46766
+ logger: ctx.logger
46767
+ });
46768
+ }
46769
+ return await executeTradeoffPanelBody(input, ctx.logger);
46632
46770
  } catch (error) {
46633
46771
  return toolStructuredError({
46634
46772
  errorCategory: "internal",
46635
- message: `Tradeoff panel failed: ${getErrorMessage(error)}`
46773
+ message: `${TRADEOFF_PANEL_ASYNC_HINT} Tradeoff panel failed: ${getErrorMessage(error)}`
46636
46774
  });
46637
46775
  }
46638
46776
  }
@@ -48179,7 +48317,7 @@ var FeedbackCollectorConfigSchema = z112.object({
48179
48317
  });
48180
48318
 
48181
48319
  // src/learning/outcome-feedback-helpers.ts
48182
- import { randomUUID as randomUUID14 } from "crypto";
48320
+ import { randomUUID as randomUUID19 } from "crypto";
48183
48321
  function countOutcomesByClass(outcomes) {
48184
48322
  const counts = {
48185
48323
  success: 0,
@@ -48232,7 +48370,7 @@ function generateRewardExplanation(outcome, reward) {
48232
48370
  }
48233
48371
  function createRoutingDecision(params) {
48234
48372
  return {
48235
- id: randomUUID14(),
48373
+ id: randomUUID19(),
48236
48374
  timestamp: getTimeProvider().nowIso(),
48237
48375
  ...params
48238
48376
  };
@@ -48488,7 +48626,7 @@ var DEFAULT_FEEDBACK_INTEGRATION_CONFIG = {
48488
48626
  };
48489
48627
 
48490
48628
  // src/learning/feedback-integration.ts
48491
- import { randomUUID as randomUUID15 } from "crypto";
48629
+ import { randomUUID as randomUUID20 } from "crypto";
48492
48630
  var STEP_QUALITY_SCORING = {
48493
48631
  /** Base score for successful steps. */
48494
48632
  successBase: 0.8,
@@ -48564,8 +48702,8 @@ var FeedbackIntegration = class {
48564
48702
  });
48565
48703
  }
48566
48704
  recordRoutingDecision(decision, traceId) {
48567
- const id = randomUUID15();
48568
- const trace = traceId ?? randomUUID15();
48705
+ const id = randomUUID20();
48706
+ const trace = traceId ?? randomUUID20();
48569
48707
  const now = getTimeProvider().now();
48570
48708
  this.evictStaleEntriesThrottled(now);
48571
48709
  if (this.decisionMap.size >= MAX_DECISION_MAP_SIZE) {
@@ -48639,7 +48777,7 @@ var FeedbackIntegration = class {
48639
48777
  } = params;
48640
48778
  const outcomeClass = this.determineOutcomeClass(success, qualityScore);
48641
48779
  const completionRatio = success ? 1 : qualityScore / this.config.successQualityThreshold;
48642
- const trace = traceId ?? randomUUID15();
48780
+ const trace = traceId ?? randomUUID20();
48643
48781
  const outcome = {
48644
48782
  routingDecisionId,
48645
48783
  timestamp: getTimeProvider().nowIso(),
@@ -50322,4 +50460,4 @@ export {
50322
50460
  shutdownFeedbackSubscriber,
50323
50461
  createEventBusBridge
50324
50462
  };
50325
- //# sourceMappingURL=chunk-SOGHVI6W.js.map
50463
+ //# sourceMappingURL=chunk-2SIYUWT2.js.map