@okxweb3/a2a-node 0.2.4-beta-e7a52faf6f-260812104443 → 0.2.4

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 (3) hide show
  1. package/dist/cli.js +348 -191
  2. package/dist/index.js +311 -188
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -26604,7 +26604,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
26604
26604
  client: {
26605
26605
  id: "gateway-client",
26606
26606
  displayName: "okx-a2a-node",
26607
- version: "0.2.4-beta-e7a52faf6f-260812104443",
26607
+ version: "0.2.4",
26608
26608
  platform: "node",
26609
26609
  mode: "backend",
26610
26610
  instanceId
@@ -26615,7 +26615,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
26615
26615
  commands: [],
26616
26616
  permissions: {},
26617
26617
  locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
26618
- userAgent: `okx-a2a-node/${"0.2.4-beta-e7a52faf6f-260812104443"}`,
26618
+ userAgent: `okx-a2a-node/${"0.2.4"}`,
26619
26619
  auth: {
26620
26620
  ...config.token ? { token: config.token } : {},
26621
26621
  ...config.password ? { password: config.password } : {}
@@ -28181,6 +28181,31 @@ var init_runtime_switch = __esm({
28181
28181
  }
28182
28182
  });
28183
28183
 
28184
+ // src/job-provider.ts
28185
+ function setJobProvider(options) {
28186
+ return options.store.setJobProviderBinding({
28187
+ jobId: options.jobId,
28188
+ provider: normalizeAiProvider(options.provider)
28189
+ });
28190
+ }
28191
+ function setJobProviderToCurrentPlatform(options) {
28192
+ const provider = detectCurrentAiProvider(options.env ?? process.env);
28193
+ if (!provider) {
28194
+ return null;
28195
+ }
28196
+ return setJobProvider({
28197
+ store: options.store,
28198
+ jobId: options.jobId,
28199
+ provider
28200
+ });
28201
+ }
28202
+ var init_job_provider = __esm({
28203
+ "src/job-provider.ts"() {
28204
+ "use strict";
28205
+ init_ai_provider();
28206
+ }
28207
+ });
28208
+
28184
28209
  // src/task-config.ts
28185
28210
  function resolveAiPermissionPreset(options = {}) {
28186
28211
  const env = options.env ?? process.env;
@@ -28499,7 +28524,7 @@ var init_sentry_config = __esm({
28499
28524
  environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
28500
28525
  SENTRY_CONFIG = {
28501
28526
  projectName: "okx/openclaw-okx-a2a-extension",
28502
- release: "0.2.4-beta-e7a52faf6f-260812104443",
28527
+ release: "0.2.4",
28503
28528
  environment,
28504
28529
  runtimeContainer: normalizeRuntimeContainer(process.env.OKX_A2A_RUNTIME_CONTAINER)
28505
28530
  };
@@ -39669,7 +39694,7 @@ async function exportDiagnosticLogs(options) {
39669
39694
  node: process.version,
39670
39695
  platform: process.platform,
39671
39696
  arch: process.arch,
39672
- packageVersion: true ? "0.2.4-beta-e7a52faf6f-260812104443" : "unknown",
39697
+ packageVersion: true ? "0.2.4" : "unknown",
39673
39698
  sensitiveContentIncluded: options.includeSensitiveContent,
39674
39699
  listenerAndLlmContentIncluded: true,
39675
39700
  credentialsAlwaysRedacted: true,
@@ -40783,7 +40808,7 @@ function redactArgsForLog(args) {
40783
40808
  function commandForLog(bin, args) {
40784
40809
  return `${bin} ${redactArgsForLog(args).join(" ")}`;
40785
40810
  }
40786
- async function exec(args) {
40811
+ async function exec(args, options = {}) {
40787
40812
  const bin = await resolve9();
40788
40813
  const cmd = commandForLog(bin, args);
40789
40814
  logWithTimestamp(`[onchainos] exec: ${cmd}`);
@@ -40797,7 +40822,8 @@ async function exec(args) {
40797
40822
  try {
40798
40823
  const result = await execFileAsync2(invocation.command, invocation.args, {
40799
40824
  windowsHide: true,
40800
- windowsVerbatimArguments: invocation.windowsVerbatimArguments
40825
+ windowsVerbatimArguments: invocation.windowsVerbatimArguments,
40826
+ timeout: options.timeoutMs
40801
40827
  });
40802
40828
  logWithTimestamp(
40803
40829
  `[onchainos] exec done: ${cmd} (${Date.now() - t0}ms, stdout=${result.stdout.length}B, stderr=${result.stderr.length}B)`
@@ -40830,7 +40856,8 @@ async function exec(args) {
40830
40856
  stdoutBytes: String(Buffer.byteLength(String(err2?.stdout ?? ""), "utf8")),
40831
40857
  cliErrorName: err2 instanceof Error ? err2.name : "",
40832
40858
  cliErrorMessageLength: String(String(err2?.message ?? "").length),
40833
- durationMs: String(Date.now() - t0)
40859
+ durationMs: String(Date.now() - t0),
40860
+ timeoutMs: String(options.timeoutMs ?? "")
40834
40861
  }
40835
40862
  );
40836
40863
  throw err2;
@@ -55595,14 +55622,24 @@ function extractStreamErrorTelemetry(error) {
55595
55622
  }
55596
55623
  return telemetry;
55597
55624
  }
55598
- function createKeyedFlight(discriminator, operation) {
55625
+ function replayFlightDiscriminator(clientGeneration, isOfflineReplay) {
55626
+ return isOfflineReplay ? `startup_offline:${clientGeneration}` : `online_repair:${clientGeneration}`;
55627
+ }
55628
+ function createKeyedFlight(discriminator, operation, shouldRunAfterActive) {
55599
55629
  let resolve14;
55600
55630
  let reject;
55601
55631
  const promise = new Promise((resolvePromise, rejectPromise) => {
55602
55632
  resolve14 = resolvePromise;
55603
55633
  reject = rejectPromise;
55604
55634
  });
55605
- return { discriminator, operation, promise, resolve: resolve14, reject };
55635
+ return {
55636
+ discriminator,
55637
+ operation,
55638
+ promise,
55639
+ resolve: resolve14,
55640
+ reject,
55641
+ shouldRunAfterActive
55642
+ };
55606
55643
  }
55607
55644
  var TRANSPORT_FAILURE_PATTERNS, KNOWN_CAUSE_CODES, KNOWN_CAUSE_KINDS, KNOWN_GRPC_METHODS, StreamRecoveryTelemetry, KeyedSingleFlight;
55608
55645
  var init_stream_recovery_telemetry = __esm({
@@ -55630,6 +55667,7 @@ var init_stream_recovery_telemetry = __esm({
55630
55667
  }
55631
55668
  markError(nowMs = Date.now()) {
55632
55669
  if (this.activeRecovery) {
55670
+ this.activeRecovery.candidateStartedAtMs = void 0;
55633
55671
  return {
55634
55672
  recoverySequence: this.activeRecovery.sequence,
55635
55673
  alreadyRecovering: true
@@ -55643,9 +55681,26 @@ var init_stream_recovery_telemetry = __esm({
55643
55681
  if (!this.activeRecovery) {
55644
55682
  return void 0;
55645
55683
  }
55684
+ this.activeRecovery.candidateStartedAtMs = nowMs;
55685
+ return {
55686
+ recoverySequence: this.activeRecovery.sequence,
55687
+ candidateStartedAtMs: nowMs
55688
+ };
55689
+ }
55690
+ markStable(nowMs = Date.now()) {
55691
+ if (this.activeRecovery?.candidateStartedAtMs === void 0) {
55692
+ return void 0;
55693
+ }
55646
55694
  const completed = {
55647
55695
  recoverySequence: this.activeRecovery.sequence,
55648
- recoveryDurationMs: Math.max(0, nowMs - this.activeRecovery.startedAtMs)
55696
+ recoveryDurationMs: Math.max(
55697
+ 0,
55698
+ this.activeRecovery.candidateStartedAtMs - this.activeRecovery.startedAtMs
55699
+ ),
55700
+ recoveryConfirmationDurationMs: Math.max(
55701
+ 0,
55702
+ nowMs - this.activeRecovery.startedAtMs
55703
+ )
55649
55704
  };
55650
55705
  this.activeRecovery = void 0;
55651
55706
  return completed;
@@ -55656,7 +55711,7 @@ var init_stream_recovery_telemetry = __esm({
55656
55711
  };
55657
55712
  KeyedSingleFlight = class {
55658
55713
  inFlight = /* @__PURE__ */ new Map();
55659
- run(key, discriminator, operation) {
55714
+ run(key, discriminator, operation, options = {}) {
55660
55715
  const normalizedKey = key.toLowerCase();
55661
55716
  const state = this.inFlight.get(normalizedKey);
55662
55717
  if (!state) {
@@ -55666,7 +55721,22 @@ var init_stream_recovery_telemetry = __esm({
55666
55721
  return active.promise;
55667
55722
  }
55668
55723
  if (state.active.discriminator === discriminator) {
55669
- return state.active.promise;
55724
+ if (!options.queueBehindActive) {
55725
+ return state.active.promise;
55726
+ }
55727
+ const queued2 = state.queued.find(
55728
+ (flight3) => flight3.discriminator === discriminator
55729
+ );
55730
+ if (queued2) {
55731
+ return queued2.promise;
55732
+ }
55733
+ const flight2 = createKeyedFlight(
55734
+ discriminator,
55735
+ operation,
55736
+ options.shouldRunAfterActive
55737
+ );
55738
+ state.queued.push(flight2);
55739
+ return flight2.promise;
55670
55740
  }
55671
55741
  const queued = state.queued.find(
55672
55742
  (flight2) => flight2.discriminator === discriminator
@@ -55682,15 +55752,15 @@ var init_stream_recovery_telemetry = __esm({
55682
55752
  void Promise.resolve().then(flight.operation).then(
55683
55753
  (value) => {
55684
55754
  flight.resolve(value);
55685
- this.advance(key, flight);
55755
+ this.advanceAfterSuccess(key, flight, value);
55686
55756
  },
55687
55757
  (error) => {
55688
55758
  flight.reject(error);
55689
- this.advance(key, flight);
55759
+ this.advanceAfterFailure(key, flight, error);
55690
55760
  }
55691
55761
  );
55692
55762
  }
55693
- advance(key, completed) {
55763
+ advanceAfterSuccess(key, completed, value) {
55694
55764
  const state = this.inFlight.get(key);
55695
55765
  if (state?.active !== completed) {
55696
55766
  return;
@@ -55700,6 +55770,29 @@ var init_stream_recovery_telemetry = __esm({
55700
55770
  this.inFlight.delete(key);
55701
55771
  return;
55702
55772
  }
55773
+ if (next.shouldRunAfterActive && !next.shouldRunAfterActive(value)) {
55774
+ next.resolve(value);
55775
+ this.advanceAfterSuccess(key, completed, value);
55776
+ return;
55777
+ }
55778
+ state.active = next;
55779
+ this.execute(key, next);
55780
+ }
55781
+ advanceAfterFailure(key, completed, error) {
55782
+ const state = this.inFlight.get(key);
55783
+ if (state?.active !== completed) {
55784
+ return;
55785
+ }
55786
+ const next = state.queued.shift();
55787
+ if (!next) {
55788
+ this.inFlight.delete(key);
55789
+ return;
55790
+ }
55791
+ if (next.shouldRunAfterActive) {
55792
+ next.reject(error);
55793
+ this.advanceAfterFailure(key, completed, error);
55794
+ return;
55795
+ }
55703
55796
  state.active = next;
55704
55797
  this.execute(key, next);
55705
55798
  }
@@ -56565,11 +56658,11 @@ function replayScanBackoffMs(consecutiveFailures) {
56565
56658
  function isOfflineReplayForTrigger(trigger) {
56566
56659
  return trigger === "startup";
56567
56660
  }
56568
- function replaySingleFlightDiscriminator(trigger, clientGeneration, recoveryIdentity) {
56569
- if (trigger === "stream_recovery") {
56570
- return `stream_recovery:${clientGeneration}:${recoveryIdentity ?? "unknown"}`;
56571
- }
56572
- return isOfflineReplayForTrigger(trigger) ? `startup_offline:${clientGeneration}` : `online_repair:${clientGeneration}`;
56661
+ function replaySingleFlightDiscriminator(trigger, clientGeneration) {
56662
+ return replayFlightDiscriminator(
56663
+ clientGeneration,
56664
+ isOfflineReplayForTrigger(trigger)
56665
+ );
56573
56666
  }
56574
56667
  function createOfflineReplayAddressSummary(address) {
56575
56668
  return {
@@ -56589,7 +56682,7 @@ function createOfflineReplayAddressSummary(address) {
56589
56682
  durationMs: 0
56590
56683
  };
56591
56684
  }
56592
- var import_node_fs22, import_node_path26, DEFAULT_DATA_DIR, XMTP_INSTALLATION_WARNING_THRESHOLD, XMTP_INSTALLATION_NEAR_LIMIT_THRESHOLD, REPLAY_SCAN_INITIAL_BACKOFF_MS, REPLAY_SCAN_MAX_BACKOFF_MS, SENSITIVE_WORDS_LAZY_RETRY_COOLDOWN_MS, InboundReplayGate, SYSTEM_CONFIG_DEFAULTS, STREAM_RECOVERY_ALERT_THRESHOLD_MS, REPLAY_GATE_DRAIN_MAX_ATTEMPTS, REPLAY_GATE_DRAIN_RETRY_DELAY_MS, SEMVER_RE, isRecord5, isPositiveNumber, SYSTEM_CONFIG_VALIDATORS, XmtpService;
56685
+ var import_node_fs22, import_node_path26, DEFAULT_DATA_DIR, XMTP_INSTALLATION_WARNING_THRESHOLD, XMTP_INSTALLATION_NEAR_LIMIT_THRESHOLD, REPLAY_SCAN_INITIAL_BACKOFF_MS, REPLAY_SCAN_MAX_BACKOFF_MS, SENSITIVE_WORDS_LAZY_RETRY_COOLDOWN_MS, InboundReplayGate, SYSTEM_CONFIG_DEFAULTS, STREAM_RECOVERY_ALERT_THRESHOLD_MS, STREAM_RECOVERY_STABILITY_WINDOW_MS, REPLAY_GATE_DRAIN_MAX_ATTEMPTS, REPLAY_GATE_DRAIN_RETRY_DELAY_MS, SEMVER_RE, isRecord5, isPositiveNumber, SYSTEM_CONFIG_VALIDATORS, XmtpService;
56593
56686
  var init_xmtp_sdk = __esm({
56594
56687
  "../core/src/xmtp-sdk/index.ts"() {
56595
56688
  "use strict";
@@ -56697,6 +56790,7 @@ var init_xmtp_sdk = __esm({
56697
56790
  }
56698
56791
  };
56699
56792
  STREAM_RECOVERY_ALERT_THRESHOLD_MS = 3e4;
56793
+ STREAM_RECOVERY_STABILITY_WINDOW_MS = 1e4;
56700
56794
  REPLAY_GATE_DRAIN_MAX_ATTEMPTS = 3;
56701
56795
  REPLAY_GATE_DRAIN_RETRY_DELAY_MS = 100;
56702
56796
  SEMVER_RE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*)?$/;
@@ -56751,6 +56845,9 @@ var init_xmtp_sdk = __esm({
56751
56845
  replayScanClearTimeout = (timer) => clearTimeout(timer);
56752
56846
  inboundReplayGates = /* @__PURE__ */ new Map();
56753
56847
  streamRecoveryCleanupByAddress = /* @__PURE__ */ new Map();
56848
+ streamRecoverySetTimeout = (callback, delayMs) => setTimeout(callback, delayMs);
56849
+ streamRecoveryClearTimeout = (timer) => clearTimeout(timer);
56850
+ streamStartSetTimeout = (callback, delayMs) => setTimeout(callback, delayMs);
56754
56851
  nextClientGeneration = 1;
56755
56852
  clientGenerationByClient = /* @__PURE__ */ new WeakMap();
56756
56853
  resolveStartupReplayCompletion;
@@ -58203,10 +58300,14 @@ var init_xmtp_sdk = __esm({
58203
58300
  }
58204
58301
  const delay = BASE_DELAY_MS * 2 ** attempt;
58205
58302
  logWithTimestamp(`${tag} reconnecting in ${delay}ms (attempt=${attempt + 1})`);
58206
- setTimeout(() => void startWithRetry(attempt + 1), delay);
58303
+ this.streamStartSetTimeout(
58304
+ () => void startWithRetry(attempt + 1),
58305
+ delay
58306
+ );
58207
58307
  };
58208
58308
  const streamRecovery = new StreamRecoveryTelemetry();
58209
58309
  let recoveryTimeout;
58310
+ let recoveryStabilityTimeout;
58210
58311
  let pendingRecoveryGate;
58211
58312
  let recoveryDisposed = false;
58212
58313
  this.cancelStreamRecoveryForAddress(address);
@@ -58214,9 +58315,13 @@ var init_xmtp_sdk = __esm({
58214
58315
  recoveryDisposed = true;
58215
58316
  streamRecovery.cancel();
58216
58317
  if (recoveryTimeout) {
58217
- clearTimeout(recoveryTimeout);
58318
+ this.streamRecoveryClearTimeout(recoveryTimeout);
58218
58319
  recoveryTimeout = void 0;
58219
58320
  }
58321
+ if (recoveryStabilityTimeout) {
58322
+ this.streamRecoveryClearTimeout(recoveryStabilityTimeout);
58323
+ recoveryStabilityTimeout = void 0;
58324
+ }
58220
58325
  };
58221
58326
  this.streamRecoveryCleanupByAddress.set(
58222
58327
  addressKey,
@@ -58231,6 +58336,10 @@ var init_xmtp_sdk = __esm({
58231
58336
  logger.error(LogEvent.AGENT_UNHANDLED_ERROR, err2, agentExtras(identity));
58232
58337
  return;
58233
58338
  }
58339
+ if (recoveryStabilityTimeout) {
58340
+ this.streamRecoveryClearTimeout(recoveryStabilityTimeout);
58341
+ recoveryStabilityTimeout = void 0;
58342
+ }
58234
58343
  const recovery = streamRecovery.markError();
58235
58344
  const errorTelemetry = extractStreamErrorTelemetry(err2);
58236
58345
  if (!recovery.alreadyRecovering) {
@@ -58245,10 +58354,11 @@ var init_xmtp_sdk = __esm({
58245
58354
  recoveryAlreadyActive: String(recovery.alreadyRecovering)
58246
58355
  });
58247
58356
  if (!recovery.alreadyRecovering) {
58248
- recoveryTimeout = setTimeout(() => {
58357
+ recoveryTimeout = this.streamRecoverySetTimeout(() => {
58249
58358
  if (recoveryDisposed || this.clients.get(address) !== agent || this.stoppedAddresses.has(addressKey) || streamRecovery.activeSequence !== recovery.recoverySequence) {
58250
58359
  return;
58251
58360
  }
58361
+ recoveryTimeout = void 0;
58252
58362
  logger.error(LogEvent.AGENT_STREAM_RECOVERY_TIMEOUT, void 0, {
58253
58363
  ...agentExtras(identity),
58254
58364
  ...errorTelemetry,
@@ -58257,6 +58367,22 @@ var init_xmtp_sdk = __esm({
58257
58367
  recoveryDurationMs: String(STREAM_RECOVERY_ALERT_THRESHOLD_MS),
58258
58368
  thresholdMs: String(STREAM_RECOVERY_ALERT_THRESHOLD_MS)
58259
58369
  });
58370
+ const timedOutGate = pendingRecoveryGate;
58371
+ pendingRecoveryGate = void 0;
58372
+ void this.drainInboundReplayGate(address, timedOutGate).catch(
58373
+ (drainError) => {
58374
+ logger.error(
58375
+ LogEvent.OFFLINE_REPLAY_FAILED,
58376
+ drainError instanceof Error ? drainError : new Error(String(drainError)),
58377
+ {
58378
+ ...agentExtras(identity),
58379
+ clientGeneration: String(clientGeneration),
58380
+ recoverySequence: String(recovery.recoverySequence),
58381
+ stage: "streamRecovery/timeout-drain-gate"
58382
+ }
58383
+ );
58384
+ }
58385
+ );
58260
58386
  }, STREAM_RECOVERY_ALERT_THRESHOLD_MS);
58261
58387
  }
58262
58388
  });
@@ -58264,60 +58390,61 @@ var init_xmtp_sdk = __esm({
58264
58390
  if (recoveryDisposed || this.clients.get(address) !== agent || this.stoppedAddresses.has(addressKey)) {
58265
58391
  return;
58266
58392
  }
58267
- const recovery = streamRecovery.markStarted();
58268
- if (recoveryTimeout) {
58269
- clearTimeout(recoveryTimeout);
58270
- recoveryTimeout = void 0;
58271
- }
58393
+ const candidate = streamRecovery.markStarted();
58272
58394
  logWithTimestamp(
58273
58395
  `${tag} agent stream started agentId=${identity.onchainosAgentId ?? "(unknown)"} inboxId=${identity.inboxId ?? "(unknown)"} role=${identity.role ?? "(unknown)"} consentStates=Allowed,Unknown lastSync=${formatLogTimestamp2(this.syncByAddress.get(address))}`
58274
58396
  );
58275
- if (recovery) {
58276
- const recoveryGate = pendingRecoveryGate;
58277
- pendingRecoveryGate = void 0;
58278
- logger.info(LogEvent.AGENT_STREAM_RECOVERED, {
58279
- ...agentExtras(identity),
58280
- clientGeneration: String(clientGeneration),
58281
- recoverySequence: String(recovery.recoverySequence),
58282
- recoveryDurationMs: String(recovery.recoveryDurationMs)
58283
- });
58284
- void (async () => {
58285
- try {
58286
- const summary = await this.replayOfflineMessagesForStreamRecovery(
58287
- address,
58288
- String(recovery.recoverySequence),
58289
- agent
58290
- );
58291
- if (summary.outcome === "completed" && !recoveryDisposed && this.clients.get(address) === agent) {
58292
- logger.info(LogEvent.AGENT_STREAM_RECOVERY_REPLAY_COMPLETED, {
58293
- ...agentExtras(identity),
58294
- clientGeneration: String(clientGeneration),
58295
- recoverySequence: String(recovery.recoverySequence),
58296
- replayed: String(summary.replayed),
58297
- skipped: String(summary.skipped),
58298
- conversationCount: String(summary.conversations),
58299
- replayDurationMs: String(summary.durationMs),
58300
- outcome: "success",
58301
- replayOutcome: summary.outcome
58302
- });
58303
- }
58304
- } catch (err2) {
58305
- logWithTimestamp(`${tag} recovery offline replay failed:`, err2);
58306
- logger.error(
58307
- LogEvent.OFFLINE_REPLAY_FAILED,
58308
- err2 instanceof Error ? err2 : new Error(String(err2)),
58309
- {
58310
- ...agentExtras(identity),
58311
- clientGeneration: String(clientGeneration),
58312
- recoverySequence: String(recovery.recoverySequence),
58313
- stage: "streamRecovery/replay"
58314
- }
58315
- );
58316
- } finally {
58397
+ if (candidate) {
58398
+ if (recoveryStabilityTimeout) {
58399
+ this.streamRecoveryClearTimeout(recoveryStabilityTimeout);
58400
+ }
58401
+ recoveryStabilityTimeout = this.streamRecoverySetTimeout(() => {
58402
+ recoveryStabilityTimeout = void 0;
58403
+ if (recoveryDisposed || this.clients.get(address) !== agent || this.stoppedAddresses.has(addressKey) || streamRecovery.activeSequence !== candidate.recoverySequence) {
58404
+ return;
58405
+ }
58406
+ const recovery = streamRecovery.markStable();
58407
+ if (!recovery) {
58408
+ return;
58409
+ }
58410
+ if (recoveryTimeout) {
58411
+ this.streamRecoveryClearTimeout(recoveryTimeout);
58412
+ recoveryTimeout = void 0;
58413
+ }
58414
+ const recoveryGate = pendingRecoveryGate;
58415
+ pendingRecoveryGate = void 0;
58416
+ logger.info(LogEvent.AGENT_STREAM_RECOVERED, {
58417
+ ...agentExtras(identity),
58418
+ clientGeneration: String(clientGeneration),
58419
+ recoverySequence: String(recovery.recoverySequence),
58420
+ recoveryDurationMs: String(recovery.recoveryDurationMs),
58421
+ recoveryConfirmationDurationMs: String(
58422
+ recovery.recoveryConfirmationDurationMs
58423
+ ),
58424
+ stabilityWindowMs: String(STREAM_RECOVERY_STABILITY_WINDOW_MS)
58425
+ });
58426
+ void (async () => {
58317
58427
  try {
58318
- await this.drainInboundReplayGate(address, recoveryGate);
58428
+ const summary = await this.replayOfflineMessagesForStreamRecovery(
58429
+ address,
58430
+ String(recovery.recoverySequence),
58431
+ agent
58432
+ );
58433
+ if (summary.outcome === "completed" && !recoveryDisposed && this.clients.get(address) === agent) {
58434
+ logger.info(LogEvent.AGENT_STREAM_RECOVERY_REPLAY_COMPLETED, {
58435
+ ...agentExtras(identity),
58436
+ clientGeneration: String(clientGeneration),
58437
+ recoverySequence: String(recovery.recoverySequence),
58438
+ replayed: String(summary.replayed),
58439
+ skipped: String(summary.skipped),
58440
+ conversationCount: String(summary.conversations),
58441
+ replayDurationMs: String(summary.durationMs),
58442
+ outcome: "success",
58443
+ replayOutcome: summary.outcome
58444
+ });
58445
+ }
58319
58446
  } catch (err2) {
58320
- logWithTimestamp(`${tag} recovery replay gate drain failed:`, err2);
58447
+ logWithTimestamp(`${tag} recovery offline replay failed:`, err2);
58321
58448
  logger.error(
58322
58449
  LogEvent.OFFLINE_REPLAY_FAILED,
58323
58450
  err2 instanceof Error ? err2 : new Error(String(err2)),
@@ -58325,12 +58452,28 @@ var init_xmtp_sdk = __esm({
58325
58452
  ...agentExtras(identity),
58326
58453
  clientGeneration: String(clientGeneration),
58327
58454
  recoverySequence: String(recovery.recoverySequence),
58328
- stage: "streamRecovery/drain-gate"
58455
+ stage: "streamRecovery/replay"
58329
58456
  }
58330
58457
  );
58458
+ } finally {
58459
+ try {
58460
+ await this.drainInboundReplayGate(address, recoveryGate);
58461
+ } catch (err2) {
58462
+ logWithTimestamp(`${tag} recovery replay gate drain failed:`, err2);
58463
+ logger.error(
58464
+ LogEvent.OFFLINE_REPLAY_FAILED,
58465
+ err2 instanceof Error ? err2 : new Error(String(err2)),
58466
+ {
58467
+ ...agentExtras(identity),
58468
+ clientGeneration: String(clientGeneration),
58469
+ recoverySequence: String(recovery.recoverySequence),
58470
+ stage: "streamRecovery/drain-gate"
58471
+ }
58472
+ );
58473
+ }
58331
58474
  }
58332
- }
58333
- })();
58475
+ })();
58476
+ }, STREAM_RECOVERY_STABILITY_WINDOW_MS);
58334
58477
  }
58335
58478
  if (process.env.XMTP_FORCE_DEBUG === "true") {
58336
58479
  void logDetails(agent).catch((err2) => {
@@ -58349,7 +58492,7 @@ var init_xmtp_sdk = __esm({
58349
58492
  logWithTimestamp(`${tag} message listener started`);
58350
58493
  });
58351
58494
  }
58352
- async replayOfflineMessagesForAddress(address, expectedClient, trigger = "periodic_repair") {
58495
+ async replayOfflineMessagesForAddress(address, expectedClient, trigger = "periodic_repair", recoveryIdentity) {
58353
58496
  const addressReplayStartedAt = Date.now();
58354
58497
  const summary = createOfflineReplayAddressSummary(address);
58355
58498
  const isOfflineReplay = isOfflineReplayForTrigger(trigger);
@@ -58449,6 +58592,8 @@ var init_xmtp_sdk = __esm({
58449
58592
  walletAddress: address,
58450
58593
  stage: `offlineReplay/${stage}`,
58451
58594
  trigger,
58595
+ clientGeneration: String(clientGeneration),
58596
+ ...recoveryIdentity ? { recoverySequence: recoveryIdentity } : {},
58452
58597
  outcome: "failed",
58453
58598
  replayOutcome: summary.outcome,
58454
58599
  consecutiveFailures: String(consecutiveFailures),
@@ -58643,8 +58788,7 @@ var init_xmtp_sdk = __esm({
58643
58788
  const clientGeneration = expectedClient ? this.getClientGeneration(expectedClient) : "missing";
58644
58789
  const eligibilityClass = replaySingleFlightDiscriminator(
58645
58790
  trigger,
58646
- clientGeneration,
58647
- recoveryIdentity
58791
+ clientGeneration
58648
58792
  );
58649
58793
  return this.offlineReplaySingleFlight.run(
58650
58794
  address,
@@ -58654,9 +58798,14 @@ var init_xmtp_sdk = __esm({
58654
58798
  return this.replayOfflineMessagesForAddress(
58655
58799
  address,
58656
58800
  expectedClient,
58657
- trigger
58801
+ trigger,
58802
+ recoveryIdentity
58658
58803
  );
58659
- }
58804
+ },
58805
+ trigger === "stream_recovery" ? {
58806
+ queueBehindActive: true,
58807
+ shouldRunAfterActive: (summary) => summary.outcome === "completed"
58808
+ } : void 0
58660
58809
  );
58661
58810
  }
58662
58811
  async replayOfflineMessagesForStreamRecovery(address, recoveryIdentity, expectedClient) {
@@ -58947,13 +59096,17 @@ function parseWalletLoginStatus(stdout) {
58947
59096
  }
58948
59097
  return response.data.loggedIn;
58949
59098
  }
58950
- async function queryWalletLoginStatus() {
59099
+ async function queryWalletLoginStatus(options = {}) {
58951
59100
  logWithTimestamp("[onchainos] checking wallet login status");
58952
- const { stdout } = await exec(["wallet", "status"]);
59101
+ const { stdout } = await exec(
59102
+ ["wallet", "status"],
59103
+ { timeoutMs: options.timeoutMs ?? WALLET_STATUS_TIMEOUT_MS }
59104
+ );
58953
59105
  const loggedIn = parseWalletLoginStatus(stdout);
58954
59106
  logWithTimestamp(`[onchainos] wallet login status: ${loggedIn ? "logged in" : "logged out"}`);
58955
59107
  return loggedIn;
58956
59108
  }
59109
+ var WALLET_STATUS_TIMEOUT_MS;
58957
59110
  var init_wallet_status = __esm({
58958
59111
  "../core/src/xmtp-sdk/onchainos/wallet-status.ts"() {
58959
59112
  "use strict";
@@ -58961,6 +59114,7 @@ var init_wallet_status = __esm({
58961
59114
  init_sentry_logger();
58962
59115
  init_bin();
58963
59116
  init_cli_response();
59117
+ WALLET_STATUS_TIMEOUT_MS = 1e4;
58964
59118
  }
58965
59119
  });
58966
59120
 
@@ -59048,19 +59202,22 @@ function logAgentListResponse(input) {
59048
59202
  onchainosAgentListDiagnosticText: input.stderr
59049
59203
  });
59050
59204
  }
59051
- async function fetchAgentPage(page) {
59205
+ async function fetchAgentPage(page, timeoutMs) {
59052
59206
  const startedAt = Date.now();
59053
59207
  let stdout;
59054
59208
  let stderr;
59055
59209
  try {
59056
- ({ stdout, stderr } = await exec([
59057
- "agent",
59058
- "get",
59059
- "--page",
59060
- String(page),
59061
- "--page-size",
59062
- String(PAGE_SIZE)
59063
- ]));
59210
+ ({ stdout, stderr } = await exec(
59211
+ [
59212
+ "agent",
59213
+ "get",
59214
+ "--page",
59215
+ String(page),
59216
+ "--page-size",
59217
+ String(PAGE_SIZE)
59218
+ ],
59219
+ { timeoutMs }
59220
+ ));
59064
59221
  } catch (err2) {
59065
59222
  const errStdout = typeof err2?.stdout === "string" ? err2.stdout : "";
59066
59223
  const errStderr = typeof err2?.stderr === "string" ? err2.stderr : "";
@@ -59204,13 +59361,28 @@ async function fetchAgentByAddress(communicationAddress) {
59204
59361
  agentByIdCache.set(res.data.agentId, res.data);
59205
59362
  return res.data;
59206
59363
  }
59207
- async function listAllAgentsWithMetadata(previousFingerprint) {
59364
+ async function listAllAgentsWithMetadata(previousFingerprint, options = {}) {
59208
59365
  const startedAt = Date.now();
59366
+ const pageTimeoutMs = positiveTimeoutOrDefault(
59367
+ options.pageTimeoutMs,
59368
+ AGENT_GET_PAGE_TIMEOUT_MS
59369
+ );
59370
+ const totalTimeoutMs = positiveTimeoutOrDefault(
59371
+ options.totalTimeoutMs,
59372
+ AGENT_LIST_TIMEOUT_MS
59373
+ );
59209
59374
  const agents = [];
59210
59375
  const stderrs = [];
59211
59376
  let page = 1;
59212
59377
  while (true) {
59213
- const { data, stderr } = await fetchAgentPage(page);
59378
+ const remainingMs = totalTimeoutMs - (Date.now() - startedAt);
59379
+ if (remainingMs <= 0) {
59380
+ throw agentListTimeoutError(totalTimeoutMs);
59381
+ }
59382
+ const { data, stderr } = await fetchAgentPage(
59383
+ page,
59384
+ Math.min(pageTimeoutMs, remainingMs)
59385
+ );
59214
59386
  if (stderr) {
59215
59387
  stderrs.push(`page=${page}: ${stderr}`);
59216
59388
  }
@@ -59237,6 +59409,14 @@ async function listAllAgentsWithMetadata(previousFingerprint) {
59237
59409
  durationMs: Date.now() - startedAt
59238
59410
  };
59239
59411
  }
59412
+ function positiveTimeoutOrDefault(value, fallback) {
59413
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
59414
+ }
59415
+ function agentListTimeoutError(timeoutMs) {
59416
+ const error = new Error(`onchainos agent list timed out after ${timeoutMs}ms`);
59417
+ error.code = "ETIMEDOUT";
59418
+ return error;
59419
+ }
59240
59420
  function fingerprintAgents(agents) {
59241
59421
  return agents.map((a) => [
59242
59422
  a.agentId,
@@ -59437,7 +59617,7 @@ async function fetchSensitiveWords() {
59437
59617
  );
59438
59618
  return result;
59439
59619
  }
59440
- var MESSAGE_ELIGIBILITY_SERVICE_UNAVAILABLE_AI_HINT, lastExpiredNotifyAt, EXPIRED_NOTIFY_COOLDOWN_MS, PAGE_SIZE, agentByIdCache, ONCHAINOS_CHAIN_INDEX;
59620
+ var MESSAGE_ELIGIBILITY_SERVICE_UNAVAILABLE_AI_HINT, lastExpiredNotifyAt, EXPIRED_NOTIFY_COOLDOWN_MS, PAGE_SIZE, AGENT_GET_PAGE_TIMEOUT_MS, AGENT_LIST_TIMEOUT_MS, agentByIdCache, ONCHAINOS_CHAIN_INDEX;
59441
59621
  var init_onchainos = __esm({
59442
59622
  "../core/src/xmtp-sdk/onchainos/index.ts"() {
59443
59623
  "use strict";
@@ -59456,6 +59636,8 @@ var init_onchainos = __esm({
59456
59636
  lastExpiredNotifyAt = 0;
59457
59637
  EXPIRED_NOTIFY_COOLDOWN_MS = 5 * 60 * 1e3;
59458
59638
  PAGE_SIZE = 50;
59639
+ AGENT_GET_PAGE_TIMEOUT_MS = 1e4;
59640
+ AGENT_LIST_TIMEOUT_MS = 3e4;
59459
59641
  agentByIdCache = /* @__PURE__ */ new Map();
59460
59642
  ONCHAINOS_CHAIN_INDEX = "196";
59461
59643
  }
@@ -59574,14 +59756,9 @@ var init_signer = __esm({
59574
59756
  });
59575
59757
 
59576
59758
  // ../core/src/a2a/pending-conversation.ts
59577
- function buildPendingConversationBackupNotice(jobId) {
59578
- return PENDING_CONVERSATION_BACKUP_NOTICE_TEMPLATE.replace("${jobId}", jobId);
59579
- }
59580
- var PENDING_CONVERSATION_BACKUP_NOTICE_TEMPLATE;
59581
59759
  var init_pending_conversation = __esm({
59582
59760
  "../core/src/a2a/pending-conversation.ts"() {
59583
59761
  "use strict";
59584
- PENDING_CONVERSATION_BACKUP_NOTICE_TEMPLATE = "[event:provider_conversation][jobId:${jobId}] There are new conversation requests pending.";
59585
59762
  }
59586
59763
  });
59587
59764
 
@@ -65683,17 +65860,22 @@ async function maybeAllowProviderGroup(deps, chatType, conversationId) {
65683
65860
  );
65684
65861
  }
65685
65862
  }
65686
- function shouldKeepInboundGroupPendingForBuyer(input) {
65687
- return input.consentState === import_node_bindings2.ConsentState.Unknown && !input.hasExistingSession && (input.localAgentRole === 1 /* CLIENT */ || input.localAgentRole == null);
65688
- }
65689
- function buildPendingConversationBackupDispatch(input) {
65690
- return {
65691
- sessionKey: buildBackupJobSessionKey(input.jobId),
65692
- content: buildPendingConversationBackupNotice(input.jobId),
65693
- messageId: `pending-conversation:${input.messageId}`,
65863
+ function ensureInboundGroupSession(deps, input) {
65864
+ const sessionKey = buildSessionKey({
65694
65865
  jobId: input.jobId,
65695
- agentId: null
65696
- };
65866
+ myAgentId: input.myAgentId,
65867
+ toAgentId: input.toAgentId
65868
+ });
65869
+ deps.sessionStore?.upsertSession({
65870
+ sessionKey,
65871
+ jobId: input.jobId,
65872
+ myAgentId: input.myAgentId,
65873
+ toAgentId: input.toAgentId,
65874
+ groupId: input.groupId,
65875
+ myAgentXmtpAddress: deps.myXmtpAddress,
65876
+ toAgentXmtpAddress: input.toAgentXmtpAddress
65877
+ });
65878
+ return sessionKey;
65697
65879
  }
65698
65880
  function inboundStageExtras(stage, outcome) {
65699
65881
  return {
@@ -65750,30 +65932,6 @@ function buildInboundTerminalExtras(input) {
65750
65932
  })
65751
65933
  };
65752
65934
  }
65753
- function notifyPendingConversationToBackup(params) {
65754
- const event = buildPendingConversationBackupDispatch({
65755
- jobId: params.jobId,
65756
- messageId: params.messageId
65757
- });
65758
- void Promise.resolve(params.deps.onSessionMessage?.(event)).catch((err2) => {
65759
- logWithTimestamp(`[okx-agent-task:${params.deps.myXmtpAddress}] pending conversation backup dispatch failed:`, err2);
65760
- logger.error(LogEvent.INBOUND_DISPATCH_FAILED, toLoggableError(err2), {
65761
- ...buildInboundTerminalExtras({
65762
- terminalState: "dispatch_failed",
65763
- myXmtpAddress: params.deps.myXmtpAddress,
65764
- messageId: event.messageId,
65765
- jobId: params.jobId,
65766
- sessionKey: event.sessionKey,
65767
- route: "backup",
65768
- reason: "pending_backup_dispatch_failed"
65769
- }),
65770
- // Each fire-and-forget dispatch overrides the generic checkpoint with the
65771
- // `_failed` twin of its own success checkpoint, so the four paths stay
65772
- // distinguishable in the funnel.
65773
- checkpoint: "inbound/pending_backup_dispatch_failed"
65774
- });
65775
- });
65776
- }
65777
65935
  function maybeNotifyInboundAgentMessage(params) {
65778
65936
  if (params.chatType === "dm") {
65779
65937
  return;
@@ -66581,7 +66739,7 @@ async function processFileMessage(ctx, deps, options = {}) {
66581
66739
  }
66582
66740
  const sender = isPlainObject3(payloadObject?.sender) ? payloadObject.sender : null;
66583
66741
  const localAgent = service.getAgentByAddress(deps.myXmtpAddress);
66584
- const myAgentId = localAgent?.agentId ?? sessionAgentId ?? null;
66742
+ const myAgentId = localAgent?.agentId ?? readString5(payloadObject?.receiverAgentId) ?? sessionAgentId ?? null;
66585
66743
  const toAgentId = readString5(sender?.agentId);
66586
66744
  const accepted = await verifyInboundA2AGroupMessage({
66587
66745
  payload: parsed.parsed ? parsed.payload : null,
@@ -66599,50 +66757,13 @@ async function processFileMessage(ctx, deps, options = {}) {
66599
66757
  if (!accepted) {
66600
66758
  return true;
66601
66759
  }
66602
- const sessionKey = buildSessionKey({
66603
- jobId: route.jobId,
66604
- myAgentId,
66605
- toAgentId
66606
- });
66607
- const existingSession = deps.sessionStore?.getSession(sessionKey) ?? null;
66608
66760
  const routedMessageId = messageId || `group-${(0, import_node_crypto14.randomUUID)()}`;
66609
- const consentState = ctx.conversation instanceof Group ? ctx.conversation.consentState() : void 0;
66610
- if (shouldKeepInboundGroupPendingForBuyer({
66611
- consentState,
66612
- localAgentRole: localAgent?.role ?? null,
66613
- hasExistingSession: !!existingSession
66614
- })) {
66615
- logWithTimestamp(
66616
- `[okx-agent-task:${deps.myXmtpAddress}] buyer inbound group kept pending: session=${sessionKey} job=${shortenLogValue(route.jobId)} group=${conversationId} consent=${String(consentState)} message=${shortenLogValue(routedMessageId)}`
66617
- );
66618
- logger.info(LogEvent.INBOUND_BUYER_PENDING, {
66619
- ...agentExtras({ walletAddress: deps.myXmtpAddress, onchainosAgentId: localAgent?.agentId }),
66620
- peerWalletAddress: senderAddress,
66621
- peerInboxId: ctx.message.senderInboxId ?? "",
66622
- peerAgentId: toAgentId ?? "",
66623
- taskId: route.jobId,
66624
- conversationId,
66625
- messageId: routedMessageId,
66626
- consentState: String(consentState),
66627
- ...inboundStageExtras("inbound/buyer_pending", "pending"),
66628
- reason: "unknown_group_without_session",
66629
- ...timing.extras()
66630
- });
66631
- notifyPendingConversationToBackup({
66632
- deps,
66633
- jobId: route.jobId,
66634
- messageId: routedMessageId
66635
- });
66636
- return true;
66637
- }
66638
- deps.sessionStore?.upsertSession({
66639
- sessionKey,
66761
+ const sessionKey = ensureInboundGroupSession(deps, {
66640
66762
  jobId: route.jobId,
66641
66763
  myAgentId,
66642
66764
  toAgentId,
66643
- groupId: conversationId || null,
66644
- myAgentXmtpAddress: deps.myXmtpAddress,
66645
- toAgentXmtpAddress: senderAddress || null
66765
+ groupId: conversationId,
66766
+ toAgentXmtpAddress: senderAddress || readString5(payloadObject?.fromXmtpAddress)
66646
66767
  });
66647
66768
  const dispatchStartedAt = Date.now();
66648
66769
  void Promise.resolve(deps.onSessionMessage?.({
@@ -67068,6 +67189,7 @@ var init_user_attention_watchers = __esm({
67068
67189
  var listener_exports = {};
67069
67190
  __export(listener_exports, {
67070
67191
  AUTH_RECOVERY_PROBE_INTERVAL_MS: () => AUTH_RECOVERY_PROBE_INTERVAL_MS,
67192
+ AUTH_RECOVERY_REFRESH_BACKOFF_MS: () => AUTH_RECOVERY_REFRESH_BACKOFF_MS,
67071
67193
  AgentRefreshAuthGate: () => AgentRefreshAuthGate,
67072
67194
  AgentRefreshCoordinator: () => AgentRefreshCoordinator,
67073
67195
  DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC: () => DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC,
@@ -67333,7 +67455,7 @@ async function runListenerWithLock(options, paths) {
67333
67455
  }
67334
67456
  }),
67335
67457
  notifySessionExpired: (command) => {
67336
- const rawText = `The onchainos login session has expired while running ${command}. Run \`onchainos wallet login\`; A2A will recover within 60 seconds, or run \`okx-a2a agent refresh\` to recover immediately.`;
67458
+ const rawText = `The onchainos login session has expired while running ${command}. Run \`onchainos wallet login\`; A2A will retry recovery automatically within 60 seconds, or run \`okx-a2a agent refresh\` to retry immediately.`;
67337
67459
  void store.appendBackup(buildSystemStoredMessage({
67338
67460
  reason: "onchainos-session-expired",
67339
67461
  rawText,
@@ -67361,12 +67483,12 @@ async function runListenerWithLock(options, paths) {
67361
67483
  });
67362
67484
  }
67363
67485
  });
67364
- service.setPluginVersion("0.2.4-beta-e7a52faf6f-260812104443");
67486
+ service.setPluginVersion("0.2.4");
67365
67487
  await service.init();
67366
67488
  const pluginVersionStatus = service.pluginVersionStatus;
67367
67489
  if (pluginVersionStatus.unavailable) {
67368
67490
  throw new Error(
67369
- `@okxweb3/a2a-node v${"0.2.4-beta-e7a52faf6f-260812104443"} is below the required minimum v${pluginVersionStatus.minVersion}`
67491
+ `@okxweb3/a2a-node v${"0.2.4"} is below the required minimum v${pluginVersionStatus.minVersion}`
67370
67492
  );
67371
67493
  }
67372
67494
  const systemConfig = service.getSystemConfig();
@@ -67384,7 +67506,7 @@ async function runListenerWithLock(options, paths) {
67384
67506
  onchainosAgentId: "*",
67385
67507
  reason: "system-config missing sentryDsn",
67386
67508
  pluginId: "@okxweb3/a2a-node",
67387
- pluginVersion: "0.2.4-beta-e7a52faf6f-260812104443"
67509
+ pluginVersion: "0.2.4"
67388
67510
  });
67389
67511
  }
67390
67512
  logWithTimestamp(
@@ -67812,7 +67934,7 @@ async function timeSettled(fn) {
67812
67934
  return { durationMs: Date.now() - startedAt, error };
67813
67935
  }
67814
67936
  }
67815
- var import_node_fs25, import_promises13, import_node_os11, import_node_path30, DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC, DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC, XMTP_CLIENT_RECYCLE_INTERVAL_ENV, HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS, AUTH_RECOVERY_PROBE_INTERVAL_MS, AgentRefreshAuthGate, AgentRefreshCoordinator, ListenerDeferredTaskScheduler, ListenerMaintenanceGate, UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY, SHUTDOWN_FORCE_RESOLVE_MS;
67937
+ var import_node_fs25, import_promises13, import_node_os11, import_node_path30, DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC, DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC, XMTP_CLIENT_RECYCLE_INTERVAL_ENV, HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS, AUTH_RECOVERY_PROBE_INTERVAL_MS, AUTH_RECOVERY_REFRESH_BACKOFF_MS, AgentRefreshAuthGate, AgentRefreshCoordinator, ListenerDeferredTaskScheduler, ListenerMaintenanceGate, UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY, SHUTDOWN_FORCE_RESOLVE_MS;
67816
67938
  var init_listener = __esm({
67817
67939
  "src/listener.ts"() {
67818
67940
  "use strict";
@@ -67846,6 +67968,7 @@ var init_listener = __esm({
67846
67968
  XMTP_CLIENT_RECYCLE_INTERVAL_ENV = "OKX_A2A_XMTP_CLIENT_RECYCLE_INTERVAL_SEC";
67847
67969
  HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS = 2e3;
67848
67970
  AUTH_RECOVERY_PROBE_INTERVAL_MS = 6e4;
67971
+ AUTH_RECOVERY_REFRESH_BACKOFF_MS = [6e4, 12e4, 3e5];
67849
67972
  AgentRefreshAuthGate = class {
67850
67973
  authBlocked = false;
67851
67974
  get blocked() {
@@ -67870,6 +67993,8 @@ var init_listener = __esm({
67870
67993
  authGate = new AgentRefreshAuthGate();
67871
67994
  refreshInFlight = null;
67872
67995
  recoveryProbeInFlight = null;
67996
+ recoveryRefreshFailureCount = 0;
67997
+ nextRecoveryRefreshAtMs = 0;
67873
67998
  get blocked() {
67874
67999
  return this.authGate.blocked;
67875
68000
  }
@@ -67878,6 +68003,8 @@ var init_listener = __esm({
67878
68003
  try {
67879
68004
  const result = await this.options.lookup(previousFingerprint);
67880
68005
  this.authGate.recordSuccess();
68006
+ this.recoveryRefreshFailureCount = 0;
68007
+ this.nextRecoveryRefreshAtMs = 0;
67881
68008
  if (wasBlocked) {
67882
68009
  this.options.onAuthRecovered?.();
67883
68010
  }
@@ -67899,7 +68026,7 @@ var init_listener = __esm({
67899
68026
  return this.runRefresh();
67900
68027
  }
67901
68028
  runRecoveryProbe() {
67902
- if (this.options.isStopping() || !this.authGate.blocked || !this.options.checkLoggedIn) {
68029
+ if (this.options.isStopping() || !this.authGate.blocked || !this.options.checkLoggedIn || this.now() < this.nextRecoveryRefreshAtMs) {
67903
68030
  return Promise.resolve(null);
67904
68031
  }
67905
68032
  if (this.recoveryProbeInFlight) {
@@ -67911,8 +68038,15 @@ var init_listener = __esm({
67911
68038
  return null;
67912
68039
  }
67913
68040
  const refresh = await this.runRefresh();
67914
- return this.authGate.blocked ? null : refresh;
67915
- })().finally(() => {
68041
+ if (this.authGate.blocked) {
68042
+ this.recordRecoveryRefreshFailure();
68043
+ return null;
68044
+ }
68045
+ return refresh;
68046
+ })().catch((err2) => {
68047
+ this.recordRecoveryRefreshFailure();
68048
+ throw err2;
68049
+ }).finally(() => {
67916
68050
  this.recoveryProbeInFlight = null;
67917
68051
  });
67918
68052
  return this.recoveryProbeInFlight;
@@ -67926,6 +68060,17 @@ var init_listener = __esm({
67926
68060
  });
67927
68061
  return this.refreshInFlight;
67928
68062
  }
68063
+ now() {
68064
+ return this.options.now?.() ?? Date.now();
68065
+ }
68066
+ recordRecoveryRefreshFailure() {
68067
+ const backoffIndex = Math.min(
68068
+ this.recoveryRefreshFailureCount,
68069
+ AUTH_RECOVERY_REFRESH_BACKOFF_MS.length - 1
68070
+ );
68071
+ this.nextRecoveryRefreshAtMs = this.now() + AUTH_RECOVERY_REFRESH_BACKOFF_MS[backoffIndex];
68072
+ this.recoveryRefreshFailureCount += 1;
68073
+ }
67929
68074
  };
67930
68075
  ListenerDeferredTaskScheduler = class {
67931
68076
  timers = /* @__PURE__ */ new Set();
@@ -112545,6 +112690,13 @@ async function watchUserAttention(store, parsed, json) {
112545
112690
  throw new Error("--from-now has been removed; user watch always returns existing pending items first");
112546
112691
  }
112547
112692
  const jobId = normalizeWatchJobId(parsed.options.get("job-id"));
112693
+ if (jobId) {
112694
+ setJobProviderToCurrentPlatform({
112695
+ store,
112696
+ jobId,
112697
+ env: process.env
112698
+ });
112699
+ }
112548
112700
  const provider = readProviderFilter(store, parsed, jobId);
112549
112701
  const preparation = await prepareRuntimeSelectionForWatchedJob(store, jobId, json);
112550
112702
  assertWatchedJobPrepared(jobId, preparation, json);
@@ -113392,6 +113544,7 @@ var init_user_attention_cli = __esm({
113392
113544
  init_session_store();
113393
113545
  init_user_attention_ipc();
113394
113546
  init_ai_provider();
113547
+ init_job_provider();
113395
113548
  init_outbound_behavior();
113396
113549
  init_openclaw_gateway();
113397
113550
  init_openclaw_gateway_config();
@@ -115755,7 +115908,7 @@ async function getCurrentNodeCliVersion() {
115755
115908
  return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
115756
115909
  }
115757
115910
  function getBundledNodeCliVersion() {
115758
- return true ? "0.2.4-beta-e7a52faf6f-260812104443" : null;
115911
+ return true ? "0.2.4" : null;
115759
115912
  }
115760
115913
  function readConfiguredAiProvider() {
115761
115914
  const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
@@ -115965,7 +116118,7 @@ async function updateHermes(release, options) {
115965
116118
  }
115966
116119
  }
115967
116120
  async function installGatewayPluginForDoctor(target) {
115968
- const release = isPrereleaseVersion("0.2.4-beta-e7a52faf6f-260812104443") ? "beta" : "latest";
116121
+ const release = isPrereleaseVersion("0.2.4") ? "beta" : "latest";
115969
116122
  const insideTargetGateway = detectGatewayInvocation() === target;
115970
116123
  const options = {
115971
116124
  restart: !insideTargetGateway,
@@ -117008,7 +117161,7 @@ async function runDoctor(options = {}) {
117008
117161
  platform: options.platform ?? process.platform,
117009
117162
  env: options.env ?? process.env,
117010
117163
  target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
117011
- cliVersion: options.cliVersion ?? (true ? "0.2.4-beta-e7a52faf6f-260812104443" : "0.0.0"),
117164
+ cliVersion: options.cliVersion ?? (true ? "0.2.4" : "0.0.0"),
117012
117165
  fixMode: options.fix === true,
117013
117166
  nonInteractive: options.nonInteractive === true,
117014
117167
  packageChanged: false,
@@ -117996,6 +118149,7 @@ init_command_store();
117996
118149
  init_file_store();
117997
118150
  init_ai_provider();
117998
118151
  init_runtime_switch();
118152
+ init_job_provider();
117999
118153
  init_session_store();
118000
118154
  init_paths();
118001
118155
  init_task_config();
@@ -118005,7 +118159,7 @@ init_sentry_logger();
118005
118159
  init_sentry_config();
118006
118160
  var CURRENT_GATEWAY_SESSION_KEYS_ENV4 = "OKX_A2A_CURRENT_GATEWAY_SESSION_KEYS";
118007
118161
  function printUsage3() {
118008
- console.log(`okx-a2a ${"0.2.4-beta-e7a52faf6f-260812104443"}
118162
+ console.log(`okx-a2a ${"0.2.4"}
118009
118163
 
118010
118164
  Usage:
118011
118165
  okx-a2a <command> [options]
@@ -118045,7 +118199,7 @@ Run \`okx-a2a <command> -h\` for command-specific help.
118045
118199
  `);
118046
118200
  }
118047
118201
  function printVersion() {
118048
- console.log("0.2.4-beta-e7a52faf6f-260812104443");
118202
+ console.log("0.2.4");
118049
118203
  }
118050
118204
  function printDaemonUsage() {
118051
118205
  console.log(`Usage: okx-a2a daemon <start|restart|stop|status|autostart> [options]
@@ -119184,8 +119338,11 @@ async function handleJobProvider(args) {
119184
119338
  }
119185
119339
  if (subcommand === "set") {
119186
119340
  const jobId = readRequiredOption4(rest, "--job-id");
119187
- const provider = normalizeAiProvider(readRequiredOption4(rest, "--provider"));
119188
- const binding = store.setJobProviderBinding({ jobId, provider });
119341
+ const binding = setJobProvider({
119342
+ store,
119343
+ jobId,
119344
+ provider: readRequiredOption4(rest, "--provider")
119345
+ });
119189
119346
  if (json) {
119190
119347
  console.log(JSON.stringify({ ok: true, binding }));
119191
119348
  } else {
@@ -119481,7 +119638,7 @@ async function main() {
119481
119638
  if (command === "xmtp-test") {
119482
119639
  const { handleXmtpTestCommand: handleXmtpTestCommand2 } = await Promise.resolve().then(() => (init_xmtp_test_cli(), xmtp_test_cli_exports));
119483
119640
  await handleXmtpTestCommand2(process.argv.slice(3), {
119484
- packageVersion: "0.2.4-beta-e7a52faf6f-260812104443",
119641
+ packageVersion: "0.2.4",
119485
119642
  agentSdkVersion: "2.3.0",
119486
119643
  nodeSdkVersion: "6.1.0",
119487
119644
  nodeBindingsVersion: "1.11.0"