oasis_test_v2 2.2.86 → 2.2.88

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.
Files changed (2) hide show
  1. package/dist/index.js +111 -64
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -141260,7 +141260,7 @@ ${m2.spec.split("\n").map((l) => ` > ${l}`).join("\n")}`);
141260
141260
  // 队列从 N 变 N+1、随后 conclude 撞 queue not quiescent(本文件「怎么提交」那段注释记的卡死形状)。
141261
141261
  ...args.action === "review" || integrating || queueTaskDue ? [] : [
141262
141262
  ``,
141263
- `### \u4EA4\u4ED8\u65F6\u7684\u975E\u963B\u585E\u4FE1\u606F`,
141263
+ `### \u4EA4\u4ED8\u65F6\u5199\u7ED9\u4E0B\u6E38\u7684\u6CE8\u610F\u4E8B\u9879`,
141264
141264
  `\u4E0B\u9762\u51E0\u9879\u662F\u4EA4\u4ED8\u547D\u4EE4\uFF08\`oasis propose\`\uFF09\u7684\u53C2\u6570\uFF0C\u76F4\u63A5\u52A0\u5728\u90A3\u6761\u547D\u4EE4\u540E\u9762\uFF0C\u548C \`--reason\` \u5199\u5728\u4E00\u8D77\uFF1B\`oasis conclude\` \u53EA\u6536 \`--note\`\uFF0C\u5199\u5728 conclude \u4E0A\u7684\u5176\u5B83\u53C2\u6570\u4E0D\u4F1A\u88AB\u8BB0\u5F55\u3002`,
141265
141265
  `\`--reason\` \u5199\u660E\u76F8\u5BF9\u4E0A\u4E00\u7248\u6539\u4E86\u4EC0\u4E48\u3001\u4E3A\u4EC0\u4E48\u3001\u53EF\u80FD\u5F71\u54CD\u4EC0\u4E48\uFF1B\u9996\u6B21\u7248\u672C\u8BF4\u660E\u672C\u7248\u5B8C\u6210\u601D\u8DEF\u548C\u5185\u5BB9\u3002`,
141266
141266
  `\u53EA\u6709\u5F53\u524D\u7248\u672C\u5DF2\u7ECF\u8FBE\u5230\u4EA4\u4ED8\u6807\u51C6\u65F6\uFF0C\u624D\u53EF\u4EE5\u8BB0\u5F55\uFF08\u6BCF\u9879\u53EF\u4EE5\u5199\u591A\u6761\uFF0C\u7528\u82F1\u6587\u5206\u53F7 \`;\` \u9694\u5F00\uFF1B\u4EE5\u4E0B\u67D0\u4E00\u9879\u5982\u679C\u6CA1\u6709\u5C31\u4E0D\u5199\uFF0C\u540C\u65F6\u8BE5\u53C2\u6570\u4E5F\u4E0D\u5199\uFF09\uFF1A`,
@@ -143302,9 +143302,12 @@ ${supplemental.taskAppend.trim()}
143302
143302
  bundle.files["TASK.md"] += [
143303
143303
  "",
143304
143304
  "## \u6267\u884C\u6062\u590D\uFF08\u4EC5\u5F53\u524D\u8282\u70B9\uFF09",
143305
- "\u672C\u8F6E\u662F\u540C\u4E00\u8282\u70B9\u4E0A\u4E00\u6B21 Attempt \u4E2D\u65AD\u540E\u7684\u7EE7\u7EED\u6267\u884C\u3002\u5F00\u5DE5\u524D\u5148\u8BFB `execution/RESUME.md`\uFF0C",
143306
- "\u6838\u5BF9\u6700\u65B0 Checkpoint\u3001\u5DF2\u5B8C\u6210\u6B65\u9AA4\u3001durable outputs\u3001ExternalEffects \u4E0E\u672A\u51B3\u6B65\u9AA4\uFF1B",
143307
- "\u4ECE\u5C1A\u672A\u5B8C\u6210\u7684\u90E8\u5206\u7EE7\u7EED\uFF0C\u907F\u514D\u91CD\u590D\u5DF2\u7ECF\u786E\u8BA4\u5B8C\u6210\u7684\u6B65\u9AA4\u6216\u5916\u90E8\u526F\u4F5C\u7528\u3002",
143305
+ // 2026-09-24(语菲定稿):进度记录可能比实际慢一步(K-04),换了执行机器时工作目录是新的、
143306
+ // 上一趟写的文件都不在(K-05 第三趟)——两种情况都以工作目录里实际有的文件为准。
143307
+ "\u672C\u8F6E\u662F\u540C\u4E00\u8282\u70B9\u4E0A\u4E00\u6B21\u6267\u884C\u4E2D\u65AD\u540E\u7684\u7EE7\u7EED\u3002\u5F00\u5DE5\u524D\u5148\u8BFB `execution/RESUME.md`\uFF0C\u91CC\u9762\u662F\u4E0A\u4E00\u6B21\u6700\u540E\u8BB0\u4E0B\u7684\u8FDB\u5EA6\uFF1B",
143308
+ "\u518D\u67E5\u770B\u5DE5\u4F5C\u76EE\u5F55\u91CC\u5B9E\u9645\u5DF2\u6709\u7684\u6587\u4EF6\uFF0C\u4EE5\u5B9E\u9645\u60C5\u51B5\u4E3A\u51C6\uFF1A",
143309
+ "- \u8FDB\u5EA6\u91CC\u8BF4\u5DF2\u7ECF\u5199\u597D\u7684\u6587\u4EF6\uFF0C\u5DE5\u4F5C\u76EE\u5F55\u91CC\u8FD8\u5728\u7684\uFF0C\u76F4\u63A5\u63A5\u7740\u7528\uFF1B",
143310
+ "- \u5DE5\u4F5C\u76EE\u5F55\u91CC\u6CA1\u6709\u7684\uFF08\u6BD4\u5982\u8FD9\u6B21\u6362\u4E86\u6267\u884C\u673A\u5668\uFF0C\u5DE5\u4F5C\u76EE\u5F55\u662F\u65B0\u7684\uFF09\uFF0C\u8981\u91CD\u65B0\u5199\u3002",
143308
143311
  "\u8FD9\u4EFD\u6062\u590D\u6750\u6599\u4E0D\u662F\u4E0A\u6E38\u8282\u70B9\u7684\u4E1A\u52A1\u4EA4\u63A5\uFF1B\u4E0A\u6E38\u4EA4\u63A5\u4ECD\u4EE5 `inputs/*/_HANDOFF.md` \u4E3A\u51C6\u3002",
143309
143312
  ""
143310
143313
  ].join("\n");
