@okxweb3/a2a-node 0.2.8 → 0.2.9-beta-912b775358-260824171011

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 +760 -112
  2. package/dist/index.js +725 -91
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3992,7 +3992,7 @@ var require_is = __commonJS({
3992
3992
  function isPrimitive(wat) {
3993
3993
  return wat === null || typeof wat !== "object" && typeof wat !== "function";
3994
3994
  }
3995
- function isPlainObject4(wat) {
3995
+ function isPlainObject6(wat) {
3996
3996
  return isBuiltin(wat, "Object");
3997
3997
  }
3998
3998
  function isEvent(wat) {
@@ -4008,7 +4008,7 @@ var require_is = __commonJS({
4008
4008
  return Boolean(wat && wat.then && typeof wat.then === "function");
4009
4009
  }
4010
4010
  function isSyntheticEvent(wat) {
4011
- return isPlainObject4(wat) && "nativeEvent" in wat && "preventDefault" in wat && "stopPropagation" in wat;
4011
+ return isPlainObject6(wat) && "nativeEvent" in wat && "preventDefault" in wat && "stopPropagation" in wat;
4012
4012
  }
4013
4013
  function isNaN2(wat) {
4014
4014
  return typeof wat === "number" && wat !== wat;
@@ -4031,7 +4031,7 @@ var require_is = __commonJS({
4031
4031
  exports2.isEvent = isEvent;
4032
4032
  exports2.isInstanceOf = isInstanceOf;
4033
4033
  exports2.isNaN = isNaN2;
4034
- exports2.isPlainObject = isPlainObject4;
4034
+ exports2.isPlainObject = isPlainObject6;
4035
4035
  exports2.isPrimitive = isPrimitive;
4036
4036
  exports2.isRegExp = isRegExp;
4037
4037
  exports2.isString = isString;
@@ -19284,6 +19284,17 @@ var init_events = __esm({
19284
19284
  SYSTEM_NOTIFICATION_ROUTED: "System notification routed",
19285
19285
  HERMES_SESSION_ROUTE_BINDING: "Hermes session route binding",
19286
19286
  DOCTOR_REPORT: "Doctor report",
19287
+ // Paginated WakeupNotify recovery (BL-011) + bounded AI concurrency telemetry.
19288
+ // All info-level events below must ALSO be listed in SENTRY_INFO_ALLOWLIST
19289
+ // (index.ts) or info() drops them silently.
19290
+ WAKEUP_PULL_STARTED: "WakeupNotify pull started",
19291
+ WAKEUP_PULL_PAGE_FETCHED: "WakeupNotify pull page fetched",
19292
+ WAKEUP_PULL_PAGE_RETRY: "WakeupNotify pull page retry",
19293
+ WAKEUP_PULL_COMPLETED: "WakeupNotify pull completed",
19294
+ WAKEUP_NOTIFICATION_REJECTED: "WakeupNotify notification rejected",
19295
+ WAKEUP_CHUNK_DISPATCHED: "WakeupNotify chunk dispatched",
19296
+ WAKEUP_IN_MEMORY_WORK_DROPPED: "WakeupNotify in-memory work dropped",
19297
+ AI_CONCURRENCY_SNAPSHOT: "AI concurrency snapshot",
19287
19298
  // ── error ─────────────────────────────────────────────────────
19288
19299
  XMTP_CONNECTION_FAILED: "XMTP connection failed",
19289
19300
  CONVERSATIONS_STREAM_FAILED: "conversations.stream failed",
@@ -19338,6 +19349,7 @@ var init_events = __esm({
19338
19349
  AI_RUN_TOOL_FAILED: "AI run tool failed",
19339
19350
  IPC_FAILED: "IPC failed",
19340
19351
  NOTIFY_AGENTS_WAKEUP_FAILED: "Notify agents wakeup failed",
19352
+ WAKEUP_PULL_FAILED: "WakeupNotify pull failed",
19341
19353
  OUTBOUND_AGENT_LOOKUP_FAILED: "Outbound agent lookup failed",
19342
19354
  OUTBOUND_ELIGIBILITY_CHECK_FAILED: "Outbound eligibility check failed",
19343
19355
  OUTBOUND_ELIGIBILITY_BYPASSED: "Outbound eligibility bypassed",
@@ -20145,6 +20157,15 @@ var init_sentry_logger = __esm({
20145
20157
  LogEvent.USER_CHANNEL_MESSAGE_DELIVERED,
20146
20158
  LogEvent.SYSTEM_NOTIFICATION_RECEIVED,
20147
20159
  LogEvent.SYSTEM_NOTIFICATION_ROUTED,
20160
+ // Paginated WakeupNotify recovery (BL-011) + bounded AI concurrency telemetry.
20161
+ LogEvent.WAKEUP_PULL_STARTED,
20162
+ LogEvent.WAKEUP_PULL_PAGE_FETCHED,
20163
+ LogEvent.WAKEUP_PULL_PAGE_RETRY,
20164
+ LogEvent.WAKEUP_PULL_COMPLETED,
20165
+ LogEvent.WAKEUP_NOTIFICATION_REJECTED,
20166
+ LogEvent.WAKEUP_CHUNK_DISPATCHED,
20167
+ LogEvent.WAKEUP_IN_MEMORY_WORK_DROPPED,
20168
+ LogEvent.AI_CONCURRENCY_SNAPSHOT,
20148
20169
  LogEvent.HERMES_SESSION_ROUTE_BINDING,
20149
20170
  LogEvent.INBOUND_BLOCKED_ADDRESS_MISMATCH,
20150
20171
  LogEvent.INBOUND_BLOCKED_INELIGIBLE,
@@ -30985,7 +31006,7 @@ var require_websocket2 = __commonJS({
30985
31006
  var http2 = require("http");
30986
31007
  var net = require("net");
30987
31008
  var tls = require("tls");
30988
- var { randomBytes: randomBytes3, createHash: createHash6 } = require("crypto");
31009
+ var { randomBytes: randomBytes3, createHash: createHash7 } = require("crypto");
30989
31010
  var { Duplex, Readable } = require("stream");
30990
31011
  var { URL: URL2 } = require("url");
30991
31012
  var PerMessageDeflate = require_permessage_deflate();
@@ -31645,7 +31666,7 @@ var require_websocket2 = __commonJS({
31645
31666
  abortHandshake(websocket, socket, "Invalid Upgrade header");
31646
31667
  return;
31647
31668
  }
31648
- const digest = createHash6("sha1").update(key + GUID).digest("base64");
31669
+ const digest = createHash7("sha1").update(key + GUID).digest("base64");
31649
31670
  if (res.headers["sec-websocket-accept"] !== digest) {
31650
31671
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
31651
31672
  return;
@@ -32012,7 +32033,7 @@ var require_websocket_server = __commonJS({
32012
32033
  var EventEmitter2 = require("events");
32013
32034
  var http2 = require("http");
32014
32035
  var { Duplex } = require("stream");
32015
- var { createHash: createHash6 } = require("crypto");
32036
+ var { createHash: createHash7 } = require("crypto");
32016
32037
  var extension = require_extension();
32017
32038
  var PerMessageDeflate = require_permessage_deflate();
32018
32039
  var subprotocol = require_subprotocol();
@@ -32313,7 +32334,7 @@ var require_websocket_server = __commonJS({
32313
32334
  );
32314
32335
  }
32315
32336
  if (this._state > RUNNING) return abortHandshake(socket, 503);
32316
- const digest = createHash6("sha1").update(key + GUID).digest("base64");
32337
+ const digest = createHash7("sha1").update(key + GUID).digest("base64");
32317
32338
  const headers = [
32318
32339
  "HTTP/1.1 101 Switching Protocols",
32319
32340
  "Upgrade: websocket",
@@ -32435,7 +32456,7 @@ var init_sentry_config = __esm({
32435
32456
  environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
32436
32457
  SENTRY_CONFIG = {
32437
32458
  projectName: "okx/openclaw-okx-a2a-extension",
32438
- release: "0.2.8",
32459
+ release: "0.2.9-beta-912b775358-260824171011",
32439
32460
  environment,
32440
32461
  runtimeContainer: normalizeRuntimeContainer(process.env.OKX_A2A_RUNTIME_CONTAINER)
32441
32462
  };
@@ -33376,7 +33397,7 @@ async function getCurrentNodeCliVersion() {
33376
33397
  return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
33377
33398
  }
33378
33399
  function getBundledNodeCliVersion() {
33379
- return true ? "0.2.8" : null;
33400
+ return true ? "0.2.9-beta-912b775358-260824171011" : null;
33380
33401
  }
33381
33402
  function readConfiguredAiProvider() {
33382
33403
  const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
@@ -33586,7 +33607,7 @@ async function updateHermes(release, options) {
33586
33607
  }
33587
33608
  }
33588
33609
  async function installGatewayPluginForDoctor(target) {
33589
- const release = isPrereleaseVersion("0.2.8") ? "beta" : "latest";
33610
+ const release = isPrereleaseVersion("0.2.9-beta-912b775358-260824171011") ? "beta" : "latest";
33590
33611
  const insideTargetGateway = detectGatewayInvocation() === target;
33591
33612
  const options = {
33592
33613
  restart: !insideTargetGateway,
@@ -44299,6 +44320,7 @@ __export(index_exports, {
44299
44320
  CODEX_RECOVERY_ACTIONS: () => CODEX_RECOVERY_ACTIONS,
44300
44321
  CommandStore: () => CommandStore,
44301
44322
  DEFAULT_AI_PERMISSION_PRESET: () => DEFAULT_AI_PERMISSION_PRESET,
44323
+ DEFAULT_MAX_ACTIVE_AI_EXECUTIONS: () => DEFAULT_MAX_ACTIVE_AI_EXECUTIONS,
44302
44324
  DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC: () => DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC,
44303
44325
  DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC: () => DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC,
44304
44326
  DOCTOR_MIN_NODE_VERSION: () => DOCTOR_MIN_NODE_VERSION,
@@ -44327,6 +44349,7 @@ __export(index_exports, {
44327
44349
  USER_ATTENTION_WATCH_PARENT_CHECK_MS: () => USER_ATTENTION_WATCH_PARENT_CHECK_MS,
44328
44350
  USER_ATTENTION_WATCH_REPLACED_MESSAGE: () => USER_ATTENTION_WATCH_REPLACED_MESSAGE,
44329
44351
  UserCancelledAiProviderSelectionError: () => UserCancelledAiProviderSelectionError,
44352
+ WAKEUP_PAGE_SIZE: () => WAKEUP_PAGE_SIZE,
44330
44353
  WALLET_STATUS_TIMEOUT_MS: () => WALLET_STATUS_TIMEOUT_MS,
44331
44354
  XMTP_CLIENT_RECYCLE_INTERVAL_ENV: () => XMTP_CLIENT_RECYCLE_INTERVAL_ENV,
44332
44355
  XmtpDm: () => Dm,
@@ -44352,6 +44375,7 @@ __export(index_exports, {
44352
44375
  buildCodexRecoveryGuidance: () => buildCodexRecoveryGuidance,
44353
44376
  buildDispatchSessionKey: () => buildDispatchSessionKey,
44354
44377
  buildDoctorSentryExtra: () => buildDoctorSentryExtra,
44378
+ buildDroppedWorkTelemetry: () => buildDroppedWorkTelemetry,
44355
44379
  buildExternalCommandInvocation: () => buildExternalCommandInvocation,
44356
44380
  buildGatewayOutboundExtra: () => buildGatewayOutboundExtra,
44357
44381
  buildInboundTerminalExtras: () => buildInboundTerminalExtras,
@@ -44391,9 +44415,11 @@ __export(index_exports, {
44391
44415
  commandExists: () => commandExists,
44392
44416
  createAiToolFailureTracker: () => createAiToolFailureTracker,
44393
44417
  createFileMessageHandler: () => createFileMessageHandler,
44418
+ createOnchainosWakeupFetchPage: () => createOnchainosWakeupFetchPage,
44394
44419
  createOutboundBehavior: () => createOutboundBehavior,
44395
44420
  createUserAttentionWatchParentMonitor: () => createUserAttentionWatchParentMonitor,
44396
44421
  currentOpenClawGatewaySessionKey: () => currentOpenClawGatewaySessionKey,
44422
+ deriveWakeupDedupeKey: () => deriveWakeupDedupeKey,
44397
44423
  detectAiProviders: () => detectAiProviders,
44398
44424
  detectAiRuntimeSurface: () => detectAiRuntimeSurface,
44399
44425
  detectCurrentAiProvider: () => detectCurrentAiProvider,
@@ -44409,7 +44435,9 @@ __export(index_exports, {
44409
44435
  exportDiagnosticLogs: () => exportDiagnosticLogs,
44410
44436
  extractAiSessionId: () => extractAiSessionId,
44411
44437
  extractDirectToUserNotification: () => extractDirectToUserNotification,
44438
+ extractSystemNotification: () => extractSystemNotification,
44412
44439
  extractXmtpSentAtMs: () => extractXmtpSentAtMs2,
44440
+ fetchAllWakeupNotifications: () => fetchAllWakeupNotifications,
44413
44441
  findWindowsNativeOkxA2aExe: () => findWindowsNativeOkxA2aExe,
44414
44442
  followFile: () => followFile,
44415
44443
  formatDoctorReportForHumans: () => formatDoctorReportForHumans,
@@ -44427,6 +44455,7 @@ __export(index_exports, {
44427
44455
  hashDiagnosticFileContent: () => hashDiagnosticFileContent,
44428
44456
  heartbeatUserAttentionWatcher: () => heartbeatUserAttentionWatcher,
44429
44457
  hermesConfigEnablesOkxA2a: () => hermesConfigEnablesOkxA2a,
44458
+ ingestWakeupNotification: () => ingestWakeupNotification,
44430
44459
  installSystemdAutostart: () => installSystemdAutostart,
44431
44460
  installWindowsNativeLauncher: () => installWindowsNativeLauncher,
44432
44461
  installedAutostartHasCurrentConfiguration: () => installedAutostartHasCurrentConfiguration,
@@ -44445,12 +44474,15 @@ __export(index_exports, {
44445
44474
  isSqliteBusyError: () => isSqliteBusyError,
44446
44475
  isSystemdManagerUnavailableMessage: () => isSystemdManagerUnavailableMessage,
44447
44476
  isTagKey: () => isTagKey,
44477
+ isValidWakeupItem: () => isValidWakeupItem,
44448
44478
  isWindowsElevated: () => isWindowsElevated,
44449
44479
  killProcessTree: () => killProcessTree,
44450
44480
  launchdPlistHasCurrentRestartPolicy: () => launchdPlistHasCurrentRestartPolicy,
44451
44481
  listAllAgentsWithMetadata: () => listAllAgentsWithMetadata,
44482
+ logDroppedWakeupWorkOnShutdown: () => logDroppedWakeupWorkOnShutdown,
44452
44483
  logWinCompat: () => logWinCompat,
44453
44484
  logXmtpMessageSent: () => logXmtpMessageSent,
44485
+ mapCliStdoutToWakeupResponse: () => mapCliStdoutToWakeupResponse,
44454
44486
  maybeRecommendOnchainosUpgrade: () => maybeRecommendOnchainosUpgrade,
44455
44487
  mergeA2AEnvelopeTips: () => mergeA2AEnvelopeTips,
44456
44488
  messageEligibleHelpAdvertisesOfflineReplay: () => messageEligibleHelpAdvertisesOfflineReplay,
@@ -44506,6 +44538,7 @@ __export(index_exports, {
44506
44538
  resolveDirectCommunicationSessionTarget: () => resolveDirectCommunicationSessionTarget,
44507
44539
  resolveDoctorTarget: () => resolveDoctorTarget,
44508
44540
  resolveEnvelopePayload: () => resolveEnvelopePayload,
44541
+ resolveMaxActiveAiExecutions: () => resolveMaxActiveAiExecutions,
44509
44542
  resolveNpmCmdShimScript: () => resolveNpmCmdShimScript,
44510
44543
  resolveOfflineReplayCapabilityMarker: () => resolveOfflineReplayCapabilityMarker,
44511
44544
  resolveOfflineReplayIntervalSec: () => resolveOfflineReplayIntervalSec,
@@ -44519,6 +44552,7 @@ __export(index_exports, {
44519
44552
  resolveTaskHome: () => resolveTaskHome,
44520
44553
  resolveTaskPaths: () => resolveTaskPaths,
44521
44554
  resolveUserAttentionIpcPath: () => resolveUserAttentionIpcPath,
44555
+ resolveWakeupChunkSize: () => resolveWakeupChunkSize,
44522
44556
  resolveWindowsAutostartPaths: () => resolveWindowsAutostartPaths,
44523
44557
  resolveXmtpClientRecycleIntervalSec: () => resolveXmtpClientRecycleIntervalSec,
44524
44558
  restartSystemdAutostart: () => restartSystemdAutostart,
@@ -44539,6 +44573,7 @@ __export(index_exports, {
44539
44573
  startDaemonRespectingSupervisor: () => startDaemonRespectingSupervisor,
44540
44574
  startUserAttentionEventServer: () => startUserAttentionEventServer,
44541
44575
  startUserAttentionWatcherCoordinator: () => startUserAttentionWatcherCoordinator,
44576
+ startWakeupNotifyPull: () => startWakeupNotifyPull,
44542
44577
  stopDaemon: () => stopDaemon,
44543
44578
  stopOpenClawGateway: () => stopOpenClawGateway,
44544
44579
  stopSystemdAutostart: () => stopSystemdAutostart,
@@ -48170,6 +48205,34 @@ var CommandStore = class {
48170
48205
  }
48171
48206
  return null;
48172
48207
  }
48208
+ /**
48209
+ * Read-only lookup of a command's current lifecycle state by id. Returns null
48210
+ * when no row exists. Used by the WakeupNotify recovery reconcile to decide
48211
+ * whether an in-flight wakeup's command completed, failed, or was orphaned by a
48212
+ * crash — it does not mutate the queue or alter recovery behavior.
48213
+ */
48214
+ getCommandState(commandId) {
48215
+ const row = this.db.prepare(`
48216
+ SELECT status, result_json, processing_started_at_ms FROM command_queue
48217
+ WHERE id = ?
48218
+ `).get(commandId);
48219
+ if (!row?.status) {
48220
+ return null;
48221
+ }
48222
+ let ok = null;
48223
+ if (row.result_json) {
48224
+ try {
48225
+ ok = Boolean(JSON.parse(row.result_json).ok);
48226
+ } catch {
48227
+ ok = null;
48228
+ }
48229
+ }
48230
+ return {
48231
+ status: row.status,
48232
+ ok,
48233
+ processingStartedAtMs: row.processing_started_at_ms ?? null
48234
+ };
48235
+ }
48173
48236
  close() {
48174
48237
  this.db.close();
48175
48238
  }
@@ -58251,36 +58314,15 @@ var XmtpService = class _XmtpService {
58251
58314
  timer
58252
58315
  });
58253
58316
  }
58254
- notifyAgentsWakeupAfterReplay() {
58255
- const notifyAgentsWakeup2 = this.tools.notifyAgentsWakeup;
58256
- const agentIds = this.allAgents.map((agent) => agent.agentId);
58257
- if (!notifyAgentsWakeup2 || agentIds.length === 0) {
58258
- return;
58259
- }
58260
- void notifyAgentsWakeup2(agentIds).then(() => {
58261
- logger.info(LogEvent.AGENTS_WAKEUP_NOTIFIED, {
58262
- count: String(agentIds.length),
58263
- onchainosAgentIds: agentIds.join(","),
58264
- stage: "after-startup-replay"
58265
- });
58266
- }).catch((err) => {
58267
- logWithTimestamp("[xmtp-sdk] notifyAgentsWakeup unexpected error:", err);
58268
- logger.error(
58269
- LogEvent.NOTIFY_AGENTS_WAKEUP_FAILED,
58270
- err instanceof Error ? err : new Error(String(err)),
58271
- {
58272
- count: String(agentIds.length),
58273
- stage: "after-startup-replay"
58274
- }
58275
- );
58276
- });
58277
- }
58278
58317
  /**
58279
58318
  * Completes the startup handoff from stored history to the live stream.
58280
58319
  * Listeners are already attached, but their host handlers stay buffered
58281
- * until replay finishes and the buffer is drained. Only then do we tell
58282
- * the backend that the agents are awake, so wakeup-triggered messages
58283
- * cannot overtake the stored backlog.
58320
+ * until replay finishes and the buffer is drained.
58321
+ *
58322
+ * Telling the backend the agents are awake is deliberately NOT done here.
58323
+ * The daemon (listener.ts) runs the paginated task-wakeup pull AFTER the bounded
58324
+ * command processor is ready, so wakeup-triggered work cannot be dispatched
58325
+ * before the processor exists.
58284
58326
  */
58285
58327
  async completeStartupReplay() {
58286
58328
  const startupGates = new Map(
@@ -58295,7 +58337,6 @@ var XmtpService = class _XmtpService {
58295
58337
  }
58296
58338
  this.resolveStartupReplayCompletion?.();
58297
58339
  this.resolveStartupReplayCompletion = void 0;
58298
- this.notifyAgentsWakeupAfterReplay();
58299
58340
  return summary;
58300
58341
  }
58301
58342
  async startListeningForAddresses(addresses) {
@@ -59967,39 +60008,6 @@ function fingerprintAgents(agents) {
59967
60008
  function filterNoisyAgentIdentityLog(stderr) {
59968
60009
  return stderr.split(/\r?\n/).filter((line) => !line.includes("[agent-identity] get response")).join("\n").trim();
59969
60010
  }
59970
- function previewLogText(value, max = 300) {
59971
- const normalized = value.replace(/\s+/g, " ").trim();
59972
- return normalized.length > max ? `${normalized.slice(0, max)}...` : normalized;
59973
- }
59974
- async function notifyAgentsWakeup(agentIds) {
59975
- if (agentIds.length === 0) {
59976
- logWithTimestamp("[onchainos] wakeup-notify: agentIds empty, skipping");
59977
- return;
59978
- }
59979
- const ids = agentIds.join(",");
59980
- logWithTimestamp(`[onchainos] sending wakeup-notify (agent-ids=${ids})`);
59981
- try {
59982
- const { stdout, stderr } = await exec([
59983
- "agent",
59984
- "wakeup-notify",
59985
- "--agent-ids",
59986
- ids
59987
- ]);
59988
- if (stderr) {
59989
- logWithTimestamp(`[onchainos] stderr (wakeup-notify): ${stderr}`);
59990
- }
59991
- logWithTimestamp(
59992
- `[onchainos] wakeup-notify result agentIds=${ids} stdoutBytes=${Buffer.byteLength(stdout ?? "", "utf8")} stdoutPreview=${previewLogText(stdout ?? "")}`
59993
- );
59994
- logWithTimestamp(`[onchainos] wakeup-notify succeeded (agent-ids=${ids})`);
59995
- } catch (err) {
59996
- guardCatchSessionExpired2(err, "wakeup-notify");
59997
- logWithTimestamp(
59998
- `[onchainos] wakeup-notify failed (agent-ids=${ids}):`,
59999
- err?.message ?? err
60000
- );
60001
- }
60002
- }
60003
60011
  async function sendHeartbeat(chainIndex) {
60004
60012
  logWithTimestamp(`[onchainos] sending heartbeat (chain-index=${chainIndex})`);
60005
60013
  try {
@@ -60933,7 +60941,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
60933
60941
  client: {
60934
60942
  id: "gateway-client",
60935
60943
  displayName: "okx-a2a-node",
60936
- version: "0.2.8",
60944
+ version: "0.2.9-beta-912b775358-260824171011",
60937
60945
  platform: "node",
60938
60946
  mode: "backend",
60939
60947
  instanceId
@@ -60944,7 +60952,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
60944
60952
  commands: [],
60945
60953
  permissions: {},
60946
60954
  locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
60947
- userAgent: `okx-a2a-node/${"0.2.8"}`,
60955
+ userAgent: `okx-a2a-node/${"0.2.9-beta-912b775358-260824171011"}`,
60948
60956
  auth: {
60949
60957
  ...config.token ? { token: config.token } : {},
60950
60958
  ...config.password ? { password: config.password } : {}
@@ -64032,6 +64040,23 @@ function isRecord5(value) {
64032
64040
  return !!value && typeof value === "object" && !Array.isArray(value);
64033
64041
  }
64034
64042
 
64043
+ // src/ai-concurrency-config.ts
64044
+ var DEFAULT_MAX_ACTIVE_AI_EXECUTIONS = 4;
64045
+ function resolveMaxActiveAiExecutions(env = process.env) {
64046
+ const raw = env.OKX_A2A_MAX_ACTIVE_AI_EXECUTIONS ?? env.OKX_AGENT_TASK_MAX_ACTIVE_AI_EXECUTIONS;
64047
+ if (raw === void 0 || raw.trim() === "") {
64048
+ return { limit: DEFAULT_MAX_ACTIVE_AI_EXECUTIONS, anomaly: null };
64049
+ }
64050
+ const parsed = Number(raw);
64051
+ if (Number.isFinite(parsed) && Number.isInteger(parsed) && parsed > 0) {
64052
+ return { limit: parsed, anomaly: null };
64053
+ }
64054
+ return {
64055
+ limit: DEFAULT_MAX_ACTIVE_AI_EXECUTIONS,
64056
+ anomaly: `invalid value "${raw}", using default ${DEFAULT_MAX_ACTIVE_AI_EXECUTIONS}`
64057
+ };
64058
+ }
64059
+
64035
64060
  // src/command-processor.ts
64036
64061
  var DEFAULT_COMMAND_EXECUTION_TIMEOUT_MS = 5e4;
64037
64062
  var DEFAULT_COMMAND_STALE_TIMEOUT_MS = 12e4;
@@ -64085,6 +64110,17 @@ function startCommandProcessor(params) {
64085
64110
  const executionTimeoutMs = readPositiveEnv("OKX_A2A_COMMAND_EXECUTION_TIMEOUT_MS", DEFAULT_COMMAND_EXECUTION_TIMEOUT_MS);
64086
64111
  const staleTimeoutMs = readPositiveEnv("OKX_A2A_COMMAND_STALE_TIMEOUT_MS", DEFAULT_COMMAND_STALE_TIMEOUT_MS);
64087
64112
  const aiStaleTimeoutMs = readPositiveEnv("OKX_A2A_AI_COMMAND_STALE_TIMEOUT_MS", DEFAULT_AI_COMMAND_STALE_TIMEOUT_MS);
64113
+ const { limit: maxActiveAiExecutions, anomaly: aiLimitAnomaly } = resolveMaxActiveAiExecutions(process.env);
64114
+ if (aiLimitAnomaly) {
64115
+ logWithTimestamp(`[okx-agent-task] AI concurrency limit config anomaly: ${aiLimitAnomaly}`);
64116
+ logger.info(LogEvent.AI_CONCURRENCY_SNAPSHOT, {
64117
+ component: "node_command_processor",
64118
+ stage: "config",
64119
+ reason: "invalid_config_using_default",
64120
+ configuredLimit: String(maxActiveAiExecutions),
64121
+ anomaly: aiLimitAnomaly
64122
+ });
64123
+ }
64088
64124
  let inFlight = false;
64089
64125
  let aiScanInFlight = false;
64090
64126
  const activeAiQueueKeys = /* @__PURE__ */ new Set();
@@ -64174,6 +64210,9 @@ function startCommandProcessor(params) {
64174
64210
  inFlight = false;
64175
64211
  }
64176
64212
  };
64213
+ const AI_SNAPSHOT_MIN_INTERVAL_MS = 15e3;
64214
+ let lastAiSnapshotSignature = "";
64215
+ let lastAiSnapshotAtMs = 0;
64177
64216
  const aiTick = async () => {
64178
64217
  if (aiScanInFlight) {
64179
64218
  return;
@@ -64186,15 +64225,33 @@ function startCommandProcessor(params) {
64186
64225
  skipCommandIds: activeAiCommandIds
64187
64226
  });
64188
64227
  const pending = await commands.listPendingEntries();
64228
+ const pendingAi = pending.filter((entry) => isAiDispatchCommand(entry.command));
64229
+ if (activeAiCommandIds.size > 0 || pendingAi.length > 0) {
64230
+ const snapshotNow = Date.now();
64231
+ const oldestQueuedAgeMs = pendingAi.reduce((oldest, entry) => {
64232
+ const createdAt = Number.isFinite(entry.command.createdAt) ? entry.command.createdAt : entry.mtimeMs;
64233
+ return Math.max(oldest, snapshotNow - createdAt);
64234
+ }, 0);
64235
+ const snapshotSignature = `${maxActiveAiExecutions}|${activeAiCommandIds.size}|${pendingAi.length}`;
64236
+ if (snapshotSignature !== lastAiSnapshotSignature || snapshotNow - lastAiSnapshotAtMs >= AI_SNAPSHOT_MIN_INTERVAL_MS) {
64237
+ lastAiSnapshotSignature = snapshotSignature;
64238
+ lastAiSnapshotAtMs = snapshotNow;
64239
+ logger.info(LogEvent.AI_CONCURRENCY_SNAPSHOT, {
64240
+ component: "node_command_processor",
64241
+ configuredLimit: String(maxActiveAiExecutions),
64242
+ activeCount: String(activeAiCommandIds.size),
64243
+ queueDepth: String(pendingAi.length),
64244
+ oldestQueuedAgeMs: String(oldestQueuedAgeMs)
64245
+ });
64246
+ }
64247
+ } else {
64248
+ lastAiSnapshotSignature = "";
64249
+ }
64189
64250
  for (const entry of pending) {
64190
64251
  const command = entry.command;
64191
64252
  if (!isAiDispatchCommand(command)) {
64192
64253
  continue;
64193
64254
  }
64194
- const queueKey = buildAiCommandQueueKey(command);
64195
- if (activeAiQueueKeys.has(queueKey)) {
64196
- continue;
64197
- }
64198
64255
  if (isStalePending(entry, aiStaleTimeoutMs)) {
64199
64256
  const message = `${command.type}/${command.kind} command expired after ${formatDuration2(Date.now() - command.createdAt)} in pending queue`;
64200
64257
  await commands.completePending(command, {
@@ -64205,13 +64262,20 @@ function startCommandProcessor(params) {
64205
64262
  stage: "pending",
64206
64263
  ageMs: Date.now() - command.createdAt,
64207
64264
  timeoutMs: aiStaleTimeoutMs,
64208
- reason: "pending_expired"
64265
+ reason: "queue_expired"
64209
64266
  }));
64210
64267
  logWithTimestamp(
64211
64268
  `[okx-agent-task] ${command.type}/${command.kind} command expired id=${command.id}: ${message}`
64212
64269
  );
64213
64270
  continue;
64214
64271
  }
64272
+ if (activeAiCommandIds.size >= maxActiveAiExecutions) {
64273
+ continue;
64274
+ }
64275
+ const queueKey = buildAiCommandQueueKey(command);
64276
+ if (activeAiQueueKeys.has(queueKey)) {
64277
+ continue;
64278
+ }
64215
64279
  const processingPath = await commands.take(command);
64216
64280
  if (!processingPath) {
64217
64281
  continue;
@@ -64784,6 +64848,9 @@ function isStalePending(entry, staleTimeoutMs) {
64784
64848
  return Date.now() - createdAt > staleTimeoutMs;
64785
64849
  }
64786
64850
  function buildAiCommandQueueKey(command) {
64851
+ if (command.jobId) {
64852
+ return `job:${command.jobId}`;
64853
+ }
64787
64854
  if (command.kind === "job-message") {
64788
64855
  return buildDispatchSessionKey(command.jobId, command.sessionAgentId);
64789
64856
  }
@@ -66537,6 +66604,10 @@ function createOnchainosSigner(agent) {
66537
66604
  // src/listener.ts
66538
66605
  init_session_store();
66539
66606
 
66607
+ // src/wakeup-pull.ts
66608
+ init_log();
66609
+ init_sentry_logger();
66610
+
66540
66611
  // src/ai-dispatch-queue.ts
66541
66612
  async function enqueueAiJobMessageDispatch(params) {
66542
66613
  const commands = params.commands ?? new CommandStore(params.homeDir);
@@ -66562,11 +66633,539 @@ async function enqueueAiSessionMessageDispatch(params) {
66562
66633
  return command;
66563
66634
  }
66564
66635
 
66636
+ // src/wakeup-notify-client.ts
66637
+ var import_node_crypto13 = require("node:crypto");
66638
+ var DEFAULT_MAX_PAGE_ATTEMPTS = 3;
66639
+ var DEFAULT_PAGE_RETRY_DELAY_MS = 500;
66640
+ var TRANSIENT_TRANSPORT_PATTERN = /timed out|timeout|ETIMEDOUT|ECONNRESET|ECONNREFUSED|ENOTFOUND|EAI_AGAIN|socket hang up|network/i;
66641
+ function isTransientTransportError(err) {
66642
+ const message = err instanceof Error ? err.message : String(err);
66643
+ return TRANSIENT_TRANSPORT_PATTERN.test(message);
66644
+ }
66645
+ function isPlainObject4(value) {
66646
+ return !!value && typeof value === "object" && !Array.isArray(value);
66647
+ }
66648
+ function isValidWakeupItem(raw) {
66649
+ if (!isPlainObject4(raw)) {
66650
+ return { ok: false, reason: "malformed_item" };
66651
+ }
66652
+ if (typeof raw.agentId !== "string" || raw.agentId.length === 0) {
66653
+ return { ok: false, reason: "missing_agent_id" };
66654
+ }
66655
+ const message = raw.message;
66656
+ if (!isPlainObject4(message) || message.source !== "system") {
66657
+ return { ok: false, reason: "not_system_notification" };
66658
+ }
66659
+ if (message.event !== "wakeup_notify") {
66660
+ return { ok: false, reason: "not_wakeup_notify" };
66661
+ }
66662
+ return {
66663
+ ok: true,
66664
+ item: { agentId: raw.agentId, message }
66665
+ };
66666
+ }
66667
+ function canonicalize(value) {
66668
+ if (Array.isArray(value)) {
66669
+ return value.map(canonicalize);
66670
+ }
66671
+ if (value && typeof value === "object") {
66672
+ const source = value;
66673
+ return Object.keys(source).sort().reduce((acc, key) => {
66674
+ acc[key] = canonicalize(source[key]);
66675
+ return acc;
66676
+ }, {});
66677
+ }
66678
+ return value;
66679
+ }
66680
+ function deriveWakeupDedupeKey(item) {
66681
+ const canonicalMessage = JSON.stringify(canonicalize(item.message ?? {}));
66682
+ const identity = `${item.agentId}
66683
+ ${canonicalMessage}`;
66684
+ return `wakeup:${(0, import_node_crypto13.createHash)("sha256").update(identity).digest("hex").slice(0, 24)}`;
66685
+ }
66686
+ async function fetchAllWakeupNotifications(opts) {
66687
+ const { agentIds, fetchPage, onPage } = opts;
66688
+ const maxPages = opts.maxPages;
66689
+ const maxPageAttempts = opts.maxPageAttempts ?? DEFAULT_MAX_PAGE_ATTEMPTS;
66690
+ const retryDelayMs = opts.retryDelayMs ?? DEFAULT_PAGE_RETRY_DELAY_MS;
66691
+ const sleep4 = opts.sleep ?? ((ms) => new Promise((resolve11) => setTimeout(resolve11, ms)));
66692
+ const isRetryableError = opts.isRetryableError ?? isTransientTransportError;
66693
+ const onRetry = opts.onRetry;
66694
+ const fetchPageWithRetry = async (pageNum) => {
66695
+ let attempt = 0;
66696
+ while (true) {
66697
+ attempt++;
66698
+ try {
66699
+ return await fetchPage({ agentIds, page: pageNum });
66700
+ } catch (err) {
66701
+ if (!isRetryableError(err) || attempt >= maxPageAttempts) {
66702
+ throw err;
66703
+ }
66704
+ onRetry?.({ page: pageNum, attempt, reason: "transient_transport" });
66705
+ await sleep4(retryDelayMs * attempt + Math.floor(Math.random() * (retryDelayMs + 1)));
66706
+ }
66707
+ }
66708
+ };
66709
+ const items = [];
66710
+ const rejects = [];
66711
+ const visited = /* @__PURE__ */ new Set();
66712
+ let pagesFetched = 0;
66713
+ let page = 1;
66714
+ let terminated = "empty";
66715
+ try {
66716
+ while (true) {
66717
+ const resp = await fetchPageWithRetry(page);
66718
+ pagesFetched++;
66719
+ if (resp.code !== 0) {
66720
+ terminated = "business_error";
66721
+ break;
66722
+ }
66723
+ const rawList = resp.data?.list;
66724
+ if (!Array.isArray(rawList)) {
66725
+ rejects.push({ reason: "invalid_response_list" });
66726
+ terminated = "invalid_response";
66727
+ break;
66728
+ }
66729
+ const list = rawList;
66730
+ let itemCount = 0;
66731
+ let rejectedCount = 0;
66732
+ for (const element of list) {
66733
+ const check = isValidWakeupItem(element);
66734
+ if (check.ok) {
66735
+ items.push(check.item);
66736
+ itemCount++;
66737
+ } else {
66738
+ rejects.push({ reason: check.reason });
66739
+ rejectedCount++;
66740
+ }
66741
+ }
66742
+ const nextPage = resp.data?.nextPage;
66743
+ onPage?.({ page, itemCount, rejectedCount, hasNextPage: nextPage != null });
66744
+ if (nextPage === null) {
66745
+ terminated = items.length || rejects.length ? "next_page_null" : "empty";
66746
+ break;
66747
+ }
66748
+ if (typeof nextPage !== "number" || !Number.isInteger(nextPage) || nextPage <= 0) {
66749
+ rejects.push({ reason: "invalid_next_page" });
66750
+ terminated = "invalid_response";
66751
+ break;
66752
+ }
66753
+ visited.add(page);
66754
+ page = nextPage;
66755
+ if (visited.has(page) || maxPages !== void 0 && pagesFetched >= maxPages) {
66756
+ terminated = "max_pages";
66757
+ break;
66758
+ }
66759
+ }
66760
+ } catch {
66761
+ terminated = "transport_error";
66762
+ }
66763
+ const summary = {
66764
+ pagesFetched,
66765
+ received: items.length + rejects.length,
66766
+ persisted: 0,
66767
+ partial: 0,
66768
+ duplicates: 0,
66769
+ rejected: rejects.length,
66770
+ terminated
66771
+ };
66772
+ return { items, summary, rejects };
66773
+ }
66774
+
66775
+ // src/wakeup-notify-ingest.ts
66776
+ var MAX_TARGET_ENQUEUE_ATTEMPTS = 3;
66777
+ async function ingestWakeupNotification(item, deps) {
66778
+ const messageId = deriveWakeupDedupeKey(item);
66779
+ const itemJobId = item.message.jobId ?? null;
66780
+ const rawText = JSON.stringify({ agentId: item.agentId, message: item.message });
66781
+ const notif = extractSystemNotification(JSON.parse(rawText));
66782
+ if (!notif?.agentId) {
66783
+ return {
66784
+ status: "rejected",
66785
+ reason: "invalid_system_notification",
66786
+ dedupeKey: messageId,
66787
+ jobId: itemJobId,
66788
+ targetCount: 0
66789
+ };
66790
+ }
66791
+ const targets = resolveSystemNotificationTargets(
66792
+ { sessionStore: deps.sessionStore, myXmtpAddress: deps.myXmtpAddress ?? "", store: void 0 },
66793
+ notif
66794
+ );
66795
+ let succeeded = 0;
66796
+ let failed = 0;
66797
+ for (const target of targets) {
66798
+ let enqueued = false;
66799
+ for (let attempt = 1; attempt <= MAX_TARGET_ENQUEUE_ATTEMPTS && !enqueued; attempt++) {
66800
+ try {
66801
+ await enqueueAiSessionMessageDispatch({
66802
+ commands: deps.commands,
66803
+ event: {
66804
+ sessionKey: target.sessionKey,
66805
+ content: rawText,
66806
+ messageId,
66807
+ jobId: target.jobId ?? null,
66808
+ agentId: target.agentId ?? null
66809
+ }
66810
+ });
66811
+ enqueued = true;
66812
+ } catch {
66813
+ }
66814
+ }
66815
+ if (enqueued) {
66816
+ succeeded += 1;
66817
+ } else {
66818
+ failed += 1;
66819
+ }
66820
+ }
66821
+ if (targets.length > 0 && succeeded === 0) {
66822
+ return {
66823
+ status: "rejected",
66824
+ reason: "enqueue_failed",
66825
+ dedupeKey: messageId,
66826
+ jobId: notif.jobId ?? null,
66827
+ targetCount: 0,
66828
+ failedTargetCount: failed
66829
+ };
66830
+ }
66831
+ if (failed > 0) {
66832
+ return {
66833
+ status: "partial",
66834
+ reason: "partial_enqueue",
66835
+ dedupeKey: messageId,
66836
+ jobId: notif.jobId ?? null,
66837
+ targetCount: succeeded,
66838
+ failedTargetCount: failed
66839
+ };
66840
+ }
66841
+ return {
66842
+ status: "persisted",
66843
+ dedupeKey: messageId,
66844
+ jobId: notif.jobId ?? null,
66845
+ targetCount: succeeded
66846
+ };
66847
+ }
66848
+
66849
+ // src/wakeup-notify-transport.ts
66850
+ var TASK_WAKEUP_CLI_COMMAND = "task-wakeup";
66851
+ var DEFAULT_CLI_TIMEOUT_MS = 3e4;
66852
+ function withTimeout3(promise, timeoutMs, label) {
66853
+ return new Promise((resolve11, reject) => {
66854
+ const timer = setTimeout(() => {
66855
+ reject(new Error(`${label} timed out after ${timeoutMs}ms`));
66856
+ }, timeoutMs);
66857
+ promise.then(
66858
+ (value) => {
66859
+ clearTimeout(timer);
66860
+ resolve11(value);
66861
+ },
66862
+ (err) => {
66863
+ clearTimeout(timer);
66864
+ reject(err);
66865
+ }
66866
+ );
66867
+ });
66868
+ }
66869
+ function resolveCliTimeoutMs(override) {
66870
+ if (typeof override === "number" && Number.isFinite(override) && override > 0) {
66871
+ return override;
66872
+ }
66873
+ const raw = Number(process.env.OKX_A2A_WAKEUP_CLI_TIMEOUT_MS);
66874
+ return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_CLI_TIMEOUT_MS;
66875
+ }
66876
+ function isPlainObject5(value) {
66877
+ return !!value && typeof value === "object" && !Array.isArray(value);
66878
+ }
66879
+ function mapCliStdoutToWakeupResponse(parsed) {
66880
+ const root = isPlainObject5(parsed) ? parsed : {};
66881
+ const rootData = isPlainObject5(root.data) ? root.data : {};
66882
+ const nestedData = isPlainObject5(rootData.data) ? rootData.data : {};
66883
+ const candidates = [root, rootData, nestedData];
66884
+ let code;
66885
+ let msg;
66886
+ let list = [];
66887
+ let listFound = false;
66888
+ let nextPage = null;
66889
+ let nextPageFound = false;
66890
+ for (const candidate of candidates) {
66891
+ if (code === void 0 && typeof candidate.code === "number" && Number.isFinite(candidate.code)) {
66892
+ code = candidate.code;
66893
+ }
66894
+ if (msg === void 0 && typeof candidate.msg === "string") {
66895
+ msg = candidate.msg;
66896
+ }
66897
+ if (!listFound && Array.isArray(candidate.list)) {
66898
+ list = candidate.list;
66899
+ listFound = true;
66900
+ }
66901
+ if (!nextPageFound && "nextPage" in candidate) {
66902
+ const raw = candidate.nextPage;
66903
+ if (typeof raw === "number" && Number.isFinite(raw)) {
66904
+ nextPage = raw;
66905
+ nextPageFound = true;
66906
+ } else if (raw === null) {
66907
+ nextPage = null;
66908
+ nextPageFound = true;
66909
+ }
66910
+ }
66911
+ }
66912
+ if (code === void 0) {
66913
+ code = root.ok === true ? 0 : 1;
66914
+ }
66915
+ return {
66916
+ code,
66917
+ msg,
66918
+ data: { list: listFound ? list : void 0, nextPage: nextPageFound ? nextPage : void 0 }
66919
+ };
66920
+ }
66921
+ function createOnchainosWakeupFetchPage(deps = {}) {
66922
+ const timeoutMs = resolveCliTimeoutMs(deps.timeoutMs);
66923
+ const exec2 = deps.exec ?? ((args) => exec(args, { timeoutMs }));
66924
+ return async ({ agentIds, page }) => {
66925
+ const { stdout } = await withTimeout3(
66926
+ exec2([
66927
+ "agent",
66928
+ TASK_WAKEUP_CLI_COMMAND,
66929
+ "--agent-ids",
66930
+ agentIds.join(","),
66931
+ "--page",
66932
+ String(page)
66933
+ ]),
66934
+ timeoutMs,
66935
+ `onchainos ${TASK_WAKEUP_CLI_COMMAND}`
66936
+ );
66937
+ const parsed = parseCliJson(stdout, TASK_WAKEUP_CLI_COMMAND, {
66938
+ page: String(page)
66939
+ });
66940
+ return mapCliStdoutToWakeupResponse(parsed);
66941
+ };
66942
+ }
66943
+
66944
+ // src/wakeup-chunk-config.ts
66945
+ function resolveWakeupChunkSize(env = process.env) {
66946
+ const fallback = resolveMaxActiveAiExecutions(env).limit;
66947
+ const raw = env.OKX_A2A_WAKEUP_CHUNK_SIZE;
66948
+ if (raw === void 0 || raw.trim() === "") {
66949
+ return { chunkSize: fallback, anomaly: null };
66950
+ }
66951
+ const parsed = Number(raw);
66952
+ if (Number.isFinite(parsed) && Number.isInteger(parsed) && parsed > 0) {
66953
+ return { chunkSize: parsed, anomaly: null };
66954
+ }
66955
+ return {
66956
+ chunkSize: fallback,
66957
+ anomaly: `invalid value "${raw}", using default ${fallback}`
66958
+ };
66959
+ }
66960
+
66961
+ // src/wakeup-pull.ts
66962
+ function splitIntoChunks(items, size3) {
66963
+ const chunkSize = Math.max(1, size3);
66964
+ const chunks = [];
66965
+ for (let i = 0; i < items.length; i += chunkSize) {
66966
+ chunks.push(items.slice(i, i + chunkSize));
66967
+ }
66968
+ return chunks;
66969
+ }
66970
+ var HeartbeatChunkDispatcher = class {
66971
+ constructor(chunks, deps, shouldContinue) {
66972
+ this.chunks = chunks;
66973
+ this.deps = deps;
66974
+ this.shouldContinue = shouldContinue;
66975
+ }
66976
+ chunks;
66977
+ deps;
66978
+ shouldContinue;
66979
+ index = 0;
66980
+ /** True while a chunk is mid-dispatch (between taking it and its enqueues settling). */
66981
+ dispatching = false;
66982
+ hasPendingChunks() {
66983
+ return this.index < this.chunks.length;
66984
+ }
66985
+ remainingChunks() {
66986
+ return Math.max(0, this.chunks.length - this.index);
66987
+ }
66988
+ /**
66989
+ * Read-only view of the not-yet-started chunks (for shutdown telemetry). `index` has
66990
+ * already advanced past any in-flight chunk, so `chunks.slice(index)` is exactly the work
66991
+ * that has not begun dispatching — the in-flight chunk is excluded from the dropped counts
66992
+ * and reflected only by `inFlightChunk`.
66993
+ */
66994
+ pendingSnapshot() {
66995
+ const notStarted = this.chunks.slice(this.index);
66996
+ let droppedMessages = 0;
66997
+ const jobIds = /* @__PURE__ */ new Set();
66998
+ for (const chunk of notStarted) {
66999
+ for (const item of chunk) {
67000
+ droppedMessages += 1;
67001
+ const jobId = item.message.jobId;
67002
+ if (typeof jobId === "string" && jobId.length > 0) {
67003
+ jobIds.add(jobId);
67004
+ }
67005
+ }
67006
+ }
67007
+ return {
67008
+ remainingChunks: notStarted.length,
67009
+ droppedMessages,
67010
+ pendingJobIds: [...jobIds],
67011
+ inFlightChunk: this.dispatching
67012
+ };
67013
+ }
67014
+ /** Dispatch the next chunk: enqueue every message in it in parallel. No-op when drained. */
67015
+ async dispatchNextChunk() {
67016
+ if (this.shouldContinue && !this.shouldContinue()) {
67017
+ return;
67018
+ }
67019
+ if (this.index >= this.chunks.length) {
67020
+ return;
67021
+ }
67022
+ const chunk = this.chunks[this.index];
67023
+ this.index += 1;
67024
+ const chunkNumber = this.index;
67025
+ this.dispatching = true;
67026
+ let persisted = 0;
67027
+ let partial = 0;
67028
+ let rejected = 0;
67029
+ try {
67030
+ const outcomes = await Promise.allSettled(
67031
+ chunk.map((item) => ingestWakeupNotification(item, this.deps))
67032
+ );
67033
+ for (const outcome of outcomes) {
67034
+ if (outcome.status === "fulfilled") {
67035
+ if (outcome.value.status === "persisted") {
67036
+ persisted += 1;
67037
+ } else if (outcome.value.status === "partial") {
67038
+ partial += 1;
67039
+ } else {
67040
+ rejected += 1;
67041
+ }
67042
+ } else {
67043
+ rejected += 1;
67044
+ }
67045
+ }
67046
+ } finally {
67047
+ this.dispatching = false;
67048
+ }
67049
+ logger.info(LogEvent.WAKEUP_CHUNK_DISPATCHED, {
67050
+ component: "wakeup_pull",
67051
+ chunk: String(chunkNumber),
67052
+ chunkCount: String(this.chunks.length),
67053
+ size: String(chunk.length),
67054
+ persisted: String(persisted),
67055
+ partial: String(partial),
67056
+ rejected: String(rejected)
67057
+ });
67058
+ }
67059
+ };
67060
+ var MAX_LOGGED_PENDING_JOB_IDS = 100;
67061
+ function buildDroppedWorkTelemetry(snapshot) {
67062
+ return {
67063
+ sentry: {
67064
+ component: "wakeup_pull",
67065
+ reason: "daemon_shutdown",
67066
+ remainingChunks: String(snapshot.remainingChunks),
67067
+ droppedMessages: String(snapshot.droppedMessages),
67068
+ affectedJobCount: String(snapshot.pendingJobIds.length),
67069
+ inFlightChunk: String(snapshot.inFlightChunk)
67070
+ },
67071
+ local: {
67072
+ droppedMessages: snapshot.droppedMessages,
67073
+ pendingJobIds: snapshot.pendingJobIds.slice(0, MAX_LOGGED_PENDING_JOB_IDS),
67074
+ jobIdsTruncated: snapshot.pendingJobIds.length > MAX_LOGGED_PENDING_JOB_IDS,
67075
+ inFlightChunk: snapshot.inFlightChunk
67076
+ }
67077
+ };
67078
+ }
67079
+ function logDroppedWakeupWorkOnShutdown(dispatcher) {
67080
+ if (!dispatcher) {
67081
+ return;
67082
+ }
67083
+ const snapshot = dispatcher.pendingSnapshot();
67084
+ if (snapshot.droppedMessages === 0 && !snapshot.inFlightChunk) {
67085
+ return;
67086
+ }
67087
+ const telemetry = buildDroppedWorkTelemetry(snapshot);
67088
+ logger.info(LogEvent.WAKEUP_IN_MEMORY_WORK_DROPPED, telemetry.sentry);
67089
+ logWithTimestamp("[okx-agent-task] WakeupNotify messages dropped on shutdown", telemetry.local);
67090
+ }
67091
+ async function startWakeupNotifyPull(opts) {
67092
+ const enabled = opts.enabled ?? true;
67093
+ const fetchPage = opts.fetchPage ?? (enabled ? createOnchainosWakeupFetchPage() : void 0);
67094
+ if (!enabled || !fetchPage) {
67095
+ logWithTimestamp("[okx-agent-task] WakeupNotify pull skipped (disabled)");
67096
+ return null;
67097
+ }
67098
+ const agentIds = [
67099
+ ...new Set(
67100
+ [...opts.service.getClients().keys()].map((addr) => opts.service.getAgentByAddress(addr)?.agentId).filter((id) => typeof id === "string" && id.length > 0)
67101
+ )
67102
+ ];
67103
+ if (agentIds.length === 0) {
67104
+ logWithTimestamp("[okx-agent-task] WakeupNotify pull skipped (no active agents)");
67105
+ return null;
67106
+ }
67107
+ logger.info(LogEvent.WAKEUP_PULL_STARTED, {
67108
+ component: "wakeup_pull",
67109
+ agentCount: String(agentIds.length)
67110
+ });
67111
+ const { items, summary, rejects } = await fetchAllWakeupNotifications({
67112
+ agentIds,
67113
+ fetchPage,
67114
+ onPage: (p) => logger.info(LogEvent.WAKEUP_PULL_PAGE_FETCHED, {
67115
+ component: "wakeup_pull",
67116
+ page: String(p.page),
67117
+ itemCount: String(p.itemCount),
67118
+ rejectedCount: String(p.rejectedCount),
67119
+ hasNextPage: String(p.hasNextPage)
67120
+ }),
67121
+ onRetry: (r) => logger.info(LogEvent.WAKEUP_PULL_PAGE_RETRY, {
67122
+ component: "wakeup_pull",
67123
+ page: String(r.page),
67124
+ attempt: String(r.attempt),
67125
+ reason: r.reason
67126
+ })
67127
+ });
67128
+ for (const reject of rejects) {
67129
+ logger.info(LogEvent.WAKEUP_NOTIFICATION_REJECTED, {
67130
+ component: "wakeup_pull",
67131
+ reason: reject.reason
67132
+ });
67133
+ }
67134
+ if (summary.terminated === "transport_error" || summary.terminated === "business_error" || summary.terminated === "invalid_response") {
67135
+ logger.error(LogEvent.WAKEUP_PULL_FAILED, void 0, {
67136
+ component: "wakeup_pull",
67137
+ terminated: summary.terminated
67138
+ });
67139
+ }
67140
+ const resolved = opts.chunkSize != null ? { chunkSize: opts.chunkSize, anomaly: null } : resolveWakeupChunkSize(opts.env);
67141
+ if (resolved.anomaly) {
67142
+ logWithTimestamp(`[okx-agent-task] WakeupNotify chunk size ${resolved.anomaly}`);
67143
+ }
67144
+ const chunks = splitIntoChunks(items, resolved.chunkSize);
67145
+ logger.info(LogEvent.WAKEUP_PULL_COMPLETED, {
67146
+ component: "wakeup_pull",
67147
+ pagesFetched: String(summary.pagesFetched),
67148
+ received: String(summary.received),
67149
+ rejected: String(summary.rejected),
67150
+ chunkCount: String(chunks.length),
67151
+ size: String(resolved.chunkSize),
67152
+ terminated: summary.terminated
67153
+ });
67154
+ const deps = {
67155
+ commands: opts.commands,
67156
+ sessionStore: opts.sessionStore,
67157
+ myXmtpAddress: void 0
67158
+ };
67159
+ const dispatcher = new HeartbeatChunkDispatcher(chunks, deps, opts.shouldContinue);
67160
+ await dispatcher.dispatchNextChunk();
67161
+ return dispatcher.hasPendingChunks() ? dispatcher : null;
67162
+ }
67163
+
66565
67164
  // src/listener.ts
66566
67165
  init_paths();
66567
67166
 
66568
67167
  // src/user-attention-watchers.ts
66569
- var import_node_crypto13 = require("node:crypto");
67168
+ var import_node_crypto14 = require("node:crypto");
66570
67169
  init_sentry_logger();
66571
67170
  var USER_ATTENTION_WATCH_REPLACED_MESSAGE = "Another okx-a2a user watch with the same job scope was started, so this watcher has been closed. Do not run this watch command again automatically, because starting another watcher may interrupt a different session that is already monitoring task progress.";
66572
67171
  var USER_ATTENTION_WATCHER_SCAN_MS = 500;
@@ -66609,7 +67208,7 @@ function isOriginalParentProcessAlive(options) {
66609
67208
  }
66610
67209
  function registerUserAttentionWatcher(options) {
66611
67210
  return options.store.registerUserAttentionWatcher({
66612
- id: options.id ?? (0, import_node_crypto13.randomUUID)(),
67211
+ id: options.id ?? (0, import_node_crypto14.randomUUID)(),
66613
67212
  provider: options.provider,
66614
67213
  jobId: options.jobId,
66615
67214
  nowMs: options.nowMs ?? Date.now(),
@@ -67122,7 +67721,6 @@ async function runListenerWithLock(options, paths) {
67122
67721
  fetchSystemConfig: async () => fetchSystemConfig({
67123
67722
  notifySessionExpired: (command) => service.tools.notifySessionExpired?.(command)
67124
67723
  }),
67125
- notifyAgentsWakeup: async (agentIds) => notifyAgentsWakeup(agentIds),
67126
67724
  createSigner: (agent) => createOnchainosSigner(agent),
67127
67725
  createInboundMiddleware: (deps) => createMiddlewareFromCoreDeps(store, deps, {
67128
67726
  sessionStore,
@@ -67172,12 +67770,12 @@ async function runListenerWithLock(options, paths) {
67172
67770
  });
67173
67771
  }
67174
67772
  });
67175
- service.setPluginVersion("0.2.8");
67773
+ service.setPluginVersion("0.2.9-beta-912b775358-260824171011");
67176
67774
  await service.init();
67177
67775
  const pluginVersionStatus = service.pluginVersionStatus;
67178
67776
  if (pluginVersionStatus.unavailable) {
67179
67777
  throw new Error(
67180
- `@okxweb3/a2a-node v${"0.2.8"} is below the required minimum v${pluginVersionStatus.minVersion}`
67778
+ `@okxweb3/a2a-node v${"0.2.9-beta-912b775358-260824171011"} is below the required minimum v${pluginVersionStatus.minVersion}`
67181
67779
  );
67182
67780
  }
67183
67781
  const systemConfig = service.getSystemConfig();
@@ -67205,7 +67803,7 @@ async function runListenerWithLock(options, paths) {
67205
67803
  onchainosAgentId: "*",
67206
67804
  reason: "system-config missing sentryDsn",
67207
67805
  pluginId: "@okxweb3/a2a-node",
67208
- pluginVersion: "0.2.8"
67806
+ pluginVersion: "0.2.9-beta-912b775358-260824171011"
67209
67807
  });
67210
67808
  }
67211
67809
  logWithTimestamp(
@@ -67448,6 +68046,7 @@ async function runListenerWithLock(options, paths) {
67448
68046
  let intervalSec = Math.max(10, service.getSystemConfig().heartbeatInterval);
67449
68047
  let offlineReplayIntervalSec = resolveOfflineReplayIntervalSec(service.getSystemConfig());
67450
68048
  let xmtpClientRecycleIntervalSec = resolveXmtpClientRecycleIntervalSec(service.getSystemConfig());
68049
+ let wakeupDispatcher = null;
67451
68050
  let timer;
67452
68051
  let offlineReplayTimer;
67453
68052
  let xmtpClientRecycleTimer;
@@ -67466,6 +68065,7 @@ async function runListenerWithLock(options, paths) {
67466
68065
  versionRefresh: refreshOnchainosVersionMetadata,
67467
68066
  refresh: syncTick
67468
68067
  });
68068
+ void wakeupDispatcher?.dispatchNextChunk();
67469
68069
  }, intervalSec * 1e3);
67470
68070
  };
67471
68071
  const scheduleOfflineReplayTimer = (nextIntervalSec) => {
@@ -67580,6 +68180,22 @@ async function runListenerWithLock(options, paths) {
67580
68180
  });
67581
68181
  await markDaemonReady(paths.daemonLockPath);
67582
68182
  logWithTimestamp(`[okx-agent-task] daemon ready lock=${paths.daemonLockPath}`);
68183
+ void startWakeupNotifyPull({
68184
+ service,
68185
+ commands,
68186
+ sessionStore,
68187
+ // Stop enqueuing if a shutdown begins mid-delivery (fire-and-forget pull).
68188
+ shouldContinue: () => !stopping
68189
+ }).then((dispatcher) => {
68190
+ wakeupDispatcher = dispatcher;
68191
+ }).catch((err) => {
68192
+ logger.error(LogEvent.WAKEUP_PULL_FAILED, err instanceof Error ? err : new Error(String(err)), {
68193
+ component: "node_listener",
68194
+ stage: "wakeup_pull_start",
68195
+ reason: "wakeup_pull_unhandled_error"
68196
+ });
68197
+ logWithTimestamp("[okx-agent-task] WakeupNotify pull failed to start:", err);
68198
+ });
67583
68199
  await new Promise((resolve11) => {
67584
68200
  const shutdown2 = (signal) => {
67585
68201
  if (stopping) {
@@ -67592,6 +68208,7 @@ async function runListenerWithLock(options, paths) {
67592
68208
  resolve11();
67593
68209
  }, SHUTDOWN_FORCE_RESOLVE_MS);
67594
68210
  void (async () => {
68211
+ logDroppedWakeupWorkOnShutdown(wakeupDispatcher);
67595
68212
  deferredMaintenanceTasks.cancelAll();
67596
68213
  if (timer) {
67597
68214
  clearInterval(timer);
@@ -68595,7 +69212,7 @@ var import_node_path33 = require("node:path");
68595
69212
  var import_jszip = __toESM(require_lib3());
68596
69213
 
68597
69214
  // src/logs-export-archive.ts
68598
- var import_node_crypto14 = require("node:crypto");
69215
+ var import_node_crypto15 = require("node:crypto");
68599
69216
  var import_node_fs24 = require("node:fs");
68600
69217
  var import_promises13 = require("node:fs/promises");
68601
69218
  var import_node_path30 = require("node:path");
@@ -69231,7 +69848,7 @@ async function writeArchiveAtomically(outputPath, archive, overwrite) {
69231
69848
  await (0, import_promises13.mkdir)((0, import_node_path30.dirname)(outputPath), { recursive: true });
69232
69849
  const temporaryPath = (0, import_node_path30.join)(
69233
69850
  (0, import_node_path30.dirname)(outputPath),
69234
- `.${(0, import_node_path30.basename)(outputPath)}.${(0, import_node_crypto14.randomUUID)()}.tmp`
69851
+ `.${(0, import_node_path30.basename)(outputPath)}.${(0, import_node_crypto15.randomUUID)()}.tmp`
69235
69852
  );
69236
69853
  try {
69237
69854
  await (0, import_promises13.writeFile)(temporaryPath, archive, { flag: "wx", mode: 384 });
@@ -69250,7 +69867,7 @@ async function writeArchiveAtomically(outputPath, archive, overwrite) {
69250
69867
  }
69251
69868
  }
69252
69869
  function hashDiagnosticFileContent(content) {
69253
- return (0, import_node_crypto14.createHash)("sha256").update(content).digest("hex");
69870
+ return (0, import_node_crypto15.createHash)("sha256").update(content).digest("hex");
69254
69871
  }
69255
69872
  function isUnavailableError(err) {
69256
69873
  return !!err && typeof err === "object" && "diagnosticUnavailable" in err;
@@ -69510,7 +70127,7 @@ function isProvider2(value) {
69510
70127
  }
69511
70128
 
69512
70129
  // src/logs-export-utils.ts
69513
- var import_node_crypto15 = require("node:crypto");
70130
+ var import_node_crypto16 = require("node:crypto");
69514
70131
  var import_node_fs26 = require("node:fs");
69515
70132
  var import_promises14 = require("node:fs/promises");
69516
70133
  var import_node_path32 = require("node:path");
@@ -69653,7 +70270,7 @@ async function assertRegularFile2(path2) {
69653
70270
  }
69654
70271
  async function inspectRegularFile(path2) {
69655
70272
  const file = await assertRegularFile2(path2);
69656
- const hash2 = (0, import_node_crypto15.createHash)("sha256");
70273
+ const hash2 = (0, import_node_crypto16.createHash)("sha256");
69657
70274
  for await (const chunk of (0, import_node_fs26.createReadStream)(path2)) {
69658
70275
  hash2.update(chunk);
69659
70276
  }
@@ -69906,7 +70523,7 @@ async function exportDiagnosticLogs(options) {
69906
70523
  node: process.version,
69907
70524
  platform: process.platform,
69908
70525
  arch: process.arch,
69909
- packageVersion: true ? "0.2.8" : "unknown",
70526
+ packageVersion: true ? "0.2.9-beta-912b775358-260824171011" : "unknown",
69910
70527
  sensitiveContentIncluded: options.includeSensitiveContent,
69911
70528
  listenerAndLlmContentIncluded: true,
69912
70529
  credentialsAlwaysRedacted: true,
@@ -71788,7 +72405,7 @@ async function runDoctor(options = {}) {
71788
72405
  platform: options.platform ?? process.platform,
71789
72406
  env: options.env ?? process.env,
71790
72407
  target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
71791
- cliVersion: options.cliVersion ?? (true ? "0.2.8" : "0.0.0"),
72408
+ cliVersion: options.cliVersion ?? (true ? "0.2.9-beta-912b775358-260824171011" : "0.0.0"),
71792
72409
  fixMode: options.fix === true,
71793
72410
  nonInteractive: options.nonInteractive === true,
71794
72411
  packageChanged: false,
@@ -72007,6 +72624,9 @@ async function writeStdoutAndExit(output, code) {
72007
72624
  init_doctor_sentry();
72008
72625
  init_win_native_launcher();
72009
72626
  init_autostart_windows();
72627
+
72628
+ // src/wakeup-notify-types.ts
72629
+ var WAKEUP_PAGE_SIZE = 50;
72010
72630
  // Annotate the CommonJS export names for ESM import in node:
72011
72631
  0 && (module.exports = {
72012
72632
  AGENT_GET_PAGE_TIMEOUT_MS,
@@ -72026,6 +72646,7 @@ init_autostart_windows();
72026
72646
  CODEX_RECOVERY_ACTIONS,
72027
72647
  CommandStore,
72028
72648
  DEFAULT_AI_PERMISSION_PRESET,
72649
+ DEFAULT_MAX_ACTIVE_AI_EXECUTIONS,
72029
72650
  DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC,
72030
72651
  DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC,
72031
72652
  DOCTOR_MIN_NODE_VERSION,
@@ -72054,6 +72675,7 @@ init_autostart_windows();
72054
72675
  USER_ATTENTION_WATCH_PARENT_CHECK_MS,
72055
72676
  USER_ATTENTION_WATCH_REPLACED_MESSAGE,
72056
72677
  UserCancelledAiProviderSelectionError,
72678
+ WAKEUP_PAGE_SIZE,
72057
72679
  WALLET_STATUS_TIMEOUT_MS,
72058
72680
  XMTP_CLIENT_RECYCLE_INTERVAL_ENV,
72059
72681
  XmtpDm,
@@ -72079,6 +72701,7 @@ init_autostart_windows();
72079
72701
  buildCodexRecoveryGuidance,
72080
72702
  buildDispatchSessionKey,
72081
72703
  buildDoctorSentryExtra,
72704
+ buildDroppedWorkTelemetry,
72082
72705
  buildExternalCommandInvocation,
72083
72706
  buildGatewayOutboundExtra,
72084
72707
  buildInboundTerminalExtras,
@@ -72118,9 +72741,11 @@ init_autostart_windows();
72118
72741
  commandExists,
72119
72742
  createAiToolFailureTracker,
72120
72743
  createFileMessageHandler,
72744
+ createOnchainosWakeupFetchPage,
72121
72745
  createOutboundBehavior,
72122
72746
  createUserAttentionWatchParentMonitor,
72123
72747
  currentOpenClawGatewaySessionKey,
72748
+ deriveWakeupDedupeKey,
72124
72749
  detectAiProviders,
72125
72750
  detectAiRuntimeSurface,
72126
72751
  detectCurrentAiProvider,
@@ -72136,7 +72761,9 @@ init_autostart_windows();
72136
72761
  exportDiagnosticLogs,
72137
72762
  extractAiSessionId,
72138
72763
  extractDirectToUserNotification,
72764
+ extractSystemNotification,
72139
72765
  extractXmtpSentAtMs,
72766
+ fetchAllWakeupNotifications,
72140
72767
  findWindowsNativeOkxA2aExe,
72141
72768
  followFile,
72142
72769
  formatDoctorReportForHumans,
@@ -72154,6 +72781,7 @@ init_autostart_windows();
72154
72781
  hashDiagnosticFileContent,
72155
72782
  heartbeatUserAttentionWatcher,
72156
72783
  hermesConfigEnablesOkxA2a,
72784
+ ingestWakeupNotification,
72157
72785
  installSystemdAutostart,
72158
72786
  installWindowsNativeLauncher,
72159
72787
  installedAutostartHasCurrentConfiguration,
@@ -72172,12 +72800,15 @@ init_autostart_windows();
72172
72800
  isSqliteBusyError,
72173
72801
  isSystemdManagerUnavailableMessage,
72174
72802
  isTagKey,
72803
+ isValidWakeupItem,
72175
72804
  isWindowsElevated,
72176
72805
  killProcessTree,
72177
72806
  launchdPlistHasCurrentRestartPolicy,
72178
72807
  listAllAgentsWithMetadata,
72808
+ logDroppedWakeupWorkOnShutdown,
72179
72809
  logWinCompat,
72180
72810
  logXmtpMessageSent,
72811
+ mapCliStdoutToWakeupResponse,
72181
72812
  maybeRecommendOnchainosUpgrade,
72182
72813
  mergeA2AEnvelopeTips,
72183
72814
  messageEligibleHelpAdvertisesOfflineReplay,
@@ -72233,6 +72864,7 @@ init_autostart_windows();
72233
72864
  resolveDirectCommunicationSessionTarget,
72234
72865
  resolveDoctorTarget,
72235
72866
  resolveEnvelopePayload,
72867
+ resolveMaxActiveAiExecutions,
72236
72868
  resolveNpmCmdShimScript,
72237
72869
  resolveOfflineReplayCapabilityMarker,
72238
72870
  resolveOfflineReplayIntervalSec,
@@ -72246,6 +72878,7 @@ init_autostart_windows();
72246
72878
  resolveTaskHome,
72247
72879
  resolveTaskPaths,
72248
72880
  resolveUserAttentionIpcPath,
72881
+ resolveWakeupChunkSize,
72249
72882
  resolveWindowsAutostartPaths,
72250
72883
  resolveXmtpClientRecycleIntervalSec,
72251
72884
  restartSystemdAutostart,
@@ -72266,6 +72899,7 @@ init_autostart_windows();
72266
72899
  startDaemonRespectingSupervisor,
72267
72900
  startUserAttentionEventServer,
72268
72901
  startUserAttentionWatcherCoordinator,
72902
+ startWakeupNotifyPull,
72269
72903
  stopDaemon,
72270
72904
  stopOpenClawGateway,
72271
72905
  stopSystemdAutostart,