@zltquant/zlt-mcp 0.6.1-beta.4 → 0.6.1-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zltquant/zlt-mcp",
3
- "version": "0.6.1-beta.4",
3
+ "version": "0.6.1-beta.5",
4
4
  "description": "智量通 ZLT Quant MCP server(Windows x64;量化策略创建与本地回测)",
5
5
  "bin": {
6
6
  "zlt-mcp": "./zlt-mcp-proxy.bundle.cjs"
@@ -23782,22 +23782,22 @@ function applyBacktestPollingGuard(tool, args, result, states, contexts, activeR
23782
23782
  if (!isRecord2(parsed) || !isRecord2(parsed.Data)) return result;
23783
23783
  const data = parsed.Data;
23784
23784
  const status = Number(data.status);
23785
- if (status !== 1) {
23786
- states.delete(runId);
23787
- if (status === 0) activeRunIds.add(runId);
23788
- else activeRunIds.delete(runId);
23789
- return status === 0 ? withRunningCadence(parsed, data) : result;
23790
- }
23791
- activeRunIds.add(runId);
23792
- const suppliedCodePath = typeof args.codePath === "string" ? args.codePath.trim() : "";
23793
23785
  const context = contexts.get(runId);
23786
+ const suppliedCodePath = typeof args.codePath === "string" ? args.codePath.trim() : "";
23794
23787
  const publicAttemptFence = parseBacktestAttemptFence(args.attemptFence);
23795
- const dataPrep = buildDataPrepInfo(
23788
+ const dataPrep = status === 0 || status === 1 ? buildDataPrepInfo(
23796
23789
  context?.codePath || suppliedCodePath,
23797
23790
  data,
23798
23791
  context?.resultBaseline ?? publicAttemptFence?.resultBaseline ?? parseRunResultIdentity(args.__resultBaseline),
23799
23792
  context?.attemptStartedAtMs ?? publicAttemptFence?.attemptStartedAtMs ?? finitePositiveNumber(args.__attemptStartedAtMs)
23800
- );
23793
+ ) : void 0;
23794
+ if (status !== 1) {
23795
+ states.delete(runId);
23796
+ if (status === 0) activeRunIds.add(runId);
23797
+ else activeRunIds.delete(runId);
23798
+ return status === 0 ? withRunningCadence(parsed, { ...data, ...dataPrep }) : result;
23799
+ }
23800
+ activeRunIds.add(runId);
23801
23801
  const signature = JSON.stringify([
23802
23802
  data.status,
23803
23803
  data.phase,
@@ -23805,13 +23805,14 @@ function applyBacktestPollingGuard(tool, args, result, states, contexts, activeR
23805
23805
  data.downloadedBytes,
23806
23806
  data.downloadedFiles,
23807
23807
  dataPrep?.download_status,
23808
+ dataPrep?.download_progress,
23808
23809
  dataPrep?.download_message,
23809
23810
  dataPrep?.download_update_time
23810
23811
  ]);
23811
23812
  const previous = states.get(runId);
23812
23813
  const unchangedCount = previous?.signature === signature ? previous.unchangedCount + 1 : 1;
23813
23814
  states.set(runId, { signature, unchangedCount });
23814
- if (unchangedCount < 3) return withRunningCadence(parsed, data);
23815
+ if (unchangedCount < 3) return withRunningCadence(parsed, { ...data, ...dataPrep });
23815
23816
  const minutesSinceUpdate = typeof dataPrep?.dataPrepMinutesSinceUpdate === "number" ? dataPrep.dataPrepMinutesSinceUpdate : null;
23816
23817
  if (minutesSinceUpdate !== null && minutesSinceUpdate < STALE_DATA_PREP_MINUTES) {
23817
23818
  return {
@@ -24597,6 +24598,12 @@ function frozenBacktestResult(parsed, data) {
24597
24598
  function backtestWaitLane(runId, session, codePath, resultBaseline, attemptStartedAtMs) {
24598
24599
  let frozenCount = 0;
24599
24600
  let lastSignature = "";
24601
+ const waitStartedAt = Date.now();
24602
+ let lastSubstantiveSignature = "";
24603
+ let lastSubstantiveChangeAt = waitStartedAt;
24604
+ let lastMessageAt = waitStartedAt;
24605
+ let message = "";
24606
+ let elapsedSeconds = 0;
24600
24607
  const stateArgs = {
24601
24608
  runId,
24602
24609
  ...codePath ? { codePath } : {},
@@ -24641,7 +24648,7 @@ function backtestWaitLane(runId, session, codePath, resultBaseline, attemptStart
24641
24648
  result: shapeToolResult(BACKTEST_WAIT_POLL_IDENTITY, stateArgs, base, session)
24642
24649
  };
24643
24650
  }
24644
- const signature = JSON.stringify([
24651
+ const substantiveFields = [
24645
24652
  data.status,
24646
24653
  data.phase,
24647
24654
  data.progress,
@@ -24650,7 +24657,11 @@ function backtestWaitLane(runId, session, codePath, resultBaseline, attemptStart
24650
24657
  data.error_code,
24651
24658
  data.error_msg,
24652
24659
  currentAttemptResult ? runResult?.download_status : void 0,
24653
- currentAttemptResult && typeof runResult?.download_message === "string" ? runResult.download_message : void 0,
24660
+ currentAttemptResult ? runResult?.download_progress : void 0,
24661
+ currentAttemptResult && typeof runResult?.download_message === "string" ? runResult.download_message : void 0
24662
+ ];
24663
+ const signature = JSON.stringify([
24664
+ ...substantiveFields,
24654
24665
  currentAttemptResult && typeof runResult?.download_update_time === "string" ? runResult.download_update_time : void 0
24655
24666
  ]);
24656
24667
  frozenCount = signature === lastSignature ? frozenCount + 1 : 0;
@@ -24661,8 +24672,31 @@ function backtestWaitLane(runId, session, codePath, resultBaseline, attemptStart
24661
24672
  frozenBacktestResult(parsed, data)
24662
24673
  ) };
24663
24674
  }
24664
- const progress = typeof data.progress === "number" && Number.isFinite(data.progress) ? data.progress : 0;
24665
- return { verdict: "wait", progress };
24675
+ const now = Date.now();
24676
+ const substantiveSignature = JSON.stringify(substantiveFields);
24677
+ const changed = substantiveSignature !== lastSubstantiveSignature;
24678
+ if (changed) {
24679
+ lastSubstantiveChangeAt = now;
24680
+ lastSubstantiveSignature = substantiveSignature;
24681
+ }
24682
+ elapsedSeconds = Math.max(elapsedSeconds, Math.floor((now - waitStartedAt) / 1e3));
24683
+ if (changed || !message || now - lastMessageAt >= 3e4) {
24684
+ const prep = currentAttemptResult ? runResult : null;
24685
+ const prepProgress = typeof prep?.download_progress === "number" && Number.isFinite(prep.download_progress) ? prep.download_progress : void 0;
24686
+ const prepActive = prep?.download_status !== void 0 && Number(prep.download_status) === 1;
24687
+ const detail = [
24688
+ status === 0 ? "\u56DE\u6D4B\u51C6\u5907\u4E2D" : "\u56DE\u6D4B\u8FD0\u884C\u4E2D",
24689
+ prepActive ? `\u6570\u636E\u51C6\u5907\u72B6\u6001 ${String(prep.download_status)}` : "",
24690
+ prepActive && prepProgress !== void 0 ? `\u6570\u636E\u51C6\u5907\u5F53\u524D\u6B65\u9AA4 ${prepProgress}%\uFF08\u4E0D\u662F\u56DE\u6D4B\u603B\u8FDB\u5EA6\uFF09` : "",
24691
+ prepActive && typeof prep?.download_message === "string" ? prep.download_message : "",
24692
+ prepActive && typeof prep?.download_update_time === "string" ? `\u6570\u636E\u51C6\u5907\u66F4\u65B0\u65F6\u95F4 ${prep.download_update_time}` : "",
24693
+ typeof data.progress === "number" && Number.isFinite(data.progress) ? `\u56DE\u6D4B\u72B6\u6001\u8FDB\u5EA6 ${data.progress}%` : ""
24694
+ ].filter(Boolean).join("\uFF0C");
24695
+ const unchangedSeconds = Math.max(0, Math.floor((now - lastSubstantiveChangeAt) / 1e3));
24696
+ message = `\u56DE\u6D4B\u7B49\u5F85\uFF08\u5DF2\u7B49\u5F85 ${elapsedSeconds}\u79D2\uFF09\uFF1A${detail}` + (unchangedSeconds >= 30 ? `\uFF1B\u5B9E\u8D28\u8FDB\u5EA6\u5DF2 ${unchangedSeconds}\u79D2\u672A\u53D8\u5316\uFF0C\u4E0D\u7B49\u4E8E\u5931\u8D25\uFF0C\u7EE7\u7EED\u7B49\u5F85\u7EC8\u6001` : "");
24697
+ lastMessageAt = now;
24698
+ }
24699
+ return { verdict: "wait", progress: elapsedSeconds, details: { message } };
24666
24700
  } catch {
24667
24701
  return { verdict: "return", result: unreadableBacktestStateError(runId) };
24668
24702
  }
@@ -24702,7 +24736,8 @@ async function runWaitLoop(lane, client, timeout, session, control) {
24702
24736
  const tick = lane.tick(base);
24703
24737
  if (tick.verdict === "return") return tick.result;
24704
24738
  try {
24705
- control.heartbeat?.(tick.progress);
24739
+ if (tick.details) control.heartbeat?.(tick.progress, tick.details);
24740
+ else control.heartbeat?.(tick.progress);
24706
24741
  } catch {
24707
24742
  }
24708
24743
  if (control.abortSignal?.aborted) return waitError(10047, "\u5DF2\u53D6\u6D88\u7B49\u5F85\u3002");
@@ -24873,6 +24908,7 @@ function buildDataPrepInfo(codePath, data, resultBaseline, attemptStartedAtMs) {
24873
24908
  const runResult = resultFile.data;
24874
24909
  const info = {};
24875
24910
  if (runResult.download_status !== void 0) info.download_status = runResult.download_status;
24911
+ if (runResult.download_progress !== void 0) info.download_progress = runResult.download_progress;
24876
24912
  if (typeof runResult.download_message === "string") info.download_message = runResult.download_message;
24877
24913
  if (typeof runResult.download_update_time === "string") {
24878
24914
  info.download_update_time = runResult.download_update_time;
@@ -27651,6 +27687,9 @@ Timeout or cancellation leaves the install outcome unknown; inspect before retry
27651
27687
  Backtests: create-and-run/re-backtest keep the same MCP consumer until mcp-wait
27652
27688
  returns a terminal state or requires action (such as no-progress). The JSON keeps
27653
27689
  launch identity/configuration plus authoritative wait state. No detached keeper.
27690
+ Progress messages distinguish data preparation from strategy execution and report
27691
+ elapsed time and unchanged observations. Unchanged progress is not proof of failure.
27692
+ Read redirected stderr during background waits; do not restart on a progress warning.
27654
27693
  If isTerminal=true, finalize that run directly; do not wait again. The total timeout
27655
27694
  covers launch plus wait. Interrupted waits print backtest runId/codePath/attemptFence
27656
27695
  for recovery; the runtime may stop when the host closes. Never restart automatically.
@@ -27851,6 +27890,9 @@ function compactCliReceipt(tool, result, resultFile) {
27851
27890
  "isTerminal",
27852
27891
  "evidenceSource",
27853
27892
  "failureCause",
27893
+ "retryableByAgent",
27894
+ "requiresUserAction",
27895
+ "waitStopped",
27854
27896
  "nextAction",
27855
27897
  "recommendedAction",
27856
27898
  "error_code",