@@ -202844,7 +202847,7 @@ var init_service3 = __esm({
202844
202847
  }
202845
202848
  const actors = await this.options.resolveActors(companyId);
202846
202849
  const bindings = await actors.listBindings();
202847
- const reachability = async (actorId) => {
202850
+ const reachability = async (actorId, actorName) => {
202848
202851
  const primaryReason = await (async () => {
202849
202852
  const binding = bindings.find((b2) => b2.actorId === actorId && b2.status === "active");
202850
202853
  if (!binding) return "\u6CA1\u6709\u63A5\u8FD0\u884C\u65F6";
@@ -202854,9 +202857,15 @@ var init_service3 = __esm({
202854
202857
  })();
202855
202858
  if (primaryReason === null) return { ok: true };
202856
202859
  if (!this.options.probeAllocation) return { ok: false, reason: primaryReason };
202857
- const alt = await this.options.probeAllocation({ actorId, ...companyId ? { companyId } : {} }).catch(() => ({ reachable: true }));
202860
+ const alt = await this.options.probeAllocation({ actorId, actorName, ...companyId ? { companyId } : {} }).catch(() => ({ reachable: true }));
202858
202861
  if (alt.reachable) return { ok: true };
202859
- return { ok: false, reason: alt.reason ? `${alt.reason}\uFF08\u4E3B\u8FD0\u884C\u65F6\uFF1A${primaryReason}\uFF09` : primaryReason };
202862
+ return {
202863
+ ok: false,
202864
+ ...alt.reason ? { allocationReason: alt.reason } : {},
202865
+ // 短的那一格只放主运行时那一句。整句原因走 `allocationReason`,**不在这里再拼一遍**——
202866
+ // 两格都放会让同一段话在报错里出现两次(括号里一遍、「原因:」那行一遍)。
202867
+ reason: primaryReason
202868
+ };
202860
202869
  };
202861
202870
  if (target.startsWith("actor:")) {
202862
202871
  const actor = await actors.getActor(target);
@@ -202867,12 +202876,12 @@ var init_service3 = __esm({
202867
202876
  `\u7EC4\u7EC7\u91CC\u627E\u4E0D\u5230\u5728\u5C97\u7684 ${target}\u2014\u2014\u81EA\u5DF1\u505A\uFF0C\u5E76\u5728\u56DE\u590D\u91CC\u8BF4\u660E\u8FD9\u4E00\u6BB5\u662F\u4F60\u81EA\u5DF1\u505A\u7684\u3002`
202868
202877
  );
202869
202878
  }
202870
- const reach = await reachability(actor.id);
202879
+ const reach = await reachability(actor.id, actor.name);
202871
202880
  if (!reach.ok) {
202872
202881
  throw new DelegationError(
202873
202882
  409,
202874
202883
  "EXPERT_UNREACHABLE",
202875
- `${actor.name} \u73B0\u5728\u4E0D\u53EF\u7528\uFF08${reach.reason ?? "\u8FD0\u884C\u65F6\u4E0D\u53EF\u8FBE"}\uFF09\u2014\u2014\u81EA\u5DF1\u505A\uFF0C\u6216\u6362\u4E00\u4E2A\u5C97\u4F4D\u3002`,
202884
+ _DelegationService.unreachableText(actor.name, reach),
202876
202885
  { expertActorId: actor.id, expertName: actor.name }
202877
202886
  );
202878
202887
  }
@@ -202887,19 +202896,34 @@ var init_service3 = __esm({
202887
202896
  );
202888
202897
  }
202889
202898
  let lastReason;
202899
+ let lastAllocationReason;
202890
202900
  for (const candidate of candidates) {
202891
- const reach = await reachability(candidate.id);
202901
+ const reach = await reachability(candidate.id, candidate.name);
202892
202902
  if (reach.ok) return { actorId: candidate.id, name: candidate.name };
202893
202903
  lastReason = reach.reason ?? lastReason;
202904
+ lastAllocationReason = reach.allocationReason ?? lastAllocationReason;
202894
202905
  }
202895
202906
  const first = candidates[0];
202896
202907
  throw new DelegationError(
202897
202908
  409,
202898
202909
  "EXPERT_UNREACHABLE",
202899
- `\u300C${target}\u300D\u5C97\u4F4D\u4E0A\u7684\u540C\u4E8B\uFF08${candidates.map((a) => a.name).join("\u3001")}\uFF09\u73B0\u5728\u90FD\u4E0D\u53EF\u7528\uFF08${lastReason ?? "\u8FD0\u884C\u65F6\u4E0D\u53EF\u8FBE"}\uFF09\u2014\u2014\u81EA\u5DF1\u505A\uFF0C\u6216\u6362\u4E00\u4E2A\u5C97\u4F4D\u3002`,
202910
+ `\u300C${target}\u300D\u5C97\u4F4D\u4E0A\u7684\u540C\u4E8B\uFF08${candidates.map((a) => a.name).join("\u3001")}\uFF09\u73B0\u5728\u90FD\u4E0D\u53EF\u7528\uFF08${lastReason ?? "\u8FD0\u884C\u65F6\u4E0D\u53EF\u8FBE"}\uFF09\u2014\u2014\u81EA\u5DF1\u505A\uFF0C\u6216\u6362\u4E00\u4E2A\u5C97\u4F4D\u3002` + (lastAllocationReason ? `
202911
+ \u539F\u56E0\uFF1A${lastAllocationReason}` : ""),
202900
202912
  { expertActorId: first.id, expertName: first.name }
202901
202913
  );
202902
202914
  }
202915
+ /**
202916
+ * `EXPERT_UNREACHABLE` 那句话(ADR 0616)。**结论在前、原因在后**:读它的是 LLM,
202917
+ * 它读完第一行就要决定改走「自己干」那条路(§8.2)。
202918
+ *
202919
+ * 分配给出原因时把**那一整句原文**单起一行,不塞进括号里——它自己已经带了机器名、为什么
202920
+ * (已到并发上限 / 标记为故障 / 没有可用绑定)和下一步怎么办,再套一层括号就读不成句子了。
202921
+ */
202922
+ static unreachableText(name, reach) {
202923
+ const head = `${name} \u73B0\u5728\u4E0D\u53EF\u7528\uFF08${reach.reason ?? "\u8FD0\u884C\u65F6\u4E0D\u53EF\u8FBE"}\uFF09\u2014\u2014\u81EA\u5DF1\u505A\uFF0C\u6216\u6362\u4E00\u4E2A\u5C97\u4F4D\u3002`;
202924
+ return reach.allocationReason ? `${head}
202925
+ \u539F\u56E0\uFF1A${reach.allocationReason}` : head;
202926
+ }
202903
202927
  /**
202904
202928
  * 第 `attempt` 次尝试用的 label 候选(`desired`、`desired-2`、`desired-3`…)。
202905
202929
  *
@@ -203409,6 +203433,11 @@ var init_service3 = __esm({
203409
203433
  const settled = await store?.patch(record9.id, {
203410
203434
  state: "failed",
203411
203435
  failureKind: "not-started",
203436
+ /* ★ ADR 0616:**原因也要落台账**。上一版只把它写进子会话的占位行(= 用户在界面上看到的
203437
+ 那一句)和轮次账本的 `lastError`,台账上一个字都没有——于是 `--status` 与回流给主会话的
203438
+ 那条通告都只剩 `not-started`,派活的那一方(助理 agent)读不到「所有候选都到并发上限」
203439
+ 这种真原因,只能猜。2026-09-24 实测它猜成了「节点掉线」。 */
203440
+ failureReason: message2,
203412
203441
  settledSeq: record9.settledSeq + 1,
203413
203442
  consecutiveFails: record9.consecutiveFails + 1,
203414
203443
  settledAt: failedAt
@@ -203487,6 +203516,9 @@ var init_service3 = __esm({
203487
203516
  consecutiveFails,
203488
203517
  state: failureKind2 ? "failed" : "done",
203489
203518
  failureKind: failureKind2 ?? null,
203519
+ /* 这几档(跑起来过之后才失败 / 跑成了)的原因已经在本轮 `roundSummaries[].text` 里,
203520
+ 不在台账上再存一份;同时把上一轮 `not-started` 留下的原文清掉,免得读到的是过期原因。 */
203521
+ failureReason: null,
203490
203522
  settledSeq: settledSeqAtRound,
203491
203523
  settledAt: at2
203492
203524
  }).catch(() => null);
@@ -203557,6 +203589,8 @@ var init_service3 = __esm({
203557
203589
  // 退出帧丢失后被时钟闭合 = `interrupted`(§9),不是 `not-started`——它确实起来过。
203558
203590
  // run 报的是墙钟超时时归 `timeout`(Bug 0221):同样起来过,但「到点被停」与「断了」说法不同。
203559
203591
  failureKind: timedOut ? "timeout" : "interrupted",
203592
+ // 同 settleRound:这两档的原因在本轮摘要里,台账只清掉上一轮 not-started 的原文。
203593
+ failureReason: null,
203560
203594
  consecutiveFails: record9.consecutiveFails + 1,
203561
203595
  settledSeq: settledSeqAtRound,
203562
203596
  settledAt: at2
@@ -203672,6 +203706,7 @@ var init_service3 = __esm({
203672
203706
  const released = await store.patch(record9.id, {
203673
203707
  state: "running",
203674
203708
  failureKind: null,
203709
+ failureReason: null,
203675
203710
  settledAt: null,
203676
203711
  childRunId: null,
203677
203712
  // 换一把轮次账本业务键 + 释放派发所有权,否则新一轮会被上一轮的预约判成 `resumed` 而永远不派。
@@ -203682,6 +203717,7 @@ var init_service3 = __esm({
203682
203717
  const restore = () => store.patch(record9.id, {
203683
203718
  state: record9.state,
203684
203719
  failureKind: record9.failureKind ?? null,
203720
+ failureReason: record9.failureReason ?? null,
203685
203721
  settledAt: record9.settledAt ?? null,
203686
203722
  childRunId: record9.childRunId ?? null,
203687
203723
  dispatchedAt: record9.dispatchedAt ?? null
@@ -203878,6 +203914,7 @@ ${inboundBundle.paths.map((path47) => `- ${path47}`).join("\n")}` : text7,
203878
203914
  await store.patch(record9.id, {
203879
203915
  state: "running",
203880
203916
  failureKind: null,
203917
+ failureReason: null,
203881
203918
  settledAt: null,
203882
203919
  childRunId: null,
203883
203920
  // 释放派发所有权:这条追加要触发新的一轮,得让下一次 `claimDispatch` 抢得到。
@@ -203941,6 +203978,8 @@ ${inboundBundle.paths.map((path47) => `- ${path47}`).join("\n")}` : text7,
203941
203978
  ...expert?.name ? { expertName: expert.name } : {},
203942
203979
  state: record9.state,
203943
203980
  ...record9.failureKind ? { failureKind: record9.failureKind } : {},
203981
+ // ADR 0616:`--status` 要说得出「为什么没派出去」,不能只给一个 `not-started`。
203982
+ ...record9.failureReason ? { failureReason: record9.failureReason } : {},
203944
203983
  ...record9.label ? { label: record9.label } : {},
203945
203984
  ...record9.taskDigest ? { taskDigest: record9.taskDigest } : {},
203946
203985
  roundSummaries: record9.roundSummaries,
@@ -204536,6 +204575,7 @@ function delegationReturnText(terminal, opts) {
204536
204575
  head,
204537
204576
  `\u59D4\u6D3E id\uFF1A${record9.id.slice(0, 8)}\u3000label\uFF1A${record9.label ?? "\uFF08\u65E0\uFF09"}` + (record9.failureKind ? `\u3000\u7ED3\u675F\u539F\u56E0\uFF1A${record9.failureKind}` : "")
204538
204577
  ];
204578
+ if (record9.failureReason?.trim()) lines.push(`\u539F\u56E0\uFF1A${record9.failureReason.trim()}`);
204539
204579
  const trimmed = trimRoundSummariesForReturn(record9.roundSummaries, opts.recentRounds);
204540
204580
  if (trimmed.length > 0) {
204541
204581
  lines.push("", `\u4E13\u5BB6\u5404\u8F6E\u5C0F\u7ED3\uFF08\u5171 ${trimmed.length} \u8F6E\uFF1B\u6700\u8FD1 ${opts.recentRounds} \u8F6E\u7ED9\u5168\u6587\uFF0C\u66F4\u65E9\u7684\u53EA\u7559\u9996\u884C\uFF0C\u5168\u6587\u7528 \`oasis delegate --status\` \u770B\uFF09\uFF1A`);
@@ -246579,32 +246619,34 @@ var init_allocate = __esm({
246579
246619
  function describeRejections(rejections) {
246580
246620
  return rejections.map((r) => `${r.nodeName} \xB7 ${r.runtimeKind}\uFF08${CAUSE_TEXT[r.cause]}${r.detail ? `\uFF1A${r.detail}` : ""}\uFF09`).join("\uFF1B");
246581
246621
  }
246582
- function requireAllocation(result, who) {
246583
- if (result.ok) return result;
246622
+ function describeAllocationFailure(result, who) {
246584
246623
  const subject = who?.actorName?.trim() ? `\u300C${who.actorName.trim()}\u300D` : "\u8FD9\u4F4D Agent";
246585
246624
  const what = who?.what?.trim() ? `${who.what.trim()}\uFF1A` : "";
246586
246625
  const detail = describeRejections(result.rejections);
246587
246626
  if (result.reason === "no-candidates") {
246588
- throw new RuntimeAllocationError(
246589
- "RUNTIME_ALLOCATION_NO_CANDIDATES",
246590
- `${what}${subject}\u6CA1\u6709\u53EF\u7528\u7684\u8FD0\u884C\u65F6\u76EE\u6807\uFF1A\u65E2\u6CA1\u6709\u4E3B\u8FD0\u884C\u65F6\u7ED1\u5B9A\uFF0C\u4E5F\u6CA1\u6709\u914D\u7F6E\u5019\u9009\u8FD0\u884C\u65F6\u3002\u8BF7\u5728\u5458\u5DE5\u8BE6\u60C5\u9875\u7684\u300C\u9ED8\u8BA4\u8FD0\u884C\u914D\u7F6E\u300D\u91CC\u7ED1\u5B9A\u4E00\u4E2A\u8FD0\u884C\u65F6\uFF0C\u6216\u52A0\u4E00\u6761\u5019\u9009\u8FD0\u884C\u65F6\u3002`,
246591
- result.rejections
246592
- );
246627
+ return {
246628
+ code: "RUNTIME_ALLOCATION_NO_CANDIDATES",
246629
+ status: 409,
246630
+ message: `${what}${subject}\u6CA1\u6709\u53EF\u7528\u7684\u8FD0\u884C\u65F6\u76EE\u6807\uFF1A\u65E2\u6CA1\u6709\u4E3B\u8FD0\u884C\u65F6\u7ED1\u5B9A\uFF0C\u4E5F\u6CA1\u6709\u914D\u7F6E\u5019\u9009\u8FD0\u884C\u65F6\u3002\u8BF7\u5728\u5458\u5DE5\u8BE6\u60C5\u9875\u7684\u300C\u9ED8\u8BA4\u8FD0\u884C\u914D\u7F6E\u300D\u91CC\u7ED1\u5B9A\u4E00\u4E2A\u8FD0\u884C\u65F6\uFF0C\u6216\u52A0\u4E00\u6761\u5019\u9009\u8FD0\u884C\u65F6\u3002`
246631
+ };
246593
246632
  }
246594
246633
  if (result.reason === "all-at-capacity") {
246595
- throw new RuntimeAllocationError(
246596
- "RUNTIME_ALLOCATION_ALL_AT_CAPACITY",
246597
- `${what}${subject}\u7684\u8FD0\u884C\u65F6\u5168\u90E8\u5DF2\u5230\u5E76\u53D1\u4E0A\u9650\uFF0C\u672C\u6B21\u6CA1\u6709\u6D3E\u51FA\uFF1A${detail}\u3002\u8BF7\u7B49\u5F53\u524D\u4F1A\u8BDD\u8DD1\u5B8C\uFF0C\u6216\u5728\u8FD0\u884C\u65F6\u7BA1\u7406\u9875\u628A\u8FD9\u4E9B\u8282\u70B9\u7684\u5E76\u53D1\u4E0A\u9650\u8C03\u9AD8\u3002`,
246598
- result.rejections,
246599
- 503
246600
- );
246634
+ return {
246635
+ code: "RUNTIME_ALLOCATION_ALL_AT_CAPACITY",
246636
+ status: 503,
246637
+ message: `${what}${subject}\u7684\u8FD0\u884C\u65F6\u5168\u90E8\u5DF2\u5230\u5E76\u53D1\u4E0A\u9650\uFF0C\u672C\u6B21\u6CA1\u6709\u6D3E\u51FA\uFF1A${detail}\u3002\u8BF7\u7B49\u5F53\u524D\u4F1A\u8BDD\u8DD1\u5B8C\uFF0C\u6216\u5728\u8FD0\u884C\u65F6\u7BA1\u7406\u9875\u628A\u8FD9\u4E9B\u8282\u70B9\u7684\u5E76\u53D1\u4E0A\u9650\u8C03\u9AD8\u3002`
246638
+ };
246601
246639
  }
246602
- throw new RuntimeAllocationError(
246603
- "RUNTIME_ALLOCATION_ALL_UNAVAILABLE",
246604
- `${what}${subject}\u7684\u8FD0\u884C\u65F6\u76EE\u524D\u90FD\u4E0D\u53EF\u7528\uFF0C\u672C\u6B21\u6CA1\u6709\u6D3E\u51FA\uFF1A${detail}\u3002\u8BF7\u786E\u8BA4\u90A3\u4E9B\u673A\u5668\u5F00\u7740\u3001\u8282\u70B9\u7A0B\u5E8F\u5728\u8FD0\u884C\u3001\u8FD0\u884C\u65F6\u5DF2\u767B\u5F55\u4E14\u989D\u5EA6\u672A\u8017\u5C3D\uFF1B\u6216\u5728\u5458\u5DE5\u8BE6\u60C5\u9875\u52A0\u4E00\u6761\u522B\u7684\u5019\u9009\u8FD0\u884C\u65F6\u3002`,
246605
- result.rejections,
246606
- result.reason === "all-tried" ? 409 : 503
246607
- );
246640
+ return {
246641
+ code: "RUNTIME_ALLOCATION_ALL_UNAVAILABLE",
246642
+ status: result.reason === "all-tried" ? 409 : 503,
246643
+ message: `${what}${subject}\u7684\u8FD0\u884C\u65F6\u76EE\u524D\u90FD\u4E0D\u53EF\u7528\uFF0C\u672C\u6B21\u6CA1\u6709\u6D3E\u51FA\uFF1A${detail}\u3002\u8BF7\u786E\u8BA4\u90A3\u4E9B\u673A\u5668\u5F00\u7740\u3001\u8282\u70B9\u7A0B\u5E8F\u5728\u8FD0\u884C\u3001\u8FD0\u884C\u65F6\u5DF2\u767B\u5F55\u4E14\u989D\u5EA6\u672A\u8017\u5C3D\uFF1B\u6216\u5728\u5458\u5DE5\u8BE6\u60C5\u9875\u52A0\u4E00\u6761\u522B\u7684\u5019\u9009\u8FD0\u884C\u65F6\u3002`
246644
+ };
246645
+ }
246646
+ function requireAllocation(result, who) {
246647
+ if (result.ok) return result;
246648
+ const failure2 = describeAllocationFailure(result, who);
246649
+ throw new RuntimeAllocationError(failure2.code, failure2.message, result.rejections, failure2.status);
246608
246650
  }
246609
246651
  var RuntimeAllocationError, CAUSE_TEXT;
246610
246652
  var init_errors6 = __esm({
@@ -249352,8 +249394,10 @@ function executionContinuityDomain(service) {
249352
249394
  router.post("/api/execution-continuity/attempts/:id/checkpoints", async (req) => {
249353
249395
  const attemptId = resolveAttemptWriter(req, req.params.id);
249354
249396
  const b2 = req.body ?? {};
249397
+ if (b2.pendingSteps === void 0) b2.pendingSteps = [];
249398
+ if (b2.recoverability === void 0) b2.recoverability = "partial";
249355
249399
  if (!isStringArray(b2.pendingSteps) || !b2.recoverability || !["full", "partial", "none"].includes(b2.recoverability) || b2.durableRefs !== void 0 && !isRefArray(b2.durableRefs) || b2.completedStepIds !== void 0 && !isStringArray(b2.completedStepIds) || b2.trigger !== void 0 && !AGENT_CHECKPOINT_TRIGGERS.includes(b2.trigger)) {
249356
- throw new ApiError(400, "BAD_REQUEST", "\u7F3A\u5C11 pendingSteps \u6216 recoverability(full|partial|none)");
249400
+ throw new ApiError(400, "BAD_REQUEST", "pendingSteps \u987B\u4E3A\u5B57\u7B26\u4E32\u6570\u7EC4\uFF1Brecoverability \u53EA\u80FD\u662F full|partial|none");
249357
249401
  }
249358
249402
  const checkpoint = await service.checkpoint({
249359
249403
  attemptId,
@@ -249473,6 +249517,9 @@ function mergeContinuityRefs2(primary, extra) {
249473
249517
  }
249474
249518
  return out;
249475
249519
  }
249520
+ function stripRecoverability(text7) {
249521
+ return text7.replace(/\s*recoverability=\w+/g, "");
249522
+ }
249476
249523
  function renderResumePack(pack) {
249477
249524
  const lines = [
249478
249525
  "# ResumePack",
@@ -249486,7 +249533,7 @@ function renderResumePack(pack) {
249486
249533
  lines.push("", "## Previous attempt");
249487
249534
  if (!pack.previousAttempt) lines.push("- This is the first attempt.");
249488
249535
  else {
249489
- lines.push(`- Attempt ${pack.previousAttempt.attemptNo ?? "?"}: ${pack.previousHandoff?.summary || pack.previousAttempt.status}`);
249536
+ lines.push(`- Attempt ${pack.previousAttempt.attemptNo ?? "?"}: ${stripRecoverability(pack.previousHandoff?.summary || pack.previousAttempt.status)}`);
249490
249537
  const cp = pack.latestCheckpoint;
249491
249538
  const recoverySource = pack.recoverySourceAttempt ?? (cp ? pack.previousAttempt : null);
249492
249539
  if (cp && recoverySource && recoverySource.id !== pack.previousAttempt.id) {
@@ -249494,7 +249541,6 @@ function renderResumePack(pack) {
249494
249541
  }
249495
249542
  const done = cp?.completedStepIds ?? [];
249496
249543
  const durable = (cp?.durableRefs.length ? cp.durableRefs : pack.previousHandoff?.changedOutputs) ?? [];
249497
- if (cp) lines.push(`- Recoverability: ${cp.recoverability}`);
249498
249544
  if (done.length > 0) lines.push(`- \u4E0A\u4E00\u8D9F\u5DF2\u5B8C\u6210\u7684\u6B65\u9AA4\uFF1A${done.join("\u3001")}`);
249499
249545
  for (const ref2 of durable) {
249500
249546
  lines.push(` - durable: ${renderRefId(ref2)}${ref2.version ? `@${ref2.version}` : ""}${ref2.label ? ` \u2014 ${ref2.label}` : ""}`);
@@ -249507,20 +249553,6 @@ function renderResumePack(pack) {
249507
249553
  );
249508
249554
  }
249509
249555
  }
249510
- lines.push("", "## External effects");
249511
- const effectSummary = pack.externalEffectSummary;
249512
- if (effectSummary.total === 0) lines.push("- None recorded");
249513
- else {
249514
- const totals = effectSummary.totalByStatus;
249515
- const included = effectSummary.includedByStatus;
249516
- lines.push(
249517
- `- ${effectSummary.total} total; showing all ${included.pending} pending, latest ${included.succeeded} of ${totals.succeeded} succeeded, and latest ${included.failed} of ${totals.failed} retryable failed. Older records remain available through the history query.`
249518
- );
249519
- }
249520
- for (const effect of pack.externalEffects) {
249521
- const action = effect.status === "succeeded" ? "do not repeat" : effect.status === "pending" ? "execution uncertain; reconcile before retry" : "failed; retry allowed";
249522
- lines.push(`- [${effect.status}/${effect.source}] ${effect.kind} \u2192 ${effect.target} (${action}; key ${effect.idempotencyKey})`);
249523
- }
249524
249556
  const snapshot = Buffer.from(JSON.stringify(pack), "utf8").toString("base64url");
249525
249557
  lines.push("", `${RESUME_SNAPSHOT_PREFIX}${snapshot}${RESUME_SNAPSHOT_SUFFIX}`);
249526
249558
  return `${lines.join("\n")}
@@ -249643,6 +249675,9 @@ function renderCoordinatorView(view, taskBackground) {
249643
249675
  node2.nodeState === null ? "- Attempt: \u6267\u884C\u8D26\u672C\u4E2D\u65E0 attempt \u8BB0\u5F55" : `- Attempt: ${node2.status}; continuity: ${node2.nodeState}; number: ${node2.attemptNo || "none"}`,
249644
249676
  `- Actor: ${node2.actorId ?? "unassigned"}; role: ${node2.role ?? "unassigned"}`
249645
249677
  );
249678
+ if (node2.work.failureReason?.trim() && (node2.work.state === "failed" || node2.work.state === "dead" || node2.work.state === "retry")) {
249679
+ lines.push(`- Work failure reason: ${node2.work.failureReason.trim()}`);
249680
+ }
249646
249681
  if (node2.dependsOn.length > 0) lines.push(`- Depends on: ${node2.dependsOn.join(", ")}`);
249647
249682
  if (node2.conclusion?.trim()) {
249648
249683
  lines.push(node2.work.acceptedWorkId ? `- Conclusion (delivered ${node2.work.acceptedWorkId}): ${node2.conclusion.trim()}` : `- Conclusion: ${node2.conclusion.trim()}`);
@@ -249654,7 +249689,7 @@ function renderCoordinatorView(view, taskBackground) {
249654
249689
  );
249655
249690
  if (source.recoveryCheckpoint) {
249656
249691
  lines.push(
249657
- ` - Recovery checkpoint: #${source.recoveryCheckpoint.seq} (${source.recoveryCheckpoint.recoverability}) from Attempt ${source.recoveredFromAttempt.attemptNo ?? "?"}`
249692
+ ` - Recovery checkpoint: #${source.recoveryCheckpoint.seq} from Attempt ${source.recoveredFromAttempt.attemptNo ?? "?"}`
249658
249693
  );
249659
249694
  for (const step of source.recoveryCheckpoint.pendingSteps) lines.push(` - Recovery pending: ${step}`);
249660
249695
  }
@@ -249664,14 +249699,14 @@ function renderCoordinatorView(view, taskBackground) {
249664
249699
  lines.push(` - Recovery Agent handoff (${handoffFrom}): ${source.recoveryHandoff.summary}`);
249665
249700
  } else if (source.recoveryHandoff.producedBy === "system_reconstructed") {
249666
249701
  lines.push(
249667
- ` - Recovery system reconstruction (${handoffFrom}, not an Agent conclusion): ${source.recoveryHandoff.summary}`
249702
+ ` - Recovery system reconstruction (${handoffFrom}, not an Agent conclusion): ${stripRecoverability(source.recoveryHandoff.summary)}`
249668
249703
  );
249669
249704
  }
249670
249705
  }
249671
249706
  for (const risk of source.recoveryHandoff?.risks ?? []) lines.push(` - Recovery risk: ${risk}`);
249672
249707
  }
249673
249708
  if (node2.progress) {
249674
- lines.push(`- Latest checkpoint: ${node2.progress.recoverability} at ${node2.progress.lastCheckpointAt}`);
249709
+ lines.push(`- Latest checkpoint at ${node2.progress.lastCheckpointAt}`);
249675
249710
  for (const step of node2.progress.pendingSteps) lines.push(` - Pending: ${step}`);
249676
249711
  }
249677
249712
  if (node2.handoffProducer === "agent" && node2.summary.trim() && !sameCoordinatorText(node2.summary, node2.conclusion)) {
@@ -250454,10 +250489,12 @@ function nodeCoordinatorFactsFromSnapshot(snapshot) {
250454
250489
  for (const node2 of snapshot.nodes) {
250455
250490
  const currentWorkId = node2.latestWorkId ?? null;
250456
250491
  const currentWork = currentWorkId ? workById.get(currentWorkId) : void 0;
250492
+ const failureReason2 = typeof currentWork?.outcomeDetail?.["reason"] === "string" ? currentWork.outcomeDetail["reason"].trim() : "";
250457
250493
  const work = {
250458
250494
  currentWorkId,
250459
250495
  acceptedWorkId: node2.latestAcceptId ?? null,
250460
- state: currentWorkId === null ? "not_started" : currentWork ? workState(currentWork, hasOutput(currentWork, artifactCountByWork.get(currentWork.id) ?? 0)) : "unavailable"
250496
+ state: currentWorkId === null ? "not_started" : currentWork ? workState(currentWork, hasOutput(currentWork, artifactCountByWork.get(currentWork.id) ?? 0)) : "unavailable",
250497
+ ...failureReason2 ? { failureReason: failureReason2 } : {}
250461
250498
  };
250462
250499
  const accepted = node2.latestAcceptId ? workById.get(node2.latestAcceptId) : void 0;
250463
250500
  const conclusion = accepted?.conclusion?.trim();
@@ -268583,6 +268620,7 @@ function toRecord2(row) {
268583
268620
  expertActorId: row.expert_actor_id,
268584
268621
  state: row.state,
268585
268622
  ...row.failure_kind ? { failureKind: row.failure_kind } : {},
268623
+ ...row.failure_reason ? { failureReason: row.failure_reason } : {},
268586
268624
  ...row.child_run_id ? { childRunId: row.child_run_id } : {},
268587
268625
  ...row.invocation_id ? { invocationId: row.invocation_id } : {},
268588
268626
  ...row.label ? { label: row.label } : {},
@@ -268645,6 +268683,9 @@ var init_postgres_delegations = __esm({
268645
268683
  )`);
268646
268684
  for (const [col, type] of [
268647
268685
  ["failure_kind", "text"],
268686
+ // 这次失败的原因原文(ADR 0616)。存量行 NULL = 那次失败没留下原文(本列落地之前写的),
268687
+ // `--status` 与回流通告照旧只打 `failure_kind`,与改动前逐字相同。
268688
+ ["failure_reason", "text"],
268648
268689
  ["child_run_id", "text"],
268649
268690
  ["invocation_id", "text"],
268650
268691
  ["label", "text"],
@@ -268688,9 +268729,9 @@ var init_postgres_delegations = __esm({
268688
268729
  const inserted = await this.pool.query(
268689
268730
  `INSERT INTO ${this.s}.chat_session_delegations
268690
268731
  (id, parent_session_id, parent_message_id, child_session_id, expert_actor_id, state,
268691
- failure_kind, child_run_id, invocation_id, label, task_digest, round_summaries,
268732
+ failure_kind, failure_reason, child_run_id, invocation_id, label, task_digest, round_summaries,
268692
268733
  consecutive_fails, settled_seq, created_at, settled_at, dispatched_at, dispatch_seq)
268693
- VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12::jsonb,$13,$14,$15,$16,$17,$18)
268734
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13::jsonb,$14,$15,$16,$17,$18,$19)
268694
268735
  ON CONFLICT DO NOTHING
268695
268736
  RETURNING *`,
268696
268737
  [
@@ -268701,6 +268742,7 @@ var init_postgres_delegations = __esm({
268701
268742
  record9.expertActorId,
268702
268743
  record9.state,
268703
268744
  record9.failureKind ?? null,
268745
+ record9.failureReason ?? null,
268704
268746
  record9.childRunId ?? null,
268705
268747
  record9.invocationId ?? null,
268706
268748
  record9.label ?? null,
@@ -268781,6 +268823,7 @@ var init_postgres_delegations = __esm({
268781
268823
  };
268782
268824
  if (patch.state !== void 0) put3("state", patch.state);
268783
268825
  if (patch.failureKind !== void 0) put3("failure_kind", patch.failureKind);
268826
+ if (patch.failureReason !== void 0) put3("failure_reason", patch.failureReason);
268784
268827
  if (patch.childRunId !== void 0) put3("child_run_id", patch.childRunId);
268785
268828
  if (patch.label !== void 0) put3("label", patch.label);
268786
268829
  if (patch.roundSummaries !== void 0) put3("round_summaries", JSON.stringify(patch.roundSummaries), "::jsonb");
@@ -268942,6 +268985,7 @@ var init_postgres_delegations = __esm({
268942
268985
  if (otherPatch) {
268943
268986
  if (otherPatch.state !== void 0) put3("state", otherPatch.state);
268944
268987
  if (otherPatch.failureKind !== void 0) put3("failure_kind", otherPatch.failureKind);
268988
+ if (otherPatch.failureReason !== void 0) put3("failure_reason", otherPatch.failureReason);
268945
268989
  if (otherPatch.childRunId !== void 0) put3("child_run_id", otherPatch.childRunId);
268946
268990
  if (otherPatch.label !== void 0) put3("label", otherPatch.label);
268947
268991
  if (otherPatch.consecutiveFails !== void 0) put3("consecutive_fails", otherPatch.consecutiveFails);
@@ -278998,6 +279042,7 @@ __export(src_exports2, {
278998
279042
  deliverWorkorderBroadcast: () => deliverWorkorderBroadcast,
278999
279043
  deriveNodeHealth: () => deriveNodeHealth,
279000
279044
  describeAllocationChoice: () => describeAllocationChoice,
279045
+ describeAllocationFailure: () => describeAllocationFailure,
279001
279046
  describeAttachmentsForAppend: () => describeAttachmentsForAppend,
279002
279047
  describeNodeFault: () => describeNodeFault,
279003
279048
  describeRejections: () => describeRejections,
@@ -285664,13 +285709,13 @@ async function startServe(opts) {
285664
285709
  * 用 `tryAllocate`(不抛、不消耗重试次数):这里只是问「挑不挑得出来」,真正的分配在
285665
285710
  * 那一轮派发时再跑一次——两次之间机器状态可能变,以派发那一次为准。
285666
285711
  */
285667
- delegationProbeAllocation: async ({ actorId, companyId }) => {
285712
+ delegationProbeAllocation: async ({ actorId, actorName, companyId }) => {
285668
285713
  const result = await runtimeAllocatorFor(companyId ?? defaultCompanyId).tryAllocate({
285669
285714
  actorId,
285670
285715
  unitOfWork: `delegation-preflight:${actorId}`
285671
285716
  });
285672
285717
  if (result.ok) return { reachable: true };
285673
- return { reachable: false, reason: describeRejections(result.rejections) || "\u6CA1\u6709\u53EF\u7528\u7684\u8FD0\u884C\u65F6\u76EE\u6807" };
285718
+ return { reachable: false, reason: describeAllocationFailure(result, { actorName }).message };
285674
285719
  },
285675
285720
  // ADR 会话投递 D4:/api/chat 与渠道入站据它占同一个会话槽(自动化侧经 automations 域接同一实例)。
285676
285721
  chatTurns: chatTurnStore,
@@ -292957,16 +293002,16 @@ var COMMAND_DECLS = {
292957
293002
  },
292958
293003
  "continuity-checkpoint": {
292959
293004
  group: "\u56FE\u673A\u5236\uFF08\xA76/\xA77\uFF09",
292960
- usage: "oasis continuity-checkpoint --pending <list> --recoverability full|partial|none [--trigger plan_completed|stage_completed] [--refs <json-array>] [--completed <list>]",
293005
+ usage: "oasis continuity-checkpoint [--completed <list>] [--pending <list>] [--recoverability full|partial|none] [--trigger plan_completed|stage_completed] [--refs <json-array>]",
292961
293006
  description: "\u4E3A\u5F53\u524D\u6D3E\u53D1 attempt \u8FFD\u52A0\u53EF\u6062\u590D\u68C0\u67E5\u70B9\uFF08\u81EA\u52A8\u4FDD\u7559\u6700\u65B0\u4E94\u4E2A\uFF09\u3002",
292962
293007
  flags: [
292963
- { name: "pending", desc: `\u5F85\u5B8C\u6210\u6B65\u9AA4\u3002JSON \u6570\u7EC4 '["a","b"]' \u6216\u5206\u53F7\u5206\u9694 "a; b" \u90FD\u6536`, required: true },
292964
- { name: "recoverability", desc: "\u6062\u590D\u7A0B\u5EA6\uFF08full | partial | none\uFF09", required: true },
293008
+ { name: "pending", desc: '\u8FD8\u6CA1\u505A\u7684\u6B65\u9AA4\u3002\u5206\u53F7\u5206\u9694 "a; b" \u6216 JSON \u6570\u7EC4\u90FD\u6536\uFF1B\u4E0D\u5199\u6216\u5199\u7A7A = \u6CA1\u6709\u5269\u4F59' },
293009
+ { name: "recoverability", desc: "\u6062\u590D\u7A0B\u5EA6\uFF08full | partial | none\uFF09\uFF0C\u53EF\u9009\uFF1B\u4E0D\u5199\u6309 partial \u8BB0" },
292965
293010
  { name: "refs", desc: "\u5DF2\u6301\u4E45\u5316\u4EA7\u51FA\u5F15\u7528 JSON array" },
292966
- { name: "completed", desc: "\u5DF2\u5B8C\u6210\u7684\u7A33\u5B9A\u6B65\u9AA4 id\u3002JSON \u6570\u7EC4\u6216\u5206\u53F7\u5206\u9694\u90FD\u6536" },
293011
+ { name: "completed", desc: "\u5230\u73B0\u5728\u4E3A\u6B62\u786E\u5B9E\u505A\u5B8C\u7684\u6B65\u9AA4\u3002\u5206\u53F7\u5206\u9694\u6216 JSON \u6570\u7EC4\u90FD\u6536" },
292967
293012
  { name: "trigger", desc: "\u7ED3\u6784\u5316\u8FB9\u754C\uFF08plan_completed | stage_completed\uFF1B\u7701\u7565\u4E3A\u666E\u901A agent checkpoint\uFF09" }
292968
293013
  ],
292969
- examples: [`oasis continuity-checkpoint --pending '["run tests"]' --recoverability full --refs '[{"kind":"file","id":"src/x.ts"}]'`]
293014
+ examples: ['oasis continuity-checkpoint --completed "\u67E5\u5B8C\u5317\u4EAC\u3001\u4E0A\u6D77\u653F\u7B56\uFF0C\u7ED3\u8BBA\u8BB0\u5728 notes.md; \u5199\u597D deliverable/beijing.md" --pending "\u5199 deliverable/shanghai.md; \u5199\u603B\u7ED3.md"']
292970
293015
  },
292971
293016
  "continuity-effect": {
292972
293017
  group: "\u56FE\u673A\u5236\uFF08\xA76/\xA77\uFF09",
@@ -294810,7 +294855,7 @@ async function waitForCommandAuthorization(base, headers, draftId, fallback) {
294810
294855
  }
294811
294856
  }
294812
294857
  }
294813
- var CLI_VERSION = "2.2.86" ? "2.2.86" : "dev";
294858
+ var CLI_VERSION = "2.2.88" ? "2.2.88" : "dev";
294814
294859
  function apiHeaders(token, company) {
294815
294860
  const headers = {
294816
294861
  authorization: `Bearer ${token}`,
@@ -295500,6 +295545,7 @@ async function runCli(argv, println = console.log, progressln = console.error) {
295500
295545
  }
295501
295546
  println(`${detail.label ?? "(\u65E0\u77ED\u540D)"} ${detail.expertName ?? detail.expertActorId} ${detail.state}${detail.failureKind ? `/${detail.failureKind}` : ""}`);
295502
295547
  println(`id=${detail.id} \u5B50\u4F1A\u8BDD=${detail.childSessionId} \u5F85\u8F6C\u8FBE=${detail.pendingInputs} \u8FDE\u7EED\u5931\u8D25=${detail.consecutiveFails}`);
295548
+ if (detail.failureReason) println(`\u539F\u56E0\uFF1A${detail.failureReason}`);
295503
295549
  if (detail.taskDigest) println(`\u4EFB\u52A1\uFF1A${detail.taskDigest}`);
295504
295550
  for (const round of detail.roundSummaries) println(`
295505
295551
  \u7B2C ${round.round} \u8F6E\uFF08${round.at}\uFF09\uFF1A
@@ -295755,9 +295801,10 @@ Trace: ${run.traceRunId}`);
295755
295801
  break;
295756
295802
  }
295757
295803
  case "continuity-checkpoint": {
295804
+ const pendingRaw = flags.get("pending");
295758
295805
  const result = await api.post("/api/execution-continuity/attempts/current/checkpoints", {
295759
- pendingSteps: parseStringArrayFlag(need(flags, "pending"), "pending"),
295760
- recoverability: need(flags, "recoverability"),
295806
+ pendingSteps: pendingRaw === void 0 || pendingRaw.trim() === "" ? [] : parseStringArrayFlag(pendingRaw, "pending"),
295807
+ ...flags.has("recoverability") ? { recoverability: flags.get("recoverability") } : {},
295761
295808
  durableRefs: flags.has("refs") ? parseArrayFlag(flags.get("refs"), "refs") : [],
295762
295809
  completedStepIds: flags.has("completed") ? parseStringArrayFlag(flags.get("completed"), "completed") : [],
295763
295810
  ...flags.has("trigger") ? { trigger: flags.get("trigger") } : {}
@@ -298779,7 +298826,7 @@ function shimScript() {
298779
298826
  }
298780
298827
 
298781
298828
  // src/index.ts
298782
- var PKG_VERSION = true ? "2.2.86" : "dev";
298829
+ var PKG_VERSION = true ? "2.2.88" : "dev";
298783
298830
  var LOCAL_BIN = localBin();
298784
298831
  var NPM_PREFIX = npmPrefix();
298785
298832
  var INSTANCE = DEFAULT_INSTANCE;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test_v2",
3
- "version": "2.2.86",
3
+ "version": "2.2.88",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"
@@ -26,6 +26,6 @@
26
26
  "node": ">=20"
27
27
  },
28
28
  "oasisRelease": {
29
- "sourceHead": "b4a9ec478fa40119ad3a0360569d1a11af27336f"
29
+ "sourceHead": "1f98db00017415a0c5ddf248a1e5fe28aaa03acd"
30
30
  }
31
31
  }