@zltquant/zlt-mcp 0.5.0-beta.0 → 0.5.0-beta.1

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/config.json CHANGED
@@ -21,7 +21,7 @@
21
21
  },
22
22
  {
23
23
  "name": "mcp-strategy-get-template-list",
24
- "description": "获取策略参数模板列表。创建策略前应先调用本工具,根据返回的模板列表选择 templateItemVal,再调用策略创建工具。",
24
+ "description": "获取平台策略参数模板列表。创建策略前应先调用本工具,只能从实时返回的条目取 val 作为 templateItemVal,不要编造或硬编码模板标识。用户明确指定的模板优先;用户只说「推荐策略并回测」等委托选择请求时,agent 可根据返回的名称、说明和可用标签选择合适模板,无需再要求用户选择。没有其他偏好时,优先选择实时返回的带平台推荐标签且适合的日线模板;没有返回推荐标记时,若列表中存在且适合用户需求,可选择「均线择时」作为后备;否则从当前列表选择其他合适模板并简要说明理由。随后调用 mcp-create-strategy-with-template 创建。",
25
25
  "inputSchema": {
26
26
  "type": "object",
27
27
  "properties": {
@@ -47,13 +47,13 @@
47
47
  },
48
48
  {
49
49
  "name": "mcp-create-strategy-with-template",
50
- "description": "基于用户选择的策略模板创建本地策略。先用 mcp-strategy-get-template-list 取模板列表让用户选,把所选模板的 val 填入 templateItemVal;templateVal 固定为 strategy。名称默认用「模板名称+日期时间(YYMMDD-HHMM)」,调用前允许用户修改或确认——ZLTAF 对重名策略会静默不创建并返回空结果,本工具已将其转为明确的 ErrNo 10051,遇到就改用唯一名称重试,**切勿改为复用既有同名策略**。\n\n返回含 strategyId 与 localPath,请直接使用,不要再自行查询策略列表按名称猜测。",
50
+ "description": "基于平台策略模板创建本地策略。先用 mcp-strategy-get-template-list 取实时列表,把所选条目的 val 填入 templateItemVal;templateVal 固定为 strategy。用户明确指定的模板优先;用户委托推荐时允许 agent 代选,无需再要求用户选择。名称默认用「模板名称+日期时间(YYMMDD-HHMM)」,允许用户修改;用户未指定名称时直接生成唯一名称——ZLTAF 对重名策略会静默不创建并返回空结果,本工具已将其转为明确的 ErrNo 10051,遇到就改用唯一名称重试,**切勿改为复用既有同名策略**。\n\n返回含 strategyId 与 localPath,请直接使用,不要再自行查询策略列表按名称猜测。",
51
51
  "inputSchema": {
52
52
  "type": "object",
53
53
  "properties": {
54
54
  "name": {
55
55
  "type": "string",
56
- "description": "策略名称。默认使用“模板名称+日期(YYMMDD)”生成,允许用户修改;调用本工具时必须传入最终确认后的名称。"
56
+ "description": "策略名称。默认使用“模板名称+日期时间(YYMMDD-HHMM)”生成唯一名称,允许用户修改;用户未指定名称时由 agent 直接生成,调用时传入该名称。"
57
57
  },
58
58
  "templateVal": {
59
59
  "type": "string",
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "templateItemVal": {
67
67
  "type": "string",
68
- "description": "用户选择的模板 val,来自 mcp-strategy-get-template-list 返回的模板条目。调用前必须让用户选择模板。"
68
+ "description": "用户选择或委托 agent 代选的模板 val,必须来自 mcp-strategy-get-template-list 实时返回的模板条目;不要编造或硬编码。用户明确指定的模板优先。"
69
69
  },
70
70
  "userId": {
71
71
  "type": "string",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zltquant/zlt-mcp",
3
- "version": "0.5.0-beta.0",
3
+ "version": "0.5.0-beta.1",
4
4
  "description": "智量通 ZLT Quant MCP server(Windows x64;量化策略创建与本地回测)",
5
5
  "bin": {
6
6
  "zlt-mcp": "./zlt-mcp-proxy.bundle.cjs"
@@ -23302,14 +23302,14 @@ function shapeToolResult(tool, args, result, session) {
23302
23302
  session.activeBacktestRunIds.delete(args.runId);
23303
23303
  }
23304
23304
  const echoed = echoResolvedBacktestConfig(tool, args, result, session.backtestRunContexts);
23305
- const guarded = applyBacktestResultGuards(
23305
+ const guarded = annotateBacktestOutcome(tool, applyBacktestResultGuards(
23306
23306
  tool,
23307
23307
  args,
23308
23308
  echoed,
23309
23309
  session.backtestPollStates,
23310
23310
  session.backtestRunContexts,
23311
23311
  session.activeBacktestRunIds
23312
- );
23312
+ ));
23313
23313
  const activeChange = classifyActiveBacktestChange(tool, args, guarded);
23314
23314
  if (activeChange) {
23315
23315
  if (activeChange.active) session.activeBacktestRunIds.add(activeChange.runId);
@@ -23323,6 +23323,38 @@ function shapeToolResult(tool, args, result, session) {
23323
23323
  const distilled = distillFactorDetectReport(tool, args, diagnosed);
23324
23324
  return injectDebugRunId(tool, injectStrategyDocsHint(tool, distilled, session.docsPath));
23325
23325
  }
23326
+ function backtestStatusNumber(status) {
23327
+ return typeof status === "number" || typeof status === "string" && status.trim() !== "" ? Number(status) : NaN;
23328
+ }
23329
+ function annotateBacktestOutcome(tool, result) {
23330
+ if (tool.name !== "mcp-get-backtest-state") return result;
23331
+ try {
23332
+ const parsed = JSON.parse(result.content[0]?.text ?? "");
23333
+ if (!isRecord2(parsed) || !isRecord2(parsed.Data)) return result;
23334
+ const data = parsed.Data;
23335
+ const status = backtestStatusNumber(data.status);
23336
+ const reconciled = parsed.ErrNo === 10043 && data.reconciledFrom === "result.json";
23337
+ const backtestOutcome = reconciled ? "failed" : status === 0 || status === 1 ? "running" : status === 2 ? "failed" : status === 3 ? "cancelled" : status === 4 ? "terminated" : status === 5 ? "completed" : "unknown";
23338
+ const isTerminal2 = backtestOutcome !== "running" && backtestOutcome !== "unknown";
23339
+ const message = typeof data.error_msg === "string" ? data.error_msg.trim() : "";
23340
+ return {
23341
+ ...result,
23342
+ content: [{ type: "text", text: JSON.stringify({
23343
+ ...parsed,
23344
+ Data: {
23345
+ ...data,
23346
+ backtestOutcome,
23347
+ isTerminal: isTerminal2,
23348
+ evidenceSource: reconciled ? "current-attempt-result.json" : "ipc-state",
23349
+ nextAction: isTerminal2 ? "finalize-backtest" : backtestOutcome === "unknown" || data.waitStopped || data.pollingStopped ? "inspect-backtest-state" : "keep-waiting",
23350
+ ...backtestOutcome === "failed" && !reconciled && (!message || /异常(?:退出|终止)|unexpected.*exit|exited unexpectedly/i.test(message)) ? { failureCause: "unknown" } : {}
23351
+ }
23352
+ }) }]
23353
+ };
23354
+ } catch {
23355
+ return result;
23356
+ }
23357
+ }
23326
23358
  var ZLTAF_CONFIG_SEGMENTS = ["zltaf", "application-local.properties"];
23327
23359
  var FALLBACK_FACTOR_PROJECT_PATH = ["Users", "factors"];
23328
23360
  var factorProjectRootCache = /* @__PURE__ */ new Map();
@@ -24404,11 +24436,11 @@ function unreadableDownloadProgressError(uuid2) {
24404
24436
  );
24405
24437
  }
24406
24438
  function unreadableBacktestStateError(runId) {
24407
- return waitError(
24439
+ return annotateBacktestOutcome(BACKTEST_WAIT_POLL_IDENTITY, waitError(
24408
24440
  10054,
24409
24441
  "\u56DE\u6D4B\u72B6\u6001\u5E94\u7B54\u65E0\u6CD5\u89E3\u6790\uFF0C\u5DF2\u505C\u6B62\u7B49\u5F85\uFF1B\u8BF7\u7528 mcp-get-backtest-state \u590D\u67E5\u3002",
24410
24442
  { runId }
24411
- );
24443
+ ));
24412
24444
  }
24413
24445
  function factorWaitLane(executionId, session) {
24414
24446
  let staleCount = 0;
@@ -24557,7 +24589,7 @@ function backtestWaitLane(runId, session, codePath, resultBaseline, attemptStart
24557
24589
  return { verdict: "return", result: unreadableBacktestStateError(runId) };
24558
24590
  }
24559
24591
  const data = parsed.Data;
24560
- const status = Number(data.status);
24592
+ const status = backtestStatusNumber(data.status);
24561
24593
  if (!Number.isFinite(status)) {
24562
24594
  return { verdict: "return", result: unreadableBacktestStateError(runId) };
24563
24595
  }
@@ -24598,7 +24630,10 @@ function backtestWaitLane(runId, session, codePath, resultBaseline, attemptStart
24598
24630
  frozenCount = signature === lastSignature ? frozenCount + 1 : 0;
24599
24631
  lastSignature = signature;
24600
24632
  if (frozenCount >= WAIT_FROZEN_THRESHOLD) {
24601
- return { verdict: "return", result: frozenBacktestResult(parsed, data) };
24633
+ return { verdict: "return", result: annotateBacktestOutcome(
24634
+ BACKTEST_WAIT_POLL_IDENTITY,
24635
+ frozenBacktestResult(parsed, data)
24636
+ ) };
24602
24637
  }
24603
24638
  const progress = typeof data.progress === "number" && Number.isFinite(data.progress) ? data.progress : 0;
24604
24639
  return { verdict: "wait", progress };
@@ -27669,6 +27704,10 @@ function compactCliReceipt(tool, result, resultFile) {
27669
27704
  "available",
27670
27705
  "runtimeReady",
27671
27706
  "backtestReady",
27707
+ "backtestOutcome",
27708
+ "isTerminal",
27709
+ "evidenceSource",
27710
+ "failureCause",
27672
27711
  "nextAction",
27673
27712
  "recommendedAction",
27674
27713
  "error_code",