ylib-syim 0.0.38 → 0.0.39

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/bridges/main.ts +93 -103
  2. package/package.json +1 -1
package/bridges/main.ts CHANGED
@@ -422,6 +422,9 @@ type RuntimeProbeEntry = {
422
422
  last_probe_at: string;
423
423
  ok: boolean | null;
424
424
  error: string | null;
425
+ error_source?: "probe_result" | "exception" | null;
426
+ recent_error_context?: string | null;
427
+ recent_error_context_source?: "bridge_log" | null;
425
428
  result: Record<string, unknown> | null;
426
429
  source: "probe" | "event";
427
430
  };
@@ -1127,10 +1130,7 @@ function finalizeOpenClawAccountSnapshotExport(params: {
1127
1130
  snapshot.connected = runtimeStatus.link_status === "connected";
1128
1131
  snapshot.restartPending = runtimeStatus.restart_pending === true;
1129
1132
  snapshot.reconnectAttempts = Number(runtimeStatus.reconnect_count || 0);
1130
- snapshot.lastError = pickMoreSpecificErrorMessage(
1131
- runtimeStatus.last_error || null,
1132
- snapshot.lastError || null,
1133
- );
1133
+ snapshot.lastError = runtimeStatus.last_error || null;
1134
1134
  }
1135
1135
  if (snapshot.audit == null && params.runtimeAudit?.audit !== undefined) {
1136
1136
  snapshot.audit = params.runtimeAudit.audit;
@@ -3706,10 +3706,7 @@ async function buildOpenClawCompatibleAccountSnapshot(params: {
3706
3706
  lastEventAt: parseRuntimeSnapshotTimeMs(
3707
3707
  runtimeEventLiveness?.last_event_at || runtimeStatus?.last_event_at || null,
3708
3708
  ),
3709
- lastError: pickMoreSpecificErrorMessage(
3710
- runtimeStatus?.last_error || null,
3711
- runtimeDiagnostic?.last_error || null,
3712
- ),
3709
+ lastError: runtimeStatus?.last_error || null,
3713
3710
  lastStartAt: parseRuntimeSnapshotTimeMs(runtimeStatus?.started_at),
3714
3711
  lastStopAt:
3715
3712
  running === false
@@ -3975,24 +3972,6 @@ function isGenericRuntimeErrorMessage(
3975
3972
  return false;
3976
3973
  }
3977
3974
 
3978
- // pickMoreSpecificErrorMessage: 运行时辅助函数。
3979
- function pickMoreSpecificErrorMessage(
3980
- previous: string | null | undefined,
3981
- incoming: string | null | undefined,
3982
- ): string | null {
3983
- // 当新旧错误冲突时,优先保留更具体、更有排障价值的错误。
3984
- const prev = String(previous || "").trim();
3985
- const next = String(incoming || "").trim();
3986
- if (!next) return prev || null;
3987
- if (!prev) return next;
3988
- const prevGeneric = isGenericRuntimeErrorMessage(prev);
3989
- const nextGeneric = isGenericRuntimeErrorMessage(next);
3990
- if (!prevGeneric && nextGeneric) return prev;
3991
- if (prevGeneric && !nextGeneric) return next;
3992
- if (!prevGeneric && !nextGeneric && prev.length > next.length) return prev;
3993
- return next;
3994
- }
3995
-
3996
3975
  // stringifyErrorPayload: 运行时辅助函数。
3997
3976
  function stringifyErrorPayload(value: unknown): string {
3998
3977
  // 统一错误对象序列化,避免日志/接口输出不一致。
@@ -4059,6 +4038,27 @@ function toLogText(value: unknown, limit = 1500): string {
4059
4038
  }
4060
4039
  }
4061
4040
 
4041
+ // toSingleLineLogText: 运行时辅助函数。
4042
+ function toSingleLineLogText(value: unknown, limit = 1500): string {
4043
+ return toLogText(value, limit).replace(/\r?\n/g, "\\n");
4044
+ }
4045
+
4046
+ function formatRecentErrorContextLogHint(
4047
+ platform: "dingtalk" | "feishu" | "weixin",
4048
+ accountId: string,
4049
+ recentErrorContext: string | null,
4050
+ ): string {
4051
+ if (!recentErrorContext) return "recent_error_context_present=0";
4052
+ return [
4053
+ "recent_error_context_present=1",
4054
+ `context_lookup_hint=search_previous_lines_in_this_log platform=${platform}`,
4055
+ `account=${accountId}`,
4056
+ "keywords=error|失败|异常|status_code",
4057
+ "exclude=derived_error|status_error|recent_error_context",
4058
+ `中文提示=存在额外排障上下文,请在当前日志文件中向前查找同平台(${platform})、同账号(${accountId})、包含error/失败/异常/status_code的日志行,并排除derived_error/status_error/recent_error_context/context_lookup_hint行`,
4059
+ ].join(" ");
4060
+ }
4061
+
4062
4062
  // readRecentBridgeErrorFromLog: 读取并解析运行时数据。
4063
4063
  function readRecentBridgeErrorFromLog(
4064
4064
  accountId: string,
@@ -4086,6 +4086,16 @@ function readRecentBridgeErrorFromLog(
4086
4086
 
4087
4087
  for (const line of lines) {
4088
4088
  const lower = line.toLowerCase();
4089
+ if (
4090
+ lower.includes("recent_error_context=") ||
4091
+ lower.includes("context_lookup_hint=") ||
4092
+ lower.includes(" probeaccount derived_error ") ||
4093
+ lower.includes(" probe derived_error ") ||
4094
+ lower.includes(" probeaccount status_error ") ||
4095
+ lower.includes(" probe status_error ")
4096
+ ) {
4097
+ continue;
4098
+ }
4089
4099
  const hasPlatform = platformHints.some((hint) =>
4090
4100
  lower.includes(hint.toLowerCase()),
4091
4101
  );
@@ -4106,11 +4116,13 @@ function readRecentBridgeErrorFromLog(
4106
4116
  }
4107
4117
  const trimmed = line.trim();
4108
4118
  if (!trimmed) continue;
4109
- matched.push(trimmed);
4119
+ matched.push(
4120
+ trimmed.replace(/^\[[^\]]+\] \[[^\]]+\] /, "").replace(/\r?\n/g, "\\n"),
4121
+ );
4110
4122
  if (matched.length >= runtimeErrorLogFallbackLines) break;
4111
4123
  }
4112
4124
  if (matched.length > 0) {
4113
- return matched.join("\n").slice(0, 1600);
4125
+ return matched.join(" | ").slice(0, 1600);
4114
4126
  }
4115
4127
  } catch {}
4116
4128
  return null;
@@ -5626,31 +5638,21 @@ async function runFullProbeAndRefreshStatuses(params: {
5626
5638
  const probeError = buildDetailedProbeErrorMessage(
5627
5639
  probeResult as Record<string, unknown>,
5628
5640
  );
5629
- const probeErrorWithLogFallback = isGenericRuntimeErrorMessage(
5630
- probeError,
5631
- )
5632
- ? pickMoreSpecificErrorMessage(
5633
- probeError,
5634
- readRecentBridgeErrorFromLog(accountId, "dingtalk"),
5635
- )
5636
- : probeError;
5641
+ const recentErrorContext = isGenericRuntimeErrorMessage(probeError)
5642
+ ? readRecentBridgeErrorFromLog(accountId, "dingtalk")
5643
+ : null;
5637
5644
  if (!ok) {
5638
5645
  console.error(
5639
5646
  `[bridges/main] dingtalk probeAccount failed account=${accountId} raw=${toLogText(probeResult)}`,
5640
5647
  );
5641
5648
  console.error(
5642
- `[bridges/main] dingtalk probeAccount derived_error account=${accountId} error=${toLogText(probeErrorWithLogFallback || "")}`,
5649
+ `[bridges/main] dingtalk probeAccount derived_error account=${accountId} error=${toSingleLineLogText(probeError || "")} ${formatRecentErrorContextLogHint("dingtalk", accountId, recentErrorContext)}`,
5643
5650
  );
5644
5651
  }
5645
- const error = ok
5646
- ? null
5647
- : pickMoreSpecificErrorMessage(
5648
- previous?.last_error || null,
5649
- probeErrorWithLogFallback,
5650
- );
5652
+ const error = ok ? null : probeError;
5651
5653
  if (!ok) {
5652
5654
  console.error(
5653
- `[bridges/main] dingtalk probeAccount merged_error account=${accountId} error=${toLogText(error || "")}`,
5655
+ `[bridges/main] dingtalk probeAccount status_error account=${accountId} error=${toSingleLineLogText(error || "")}`,
5654
5656
  );
5655
5657
  }
5656
5658
  const probeAt = nowIso();
@@ -5661,6 +5663,10 @@ async function runFullProbeAndRefreshStatuses(params: {
5661
5663
  last_probe_at: toChina8Iso(probeAt),
5662
5664
  ok,
5663
5665
  error,
5666
+ error_source: ok ? null : "probe_result",
5667
+ recent_error_context: ok ? null : recentErrorContext,
5668
+ recent_error_context_source:
5669
+ !ok && recentErrorContext ? "bridge_log" : null,
5664
5670
  result: (probeResult as Record<string, unknown>) || null,
5665
5671
  source: "probe",
5666
5672
  });
@@ -5697,16 +5703,16 @@ async function runFullProbeAndRefreshStatuses(params: {
5697
5703
  });
5698
5704
  } catch (err) {
5699
5705
  const probeAt = nowIso();
5700
- const probeError = pickMoreSpecificErrorMessage(
5701
- previous?.last_error || null,
5702
- (err as Error).message,
5703
- );
5706
+ const probeError = String((err as Error).message || "").trim() || null;
5704
5707
  upsertRuntimeProbe({
5705
5708
  platform: "dingtalk",
5706
5709
  bot_account_id: accountId,
5707
5710
  last_probe_at: toChina8Iso(probeAt),
5708
5711
  ok: false,
5709
5712
  error: probeError,
5713
+ error_source: "exception",
5714
+ recent_error_context: null,
5715
+ recent_error_context_source: null,
5710
5716
  result: null,
5711
5717
  source: "probe",
5712
5718
  });
@@ -5762,28 +5768,18 @@ async function runFullProbeAndRefreshStatuses(params: {
5762
5768
  const probeError = buildDetailedProbeErrorMessage(
5763
5769
  probeResult as Record<string, unknown>,
5764
5770
  );
5765
- const probeErrorWithLogFallback = isGenericRuntimeErrorMessage(
5766
- probeError,
5767
- )
5768
- ? pickMoreSpecificErrorMessage(
5769
- probeError,
5770
- readRecentBridgeErrorFromLog(accountId, "dingtalk"),
5771
- )
5772
- : probeError;
5771
+ const recentErrorContext = isGenericRuntimeErrorMessage(probeError)
5772
+ ? readRecentBridgeErrorFromLog(accountId, "dingtalk")
5773
+ : null;
5773
5774
  if (!ok) {
5774
5775
  console.error(
5775
- `[bridges/main] dingtalk probe derived_error account=${accountId} error=${toLogText(probeErrorWithLogFallback || "")}`,
5776
+ `[bridges/main] dingtalk probe derived_error account=${accountId} error=${toSingleLineLogText(probeError || "")} ${formatRecentErrorContextLogHint("dingtalk", accountId, recentErrorContext)}`,
5776
5777
  );
5777
5778
  }
5778
- const error = ok
5779
- ? null
5780
- : pickMoreSpecificErrorMessage(
5781
- previous?.last_error || null,
5782
- probeErrorWithLogFallback,
5783
- );
5779
+ const error = ok ? null : probeError;
5784
5780
  if (!ok) {
5785
5781
  console.error(
5786
- `[bridges/main] dingtalk probe merged_error account=${accountId} error=${toLogText(error || "")}`,
5782
+ `[bridges/main] dingtalk probe status_error account=${accountId} error=${toSingleLineLogText(error || "")}`,
5787
5783
  );
5788
5784
  }
5789
5785
  const probeAt = nowIso();
@@ -5794,6 +5790,10 @@ async function runFullProbeAndRefreshStatuses(params: {
5794
5790
  last_probe_at: toChina8Iso(probeAt),
5795
5791
  ok,
5796
5792
  error,
5793
+ error_source: ok ? null : "probe_result",
5794
+ recent_error_context: ok ? null : recentErrorContext,
5795
+ recent_error_context_source:
5796
+ !ok && recentErrorContext ? "bridge_log" : null,
5797
5797
  result: (probeResult as Record<string, unknown>) || null,
5798
5798
  source: "probe",
5799
5799
  });
@@ -5834,16 +5834,16 @@ async function runFullProbeAndRefreshStatuses(params: {
5834
5834
  });
5835
5835
  } catch (err) {
5836
5836
  const probeAt = nowIso();
5837
- const probeError = pickMoreSpecificErrorMessage(
5838
- previous?.last_error || null,
5839
- (err as Error).message,
5840
- );
5837
+ const probeError = String((err as Error).message || "").trim() || null;
5841
5838
  upsertRuntimeProbe({
5842
5839
  platform: "dingtalk",
5843
5840
  bot_account_id: accountId,
5844
5841
  last_probe_at: toChina8Iso(probeAt),
5845
5842
  ok: false,
5846
5843
  error: probeError,
5844
+ error_source: "exception",
5845
+ recent_error_context: null,
5846
+ recent_error_context_source: null,
5847
5847
  result: null,
5848
5848
  source: "probe",
5849
5849
  });
@@ -5957,23 +5957,12 @@ async function runFullProbeAndRefreshStatuses(params: {
5957
5957
  const probeError = buildDetailedProbeErrorMessage(
5958
5958
  probeResult as Record<string, unknown>,
5959
5959
  );
5960
- const probeErrorWithLogFallback = isGenericRuntimeErrorMessage(
5961
- probeError,
5962
- )
5963
- ? pickMoreSpecificErrorMessage(
5964
- probeError,
5965
- readRecentBridgeErrorFromLog(accountId, "feishu"),
5966
- )
5967
- : probeError;
5960
+ const recentErrorContext = isGenericRuntimeErrorMessage(probeError)
5961
+ ? readRecentBridgeErrorFromLog(accountId, "feishu")
5962
+ : null;
5968
5963
  const nextStatus: RuntimeBotStatus["link_status"] =
5969
5964
  ok ? "connected" : "error";
5970
- const nextError =
5971
- nextStatus === "connected"
5972
- ? null
5973
- : pickMoreSpecificErrorMessage(
5974
- previous?.last_error || null,
5975
- probeErrorWithLogFallback,
5976
- );
5965
+ const nextError = nextStatus === "connected" ? null : probeError;
5977
5966
  const probeAt = nowIso();
5978
5967
  const runtimeHints = extractRuntimeStatusHints(probeResult);
5979
5968
  upsertRuntimeProbe({
@@ -5982,6 +5971,10 @@ async function runFullProbeAndRefreshStatuses(params: {
5982
5971
  last_probe_at: toChina8Iso(probeAt),
5983
5972
  ok,
5984
5973
  error: nextError,
5974
+ error_source: ok ? null : "probe_result",
5975
+ recent_error_context: ok ? null : recentErrorContext,
5976
+ recent_error_context_source:
5977
+ !ok && recentErrorContext ? "bridge_log" : null,
5985
5978
  result: (probeResult as Record<string, unknown>) || null,
5986
5979
  source: "probe",
5987
5980
  });
@@ -6026,6 +6019,9 @@ async function runFullProbeAndRefreshStatuses(params: {
6026
6019
  last_probe_at: toChina8Iso(probeAt),
6027
6020
  ok: false,
6028
6021
  error: probeError || null,
6022
+ error_source: "exception",
6023
+ recent_error_context: null,
6024
+ recent_error_context_source: null,
6029
6025
  result: null,
6030
6026
  source: "probe",
6031
6027
  });
@@ -6129,31 +6125,21 @@ async function runFullProbeAndRefreshStatuses(params: {
6129
6125
  const probeError = buildDetailedProbeErrorMessage(
6130
6126
  probeResult as Record<string, unknown>,
6131
6127
  );
6132
- const probeErrorWithLogFallback = isGenericRuntimeErrorMessage(
6133
- probeError,
6134
- )
6135
- ? pickMoreSpecificErrorMessage(
6136
- probeError,
6137
- readRecentBridgeErrorFromLog(accountId, "weixin"),
6138
- )
6139
- : probeError;
6128
+ const recentErrorContext = isGenericRuntimeErrorMessage(probeError)
6129
+ ? readRecentBridgeErrorFromLog(accountId, "weixin")
6130
+ : null;
6140
6131
  if (!ok) {
6141
6132
  console.error(
6142
6133
  `[bridges/main] weixin probeAccount failed account=${accountId} raw=${toLogText(probeResult)}`,
6143
6134
  );
6144
6135
  console.error(
6145
- `[bridges/main] weixin probeAccount derived_error account=${accountId} error=${toLogText(probeErrorWithLogFallback || "")}`,
6136
+ `[bridges/main] weixin probeAccount derived_error account=${accountId} error=${toSingleLineLogText(probeError || "")} ${formatRecentErrorContextLogHint("weixin", accountId, recentErrorContext)}`,
6146
6137
  );
6147
6138
  }
6148
- const error = ok
6149
- ? null
6150
- : pickMoreSpecificErrorMessage(
6151
- previous?.last_error || null,
6152
- probeErrorWithLogFallback,
6153
- );
6139
+ const error = ok ? null : probeError;
6154
6140
  if (!ok) {
6155
6141
  console.error(
6156
- `[bridges/main] weixin probeAccount merged_error account=${accountId} error=${toLogText(error || "")}`,
6142
+ `[bridges/main] weixin probeAccount status_error account=${accountId} error=${toSingleLineLogText(error || "")}`,
6157
6143
  );
6158
6144
  }
6159
6145
  const probeAt = nowIso();
@@ -6164,6 +6150,10 @@ async function runFullProbeAndRefreshStatuses(params: {
6164
6150
  last_probe_at: toChina8Iso(probeAt),
6165
6151
  ok,
6166
6152
  error,
6153
+ error_source: ok ? null : "probe_result",
6154
+ recent_error_context: ok ? null : recentErrorContext,
6155
+ recent_error_context_source:
6156
+ !ok && recentErrorContext ? "bridge_log" : null,
6167
6157
  result: (probeResult as Record<string, unknown>) || null,
6168
6158
  source: "probe",
6169
6159
  });
@@ -6200,16 +6190,16 @@ async function runFullProbeAndRefreshStatuses(params: {
6200
6190
  });
6201
6191
  } catch (err) {
6202
6192
  const probeAt = nowIso();
6203
- const probeError = pickMoreSpecificErrorMessage(
6204
- previous?.last_error || null,
6205
- (err as Error).message,
6206
- );
6193
+ const probeError = String((err as Error).message || "").trim() || null;
6207
6194
  upsertRuntimeProbe({
6208
6195
  platform: "weixin",
6209
6196
  bot_account_id: accountId,
6210
6197
  last_probe_at: toChina8Iso(probeAt),
6211
6198
  ok: false,
6212
6199
  error: probeError,
6200
+ error_source: "exception",
6201
+ recent_error_context: null,
6202
+ recent_error_context_source: null,
6213
6203
  result: null,
6214
6204
  source: "probe",
6215
6205
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ylib-syim",
3
- "version": "0.0.38",
3
+ "version": "0.0.39",
4
4
  "description": "多 IM / 多 Agent 的会话路由与上下文管理(支持 /new)",
5
5
  "type": "module",
6
6
  "exports": {