ylib-syim 0.0.38 → 0.0.40

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 +97 -114
  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
+ "match=error_level_same_platform_same_account",
4057
+ "exclude=derived_error|status_error|recent_error_context",
4058
+ `中文提示=存在额外排障上下文,请在当前日志文件中向前查找同平台(${platform})、同账号(${accountId})、error级别的日志行,并排除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,23 @@ function readRecentBridgeErrorFromLog(
4086
4086
 
4087
4087
  for (const line of lines) {
4088
4088
  const lower = line.toLowerCase();
4089
+ const trimmed = line.trim();
4090
+ if (!trimmed) continue;
4091
+ if (!/^\[[^\]]+\] \[error\] /.test(trimmed)) continue;
4092
+ const content = trimmed.replace(/^\[[^\]]+\] \[[^\]]+\] /, "");
4093
+ const contentLower = content.toLowerCase();
4094
+ if (
4095
+ contentLower.includes("recent_error_context=") ||
4096
+ contentLower.includes("context_lookup_hint=") ||
4097
+ contentLower.includes(" probeaccount derived_error ") ||
4098
+ contentLower.includes(" probe derived_error ") ||
4099
+ contentLower.includes(" probeaccount status_error ") ||
4100
+ contentLower.includes(" probe status_error ") ||
4101
+ contentLower.includes(" probeaccount merged_error ") ||
4102
+ contentLower.includes(" probe merged_error ")
4103
+ ) {
4104
+ continue;
4105
+ }
4089
4106
  const hasPlatform = platformHints.some((hint) =>
4090
4107
  lower.includes(hint.toLowerCase()),
4091
4108
  );
@@ -4094,19 +4111,7 @@ function readRecentBridgeErrorFromLog(
4094
4111
  lower.includes(String(accountId || "").toLowerCase()) ||
4095
4112
  accountId === "__default__";
4096
4113
  if (!hasAccount) continue;
4097
- if (
4098
- !(
4099
- lower.includes("error") ||
4100
- lower.includes("失败") ||
4101
- lower.includes("异常") ||
4102
- lower.includes("status code")
4103
- )
4104
- ) {
4105
- continue;
4106
- }
4107
- const trimmed = line.trim();
4108
- if (!trimmed) continue;
4109
- matched.push(trimmed);
4114
+ matched.push(content.replace(/\r?\n/g, "\\n"));
4110
4115
  if (matched.length >= runtimeErrorLogFallbackLines) break;
4111
4116
  }
4112
4117
  if (matched.length > 0) {
@@ -5626,31 +5631,21 @@ async function runFullProbeAndRefreshStatuses(params: {
5626
5631
  const probeError = buildDetailedProbeErrorMessage(
5627
5632
  probeResult as Record<string, unknown>,
5628
5633
  );
5629
- const probeErrorWithLogFallback = isGenericRuntimeErrorMessage(
5630
- probeError,
5631
- )
5632
- ? pickMoreSpecificErrorMessage(
5633
- probeError,
5634
- readRecentBridgeErrorFromLog(accountId, "dingtalk"),
5635
- )
5636
- : probeError;
5634
+ const recentErrorContext = isGenericRuntimeErrorMessage(probeError)
5635
+ ? readRecentBridgeErrorFromLog(accountId, "dingtalk")
5636
+ : null;
5637
5637
  if (!ok) {
5638
5638
  console.error(
5639
5639
  `[bridges/main] dingtalk probeAccount failed account=${accountId} raw=${toLogText(probeResult)}`,
5640
5640
  );
5641
5641
  console.error(
5642
- `[bridges/main] dingtalk probeAccount derived_error account=${accountId} error=${toLogText(probeErrorWithLogFallback || "")}`,
5642
+ `[bridges/main] dingtalk probeAccount derived_error account=${accountId} error=${toSingleLineLogText(probeError || "")} ${formatRecentErrorContextLogHint("dingtalk", accountId, recentErrorContext)}`,
5643
5643
  );
5644
5644
  }
5645
- const error = ok
5646
- ? null
5647
- : pickMoreSpecificErrorMessage(
5648
- previous?.last_error || null,
5649
- probeErrorWithLogFallback,
5650
- );
5645
+ const error = ok ? null : probeError;
5651
5646
  if (!ok) {
5652
5647
  console.error(
5653
- `[bridges/main] dingtalk probeAccount merged_error account=${accountId} error=${toLogText(error || "")}`,
5648
+ `[bridges/main] dingtalk probeAccount status_error account=${accountId} error=${toSingleLineLogText(error || "")}`,
5654
5649
  );
5655
5650
  }
5656
5651
  const probeAt = nowIso();
@@ -5661,6 +5656,10 @@ async function runFullProbeAndRefreshStatuses(params: {
5661
5656
  last_probe_at: toChina8Iso(probeAt),
5662
5657
  ok,
5663
5658
  error,
5659
+ error_source: ok ? null : "probe_result",
5660
+ recent_error_context: ok ? null : recentErrorContext,
5661
+ recent_error_context_source:
5662
+ !ok && recentErrorContext ? "bridge_log" : null,
5664
5663
  result: (probeResult as Record<string, unknown>) || null,
5665
5664
  source: "probe",
5666
5665
  });
@@ -5697,16 +5696,16 @@ async function runFullProbeAndRefreshStatuses(params: {
5697
5696
  });
5698
5697
  } catch (err) {
5699
5698
  const probeAt = nowIso();
5700
- const probeError = pickMoreSpecificErrorMessage(
5701
- previous?.last_error || null,
5702
- (err as Error).message,
5703
- );
5699
+ const probeError = String((err as Error).message || "").trim() || null;
5704
5700
  upsertRuntimeProbe({
5705
5701
  platform: "dingtalk",
5706
5702
  bot_account_id: accountId,
5707
5703
  last_probe_at: toChina8Iso(probeAt),
5708
5704
  ok: false,
5709
5705
  error: probeError,
5706
+ error_source: "exception",
5707
+ recent_error_context: null,
5708
+ recent_error_context_source: null,
5710
5709
  result: null,
5711
5710
  source: "probe",
5712
5711
  });
@@ -5762,28 +5761,18 @@ async function runFullProbeAndRefreshStatuses(params: {
5762
5761
  const probeError = buildDetailedProbeErrorMessage(
5763
5762
  probeResult as Record<string, unknown>,
5764
5763
  );
5765
- const probeErrorWithLogFallback = isGenericRuntimeErrorMessage(
5766
- probeError,
5767
- )
5768
- ? pickMoreSpecificErrorMessage(
5769
- probeError,
5770
- readRecentBridgeErrorFromLog(accountId, "dingtalk"),
5771
- )
5772
- : probeError;
5764
+ const recentErrorContext = isGenericRuntimeErrorMessage(probeError)
5765
+ ? readRecentBridgeErrorFromLog(accountId, "dingtalk")
5766
+ : null;
5773
5767
  if (!ok) {
5774
5768
  console.error(
5775
- `[bridges/main] dingtalk probe derived_error account=${accountId} error=${toLogText(probeErrorWithLogFallback || "")}`,
5769
+ `[bridges/main] dingtalk probe derived_error account=${accountId} error=${toSingleLineLogText(probeError || "")} ${formatRecentErrorContextLogHint("dingtalk", accountId, recentErrorContext)}`,
5776
5770
  );
5777
5771
  }
5778
- const error = ok
5779
- ? null
5780
- : pickMoreSpecificErrorMessage(
5781
- previous?.last_error || null,
5782
- probeErrorWithLogFallback,
5783
- );
5772
+ const error = ok ? null : probeError;
5784
5773
  if (!ok) {
5785
5774
  console.error(
5786
- `[bridges/main] dingtalk probe merged_error account=${accountId} error=${toLogText(error || "")}`,
5775
+ `[bridges/main] dingtalk probe status_error account=${accountId} error=${toSingleLineLogText(error || "")}`,
5787
5776
  );
5788
5777
  }
5789
5778
  const probeAt = nowIso();
@@ -5794,6 +5783,10 @@ async function runFullProbeAndRefreshStatuses(params: {
5794
5783
  last_probe_at: toChina8Iso(probeAt),
5795
5784
  ok,
5796
5785
  error,
5786
+ error_source: ok ? null : "probe_result",
5787
+ recent_error_context: ok ? null : recentErrorContext,
5788
+ recent_error_context_source:
5789
+ !ok && recentErrorContext ? "bridge_log" : null,
5797
5790
  result: (probeResult as Record<string, unknown>) || null,
5798
5791
  source: "probe",
5799
5792
  });
@@ -5834,16 +5827,16 @@ async function runFullProbeAndRefreshStatuses(params: {
5834
5827
  });
5835
5828
  } catch (err) {
5836
5829
  const probeAt = nowIso();
5837
- const probeError = pickMoreSpecificErrorMessage(
5838
- previous?.last_error || null,
5839
- (err as Error).message,
5840
- );
5830
+ const probeError = String((err as Error).message || "").trim() || null;
5841
5831
  upsertRuntimeProbe({
5842
5832
  platform: "dingtalk",
5843
5833
  bot_account_id: accountId,
5844
5834
  last_probe_at: toChina8Iso(probeAt),
5845
5835
  ok: false,
5846
5836
  error: probeError,
5837
+ error_source: "exception",
5838
+ recent_error_context: null,
5839
+ recent_error_context_source: null,
5847
5840
  result: null,
5848
5841
  source: "probe",
5849
5842
  });
@@ -5957,23 +5950,12 @@ async function runFullProbeAndRefreshStatuses(params: {
5957
5950
  const probeError = buildDetailedProbeErrorMessage(
5958
5951
  probeResult as Record<string, unknown>,
5959
5952
  );
5960
- const probeErrorWithLogFallback = isGenericRuntimeErrorMessage(
5961
- probeError,
5962
- )
5963
- ? pickMoreSpecificErrorMessage(
5964
- probeError,
5965
- readRecentBridgeErrorFromLog(accountId, "feishu"),
5966
- )
5967
- : probeError;
5953
+ const recentErrorContext = isGenericRuntimeErrorMessage(probeError)
5954
+ ? readRecentBridgeErrorFromLog(accountId, "feishu")
5955
+ : null;
5968
5956
  const nextStatus: RuntimeBotStatus["link_status"] =
5969
5957
  ok ? "connected" : "error";
5970
- const nextError =
5971
- nextStatus === "connected"
5972
- ? null
5973
- : pickMoreSpecificErrorMessage(
5974
- previous?.last_error || null,
5975
- probeErrorWithLogFallback,
5976
- );
5958
+ const nextError = nextStatus === "connected" ? null : probeError;
5977
5959
  const probeAt = nowIso();
5978
5960
  const runtimeHints = extractRuntimeStatusHints(probeResult);
5979
5961
  upsertRuntimeProbe({
@@ -5982,6 +5964,10 @@ async function runFullProbeAndRefreshStatuses(params: {
5982
5964
  last_probe_at: toChina8Iso(probeAt),
5983
5965
  ok,
5984
5966
  error: nextError,
5967
+ error_source: ok ? null : "probe_result",
5968
+ recent_error_context: ok ? null : recentErrorContext,
5969
+ recent_error_context_source:
5970
+ !ok && recentErrorContext ? "bridge_log" : null,
5985
5971
  result: (probeResult as Record<string, unknown>) || null,
5986
5972
  source: "probe",
5987
5973
  });
@@ -6026,6 +6012,9 @@ async function runFullProbeAndRefreshStatuses(params: {
6026
6012
  last_probe_at: toChina8Iso(probeAt),
6027
6013
  ok: false,
6028
6014
  error: probeError || null,
6015
+ error_source: "exception",
6016
+ recent_error_context: null,
6017
+ recent_error_context_source: null,
6029
6018
  result: null,
6030
6019
  source: "probe",
6031
6020
  });
@@ -6129,31 +6118,21 @@ async function runFullProbeAndRefreshStatuses(params: {
6129
6118
  const probeError = buildDetailedProbeErrorMessage(
6130
6119
  probeResult as Record<string, unknown>,
6131
6120
  );
6132
- const probeErrorWithLogFallback = isGenericRuntimeErrorMessage(
6133
- probeError,
6134
- )
6135
- ? pickMoreSpecificErrorMessage(
6136
- probeError,
6137
- readRecentBridgeErrorFromLog(accountId, "weixin"),
6138
- )
6139
- : probeError;
6121
+ const recentErrorContext = isGenericRuntimeErrorMessage(probeError)
6122
+ ? readRecentBridgeErrorFromLog(accountId, "weixin")
6123
+ : null;
6140
6124
  if (!ok) {
6141
6125
  console.error(
6142
6126
  `[bridges/main] weixin probeAccount failed account=${accountId} raw=${toLogText(probeResult)}`,
6143
6127
  );
6144
6128
  console.error(
6145
- `[bridges/main] weixin probeAccount derived_error account=${accountId} error=${toLogText(probeErrorWithLogFallback || "")}`,
6129
+ `[bridges/main] weixin probeAccount derived_error account=${accountId} error=${toSingleLineLogText(probeError || "")} ${formatRecentErrorContextLogHint("weixin", accountId, recentErrorContext)}`,
6146
6130
  );
6147
6131
  }
6148
- const error = ok
6149
- ? null
6150
- : pickMoreSpecificErrorMessage(
6151
- previous?.last_error || null,
6152
- probeErrorWithLogFallback,
6153
- );
6132
+ const error = ok ? null : probeError;
6154
6133
  if (!ok) {
6155
6134
  console.error(
6156
- `[bridges/main] weixin probeAccount merged_error account=${accountId} error=${toLogText(error || "")}`,
6135
+ `[bridges/main] weixin probeAccount status_error account=${accountId} error=${toSingleLineLogText(error || "")}`,
6157
6136
  );
6158
6137
  }
6159
6138
  const probeAt = nowIso();
@@ -6164,6 +6143,10 @@ async function runFullProbeAndRefreshStatuses(params: {
6164
6143
  last_probe_at: toChina8Iso(probeAt),
6165
6144
  ok,
6166
6145
  error,
6146
+ error_source: ok ? null : "probe_result",
6147
+ recent_error_context: ok ? null : recentErrorContext,
6148
+ recent_error_context_source:
6149
+ !ok && recentErrorContext ? "bridge_log" : null,
6167
6150
  result: (probeResult as Record<string, unknown>) || null,
6168
6151
  source: "probe",
6169
6152
  });
@@ -6200,16 +6183,16 @@ async function runFullProbeAndRefreshStatuses(params: {
6200
6183
  });
6201
6184
  } catch (err) {
6202
6185
  const probeAt = nowIso();
6203
- const probeError = pickMoreSpecificErrorMessage(
6204
- previous?.last_error || null,
6205
- (err as Error).message,
6206
- );
6186
+ const probeError = String((err as Error).message || "").trim() || null;
6207
6187
  upsertRuntimeProbe({
6208
6188
  platform: "weixin",
6209
6189
  bot_account_id: accountId,
6210
6190
  last_probe_at: toChina8Iso(probeAt),
6211
6191
  ok: false,
6212
6192
  error: probeError,
6193
+ error_source: "exception",
6194
+ recent_error_context: null,
6195
+ recent_error_context_source: null,
6213
6196
  result: null,
6214
6197
  source: "probe",
6215
6198
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ylib-syim",
3
- "version": "0.0.38",
3
+ "version": "0.0.40",
4
4
  "description": "多 IM / 多 Agent 的会话路由与上下文管理(支持 /new)",
5
5
  "type": "module",
6
6
  "exports": {