@okxweb3/a2a-node 0.2.17 → 0.2.18-beta-4dd056b897-261015113839

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 +1682 -124
  2. package/dist/index.js +1585 -127
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4008,7 +4008,7 @@ var require_is = __commonJS({
4008
4008
  function isPrimitive(wat) {
4009
4009
  return wat === null || typeof wat !== "object" && typeof wat !== "function";
4010
4010
  }
4011
- function isPlainObject4(wat) {
4011
+ function isPlainObject6(wat) {
4012
4012
  return isBuiltin(wat, "Object");
4013
4013
  }
4014
4014
  function isEvent(wat) {
@@ -4024,7 +4024,7 @@ var require_is = __commonJS({
4024
4024
  return Boolean(wat && wat.then && typeof wat.then === "function");
4025
4025
  }
4026
4026
  function isSyntheticEvent(wat) {
4027
- return isPlainObject4(wat) && "nativeEvent" in wat && "preventDefault" in wat && "stopPropagation" in wat;
4027
+ return isPlainObject6(wat) && "nativeEvent" in wat && "preventDefault" in wat && "stopPropagation" in wat;
4028
4028
  }
4029
4029
  function isNaN2(wat) {
4030
4030
  return typeof wat === "number" && wat !== wat;
@@ -4047,7 +4047,7 @@ var require_is = __commonJS({
4047
4047
  exports2.isEvent = isEvent;
4048
4048
  exports2.isInstanceOf = isInstanceOf;
4049
4049
  exports2.isNaN = isNaN2;
4050
- exports2.isPlainObject = isPlainObject4;
4050
+ exports2.isPlainObject = isPlainObject6;
4051
4051
  exports2.isPrimitive = isPrimitive;
4052
4052
  exports2.isRegExp = isRegExp;
4053
4053
  exports2.isString = isString;
@@ -19310,6 +19310,23 @@ var init_events = __esm({
19310
19310
  XMTP_RATE_LIMIT_CREATE_SUPPRESSED: "XMTP rate limit create suppressed",
19311
19311
  XMTP_RATE_LIMIT_PROBE: "XMTP rate limit probe",
19312
19312
  XMTP_RATE_LIMIT_RECOVERED: "XMTP rate limit recovered",
19313
+ // ── subscription observability info (DEXMARKET-9096) ───────────
19314
+ // All of the following logger.info checkpoints MUST also be listed in
19315
+ // SENTRY_INFO_ALLOWLIST (index.ts): info() returns early for an unlisted
19316
+ // event, which ships a checkpoint that looks implemented but emits nothing.
19317
+ SUBSCRIPTION_PUSH_STARTED: "Subscription push started",
19318
+ SUBSCRIPTION_PUSH_TARGETS_RESOLVED: "Subscription push targets resolved",
19319
+ SUBSCRIPTION_PUSH_EMPTY_TARGETS: "Subscription push empty targets",
19320
+ SUBSCRIPTION_PUSH_SUMMARY: "Subscription push summary",
19321
+ SUBSCRIPTION_INBOUND_RECEIVED: "Subscription inbound received",
19322
+ SUBSCRIPTION_INBOUND_GATE_DROPPED: "Subscription inbound gate dropped",
19323
+ SUBSCRIPTION_JOBS_QUERY_STARTED: "Subscription jobs query started",
19324
+ SUBSCRIPTION_JOBS_QUERY_SUCCEEDED: "Subscription jobs query succeeded",
19325
+ SUBSCRIPTION_JOBS_EMPTY: "Subscription jobs empty",
19326
+ SUBSCRIPTION_INBOUND_OWNERSHIP_ROUTED: "Subscription inbound ownership routed",
19327
+ SUBSCRIPTION_JOB_DISPATCHED: "Subscription job dispatched",
19328
+ SUBSCRIPTION_JOB_DUPLICATE_IGNORED: "Subscription job duplicate ignored",
19329
+ SUBSCRIPTION_FANOUT_SUMMARY: "Subscription fan-out summary",
19313
19330
  // ── error ─────────────────────────────────────────────────────
19314
19331
  XMTP_CONNECTION_FAILED: "XMTP connection failed",
19315
19332
  CONVERSATIONS_STREAM_FAILED: "conversations.stream failed",
@@ -19376,6 +19393,13 @@ var init_events = __esm({
19376
19393
  AGENT_INSTALLATION_LIMIT_NEAR: "Agent installation limit near",
19377
19394
  XMTP_HISTORY_SYNC_REQUEST_FAILED: "XMTP history sync request failed",
19378
19395
  XMTP_DEBUG_SYNC_FAILED: "XMTP debug sync failed",
19396
+ // ── subscription observability error (DEXMARKET-9096) ──────────
19397
+ // error-level: always emitted (no allowlist gate). Error objects are
19398
+ // classified by buildErrorDiagnostics — never attach raw Error.message.
19399
+ SUBSCRIPTION_PUSH_TARGET_FAILED: "Subscription push target failed",
19400
+ SUBSCRIPTION_INBOUND_AGENTIC_ID_MISSING: "Subscription inbound agenticId missing",
19401
+ SUBSCRIPTION_JOBS_FAIL_CLOSED: "Subscription jobs fail closed",
19402
+ SUBSCRIPTION_JOB_FAILED: "Subscription job failed",
19379
19403
  // Underlying XMTP SDK client close failed during recycle/removal/shutdown
19380
19404
  // (DEXMARKET-9116). Error-level → NOT added to SENTRY_INFO_ALLOWLIST.
19381
19405
  XMTP_CLIENT_CLOSE_FAILED: "XMTP client close failed"
@@ -19439,7 +19463,7 @@ function resolveDeliveryId(input) {
19439
19463
  if (slots.every((slot) => slot === "")) {
19440
19464
  return UNKNOWN_LOG_FIELD;
19441
19465
  }
19442
- const digest = (0, import_node_crypto2.createHash)("sha256").update(slots.join("|")).digest("hex");
19466
+ const digest = (0, import_node_crypto3.createHash)("sha256").update(slots.join("|")).digest("hex");
19443
19467
  return `${DERIVED_DELIVERY_ID_PREFIX}${digest.slice(0, DERIVED_DELIVERY_ID_LENGTH)}`;
19444
19468
  }
19445
19469
  function releaseFields(release) {
@@ -19557,11 +19581,11 @@ function enrichCorrelationFields(extra) {
19557
19581
  }
19558
19582
  return enriched;
19559
19583
  }
19560
- var import_node_crypto2, PROBE_NAME_PATTERN, PROBE_JOB_ID_PATTERN, XMTP_MESSAGE_ID_PATTERN, DERIVED_DELIVERY_ID_PREFIX, DERIVED_DELIVERY_ID_LENGTH, RELEASE_CODE_MAJOR_WEIGHT, RELEASE_CODE_MINOR_WEIGHT, UNKNOWN_LOG_FIELD, UNPARSABLE_RELEASE;
19584
+ var import_node_crypto3, PROBE_NAME_PATTERN, PROBE_JOB_ID_PATTERN, XMTP_MESSAGE_ID_PATTERN, DERIVED_DELIVERY_ID_PREFIX, DERIVED_DELIVERY_ID_LENGTH, RELEASE_CODE_MAJOR_WEIGHT, RELEASE_CODE_MINOR_WEIGHT, UNKNOWN_LOG_FIELD, UNPARSABLE_RELEASE;
19561
19585
  var init_log_fields = __esm({
19562
19586
  "../core/src/sentry-logger/log-fields.ts"() {
19563
19587
  "use strict";
19564
- import_node_crypto2 = require("node:crypto");
19588
+ import_node_crypto3 = require("node:crypto");
19565
19589
  PROBE_NAME_PATTERN = /probe/i;
19566
19590
  PROBE_JOB_ID_PATTERN = /^probe[-_]/i;
19567
19591
  XMTP_MESSAGE_ID_PATTERN = /^[0-9a-f]{16,}$/i;
@@ -19949,6 +19973,9 @@ function applyFatalEventDefaults(event) {
19949
19973
  function isInfoEventAllowlisted(name) {
19950
19974
  return SENTRY_INFO_ALLOWLIST.has(name);
19951
19975
  }
19976
+ function isFingerprintKey(key) {
19977
+ return SENTRY_FINGERPRINT_KEYS.includes(key);
19978
+ }
19952
19979
  function isTagKey(key) {
19953
19980
  return SENTRY_TAG_KEYS.has(key);
19954
19981
  }
@@ -19960,13 +19987,13 @@ function agentExtras(identity) {
19960
19987
  role: identity.role != null && identity.role !== "" ? String(identity.role) : UNKNOWN_FIELD
19961
19988
  };
19962
19989
  }
19963
- var Sentry, import_node_crypto3, FLOW_ID, SENTRY_EXTRA_BLOCKLIST, SENTRY_EXTRA_BLOCKED_KEY_PARTS, SENTRY_FULL_STRING_EXTRA_KEYS, SENTRY_TAG_KEYS, SENTRY_FINGERPRINT_KEYS, SENTRY_INFO_ALLOWLIST, MAX_EXTRA_STRING_LENGTH, MAX_TAG_VALUE_LENGTH, RELEASE_FIELDS, RUNTIME_FIELDS, SentryLogger, logger, initLogger, shutdown, UNKNOWN_FIELD;
19990
+ var Sentry, import_node_crypto4, FLOW_ID, SENTRY_EXTRA_BLOCKLIST, SENTRY_EXTRA_BLOCKED_KEY_PARTS, SENTRY_FULL_STRING_EXTRA_KEYS, SENTRY_TAG_KEYS, SENTRY_FINGERPRINT_KEYS, SENTRY_INFO_ALLOWLIST, MAX_EXTRA_STRING_LENGTH, MAX_TAG_VALUE_LENGTH, RELEASE_FIELDS, RUNTIME_FIELDS, SentryLogger, logger, initLogger, shutdown, UNKNOWN_FIELD;
19964
19991
  var init_sentry_logger = __esm({
19965
19992
  "../core/src/sentry-logger/index.ts"() {
19966
19993
  "use strict";
19967
19994
  init_log();
19968
19995
  Sentry = __toESM(require_cjs4());
19969
- import_node_crypto3 = require("node:crypto");
19996
+ import_node_crypto4 = require("node:crypto");
19970
19997
  init_events();
19971
19998
  init_log_fields();
19972
19999
  init_xmtp_test_metrics();
@@ -19974,7 +20001,7 @@ var init_sentry_logger = __esm({
19974
20001
  init_runtime_metadata();
19975
20002
  init_events();
19976
20003
  init_log_fields();
19977
- FLOW_ID = (0, import_node_crypto3.randomUUID)();
20004
+ FLOW_ID = (0, import_node_crypto4.randomUUID)();
19978
20005
  SENTRY_EXTRA_BLOCKLIST = /* @__PURE__ */ new Set([
19979
20006
  "args",
19980
20007
  "apikey",
@@ -20057,6 +20084,13 @@ var init_sentry_logger = __esm({
20057
20084
  ]);
20058
20085
  SENTRY_TAG_KEYS = /* @__PURE__ */ new Set([
20059
20086
  "agentId",
20087
+ // Subscription correlation agent ids (DEXMARKET-9096). Bounded-cardinality,
20088
+ // same class as agentId/senderAgentId/onchainosAgentId — promoted to indexed
20089
+ // tags for Sentry filtering. NOT added to SENTRY_FINGERPRINT_KEYS, so the
20090
+ // global issue fingerprint is unchanged. High-cardinality ids
20091
+ // (conversationId/messageId/deliveryId) are deliberately NOT here.
20092
+ "aspAgentId",
20093
+ "userAgentId",
20060
20094
  "agentPlatform",
20061
20095
  "aiProvider",
20062
20096
  "cacheName",
@@ -20224,6 +20258,22 @@ var init_sentry_logger = __esm({
20224
20258
  LogEvent.SESSION_KEY_DERIVED,
20225
20259
  LogEvent.SESSIONS_QUERIED,
20226
20260
  LogEvent.SYNC_TICK_COMPLETED,
20261
+ // Subscription observability info checkpoints (DEXMARKET-9096). Each is a
20262
+ // logger.info event; omitting any makes info() drop it silently so the whole
20263
+ // subscription trace would look implemented and emit nothing in production.
20264
+ LogEvent.SUBSCRIPTION_PUSH_STARTED,
20265
+ LogEvent.SUBSCRIPTION_PUSH_TARGETS_RESOLVED,
20266
+ LogEvent.SUBSCRIPTION_PUSH_EMPTY_TARGETS,
20267
+ LogEvent.SUBSCRIPTION_PUSH_SUMMARY,
20268
+ LogEvent.SUBSCRIPTION_INBOUND_RECEIVED,
20269
+ LogEvent.SUBSCRIPTION_INBOUND_GATE_DROPPED,
20270
+ LogEvent.SUBSCRIPTION_JOBS_QUERY_STARTED,
20271
+ LogEvent.SUBSCRIPTION_JOBS_QUERY_SUCCEEDED,
20272
+ LogEvent.SUBSCRIPTION_JOBS_EMPTY,
20273
+ LogEvent.SUBSCRIPTION_INBOUND_OWNERSHIP_ROUTED,
20274
+ LogEvent.SUBSCRIPTION_JOB_DISPATCHED,
20275
+ LogEvent.SUBSCRIPTION_JOB_DUPLICATE_IGNORED,
20276
+ LogEvent.SUBSCRIPTION_FANOUT_SUMMARY,
20227
20277
  // XMTP creation rate-limit cooldown checkpoints (DEXMARKET-9116). info() drops
20228
20278
  // any event not listed here, so these must stay registered.
20229
20279
  LogEvent.XMTP_RATE_LIMIT_COOLDOWN_STARTED,
@@ -31015,7 +31065,7 @@ var require_websocket2 = __commonJS({
31015
31065
  var http2 = require("http");
31016
31066
  var net = require("net");
31017
31067
  var tls = require("tls");
31018
- var { randomBytes: randomBytes3, createHash: createHash6 } = require("crypto");
31068
+ var { randomBytes: randomBytes3, createHash: createHash7 } = require("crypto");
31019
31069
  var { Duplex, Readable } = require("stream");
31020
31070
  var { URL: URL2 } = require("url");
31021
31071
  var PerMessageDeflate = require_permessage_deflate();
@@ -31675,7 +31725,7 @@ var require_websocket2 = __commonJS({
31675
31725
  abortHandshake(websocket, socket, "Invalid Upgrade header");
31676
31726
  return;
31677
31727
  }
31678
- const digest = createHash6("sha1").update(key + GUID).digest("base64");
31728
+ const digest = createHash7("sha1").update(key + GUID).digest("base64");
31679
31729
  if (res.headers["sec-websocket-accept"] !== digest) {
31680
31730
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
31681
31731
  return;
@@ -32042,7 +32092,7 @@ var require_websocket_server = __commonJS({
32042
32092
  var EventEmitter2 = require("events");
32043
32093
  var http2 = require("http");
32044
32094
  var { Duplex } = require("stream");
32045
- var { createHash: createHash6 } = require("crypto");
32095
+ var { createHash: createHash7 } = require("crypto");
32046
32096
  var extension = require_extension();
32047
32097
  var PerMessageDeflate = require_permessage_deflate();
32048
32098
  var subprotocol = require_subprotocol();
@@ -32343,7 +32393,7 @@ var require_websocket_server = __commonJS({
32343
32393
  );
32344
32394
  }
32345
32395
  if (this._state > RUNNING) return abortHandshake(socket, 503);
32346
- const digest = createHash6("sha1").update(key + GUID).digest("base64");
32396
+ const digest = createHash7("sha1").update(key + GUID).digest("base64");
32347
32397
  const headers = [
32348
32398
  "HTTP/1.1 101 Switching Protocols",
32349
32399
  "Upgrade: websocket",
@@ -32465,7 +32515,7 @@ var init_sentry_config = __esm({
32465
32515
  environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
32466
32516
  SENTRY_CONFIG = {
32467
32517
  projectName: "okx/openclaw-okx-a2a-extension",
32468
- release: "0.2.17",
32518
+ release: "0.2.18-beta-4dd056b897-261015113839",
32469
32519
  environment,
32470
32520
  runtimeContainer: normalizeRuntimeContainer(process.env.OKX_A2A_RUNTIME_CONTAINER)
32471
32521
  };
@@ -33421,7 +33471,7 @@ async function getCurrentNodeCliVersion() {
33421
33471
  return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
33422
33472
  }
33423
33473
  function getBundledNodeCliVersion() {
33424
- return true ? "0.2.17" : null;
33474
+ return true ? "0.2.18-beta-4dd056b897-261015113839" : null;
33425
33475
  }
33426
33476
  function readConfiguredAiProvider() {
33427
33477
  const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
@@ -33631,7 +33681,7 @@ async function updateHermes(release, options) {
33631
33681
  }
33632
33682
  }
33633
33683
  async function installGatewayPluginForDoctor(target) {
33634
- const release = isPrereleaseVersion("0.2.17") ? "beta" : "latest";
33684
+ const release = isPrereleaseVersion("0.2.18-beta-4dd056b897-261015113839") ? "beta" : "latest";
33635
33685
  const insideTargetGateway = detectGatewayInvocation() === target;
33636
33686
  const options = {
33637
33687
  restart: !insideTargetGateway,
@@ -44353,6 +44403,7 @@ __export(index_exports, {
44353
44403
  InboundReplayGate: () => InboundReplayGate,
44354
44404
  InvalidXmtpMessageStore: () => InvalidXmtpMessageStore,
44355
44405
  JOB_PROVIDER_BINDING_SOURCES: () => JOB_PROVIDER_BINDING_SOURCES,
44406
+ LIST_JOBS_BY_VERIFIED_SENDER_HELP_TOKEN: () => LIST_JOBS_BY_VERIFIED_SENDER_HELP_TOKEN,
44356
44407
  ListenerDeferredTaskScheduler: () => ListenerDeferredTaskScheduler,
44357
44408
  ListenerMaintenanceGate: () => ListenerMaintenanceGate,
44358
44409
  LogEvent: () => LogEvent,
@@ -44362,6 +44413,9 @@ __export(index_exports, {
44362
44413
  NATIVE_LAUNCHER_EXE_NAME: () => NATIVE_LAUNCHER_EXE_NAME,
44363
44414
  OPENCLAW_GATEWAY_ROUTE_GROUP_ID: () => OPENCLAW_GATEWAY_ROUTE_GROUP_ID,
44364
44415
  ProviderNotReadyError: () => ProviderNotReadyError,
44416
+ RUN_LOG_FILENAME_MAX_BYTES: () => RUN_LOG_FILENAME_MAX_BYTES,
44417
+ SUBSCRIPTION_FANOUT_MAX: () => SUBSCRIPTION_FANOUT_MAX,
44418
+ SUBSCRIPTION_MESSAGE_TYPE: () => SUBSCRIPTION_MESSAGE_TYPE,
44365
44419
  SYSTEM_NOTIFICATION_SESSION_KEY: () => SYSTEM_NOTIFICATION_SESSION_KEY,
44366
44420
  SessionBusyTracker: () => SessionBusyTracker,
44367
44421
  SessionStore: () => SessionStore,
@@ -44407,7 +44461,9 @@ __export(index_exports, {
44407
44461
  buildInboundTerminalExtras: () => buildInboundTerminalExtras,
44408
44462
  buildLaunchdPlist: () => buildLaunchdPlist,
44409
44463
  buildLauncherEntryJs: () => buildLauncherEntryJs,
44464
+ buildListJobsByVerifiedSenderArgs: () => buildListJobsByVerifiedSenderArgs,
44410
44465
  buildMessageEligibleArgs: () => buildMessageEligibleArgs,
44466
+ buildRunLogFileName: () => buildRunLogFileName,
44411
44467
  buildSchtasksCreateArgs: () => buildSchtasksCreateArgs,
44412
44468
  buildSchtasksDeleteArgs: () => buildSchtasksDeleteArgs,
44413
44469
  buildSchtasksEndArgs: () => buildSchtasksEndArgs,
@@ -44416,9 +44472,14 @@ __export(index_exports, {
44416
44472
  buildSeaConfig: () => buildSeaConfig,
44417
44473
  buildServicePath: () => buildServicePath,
44418
44474
  buildSessionKey: () => buildSessionKey,
44475
+ buildSubscriptionEnvelope: () => buildSubscriptionEnvelope,
44476
+ buildSubscriptionInboundExtras: () => buildSubscriptionInboundExtras,
44477
+ buildSubscriptionJobExtras: () => buildSubscriptionJobExtras,
44478
+ buildSubscriptionSendExtras: () => buildSubscriptionSendExtras,
44419
44479
  buildSystemMessageNotice: () => buildSystemMessageNotice,
44420
44480
  buildSystemStoredMessage: () => buildSystemStoredMessage,
44421
44481
  buildSystemdUserService: () => buildSystemdUserService,
44482
+ buildUpgradeRecommendationNotice: () => buildUpgradeRecommendationNotice,
44422
44483
  buildWin32OnchainosCandidates: () => buildWin32OnchainosCandidates,
44423
44484
  buildWindowsParentProcessProbe: () => buildWindowsParentProcessProbe,
44424
44485
  buildXmtpMessageSentExtra: () => buildXmtpMessageSentExtra,
@@ -44433,6 +44494,7 @@ __export(index_exports, {
44433
44494
  checkCodexReadiness: () => checkCodexReadiness,
44434
44495
  claimActiveDaemon: () => claimActiveDaemon,
44435
44496
  classifyJobBindingSource: () => classifyJobBindingSource,
44497
+ classifyListJobsError: () => classifyListJobsError,
44436
44498
  clearCodexReadinessCache: () => clearCodexReadinessCache,
44437
44499
  codexCommandResolvesWithoutOverride: () => codexCommandResolvesWithoutOverride,
44438
44500
  codexReadinessCacheKey: () => codexReadinessCacheKey,
@@ -44444,10 +44506,12 @@ __export(index_exports, {
44444
44506
  createOutboundBehavior: () => createOutboundBehavior,
44445
44507
  createUserAttentionWatchParentMonitor: () => createUserAttentionWatchParentMonitor,
44446
44508
  currentOpenClawGatewaySessionKey: () => currentOpenClawGatewaySessionKey,
44509
+ decideSubscriptionGate: () => decideSubscriptionGate,
44447
44510
  detectAiProviders: () => detectAiProviders,
44448
44511
  detectAiRuntimeSurface: () => detectAiRuntimeSurface,
44449
44512
  detectCurrentAiProvider: () => detectCurrentAiProvider,
44450
44513
  detectGatewayInvocation: () => detectGatewayInvocation,
44514
+ detectListJobsByVerifiedSenderSupport: () => detectListJobsByVerifiedSenderSupport,
44451
44515
  detectMessageEligibleOfflineReplaySupport: () => detectMessageEligibleOfflineReplaySupport,
44452
44516
  detectRuntime: () => detectRuntime,
44453
44517
  ensureDaemonReady: () => ensureDaemonReady,
@@ -44461,6 +44525,7 @@ __export(index_exports, {
44461
44525
  extractDirectToUserNotification: () => extractDirectToUserNotification,
44462
44526
  extractRateLimitEndpoint: () => extractRateLimitEndpoint,
44463
44527
  extractXmtpSentAtMs: () => extractXmtpSentAtMs2,
44528
+ fanOutSubscriptionJobs: () => fanOutSubscriptionJobs,
44464
44529
  findWindowsNativeOkxA2aExe: () => findWindowsNativeOkxA2aExe,
44465
44530
  followFile: () => followFile,
44466
44531
  formatDoctorReportForHumans: () => formatDoctorReportForHumans,
@@ -44473,6 +44538,7 @@ __export(index_exports, {
44473
44538
  getXmtpCreationCooldown: () => getXmtpCreationCooldown,
44474
44539
  handleCapabilitiesCommand: () => handleCapabilitiesCommand,
44475
44540
  handleDoctorCommand: () => handleDoctorCommand,
44541
+ handleSubscriptionPushCommand: () => handleSubscriptionPushCommand,
44476
44542
  handleXmtpDebugCommand: () => handleXmtpDebugCommand,
44477
44543
  handleXmtpSendCommand: () => handleXmtpSendCommand,
44478
44544
  handleXmtpTestCommand: () => handleXmtpTestCommand,
@@ -44487,6 +44553,7 @@ __export(index_exports, {
44487
44553
  invalidateResolvedOnchainosBinForTests: () => invalidateResolvedOnchainosBinForTests,
44488
44554
  isAutostartManagerUnavailableError: () => isAutostartManagerUnavailableError,
44489
44555
  isDefaultTaskHome: () => isDefaultTaskHome,
44556
+ isFingerprintKey: () => isFingerprintKey,
44490
44557
  isGatewayAvailableForHeartbeat: () => isGatewayAvailableForHeartbeat,
44491
44558
  isHermesGatewayPluginEnabled: () => isHermesGatewayPluginEnabled,
44492
44559
  isInfoEventAllowlisted: () => isInfoEventAllowlisted,
@@ -44497,6 +44564,7 @@ __export(index_exports, {
44497
44564
  isPrereleaseVersion: () => isPrereleaseVersion,
44498
44565
  isRetryableOpenClawGatewayError: () => isRetryableOpenClawGatewayError,
44499
44566
  isSqliteBusyError: () => isSqliteBusyError,
44567
+ isSubscriptionEnvelope: () => isSubscriptionEnvelope,
44500
44568
  isSystemdManagerUnavailableMessage: () => isSystemdManagerUnavailableMessage,
44501
44569
  isTagKey: () => isTagKey,
44502
44570
  isValidExternalJobId: () => isValidExternalJobId,
@@ -44505,8 +44573,12 @@ __export(index_exports, {
44505
44573
  killProcessTree: () => killProcessTree,
44506
44574
  launchdPlistHasCurrentRestartPolicy: () => launchdPlistHasCurrentRestartPolicy,
44507
44575
  listAllAgentsWithMetadata: () => listAllAgentsWithMetadata,
44576
+ listJobsByVerifiedSender: () => listJobsByVerifiedSender,
44577
+ listJobsByVerifiedSenderHelpAdvertisesCommand: () => listJobsByVerifiedSenderHelpAdvertisesCommand,
44578
+ listJobsByVerifiedSenderWithCapability: () => listJobsByVerifiedSenderWithCapability,
44508
44579
  logWinCompat: () => logWinCompat,
44509
44580
  logXmtpMessageSent: () => logXmtpMessageSent,
44581
+ logger: () => logger,
44510
44582
  maybeRecommendOnchainosUpgrade: () => maybeRecommendOnchainosUpgrade,
44511
44583
  mergeA2AEnvelopeTips: () => mergeA2AEnvelopeTips,
44512
44584
  messageEligibleHelpAdvertisesOfflineReplay: () => messageEligibleHelpAdvertisesOfflineReplay,
@@ -44514,6 +44586,8 @@ __export(index_exports, {
44514
44586
  normalizeAiProvider: () => normalizeAiProvider,
44515
44587
  normalizeAiRuntimeProvider: () => normalizeAiRuntimeProvider,
44516
44588
  normalizeHermesOkxA2aPluginConfig: () => normalizeHermesOkxA2aPluginConfig,
44589
+ normalizeListJobsResponse: () => normalizeListJobsResponse,
44590
+ normalizeSubscriptionJobs: () => normalizeSubscriptionJobs,
44517
44591
  notifyAgentMessageToUserAttention: () => notifyAgentMessageToUserAttention,
44518
44592
  notifyDirectToUserAttention: () => notifyDirectToUserAttention,
44519
44593
  notifySystemMessageToUser: () => notifySystemMessageToUser,
@@ -44524,6 +44598,7 @@ __export(index_exports, {
44524
44598
  parsePluginYamlVersion: () => parsePluginYamlVersion,
44525
44599
  parseWalletLoginStatus: () => parseWalletLoginStatus,
44526
44600
  parseWindowsParentProcessJson: () => parseWindowsParentProcessJson,
44601
+ partitionSubscriptionJobsByOwner: () => partitionSubscriptionJobsByOwner,
44527
44602
  performRuntimeSwitch: () => performRuntimeSwitch,
44528
44603
  persistAiRuntimeSurfaceBestEffort: () => persistAiRuntimeSurfaceBestEffort,
44529
44604
  persistCurrentRuntimeSelectionForNewJob: () => persistCurrentRuntimeSelectionForNewJob,
@@ -44533,12 +44608,14 @@ __export(index_exports, {
44533
44608
  printXmtpTestUsage: () => printXmtpTestUsage,
44534
44609
  probeCodexAuthStatus: () => probeCodexAuthStatus,
44535
44610
  processFileMessage: () => processFileMessage,
44611
+ processSubscriptionInbound: () => processSubscriptionInbound,
44536
44612
  queryWalletLoginStatus: () => queryWalletLoginStatus,
44537
44613
  readAiProviderTimeoutMs: () => readAiProviderTimeoutMs,
44538
44614
  readAiRuntimeSurfaceBestEffort: () => readAiRuntimeSurfaceBestEffort,
44539
44615
  readCachedCodexReadiness: () => readCachedCodexReadiness,
44540
44616
  readLastLines: () => readLastLines,
44541
44617
  readParentProcessCommandForPlatform: () => readParentProcessCommandForPlatform,
44618
+ readSubscriptionEnvelope: () => readSubscriptionEnvelope,
44542
44619
  readUserAttentionWatcherEvent: () => readUserAttentionWatcherEvent,
44543
44620
  refreshAgentsAndWait: () => refreshAgentsAndWait,
44544
44621
  refreshOnchainosVersionMetadata: () => refreshOnchainosVersionMetadata,
@@ -44549,8 +44626,10 @@ __export(index_exports, {
44549
44626
  replayScanBackoffWithJitterMs: () => replayScanBackoffWithJitterMs,
44550
44627
  reportDoctorRunToSentry: () => reportDoctorRunToSentry,
44551
44628
  reportUserNotificationFailure: () => reportUserNotificationFailure,
44629
+ resetListJobsByVerifiedSenderCapabilityForTests: () => resetListJobsByVerifiedSenderCapabilityForTests,
44552
44630
  resetMessageEligibleOfflineReplayCapabilityForTests: () => resetMessageEligibleOfflineReplayCapabilityForTests,
44553
44631
  resetResolvedOnchainosBinForTests: () => resetResolvedOnchainosBinForTests,
44632
+ resetSubscriptionTargetsForTests: () => resetSubscriptionTargetsForTests,
44554
44633
  resetXmtpCreationCooldownForTests: () => resetXmtpCreationCooldownForTests,
44555
44634
  resolveAiPermissionPreset: () => resolveAiPermissionPreset,
44556
44635
  resolveAiProviderCommand: () => resolveAiProviderCommand,
@@ -44604,6 +44683,8 @@ __export(index_exports, {
44604
44683
  stopOpenClawGateway: () => stopOpenClawGateway,
44605
44684
  stopSystemdAutostart: () => stopSystemdAutostart,
44606
44685
  subscribeUserAttentionEvents: () => subscribeUserAttentionEvents,
44686
+ subscriptionIdempotencyKey: () => subscriptionIdempotencyKey,
44687
+ summarizeSubscriptionPush: () => summarizeSubscriptionPush,
44607
44688
  summarizeXmtpTestEvents: () => summarizeXmtpTestEvents,
44608
44689
  switchProvider: () => switchProvider,
44609
44690
  switchProviderWithReadinessGate: () => switchProviderWithReadinessGate,
@@ -44612,6 +44693,7 @@ __export(index_exports, {
44612
44693
  tailFile: () => tailFile,
44613
44694
  toOpenClawGatewaySessionKey: () => toOpenClawGatewaySessionKey,
44614
44695
  toWindowsInvocation: () => toWindowsInvocation,
44696
+ tryMarkSubscriptionTarget: () => tryMarkSubscriptionTarget,
44615
44697
  writeAiPermissionPresetToConfig: () => writeAiPermissionPresetToConfig
44616
44698
  });
44617
44699
  module.exports = __toCommonJS(index_exports);
@@ -44621,12 +44703,62 @@ init_autostart();
44621
44703
 
44622
44704
  // src/ai-runner.ts
44623
44705
  init_log();
44624
- var import_node_crypto4 = require("node:crypto");
44706
+ var import_node_crypto5 = require("node:crypto");
44625
44707
  var import_node_fs11 = require("node:fs");
44626
44708
  var import_promises7 = require("node:fs/promises");
44627
44709
  var import_node_os6 = require("node:os");
44628
44710
  var import_node_path16 = require("node:path");
44629
44711
  init_ai_command();
44712
+
44713
+ // src/ai-run-log-path.ts
44714
+ var import_node_crypto2 = require("node:crypto");
44715
+ var RUN_LOG_FILENAME_MAX_BYTES = 240;
44716
+ function buildRunLogFileName(request) {
44717
+ const source = request.source;
44718
+ const sessionKey = request.sessionKey;
44719
+ const messageId = request.messageId;
44720
+ const jobId = request.jobId;
44721
+ const safeMessageId = encodeURIComponent(messageId);
44722
+ const prefix = source === "job-dispatch" ? "ai-" : "ai-session-";
44723
+ const encodedContext = source === "job-dispatch" ? encodeURIComponent(jobId ?? "unknown") : encodeURIComponent(sessionKey);
44724
+ const readable = `${prefix}${encodedContext}-${safeMessageId}.log`;
44725
+ if (Buffer.byteLength(readable, "utf8") <= RUN_LOG_FILENAME_MAX_BYTES) {
44726
+ return readable;
44727
+ }
44728
+ const readableWithoutExt = readable.slice(0, -".log".length);
44729
+ const digest = (0, import_node_crypto2.createHash)("sha256").update(readableWithoutExt).digest("hex").slice(0, 24);
44730
+ const suffix = `-${digest}.log`;
44731
+ const budgetForContext = RUN_LOG_FILENAME_MAX_BYTES - Buffer.byteLength(prefix, "utf8") - Buffer.byteLength(suffix, "utf8");
44732
+ const contextHead = truncateToUtf8ByteBudgetSafe(encodedContext, Math.max(budgetForContext, 0));
44733
+ return `${prefix}${contextHead}${suffix}`;
44734
+ }
44735
+ function truncateToUtf8ByteBudgetSafe(encoded, maxBytes) {
44736
+ if (maxBytes <= 0) {
44737
+ return "";
44738
+ }
44739
+ if (Buffer.byteLength(encoded, "utf8") <= maxBytes) {
44740
+ return encoded;
44741
+ }
44742
+ let candidateLength = Math.min(maxBytes, encoded.length);
44743
+ while (candidateLength > 0) {
44744
+ const candidate = encoded.slice(0, candidateLength);
44745
+ if (!endsWithSplitEscape(candidate)) {
44746
+ return candidate;
44747
+ }
44748
+ candidateLength -= 1;
44749
+ }
44750
+ return "";
44751
+ }
44752
+ function endsWithSplitEscape(value) {
44753
+ const percentIndex = value.lastIndexOf("%");
44754
+ if (percentIndex === -1) {
44755
+ return false;
44756
+ }
44757
+ const tail = value.length - percentIndex - 1;
44758
+ return tail < 2;
44759
+ }
44760
+
44761
+ // src/ai-runner.ts
44630
44762
  init_paths();
44631
44763
 
44632
44764
  // src/file-store.ts
@@ -46307,13 +46439,15 @@ var AiRunner = class {
46307
46439
  );
46308
46440
  }
46309
46441
  buildRunLogPath(request) {
46310
- const safeMessageId = encodeURIComponent(request.messageId);
46311
- if (request.source === "job-dispatch") {
46312
- const safeJobId = encodeURIComponent(request.jobId ?? "unknown");
46313
- return (0, import_node_path16.join)(this.logsDir, `ai-${safeJobId}-${safeMessageId}.log`);
46314
- }
46315
- const safeSessionKey = encodeURIComponent(request.sessionKey);
46316
- return (0, import_node_path16.join)(this.logsDir, `ai-session-${safeSessionKey}-${safeMessageId}.log`);
46442
+ return (0, import_node_path16.join)(
46443
+ this.logsDir,
46444
+ buildRunLogFileName({
46445
+ source: request.source,
46446
+ sessionKey: request.sessionKey,
46447
+ messageId: request.messageId,
46448
+ jobId: request.jobId
46449
+ })
46450
+ );
46317
46451
  }
46318
46452
  readRunAiSessionId(provider, request, file, sessionMeta) {
46319
46453
  if (request.source === "job-dispatch" && request.jobId) {
@@ -48035,7 +48169,7 @@ function normalizeAttentionProvider(provider) {
48035
48169
  return provider === "unknown" ? null : provider;
48036
48170
  }
48037
48171
  function stableHash(value) {
48038
- return (0, import_node_crypto4.createHash)("sha256").update(value).digest("hex").slice(0, 24);
48172
+ return (0, import_node_crypto5.createHash)("sha256").update(value).digest("hex").slice(0, 24);
48039
48173
  }
48040
48174
  function formatCommand(args) {
48041
48175
  return args.map(shellQuote).join(" ");
@@ -48062,10 +48196,11 @@ function shortenJobId(jobId) {
48062
48196
 
48063
48197
  // src/command-store.ts
48064
48198
  init_log();
48065
- var import_node_crypto5 = require("node:crypto");
48199
+ var import_node_crypto6 = require("node:crypto");
48066
48200
  var import_node_fs12 = require("node:fs");
48067
48201
  var import_node_path17 = require("node:path");
48068
48202
  init_paths();
48203
+ init_session_store();
48069
48204
  var { DatabaseSync: DatabaseSync2 } = loadSqlite2();
48070
48205
  var XMTP_DEBUG_RESULT_TTL_MS = 5 * 6e4;
48071
48206
  function stringifyForStorage(value) {
@@ -48087,7 +48222,7 @@ var CommandStore = class {
48087
48222
  }
48088
48223
  createXmtpSendCommand(params) {
48089
48224
  return {
48090
- id: (0, import_node_crypto5.randomUUID)(),
48225
+ id: (0, import_node_crypto6.randomUUID)(),
48091
48226
  type: "xmtp-send",
48092
48227
  jobId: params.jobId,
48093
48228
  message: params.message,
@@ -48101,16 +48236,27 @@ var CommandStore = class {
48101
48236
  createdAt: Date.now()
48102
48237
  };
48103
48238
  }
48239
+ createXmtpSubscriptionPushCommand(params) {
48240
+ return {
48241
+ id: (0, import_node_crypto6.randomUUID)(),
48242
+ type: "xmtp-subscription-push",
48243
+ myAgentId: params.myAgentId,
48244
+ content: params.content,
48245
+ conversationIds: params.conversationIds,
48246
+ deliveryId: params.deliveryId,
48247
+ createdAt: Date.now()
48248
+ };
48249
+ }
48104
48250
  createXmtpGetPendingListCommand() {
48105
48251
  return {
48106
- id: (0, import_node_crypto5.randomUUID)(),
48252
+ id: (0, import_node_crypto6.randomUUID)(),
48107
48253
  type: "xmtp-get-pending-list",
48108
48254
  createdAt: Date.now()
48109
48255
  };
48110
48256
  }
48111
48257
  createXmtpDenyPendingConversationCommand(params) {
48112
48258
  return {
48113
- id: (0, import_node_crypto5.randomUUID)(),
48259
+ id: (0, import_node_crypto6.randomUUID)(),
48114
48260
  type: "xmtp-deny-pending-conversation",
48115
48261
  groupId: params.groupId,
48116
48262
  jobId: params.jobId,
@@ -48121,14 +48267,14 @@ var CommandStore = class {
48121
48267
  }
48122
48268
  createXmtpRefreshAgentsCommand() {
48123
48269
  return {
48124
- id: (0, import_node_crypto5.randomUUID)(),
48270
+ id: (0, import_node_crypto6.randomUUID)(),
48125
48271
  type: "xmtp-refresh-agents",
48126
48272
  createdAt: Date.now()
48127
48273
  };
48128
48274
  }
48129
48275
  createXmtpGetConversationHistoryCommand(params) {
48130
48276
  return {
48131
- id: (0, import_node_crypto5.randomUUID)(),
48277
+ id: (0, import_node_crypto6.randomUUID)(),
48132
48278
  type: "xmtp-get-conversation-history",
48133
48279
  jobId: params.jobId,
48134
48280
  toAgentId: params.toAgentId,
@@ -48140,7 +48286,7 @@ var CommandStore = class {
48140
48286
  }
48141
48287
  createXmtpDebugCommand(params) {
48142
48288
  return {
48143
- id: (0, import_node_crypto5.randomUUID)(),
48289
+ id: (0, import_node_crypto6.randomUUID)(),
48144
48290
  type: "xmtp-debug",
48145
48291
  action: params.action,
48146
48292
  groupId: params.groupId,
@@ -48155,7 +48301,7 @@ var CommandStore = class {
48155
48301
  }
48156
48302
  createAiJobMessageDispatchCommand(params) {
48157
48303
  return {
48158
- id: (0, import_node_crypto5.randomUUID)(),
48304
+ id: (0, import_node_crypto6.randomUUID)(),
48159
48305
  type: "ai-dispatch",
48160
48306
  kind: "job-message",
48161
48307
  jobId: params.jobId,
@@ -48166,7 +48312,7 @@ var CommandStore = class {
48166
48312
  }
48167
48313
  createAiSessionMessageDispatchCommand(params) {
48168
48314
  return {
48169
- id: (0, import_node_crypto5.randomUUID)(),
48315
+ id: (0, import_node_crypto6.randomUUID)(),
48170
48316
  type: "ai-dispatch",
48171
48317
  kind: "session-message",
48172
48318
  sessionKey: params.sessionKey,
@@ -48194,6 +48340,65 @@ var CommandStore = class {
48194
48340
  );
48195
48341
  return this.commandPath(command.id);
48196
48342
  }
48343
+ /**
48344
+ * Atomic idempotent submit keyed on a business `idempotencyKey` (DEXMARKET-9035,
48345
+ * M2). The FIRST caller for a given key inserts its command and gets
48346
+ * `created: true`; every later caller with the SAME key — including after a
48347
+ * daemon / CommandStore rebuild — gets the ALREADY-persisted command back with
48348
+ * `created: false` and NO new row. Concurrency-safe: correctness rests on the
48349
+ * partial UNIQUE index on `idempotency_key`, not a check-then-insert (which
48350
+ * races), so a `INSERT ... ON CONFLICT DO NOTHING` collapses concurrent
48351
+ * duplicates to exactly one row. Recoverable SQLITE_BUSY/LOCKED errors reuse
48352
+ * the repo's bounded exponential backoff. This never changes the plain
48353
+ * `submit` path used by `xmtp-send` and every other daemon command.
48354
+ */
48355
+ async submitIdempotent(command, idempotencyKey) {
48356
+ if (!idempotencyKey) {
48357
+ throw new Error("submitIdempotent requires a non-empty idempotencyKey");
48358
+ }
48359
+ return this.withBusyRetry(
48360
+ () => this.transaction(() => {
48361
+ const now = Date.now();
48362
+ const insert = this.db.prepare(`
48363
+ INSERT INTO command_queue (
48364
+ id, type, status, command_json, result_json,
48365
+ created_at_ms, updated_at_ms, processing_started_at_ms, completed_at_ms,
48366
+ idempotency_key
48367
+ )
48368
+ VALUES (?, ?, 'pending', ?, NULL, ?, ?, NULL, NULL, ?)
48369
+ ON CONFLICT(idempotency_key) WHERE idempotency_key IS NOT NULL DO NOTHING
48370
+ `).run(
48371
+ command.id,
48372
+ command.type,
48373
+ stringifyForStorage(command),
48374
+ normalizeCreatedAt(command.createdAt, now),
48375
+ now,
48376
+ idempotencyKey
48377
+ );
48378
+ if (Number(insert.changes ?? 0) > 0) {
48379
+ return { path: this.commandPath(command.id), commandId: command.id, created: true };
48380
+ }
48381
+ const existing = this.db.prepare(`
48382
+ SELECT id FROM command_queue WHERE idempotency_key = ?
48383
+ `).get(idempotencyKey);
48384
+ const existingId = existing?.id ?? command.id;
48385
+ return { path: this.commandPath(existingId), commandId: existingId, created: false };
48386
+ })
48387
+ );
48388
+ }
48389
+ async withBusyRetry(operation) {
48390
+ const attempts = 6;
48391
+ for (let attempt = 1; ; attempt += 1) {
48392
+ try {
48393
+ return operation();
48394
+ } catch (err) {
48395
+ if (!isSqliteBusyError(err) || attempt >= attempts) {
48396
+ throw err;
48397
+ }
48398
+ await new Promise((resolve11) => setTimeout(resolve11, Math.min(50 * 2 ** (attempt - 1), 1e3)));
48399
+ }
48400
+ }
48401
+ }
48197
48402
  async listPending() {
48198
48403
  return (await this.listPendingEntries()).map((entry) => entry.command);
48199
48404
  }
@@ -48260,9 +48465,24 @@ var CommandStore = class {
48260
48465
  CREATE INDEX IF NOT EXISTS idx_command_queue_status_created
48261
48466
  ON command_queue(status, created_at_ms, id)
48262
48467
  `);
48468
+ this.ensureColumn("command_queue", "idempotency_key", "TEXT");
48469
+ this.db.exec(`
48470
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_command_queue_idempotency_key
48471
+ ON command_queue(idempotency_key)
48472
+ WHERE idempotency_key IS NOT NULL
48473
+ `);
48263
48474
  this.purgeExpiredXmtpDebugResults();
48264
48475
  this.importLegacyFileCommands();
48265
48476
  }
48477
+ ensureColumn(table, column, definition) {
48478
+ this.transaction(() => {
48479
+ const rows = this.db.prepare(`PRAGMA table_info(${table})`).all();
48480
+ if (rows.some((row) => row.name === column)) {
48481
+ return;
48482
+ }
48483
+ this.db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
48484
+ });
48485
+ }
48266
48486
  purgeExpiredXmtpDebugResults() {
48267
48487
  this.db.prepare(`
48268
48488
  DELETE FROM command_queue
@@ -48434,6 +48654,10 @@ function isDaemonCommand(value) {
48434
48654
  if (parsed.type === "xmtp-send") {
48435
48655
  return typeof parsed.jobId === "string" && typeof parsed.message === "string";
48436
48656
  }
48657
+ if (parsed.type === "xmtp-subscription-push") {
48658
+ const command = parsed;
48659
+ return typeof command.myAgentId === "string" && typeof command.content === "string" && Array.isArray(command.conversationIds) && command.conversationIds.every((item) => typeof item === "string");
48660
+ }
48437
48661
  if (parsed.type === "xmtp-get-pending-list") {
48438
48662
  return true;
48439
48663
  }
@@ -48600,7 +48824,7 @@ var import_node_path21 = require("node:path");
48600
48824
  // ../../node_modules/@xmtp/node-sdk/dist/index.js
48601
48825
  var import_node_bindings = require("@xmtp/node-bindings");
48602
48826
  var import_node_bindings2 = require("@xmtp/node-bindings");
48603
- var import_node_crypto6 = require("node:crypto");
48827
+ var import_node_crypto7 = require("node:crypto");
48604
48828
 
48605
48829
  // ../../node_modules/@xmtp/node-sdk/node_modules/@xmtp/content-type-primitives/dist/index.js
48606
48830
  var contentTypeToString = (contentType) => `${contentType.authorityId}/${contentType.typeId}:${contentType.versionMajor}.${contentType.versionMinor}`;
@@ -50322,7 +50546,7 @@ var resolveBackend = async (envOrBackend, gatewayHost) => {
50322
50546
  return createBackend({ env: envOrBackend, gatewayHost });
50323
50547
  };
50324
50548
  var createEphemeralIdentifier = () => ({
50325
- identifier: `0x${(0, import_node_crypto6.randomBytes)(20).toString("hex")}`,
50549
+ identifier: `0x${(0, import_node_crypto7.randomBytes)(20).toString("hex")}`,
50326
50550
  identifierKind: 0
50327
50551
  });
50328
50552
  var toInboxUpdatesCountMap = (value) => {
@@ -55112,7 +55336,7 @@ var sepolia = /* @__PURE__ */ defineChain({
55112
55336
  });
55113
55337
 
55114
55338
  // ../../node_modules/@xmtp/agent-sdk/dist/index.js
55115
- var import_node_crypto7 = require("node:crypto");
55339
+ var import_node_crypto8 = require("node:crypto");
55116
55340
  var version2 = "2.3.0";
55117
55341
  var fromSelf = (message, client) => {
55118
55342
  return message.senderInboxId === client.inboxId;
@@ -55807,7 +56031,7 @@ var Agent = class _Agent extends import_node_events.default {
55807
56031
  return this.#client.accountIdentifier?.identifier;
55808
56032
  }
55809
56033
  };
55810
- var CANCEL_ACTION_ID = (0, import_node_crypto7.randomUUID)();
56034
+ var CANCEL_ACTION_ID = (0, import_node_crypto8.randomUUID)();
55811
56035
  var LimitedMap = class {
55812
56036
  #map = /* @__PURE__ */ new Map();
55813
56037
  #limit;
@@ -59481,7 +59705,7 @@ function buildSendEnvelope(params) {
59481
59705
  init_log();
59482
59706
  init_sentry_logger();
59483
59707
  init_log_fields();
59484
- var import_node_crypto11 = require("node:crypto");
59708
+ var import_node_crypto12 = require("node:crypto");
59485
59709
 
59486
59710
  // ../core/src/a2a/concurrency.ts
59487
59711
  async function withSharedPromise(registry, key, fn) {
@@ -60883,17 +61107,17 @@ init_ai_provider();
60883
61107
 
60884
61108
  // src/agent-message-notice.ts
60885
61109
  init_log();
60886
- var import_node_crypto10 = require("node:crypto");
61110
+ var import_node_crypto11 = require("node:crypto");
60887
61111
  init_session_store();
60888
61112
  init_ai_provider();
60889
61113
 
60890
61114
  // src/outbound-behavior.ts
60891
61115
  init_log();
60892
- var import_node_crypto9 = require("node:crypto");
61116
+ var import_node_crypto10 = require("node:crypto");
60893
61117
 
60894
61118
  // src/openclaw-gateway.ts
60895
61119
  init_log();
60896
- var import_node_crypto8 = require("node:crypto");
61120
+ var import_node_crypto9 = require("node:crypto");
60897
61121
 
60898
61122
  // ../core/src/openclaw-gateway-config.ts
60899
61123
  var import_node_fs17 = require("node:fs");
@@ -61386,7 +61610,7 @@ async function callDeleteSessions(params) {
61386
61610
  return await callOpenClawGateway({ method: "okx-a2a.delete_sessions", params });
61387
61611
  }
61388
61612
  async function callSessionsSend(params) {
61389
- const idempotencyKey = params.idempotencyKey ?? (0, import_node_crypto8.randomUUID)();
61613
+ const idempotencyKey = params.idempotencyKey ?? (0, import_node_crypto9.randomUUID)();
61390
61614
  const sendParams = { key: params.key, message: params.message, idempotencyKey };
61391
61615
  try {
61392
61616
  return await callOpenClawGateway({ method: "sessions.send", params: sendParams });
@@ -61502,7 +61726,7 @@ async function sleep3(ms) {
61502
61726
  var MinimalGatewayClient = class {
61503
61727
  config;
61504
61728
  protocolVersion;
61505
- instanceId = (0, import_node_crypto8.randomUUID)();
61729
+ instanceId = (0, import_node_crypto9.randomUUID)();
61506
61730
  pending = /* @__PURE__ */ new Map();
61507
61731
  ws = null;
61508
61732
  ready = false;
@@ -61590,7 +61814,7 @@ var MinimalGatewayClient = class {
61590
61814
  }));
61591
61815
  }
61592
61816
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
61593
- const id = `okx-a2a-${++this.requestSeq}-${(0, import_node_crypto8.randomUUID)()}`;
61817
+ const id = `okx-a2a-${++this.requestSeq}-${(0, import_node_crypto9.randomUUID)()}`;
61594
61818
  const frame = { type: "req", id, method, params };
61595
61819
  return new Promise((resolve11, reject) => {
61596
61820
  const timer = setTimeout(() => {
@@ -61716,7 +61940,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
61716
61940
  client: {
61717
61941
  id: "gateway-client",
61718
61942
  displayName: "okx-a2a-node",
61719
- version: "0.2.17",
61943
+ version: "0.2.18-beta-4dd056b897-261015113839",
61720
61944
  platform: "node",
61721
61945
  mode: "backend",
61722
61946
  instanceId
@@ -61727,7 +61951,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
61727
61951
  commands: [],
61728
61952
  permissions: {},
61729
61953
  locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
61730
- userAgent: `okx-a2a-node/${"0.2.17"}`,
61954
+ userAgent: `okx-a2a-node/${"0.2.18-beta-4dd056b897-261015113839"}`,
61731
61955
  auth: {
61732
61956
  ...config.token ? { token: config.token } : {},
61733
61957
  ...config.password ? { password: config.password } : {}
@@ -62333,7 +62557,7 @@ function resolveSessionGateFallbackMs(env = process.env) {
62333
62557
  return DEFAULT_SESSION_GATE_FALLBACK_MS;
62334
62558
  }
62335
62559
  function resolveUserDeliveryId(input) {
62336
- return input.idempotencyKey?.trim() || (0, import_node_crypto9.randomUUID)();
62560
+ return input.idempotencyKey?.trim() || (0, import_node_crypto10.randomUUID)();
62337
62561
  }
62338
62562
  var GATEWAY_RPC_TRANSPORT = "gateway_rpc";
62339
62563
  var USER_CHANNEL_TRANSPORT = "user_channel";
@@ -63247,7 +63471,7 @@ function buildSystemMessageIdempotencyKey(input) {
63247
63471
  return `system-message:${identity}`;
63248
63472
  }
63249
63473
  function stableHash2(value) {
63250
- return (0, import_node_crypto10.createHash)("sha256").update(value).digest("hex").slice(0, 24);
63474
+ return (0, import_node_crypto11.createHash)("sha256").update(value).digest("hex").slice(0, 24);
63251
63475
  }
63252
63476
 
63253
63477
  // src/xmtp-send.ts
@@ -63716,7 +63940,7 @@ async function handleSqliteGroupSendCommand(params) {
63716
63940
  role: senderAgent?.role,
63717
63941
  sendDurationMs: Date.now() - sendStartMs
63718
63942
  });
63719
- const messageId = `outbound-${(0, import_node_crypto11.randomUUID)()}`;
63943
+ const messageId = `outbound-${(0, import_node_crypto12.randomUUID)()}`;
63720
63944
  await notifyAgentMessageToUserAttention({
63721
63945
  direction: "outbound" /* OUTBOUND */,
63722
63946
  sender: {
@@ -63837,7 +64061,7 @@ async function handleGroupSendCommand(params) {
63837
64061
  sendDurationMs: Date.now() - sendStartMs
63838
64062
  });
63839
64063
  const now = Date.now();
63840
- const messageId = `outbound-${(0, import_node_crypto11.randomUUID)()}`;
64064
+ const messageId = `outbound-${(0, import_node_crypto12.randomUUID)()}`;
63841
64065
  const stored = {
63842
64066
  id: messageId,
63843
64067
  direction: "outbound",
@@ -64056,7 +64280,7 @@ async function handleXmtpSendCommand(params) {
64056
64280
  sendDurationMs: Date.now() - sendStartMs
64057
64281
  });
64058
64282
  const now = Date.now();
64059
- const messageId = `outbound-${(0, import_node_crypto11.randomUUID)()}`;
64283
+ const messageId = `outbound-${(0, import_node_crypto12.randomUUID)()}`;
64060
64284
  const stored = {
64061
64285
  id: messageId,
64062
64286
  direction: "outbound",
@@ -64103,6 +64327,357 @@ async function handleXmtpSendCommand(params) {
64103
64327
  }
64104
64328
  }
64105
64329
 
64330
+ // src/subscription-push.ts
64331
+ init_log();
64332
+ init_sentry_logger();
64333
+
64334
+ // ../core/src/a2a/subscription-types.ts
64335
+ var SUBSCRIPTION_MESSAGE_TYPE = "a2a-subscription-push";
64336
+
64337
+ // ../core/src/a2a/subscription-envelope.ts
64338
+ function isPlainObject2(value) {
64339
+ return !!value && typeof value === "object" && !Array.isArray(value);
64340
+ }
64341
+ function buildSubscriptionEnvelope(params) {
64342
+ const envelope = {
64343
+ msgType: SUBSCRIPTION_MESSAGE_TYPE,
64344
+ content: params.content,
64345
+ senderAgentId: params.senderAgentId
64346
+ };
64347
+ if (params.deliveryId) {
64348
+ envelope.deliveryId = params.deliveryId;
64349
+ }
64350
+ return JSON.stringify(envelope);
64351
+ }
64352
+ function isSubscriptionEnvelope(payload) {
64353
+ return isPlainObject2(payload) && payload.msgType === SUBSCRIPTION_MESSAGE_TYPE;
64354
+ }
64355
+ function isNonEmptyString(value) {
64356
+ return typeof value === "string" && value.length > 0;
64357
+ }
64358
+ function readSubscriptionEnvelope(payload) {
64359
+ if (!isSubscriptionEnvelope(payload)) {
64360
+ return { ok: false, reason: "not_subscription" };
64361
+ }
64362
+ const record = payload;
64363
+ if (!isNonEmptyString(record.content)) {
64364
+ return { ok: false, reason: "missing_content" };
64365
+ }
64366
+ const envelope = {
64367
+ msgType: SUBSCRIPTION_MESSAGE_TYPE,
64368
+ content: record.content,
64369
+ senderAgentId: isNonEmptyString(record.senderAgentId) ? record.senderAgentId : ""
64370
+ };
64371
+ if (isNonEmptyString(record.deliveryId)) {
64372
+ envelope.deliveryId = record.deliveryId;
64373
+ }
64374
+ return { ok: true, envelope };
64375
+ }
64376
+
64377
+ // src/subscription-telemetry.ts
64378
+ init_log_fields();
64379
+ var SUBSCRIPTION_TRANSPORT = "xmtp";
64380
+ function definedExtras(input) {
64381
+ return Object.entries(input).reduce((out, [key, value]) => {
64382
+ if (typeof value === "string" && value.trim().length > 0) {
64383
+ out[key] = value.trim();
64384
+ }
64385
+ return out;
64386
+ }, {});
64387
+ }
64388
+ function countExtras(input) {
64389
+ return Object.entries(input).reduce((out, [key, value]) => {
64390
+ if (typeof value === "number" && Number.isFinite(value)) {
64391
+ out[key] = String(value);
64392
+ }
64393
+ return out;
64394
+ }, {});
64395
+ }
64396
+ function buildSubscriptionSendExtras(input) {
64397
+ return {
64398
+ stage: input.checkpoint,
64399
+ ...logFieldExtras({
64400
+ checkpoint: input.checkpoint,
64401
+ outcome: input.outcome ?? null,
64402
+ transport: SUBSCRIPTION_TRANSPORT,
64403
+ eventFamily: "outbound",
64404
+ deliveryId: input.deliveryId ?? null
64405
+ }),
64406
+ ...definedExtras({
64407
+ aspAgentId: input.aspAgentId,
64408
+ conversationId: input.conversationId,
64409
+ reason: input.reason
64410
+ }),
64411
+ ...countExtras({
64412
+ targetCount: input.targetCount,
64413
+ sentCount: input.sentCount,
64414
+ failedCount: input.failedCount,
64415
+ notGroupCount: input.notGroupCount
64416
+ })
64417
+ };
64418
+ }
64419
+ function buildSubscriptionInboundExtras(input) {
64420
+ return {
64421
+ stage: input.checkpoint,
64422
+ ...logFieldExtras({
64423
+ checkpoint: input.checkpoint,
64424
+ outcome: input.outcome ?? null,
64425
+ transport: SUBSCRIPTION_TRANSPORT,
64426
+ eventFamily: "inbound",
64427
+ deliveryId: input.deliveryId ?? null
64428
+ }),
64429
+ ...definedExtras({
64430
+ userAgentId: input.userAgentId,
64431
+ conversationId: input.conversationId,
64432
+ messageId: input.messageId,
64433
+ senderInboxId: input.senderInboxId,
64434
+ reason: input.reason,
64435
+ errorCode: input.errorCode
64436
+ }),
64437
+ ...countExtras({
64438
+ returnedCount: input.returnedCount,
64439
+ invalidCount: input.invalidCount,
64440
+ ownedCount: input.ownedCount,
64441
+ ignoredCount: input.ignoredCount
64442
+ })
64443
+ };
64444
+ }
64445
+ function buildSubscriptionJobExtras(input) {
64446
+ return {
64447
+ stage: input.checkpoint,
64448
+ ...logFieldExtras({
64449
+ checkpoint: input.checkpoint,
64450
+ outcome: input.outcome,
64451
+ transport: SUBSCRIPTION_TRANSPORT,
64452
+ eventFamily: "dispatch",
64453
+ deliveryId: input.deliveryId ?? null
64454
+ }),
64455
+ ...definedExtras({
64456
+ jobId: input.jobId,
64457
+ userAgentId: input.userAgentId,
64458
+ aspAgentId: input.aspAgentId,
64459
+ conversationId: input.conversationId,
64460
+ reason: input.reason
64461
+ }),
64462
+ ...countExtras({
64463
+ total: input.total,
64464
+ started: input.started,
64465
+ failed: input.failed,
64466
+ skippedDuplicate: input.skippedDuplicate
64467
+ })
64468
+ };
64469
+ }
64470
+
64471
+ // src/subscription-push.ts
64472
+ var DEFAULT_CONCURRENCY = 20;
64473
+ var conversationSyncPromises2 = /* @__PURE__ */ new WeakMap();
64474
+ function describeError(err) {
64475
+ if (err instanceof Error) {
64476
+ return err.message;
64477
+ }
64478
+ if (typeof err === "string" && err.length > 0) {
64479
+ return err;
64480
+ }
64481
+ return "unknown error";
64482
+ }
64483
+ async function requireXmtpClient2(service, address) {
64484
+ const existing = service.getClientByAddress(address);
64485
+ if (existing) {
64486
+ return existing;
64487
+ }
64488
+ await service.refreshAgents();
64489
+ const refreshed = service.getClientByAddress(address);
64490
+ if (!refreshed) {
64491
+ throw new Error(`no XMTP client found for ${address}`);
64492
+ }
64493
+ return refreshed;
64494
+ }
64495
+ function resolveLocalAddress(service, myAgentId) {
64496
+ const address = service.getAddressByAgentId(myAgentId);
64497
+ if (!address) {
64498
+ throw new Error(`No local communication address found for myAgentId=${myAgentId}`);
64499
+ }
64500
+ return address;
64501
+ }
64502
+ async function syncConversationsOnLocalMiss2(agent) {
64503
+ const conversations = agent.client.conversations;
64504
+ const existing = conversationSyncPromises2.get(conversations);
64505
+ if (existing) {
64506
+ return existing;
64507
+ }
64508
+ const pending = conversations.sync();
64509
+ conversationSyncPromises2.set(conversations, pending);
64510
+ try {
64511
+ await pending;
64512
+ } finally {
64513
+ if (conversationSyncPromises2.get(conversations) === pending) {
64514
+ conversationSyncPromises2.delete(conversations);
64515
+ }
64516
+ }
64517
+ }
64518
+ async function findGroupConversation2(agent, conversationId) {
64519
+ let conversation = await agent.client.conversations.getConversationById(conversationId);
64520
+ if (!(conversation instanceof Group)) {
64521
+ await syncConversationsOnLocalMiss2(agent);
64522
+ conversation = await agent.client.conversations.getConversationById(conversationId);
64523
+ }
64524
+ return conversation instanceof Group ? conversation : null;
64525
+ }
64526
+ async function sendSubscriptionToGroup(params) {
64527
+ const { agent, conversationId, command, myXmtpAddress, senderRole } = params;
64528
+ let conversation;
64529
+ try {
64530
+ conversation = await findGroupConversation2(agent, conversationId);
64531
+ } catch (err) {
64532
+ return { conversationId, status: "not_group", error: describeError(err) };
64533
+ }
64534
+ if (!conversation) {
64535
+ return {
64536
+ conversationId,
64537
+ status: "not_group",
64538
+ error: `conversationId=${conversationId} is not a Group (DM or unknown conversation)`
64539
+ };
64540
+ }
64541
+ const envelope = buildSubscriptionEnvelope({
64542
+ content: command.content,
64543
+ senderAgentId: command.myAgentId,
64544
+ deliveryId: command.deliveryId
64545
+ });
64546
+ const sendStartMs = Date.now();
64547
+ try {
64548
+ const xmtpMessageId = await conversation.sendText(envelope);
64549
+ logXmtpMessageSent({
64550
+ xmtpMessageId,
64551
+ conversationId,
64552
+ // V2 has no job dimension (FR-1) — deliveryId (or a fixed marker)
64553
+ // stands in for the telemetry taxonomy's jobId slot.
64554
+ jobId: command.deliveryId ?? "subscription-push",
64555
+ chatType: "group",
64556
+ component: "node_xmtp_subscription_push",
64557
+ myXmtpAddress,
64558
+ senderAgentId: command.myAgentId,
64559
+ role: senderRole,
64560
+ sendDurationMs: Date.now() - sendStartMs
64561
+ });
64562
+ const messageId = typeof xmtpMessageId === "string" && xmtpMessageId.length > 0 ? xmtpMessageId : String(xmtpMessageId);
64563
+ logWithTimestamp(
64564
+ `[okx-agent-task] subscription-push sent conversationId=${conversationId} deliveryId=${command.deliveryId ?? "(none)"}`
64565
+ );
64566
+ return { conversationId, status: "sent", messageId };
64567
+ } catch (err) {
64568
+ logWithTimestamp(
64569
+ `[okx-agent-task] subscription-push failed conversationId=${conversationId} deliveryId=${command.deliveryId ?? "(none)"}`
64570
+ );
64571
+ return { conversationId, status: "failed", error: describeError(err) };
64572
+ }
64573
+ }
64574
+ function summarizeSubscriptionPush(results) {
64575
+ let sentCount = 0;
64576
+ let failedCount = 0;
64577
+ for (const result of results) {
64578
+ if (result.status === "sent") {
64579
+ sentCount++;
64580
+ } else {
64581
+ failedCount++;
64582
+ }
64583
+ }
64584
+ return { conversationCount: results.length, sentCount, failedCount };
64585
+ }
64586
+ async function handleSubscriptionPushCommand(params) {
64587
+ const { command, service } = params;
64588
+ const aspAgentId = command.myAgentId;
64589
+ const deliveryId = command.deliveryId;
64590
+ const conversationIds = command.conversationIds ?? [];
64591
+ logger.info(
64592
+ LogEvent.SUBSCRIPTION_PUSH_STARTED,
64593
+ buildSubscriptionSendExtras({
64594
+ checkpoint: "outbound/subscription_push_started",
64595
+ aspAgentId,
64596
+ deliveryId,
64597
+ targetCount: conversationIds.length
64598
+ })
64599
+ );
64600
+ if (conversationIds.length === 0) {
64601
+ logger.info(
64602
+ LogEvent.SUBSCRIPTION_PUSH_EMPTY_TARGETS,
64603
+ buildSubscriptionSendExtras({
64604
+ checkpoint: "outbound/subscription_push_empty_targets",
64605
+ outcome: "ignored",
64606
+ aspAgentId,
64607
+ deliveryId,
64608
+ targetCount: 0,
64609
+ reason: "empty_targets"
64610
+ })
64611
+ );
64612
+ return { conversationCount: 0, sentCount: 0, failedCount: 0, results: [] };
64613
+ }
64614
+ const myXmtpAddress = resolveLocalAddress(service, command.myAgentId);
64615
+ const agent = await requireXmtpClient2(service, myXmtpAddress);
64616
+ const senderRole = service.getAgentByAddress?.(myXmtpAddress)?.role;
64617
+ logger.info(
64618
+ LogEvent.SUBSCRIPTION_PUSH_TARGETS_RESOLVED,
64619
+ buildSubscriptionSendExtras({
64620
+ checkpoint: "outbound/subscription_push_targets_resolved",
64621
+ aspAgentId,
64622
+ deliveryId,
64623
+ targetCount: conversationIds.length
64624
+ })
64625
+ );
64626
+ const settled = await parallelMap(
64627
+ conversationIds,
64628
+ (conversationId) => sendSubscriptionToGroup({
64629
+ agent,
64630
+ conversationId,
64631
+ command,
64632
+ myXmtpAddress,
64633
+ senderRole
64634
+ }),
64635
+ DEFAULT_CONCURRENCY
64636
+ );
64637
+ const results = settled.map((outcome, index2) => {
64638
+ if (outcome.status === "fulfilled") {
64639
+ return outcome.value;
64640
+ }
64641
+ return {
64642
+ conversationId: conversationIds[index2],
64643
+ status: "failed",
64644
+ error: describeError(outcome.reason)
64645
+ };
64646
+ });
64647
+ for (const result of results) {
64648
+ if (result.status === "sent") {
64649
+ continue;
64650
+ }
64651
+ logger.error(
64652
+ LogEvent.SUBSCRIPTION_PUSH_TARGET_FAILED,
64653
+ void 0,
64654
+ buildSubscriptionSendExtras({
64655
+ checkpoint: "outbound/subscription_push_target_failed",
64656
+ outcome: "failed",
64657
+ aspAgentId,
64658
+ deliveryId,
64659
+ conversationId: result.conversationId,
64660
+ reason: result.status
64661
+ })
64662
+ );
64663
+ }
64664
+ const summary = summarizeSubscriptionPush(results);
64665
+ const summaryOutcome = summary.failedCount === 0 ? "success" : summary.sentCount > 0 ? "partial" : "failed";
64666
+ logger.info(
64667
+ LogEvent.SUBSCRIPTION_PUSH_SUMMARY,
64668
+ buildSubscriptionSendExtras({
64669
+ checkpoint: "outbound/subscription_push_summary",
64670
+ outcome: summaryOutcome,
64671
+ aspAgentId,
64672
+ deliveryId,
64673
+ targetCount: summary.conversationCount,
64674
+ sentCount: summary.sentCount,
64675
+ failedCount: summary.failedCount
64676
+ })
64677
+ );
64678
+ return { ...summary, results };
64679
+ }
64680
+
64106
64681
  // src/command-processor.ts
64107
64682
  init_session_store();
64108
64683
  init_ai_provider();
@@ -64783,6 +65358,9 @@ function commandSentryExtra(command, extra = {}) {
64783
65358
  base.myAgentId = command.myAgentId ?? "";
64784
65359
  base.toAgentId = command.toAgentId ?? "";
64785
65360
  base.toXmtpAddress = command.toXmtpAddress ?? "";
65361
+ } else if (command.type === "xmtp-subscription-push") {
65362
+ base.myAgentId = command.myAgentId;
65363
+ base.conversationCount = command.conversationIds.length;
64786
65364
  } else if (command.type === "xmtp-deny-pending-conversation") {
64787
65365
  base.groupId = command.groupId;
64788
65366
  base.jobId = command.jobId ?? "";
@@ -65138,6 +65716,10 @@ async function handleDaemonCommand(command, params) {
65138
65716
  });
65139
65717
  return { ok: true, messageId: result.messageId };
65140
65718
  }
65719
+ if (command.type === "xmtp-subscription-push") {
65720
+ const result = await handleSubscriptionPushCommand({ command, service: params.service });
65721
+ return { ok: true, payload: result };
65722
+ }
65141
65723
  if (command.type === "xmtp-get-pending-list") {
65142
65724
  return { ok: true, payload: await listPendingTaskRequests(params) };
65143
65725
  }
@@ -65220,12 +65802,12 @@ async function listPendingTaskRequests(params) {
65220
65802
  }
65221
65803
  async function denyPendingConversationsByJobId(jobId, params, content) {
65222
65804
  const pending = await listPendingTaskRequests(params);
65223
- const matched = pending.filter((item) => isPlainObject2(item) && readString2(item.jobId) === jobId);
65805
+ const matched = pending.filter((item) => isPlainObject3(item) && readString2(item.jobId) === jobId);
65224
65806
  const clientAddresses = [...params.service.getClients().keys()];
65225
65807
  const targetsByKey = collectDenyTargetsFromPending(matched, clientAddresses);
65226
65808
  const groupIds = /* @__PURE__ */ new Set();
65227
65809
  for (const item of matched) {
65228
- if (!isPlainObject2(item)) {
65810
+ if (!isPlainObject3(item)) {
65229
65811
  continue;
65230
65812
  }
65231
65813
  const groupId = readString2(item.groupId);
@@ -65252,7 +65834,7 @@ async function denyPendingConversationsByJobId(jobId, params, content) {
65252
65834
  function collectDenyTargetsFromPending(pending, fallbackAddresses) {
65253
65835
  const targetsByKey = /* @__PURE__ */ new Map();
65254
65836
  for (const item of pending) {
65255
- if (!isPlainObject2(item)) {
65837
+ if (!isPlainObject3(item)) {
65256
65838
  continue;
65257
65839
  }
65258
65840
  const groupId = readString2(item.groupId);
@@ -65277,7 +65859,7 @@ ${groupId}`, {
65277
65859
  async function resolvePendingTargetsByGroupId(groupId, addresses, params) {
65278
65860
  const addressSet = addresses ? new Set(addresses) : null;
65279
65861
  const pending = (await listPendingTaskRequests(params)).filter((item) => {
65280
- if (!isPlainObject2(item) || readString2(item.groupId) !== groupId) {
65862
+ if (!isPlainObject3(item) || readString2(item.groupId) !== groupId) {
65281
65863
  return false;
65282
65864
  }
65283
65865
  const address = readString2(item.myXmtpAddress);
@@ -65397,7 +65979,7 @@ function filterKnownPendingGroups(items, sessionStore) {
65397
65979
  return items;
65398
65980
  }
65399
65981
  return items.filter((item) => {
65400
- if (!isPlainObject2(item)) {
65982
+ if (!isPlainObject3(item)) {
65401
65983
  return true;
65402
65984
  }
65403
65985
  const jobId = readString2(item.jobId);
@@ -65408,7 +65990,7 @@ function filterKnownPendingGroups(items, sessionStore) {
65408
65990
  return sessionStore.querySessions({ jobId, toAgentId, limit: 1 }).length === 0;
65409
65991
  });
65410
65992
  }
65411
- function isPlainObject2(value) {
65993
+ function isPlainObject3(value) {
65412
65994
  return !!value && typeof value === "object" && !Array.isArray(value);
65413
65995
  }
65414
65996
  function readString2(value) {
@@ -65542,6 +66124,10 @@ function formatCommandCompleted(command, result) {
65542
66124
  if (command.type === "xmtp-send") {
65543
66125
  return `[okx-agent-task] xmtp-send command completed id=${command.id} job=${command.jobId} messageId=${result.messageId}`;
65544
66126
  }
66127
+ if (command.type === "xmtp-subscription-push") {
66128
+ const payload = isPlainObject3(result.payload) ? result.payload : {};
66129
+ return `[okx-agent-task] xmtp-subscription-push command completed id=${command.id} deliveryId=${command.deliveryId ?? "(none)"} conversationCount=${payload.conversationCount ?? 0} sentCount=${payload.sentCount ?? 0} failedCount=${payload.failedCount ?? 0}`;
66130
+ }
65545
66131
  if (command.type === "xmtp-get-pending-list") {
65546
66132
  return `[okx-agent-task] xmtp-get-pending-list command completed id=${command.id}`;
65547
66133
  }
@@ -65562,8 +66148,8 @@ function formatCommandCompleted(command, result) {
65562
66148
  return `[okx-agent-task] xmtp-refresh-agents command completed id=${command.id}`;
65563
66149
  }
65564
66150
  function formatXmtpDebugCompleted(command, payload) {
65565
- const record = isPlainObject2(payload) ? payload : {};
65566
- const summary = isPlainObject2(record.summary) ? record.summary : {};
66151
+ const record = isPlainObject3(payload) ? payload : {};
66152
+ const summary = isPlainObject3(record.summary) ? record.summary : {};
65567
66153
  const count = command.action === "group-list" ? record.groupCount ?? 0 : command.action === "group-inspect" ? record.conversationFound ? 1 : 0 : summary.matchedCount ?? 0;
65568
66154
  return `[okx-agent-task] xmtp-debug command completed id=${command.id} action=${command.action} rows=${String(count)}`;
65569
66155
  }
@@ -65718,12 +66304,393 @@ function trimForUser2(value) {
65718
66304
 
65719
66305
  // src/message-handler.ts
65720
66306
  init_log();
65721
- var import_node_crypto12 = require("node:crypto");
66307
+ var import_node_crypto13 = require("node:crypto");
65722
66308
  init_sentry_logger();
65723
66309
  init_log_fields();
65724
66310
  init_paths();
65725
66311
  init_session_store();
65726
66312
  init_ai_provider();
66313
+
66314
+ // src/subscription-inbound.ts
66315
+ init_log();
66316
+ function decideSubscriptionGate(input) {
66317
+ if (!isSubscriptionEnvelope(input.payload)) {
66318
+ return { kind: "not_subscription" };
66319
+ }
66320
+ if (input.chatType === "dm") {
66321
+ return { kind: "drop", reason: "dm_subscription" };
66322
+ }
66323
+ if (input.chatType === "unknown") {
66324
+ return { kind: "drop", reason: "unknown_conversation_subscription" };
66325
+ }
66326
+ const read = readSubscriptionEnvelope(input.payload);
66327
+ if (!read.ok) {
66328
+ return { kind: "drop", reason: "invalid_envelope", detail: read.reason };
66329
+ }
66330
+ if (!input.senderInboxId) {
66331
+ return { kind: "drop", reason: "missing_sender_inbox_id" };
66332
+ }
66333
+ return { kind: "v2", envelope: read.envelope };
66334
+ }
66335
+ function partitionSubscriptionJobsByOwner(input) {
66336
+ const owned = [];
66337
+ for (const job of input.jobs) {
66338
+ if (job.userAgentId === input.localAgentId) {
66339
+ owned.push(job);
66340
+ }
66341
+ }
66342
+ return {
66343
+ owned,
66344
+ returnedCount: input.jobs.length,
66345
+ ownedCount: owned.length,
66346
+ ignoredCount: input.jobs.length - owned.length
66347
+ };
66348
+ }
66349
+ function normalizeSubscriptionJobs(input) {
66350
+ const seen = /* @__PURE__ */ new Set();
66351
+ const normalized = [];
66352
+ for (const job of input.jobs) {
66353
+ const dedupKey = `${job.jobId}|${job.userAgentId}|${job.aspAgentId}`;
66354
+ if (seen.has(dedupKey)) {
66355
+ continue;
66356
+ }
66357
+ seen.add(dedupKey);
66358
+ normalized.push({
66359
+ jobId: job.jobId,
66360
+ userAgentId: job.userAgentId,
66361
+ aspAgentId: job.aspAgentId,
66362
+ msgType: SUBSCRIPTION_MESSAGE_TYPE,
66363
+ content: input.envelope.content,
66364
+ ...input.envelope.deliveryId ? { deliveryId: input.envelope.deliveryId } : {},
66365
+ conversationId: input.conversationId,
66366
+ senderInboxId: input.senderInboxId
66367
+ });
66368
+ }
66369
+ return normalized;
66370
+ }
66371
+ function subscriptionIdempotencyKey(input) {
66372
+ const messageDimension = input.deliveryId || input.messageId;
66373
+ return `${input.myXmtpAddress}|${messageDimension}|${input.jobId}`;
66374
+ }
66375
+ var SUBSCRIPTION_TARGETS_MAX = 2e3;
66376
+ var subscriptionTargets = /* @__PURE__ */ new Map();
66377
+ function tryMarkSubscriptionTarget(key) {
66378
+ if (subscriptionTargets.has(key)) {
66379
+ return false;
66380
+ }
66381
+ subscriptionTargets.set(key, Date.now());
66382
+ while (subscriptionTargets.size > SUBSCRIPTION_TARGETS_MAX) {
66383
+ const oldest = subscriptionTargets.keys().next().value;
66384
+ if (oldest === void 0) {
66385
+ break;
66386
+ }
66387
+ subscriptionTargets.delete(oldest);
66388
+ }
66389
+ return true;
66390
+ }
66391
+ function resetSubscriptionTargetsForTests() {
66392
+ subscriptionTargets.clear();
66393
+ }
66394
+ var SUBSCRIPTION_FANOUT_MAX = 250;
66395
+ function redactSenderInboxId(senderInboxId, left = 8, right = 6) {
66396
+ if (!senderInboxId) {
66397
+ return "(none)";
66398
+ }
66399
+ if (senderInboxId.length <= left + right + 1) {
66400
+ return senderInboxId;
66401
+ }
66402
+ return `${senderInboxId.slice(0, left)}\u2026${senderInboxId.slice(-right)}`;
66403
+ }
66404
+ async function fanOutSubscriptionJobs(input) {
66405
+ const { jobs, myXmtpAddress, messageId, dispatch, concurrency } = input;
66406
+ const total = jobs.length;
66407
+ const capacityAnomaly = total > SUBSCRIPTION_FANOUT_MAX;
66408
+ if (capacityAnomaly) {
66409
+ logWithTimestamp(
66410
+ `[okx-agent-task:${myXmtpAddress}] subscription fan-out capacity anomaly: jobs=${total} max=${SUBSCRIPTION_FANOUT_MAX} message=${messageId}`
66411
+ );
66412
+ }
66413
+ const settled = await parallelMap(
66414
+ jobs,
66415
+ async (job) => {
66416
+ const idempotencyKey = subscriptionIdempotencyKey({
66417
+ myXmtpAddress,
66418
+ deliveryId: job.deliveryId,
66419
+ messageId,
66420
+ jobId: job.jobId
66421
+ });
66422
+ if (subscriptionTargets.has(idempotencyKey)) {
66423
+ return { key: idempotencyKey, outcome: "duplicate" };
66424
+ }
66425
+ const dispatchOutcome = await dispatch(job, idempotencyKey);
66426
+ const isDurableDuplicate = !!dispatchOutcome && dispatchOutcome.created === false;
66427
+ return { key: idempotencyKey, outcome: isDurableDuplicate ? "duplicate" : "started" };
66428
+ },
66429
+ concurrency ?? 20
66430
+ );
66431
+ let started = 0;
66432
+ let failed = 0;
66433
+ let skippedDuplicate = 0;
66434
+ const results = [];
66435
+ settled.forEach((result, idx) => {
66436
+ const job = jobs[idx];
66437
+ if (result.status === "rejected") {
66438
+ failed += 1;
66439
+ results.push({ jobId: job?.jobId ?? "(unknown)", outcome: "failed", error: result.reason });
66440
+ logWithTimestamp(
66441
+ `[okx-agent-task:${myXmtpAddress}] subscription dispatch failed message=${messageId} job=${job?.jobId ?? "(unknown)"} sender=${redactSenderInboxId(job?.senderInboxId)}:`,
66442
+ result.reason
66443
+ );
66444
+ return;
66445
+ }
66446
+ tryMarkSubscriptionTarget(result.value.key);
66447
+ if (result.value.outcome === "duplicate") {
66448
+ skippedDuplicate += 1;
66449
+ results.push({ jobId: job?.jobId ?? "(unknown)", outcome: "duplicate" });
66450
+ } else {
66451
+ started += 1;
66452
+ results.push({ jobId: job?.jobId ?? "(unknown)", outcome: "started" });
66453
+ }
66454
+ });
66455
+ return { total, started, failed, skippedDuplicate, capacityAnomaly, results };
66456
+ }
66457
+
66458
+ // ../core/src/xmtp-sdk/onchainos/list-jobs-by-verified-sender.ts
66459
+ init_log();
66460
+ init_sentry_logger();
66461
+ function isPlainObject4(value) {
66462
+ return !!value && typeof value === "object" && !Array.isArray(value);
66463
+ }
66464
+ function isNonEmptyString2(value) {
66465
+ return typeof value === "string" && value.length > 0;
66466
+ }
66467
+ function redactLogValue(value, left = 6, right = 4) {
66468
+ if (!value) {
66469
+ return "(none)";
66470
+ }
66471
+ if (value.length <= left + right + 1) {
66472
+ return "(redacted)";
66473
+ }
66474
+ return `${value.slice(0, left)}\u2026${value.slice(-right)}`;
66475
+ }
66476
+ function guardSessionExpired3(stdout, command) {
66477
+ if (isSessionExpired(stdout)) {
66478
+ reportSessionExpired(command);
66479
+ }
66480
+ }
66481
+ function guardCatchSessionExpired3(err, command) {
66482
+ const stdout = String(err?.stdout ?? "");
66483
+ if (stdout && isSessionExpired(stdout)) {
66484
+ reportSessionExpired(command);
66485
+ }
66486
+ }
66487
+ function buildListJobsByVerifiedSenderArgs(params) {
66488
+ return [
66489
+ "agent",
66490
+ "list-jobs-by-verified-sender",
66491
+ "--group-id",
66492
+ params.groupId,
66493
+ "--sender-inbox-id",
66494
+ params.senderInboxId,
66495
+ "--agentic-id",
66496
+ params.agenticId
66497
+ ];
66498
+ }
66499
+ var KNOWN_ERROR_CODES2 = {
66500
+ "130100079": "sender_not_authorized",
66501
+ "130100073": "sender_not_eligible"
66502
+ };
66503
+ function extractErrorText(errorLike) {
66504
+ if (typeof errorLike === "string") {
66505
+ return errorLike;
66506
+ }
66507
+ if (typeof errorLike === "number") {
66508
+ return String(errorLike);
66509
+ }
66510
+ if (errorLike && typeof errorLike === "object") {
66511
+ const anyErr = errorLike;
66512
+ return [anyErr.code, anyErr.message, anyErr.stdout, anyErr.stderr].filter((value) => typeof value === "string" || typeof value === "number").map(String).join(" ");
66513
+ }
66514
+ return errorLike == null ? "" : String(errorLike);
66515
+ }
66516
+ function classifyListJobsError(errorLike) {
66517
+ const text = extractErrorText(errorLike);
66518
+ for (const [code, reason] of Object.entries(KNOWN_ERROR_CODES2)) {
66519
+ if (text.includes(code)) {
66520
+ return { reason, errorCode: code };
66521
+ }
66522
+ }
66523
+ if (/\b401\b/.test(text)) {
66524
+ return { reason: "auth_error", errorCode: "401" };
66525
+ }
66526
+ if (/\b403\b/.test(text)) {
66527
+ return { reason: "auth_error", errorCode: "403" };
66528
+ }
66529
+ return { reason: "invalid_response" };
66530
+ }
66531
+ function normalizeListJobsResponse(data) {
66532
+ const rawJobs = isPlainObject4(data) && Array.isArray(data.jobs) ? data.jobs : [];
66533
+ const seen = /* @__PURE__ */ new Set();
66534
+ const jobs = [];
66535
+ let invalidCount = 0;
66536
+ for (const item of rawJobs) {
66537
+ if (!isPlainObject4(item) || !isNonEmptyString2(item.jobId) || !isNonEmptyString2(item.userAgentId) || !isNonEmptyString2(item.aspAgentId)) {
66538
+ invalidCount += 1;
66539
+ continue;
66540
+ }
66541
+ const key = `${item.jobId}|${item.userAgentId}|${item.aspAgentId}`;
66542
+ if (seen.has(key)) {
66543
+ continue;
66544
+ }
66545
+ seen.add(key);
66546
+ jobs.push({ jobId: item.jobId, userAgentId: item.userAgentId, aspAgentId: item.aspAgentId });
66547
+ }
66548
+ return { jobs, invalidCount };
66549
+ }
66550
+ async function listJobsByVerifiedSender(params, execFn = exec) {
66551
+ logWithTimestamp(
66552
+ `[onchainos] listing jobs by verified sender: group=${params.groupId} sender=${redactLogValue(params.senderInboxId)} agentic=${params.agenticId}`
66553
+ );
66554
+ let stdout;
66555
+ let stderr;
66556
+ try {
66557
+ ({ stdout, stderr } = await execFn(buildListJobsByVerifiedSenderArgs(params)));
66558
+ } catch (err) {
66559
+ guardCatchSessionExpired3(err, "list-jobs-by-verified-sender");
66560
+ const classified = classifyListJobsError(err);
66561
+ const reason = classified.reason === "invalid_response" ? "network_error" : classified.reason;
66562
+ warnWithTimestamp(
66563
+ `[onchainos] list-jobs-by-verified-sender exec failed (group=${params.groupId} sender=${redactLogValue(params.senderInboxId)}); fail-closed reason=${reason}`
66564
+ );
66565
+ return { status: "fail_closed", jobs: [], invalidCount: 0, reason, errorCode: classified.errorCode };
66566
+ }
66567
+ if (stderr) {
66568
+ logWithTimestamp(`[onchainos] stderr (list-jobs-by-verified-sender): ${stderr}`);
66569
+ }
66570
+ let res;
66571
+ try {
66572
+ res = parseCliJson(stdout, "list-jobs-by-verified-sender", {
66573
+ groupId: params.groupId,
66574
+ agenticId: params.agenticId
66575
+ });
66576
+ } catch {
66577
+ return { status: "fail_closed", jobs: [], invalidCount: 0, reason: "invalid_response" };
66578
+ }
66579
+ if (!res.ok) {
66580
+ guardSessionExpired3(stdout, "list-jobs-by-verified-sender");
66581
+ const classified = classifyListJobsError(res.error);
66582
+ warnWithTimestamp(
66583
+ `[onchainos] list-jobs-by-verified-sender ok=false (group=${params.groupId}); fail-closed reason=${classified.reason}`
66584
+ );
66585
+ logger.error(
66586
+ LogEvent.ONCHAINOS_CLI_ERROR,
66587
+ new Error("list-jobs-by-verified-sender ok=false"),
66588
+ cliOkFalseExtras(stdout, "list-jobs-by-verified-sender", {
66589
+ groupId: params.groupId,
66590
+ agenticId: params.agenticId,
66591
+ reason: classified.reason
66592
+ })
66593
+ );
66594
+ return { status: "fail_closed", jobs: [], invalidCount: 0, reason: classified.reason, errorCode: classified.errorCode };
66595
+ }
66596
+ const { jobs, invalidCount } = normalizeListJobsResponse(res.data);
66597
+ if (jobs.length === 0) {
66598
+ logWithTimestamp(
66599
+ `[onchainos] list-jobs-by-verified-sender: empty (group=${params.groupId} invalidCount=${invalidCount})`
66600
+ );
66601
+ return { status: "empty", jobs, invalidCount };
66602
+ }
66603
+ logWithTimestamp(
66604
+ `[onchainos] list-jobs-by-verified-sender: ok (group=${params.groupId} jobs=${jobs.length} invalidCount=${invalidCount})`
66605
+ );
66606
+ return { status: "ok", jobs, invalidCount };
66607
+ }
66608
+ var LIST_JOBS_BY_VERIFIED_SENDER_HELP_TOKEN = "list-jobs-by-verified-sender";
66609
+ function listJobsByVerifiedSenderHelpAdvertisesCommand(helpText) {
66610
+ if (typeof helpText !== "string" || helpText.length === 0) {
66611
+ return false;
66612
+ }
66613
+ const lower = helpText.toLowerCase();
66614
+ if (/unknown command|unrecognized|not a valid command|no such (sub)?command|command not found/.test(lower)) {
66615
+ return false;
66616
+ }
66617
+ return lower.includes(LIST_JOBS_BY_VERIFIED_SENDER_HELP_TOKEN);
66618
+ }
66619
+ var CAPABILITY_UPGRADE_PAIR_KEY = "onchainos:list-jobs-by-verified-sender";
66620
+ var CAPABILITY_UPGRADE_REASON = "OnchainOS does not support `agent list-jobs-by-verified-sender`; the V2 subscription shared-group inbound path is fail-closed until OnchainOS is upgraded. Upgrade the OnchainOS CLI, then re-run.";
66621
+ var capabilityProbe2 = null;
66622
+ var capabilityRecommendedPairs = /* @__PURE__ */ new Set();
66623
+ function resetListJobsByVerifiedSenderCapabilityForTests() {
66624
+ capabilityProbe2 = null;
66625
+ capabilityRecommendedPairs.clear();
66626
+ }
66627
+ function maybeRecommendListJobsUpgrade(capability) {
66628
+ if (capability.supported || capabilityRecommendedPairs.has(CAPABILITY_UPGRADE_PAIR_KEY)) {
66629
+ return;
66630
+ }
66631
+ warnWithTimestamp(
66632
+ `[onchainos] list-jobs-by-verified-sender unsupported (reason=${capability.reason}); ${CAPABILITY_UPGRADE_REASON}`
66633
+ );
66634
+ const hook = XmtpService.getInstance().tools?.notifyUpgradeRecommendation;
66635
+ if (!hook) {
66636
+ return;
66637
+ }
66638
+ capabilityRecommendedPairs.add(CAPABILITY_UPGRADE_PAIR_KEY);
66639
+ try {
66640
+ void Promise.resolve(
66641
+ hook({
66642
+ component: "onchainos",
66643
+ capability: LIST_JOBS_BY_VERIFIED_SENDER_HELP_TOKEN,
66644
+ reason: CAPABILITY_UPGRADE_REASON
66645
+ })
66646
+ ).catch((err) => {
66647
+ warnWithTimestamp("[onchainos] list-jobs-by-verified-sender upgrade notice async delivery failed:", err);
66648
+ });
66649
+ } catch (err) {
66650
+ warnWithTimestamp("[onchainos] list-jobs-by-verified-sender upgrade notice threw:", err);
66651
+ }
66652
+ }
66653
+ function detectListJobsByVerifiedSenderSupport(execFn = exec) {
66654
+ if (!capabilityProbe2) {
66655
+ capabilityProbe2 = (async () => {
66656
+ try {
66657
+ const { stdout, stderr } = await execFn([
66658
+ "agent",
66659
+ "list-jobs-by-verified-sender",
66660
+ "--help"
66661
+ ]);
66662
+ const supported = listJobsByVerifiedSenderHelpAdvertisesCommand(`${stdout}
66663
+ ${stderr}`);
66664
+ logWithTimestamp(
66665
+ `[onchainos] list-jobs-by-verified-sender capability: ${supported ? "supported" : "unsupported_cli_capability"}`
66666
+ );
66667
+ return supported ? { supported: true } : { supported: false, reason: "unsupported_cli_capability" };
66668
+ } catch (err) {
66669
+ logWithTimestamp(
66670
+ "[onchainos] list-jobs-by-verified-sender --help probe failed; treating as onchainos_upgrade_required:",
66671
+ err
66672
+ );
66673
+ return { supported: false, reason: "onchainos_upgrade_required" };
66674
+ }
66675
+ })().then((capability) => {
66676
+ maybeRecommendListJobsUpgrade(capability);
66677
+ return capability;
66678
+ });
66679
+ }
66680
+ return capabilityProbe2;
66681
+ }
66682
+ async function listJobsByVerifiedSenderWithCapability(params, execFn = exec) {
66683
+ const capability = await detectListJobsByVerifiedSenderSupport(execFn);
66684
+ if (!capability.supported) {
66685
+ warnWithTimestamp(
66686
+ `[onchainos] list-jobs-by-verified-sender skipped: CLI capability unavailable (reason=${capability.reason}) group=${params.groupId} sender=${redactLogValue(params.senderInboxId)}`
66687
+ );
66688
+ return { status: "fail_closed", jobs: [], invalidCount: 0, reason: capability.reason };
66689
+ }
66690
+ return listJobsByVerifiedSender(params, execFn);
66691
+ }
66692
+
66693
+ // src/message-handler.ts
65727
66694
  var PROCESSED_IDS_MAX = 1e3;
65728
66695
  var processedMessageIds = /* @__PURE__ */ new Map();
65729
66696
  function tryMarkProcessed(messageId) {
@@ -65740,7 +66707,7 @@ function tryMarkProcessed(messageId) {
65740
66707
  }
65741
66708
  return true;
65742
66709
  }
65743
- function isPlainObject3(value) {
66710
+ function isPlainObject5(value) {
65744
66711
  return !!value && typeof value === "object" && !Array.isArray(value);
65745
66712
  }
65746
66713
  function safeStringify(value) {
@@ -65801,9 +66768,9 @@ function readNumber(value) {
65801
66768
  }
65802
66769
  function resolveSessionAgentId(params) {
65803
66770
  const { chatType, payload, myXmtpAddress } = params;
65804
- const payloadObject = isPlainObject3(payload) ? payload : null;
65805
- const sender = isPlainObject3(payloadObject?.sender) ? payloadObject.sender : null;
65806
- const message = isPlainObject3(payloadObject?.message) ? payloadObject.message : null;
66771
+ const payloadObject = isPlainObject5(payload) ? payload : null;
66772
+ const sender = isPlainObject5(payloadObject?.sender) ? payloadObject.sender : null;
66773
+ const message = isPlainObject5(payloadObject?.message) ? payloadObject.message : null;
65807
66774
  const localAgentId = XmtpService.getInstance().getAgentByAddress(myXmtpAddress)?.agentId ?? null;
65808
66775
  if (chatType === "group") {
65809
66776
  return readString3(sender?.agentId) ?? readString3(payloadObject?.receiverAgentId) ?? localAgentId;
@@ -65814,7 +66781,7 @@ function resolveSessionAgentId(params) {
65814
66781
  return localAgentId;
65815
66782
  }
65816
66783
  function routeMessage(chatType, parsed, payload) {
65817
- if (!parsed || !isPlainObject3(payload)) {
66784
+ if (!parsed || !isPlainObject5(payload)) {
65818
66785
  return {
65819
66786
  jobId: BACKUP_JOB_ID,
65820
66787
  route: "backup",
@@ -65826,7 +66793,7 @@ function routeMessage(chatType, parsed, payload) {
65826
66793
  return jobId ? { jobId, route: "job", routeReason: "group-job-id" } : { jobId: BACKUP_JOB_ID, route: "backup", routeReason: "group-missing-job-id" };
65827
66794
  }
65828
66795
  if (chatType === "dm") {
65829
- const message = isPlainObject3(payload.message) ? payload.message : null;
66796
+ const message = isPlainObject5(payload.message) ? payload.message : null;
65830
66797
  const nestedJobId = readString3(message?.jobId);
65831
66798
  const directJobId = readString3(payload.jobId);
65832
66799
  const jobId = nestedJobId ?? directJobId;
@@ -65839,10 +66806,10 @@ function routeMessage(chatType, parsed, payload) {
65839
66806
  return { jobId: BACKUP_JOB_ID, route: "backup", routeReason: "unknown-conversation" };
65840
66807
  }
65841
66808
  function extractDirectToUserNotification(payload) {
65842
- if (!isPlainObject3(payload)) {
66809
+ if (!isPlainObject5(payload)) {
65843
66810
  return { kind: "none" };
65844
66811
  }
65845
- const message = isPlainObject3(payload.message) ? payload.message : null;
66812
+ const message = isPlainObject5(payload.message) ? payload.message : null;
65846
66813
  if (message?.isDirectToUser !== true) {
65847
66814
  return { kind: "none" };
65848
66815
  }
@@ -65866,10 +66833,10 @@ function extractDirectToUserNotification(payload) {
65866
66833
  };
65867
66834
  }
65868
66835
  function extractSystemNotification(payload) {
65869
- if (!isPlainObject3(payload)) {
66836
+ if (!isPlainObject5(payload)) {
65870
66837
  return null;
65871
66838
  }
65872
- const message = isPlainObject3(payload.message) ? payload.message : null;
66839
+ const message = isPlainObject5(payload.message) ? payload.message : null;
65873
66840
  const isDirectCommunication = message?.isDirectCommunication === true;
65874
66841
  if (message?.source !== "system" && !isDirectCommunication) {
65875
66842
  return null;
@@ -66104,7 +67071,7 @@ function inboundStageExtras(stage, outcome) {
66104
67071
  })
66105
67072
  };
66106
67073
  }
66107
- function definedExtras(input) {
67074
+ function definedExtras2(input) {
66108
67075
  return Object.entries(input).reduce((out, [key, value]) => {
66109
67076
  const text = readString3(value);
66110
67077
  if (text) {
@@ -66136,7 +67103,7 @@ function buildInboundTerminalExtras(input) {
66136
67103
  originPlatform: classifyOriginPlatform({ env: process.env }),
66137
67104
  deliveryId: resolveDeliveryId({ messageId, jobId, sessionKey })
66138
67105
  }),
66139
- ...definedExtras({
67106
+ ...definedExtras2({
66140
67107
  messageId,
66141
67108
  conversationId,
66142
67109
  chatType,
@@ -66170,7 +67137,7 @@ function maybeNotifyInboundAgentMessage(params) {
66170
67137
  return;
66171
67138
  }
66172
67139
  const content = payloadObject.content;
66173
- const sender = isPlainObject3(payloadObject.sender) ? payloadObject.sender : null;
67140
+ const sender = isPlainObject5(payloadObject.sender) ? payloadObject.sender : null;
66174
67141
  const localAgent = XmtpService.getInstance().getAgentByAddress(params.deps.myXmtpAddress);
66175
67142
  void notifyAgentMessageToUserAttention({
66176
67143
  direction: "inbound" /* INBOUND */,
@@ -66201,11 +67168,11 @@ function stringifySystemPayload(payload) {
66201
67168
  }
66202
67169
  }
66203
67170
  function summarizePayloadForLog(payload) {
66204
- if (!isPlainObject3(payload)) {
67171
+ if (!isPlainObject5(payload)) {
66205
67172
  return "payload=non-object";
66206
67173
  }
66207
- const message = isPlainObject3(payload.message) ? payload.message : null;
66208
- const sender = isPlainObject3(payload.sender) ? payload.sender : null;
67174
+ const message = isPlainObject5(payload.message) ? payload.message : null;
67175
+ const sender = isPlainObject5(payload.sender) ? payload.sender : null;
66209
67176
  const jobId = readString3(payload.jobId) ?? readString3(message?.jobId);
66210
67177
  const parts = [
66211
67178
  readString3(payload.msgType) ? `type=${readString3(payload.msgType)}` : null,
@@ -66474,7 +67441,7 @@ async function verifyInboundA2AGroupMessage(params) {
66474
67441
  messageId,
66475
67442
  groupId,
66476
67443
  jobId,
66477
- agentId: readString3(isPlainObject3(payload.sender) ? payload.sender.agentId : null),
67444
+ agentId: readString3(isPlainObject5(payload.sender) ? payload.sender.agentId : null),
66478
67445
  localAgentId: myAgent?.agentId ?? null,
66479
67446
  senderAddress,
66480
67447
  senderInboxId,
@@ -66500,7 +67467,7 @@ async function verifyInboundA2AGroupMessage(params) {
66500
67467
  });
66501
67468
  return false;
66502
67469
  }
66503
- const sender = isPlainObject3(payload.sender) ? payload.sender : null;
67470
+ const sender = isPlainObject5(payload.sender) ? payload.sender : null;
66504
67471
  const senderAgentId = readString3(sender?.agentId);
66505
67472
  const senderRole = readNumber(sender?.role);
66506
67473
  if (!senderAgentId || !myAgent) {
@@ -66669,9 +67636,302 @@ ${failureMessage}`,
66669
67636
  }
66670
67637
  return true;
66671
67638
  }
67639
+ async function processSubscriptionInbound(ctx, deps, input) {
67640
+ const { decision, conversationId, messageId } = input;
67641
+ const senderInboxId = ctx.message.senderInboxId ?? "";
67642
+ if (decision.kind === "drop") {
67643
+ logger.info(
67644
+ LogEvent.SUBSCRIPTION_INBOUND_GATE_DROPPED,
67645
+ buildSubscriptionInboundExtras({
67646
+ checkpoint: "inbound/subscription_gate_dropped",
67647
+ outcome: "dropped",
67648
+ conversationId,
67649
+ messageId,
67650
+ senderInboxId: shortenLogValue(senderInboxId),
67651
+ reason: decision.reason
67652
+ })
67653
+ );
67654
+ logWithTimestamp(
67655
+ `[okx-agent-task:${deps.myXmtpAddress}] subscription message dropped reason=${decision.reason}${decision.detail ? ` detail=${decision.detail}` : ""} conv=${conversationId} message=${shortenLogValue(messageId)} sender=${shortenLogValue(senderInboxId)}`
67656
+ );
67657
+ return true;
67658
+ }
67659
+ if (decision.kind === "not_subscription") {
67660
+ return true;
67661
+ }
67662
+ const { envelope } = decision;
67663
+ const agenticId = XmtpService.getInstance().getAgentByAddress(deps.myXmtpAddress)?.agentId;
67664
+ if (!agenticId) {
67665
+ logWithTimestamp(
67666
+ `[okx-agent-task:${deps.myXmtpAddress}] subscription fail-closed: no local agenticId for ${deps.myXmtpAddress}, conv=${conversationId} message=${shortenLogValue(messageId)}`
67667
+ );
67668
+ logger.error(
67669
+ LogEvent.SUBSCRIPTION_INBOUND_AGENTIC_ID_MISSING,
67670
+ new Error("Subscription inbound: local agenticId not resolved"),
67671
+ buildSubscriptionInboundExtras({
67672
+ checkpoint: "inbound/subscription_agentic_id",
67673
+ outcome: "blocked",
67674
+ conversationId,
67675
+ messageId,
67676
+ senderInboxId: shortenLogValue(senderInboxId),
67677
+ reason: "missing_agentic_id"
67678
+ })
67679
+ );
67680
+ return true;
67681
+ }
67682
+ logWithTimestamp(
67683
+ `[okx-agent-task:${deps.myXmtpAddress}] subscription received msgType=${envelope.msgType} conv=${conversationId} message=${shortenLogValue(messageId)} sender=${shortenLogValue(senderInboxId)}`
67684
+ );
67685
+ logger.info(
67686
+ LogEvent.SUBSCRIPTION_INBOUND_RECEIVED,
67687
+ buildSubscriptionInboundExtras({
67688
+ checkpoint: "inbound/subscription_received",
67689
+ userAgentId: agenticId,
67690
+ conversationId,
67691
+ messageId,
67692
+ deliveryId: envelope.deliveryId,
67693
+ senderInboxId: shortenLogValue(senderInboxId)
67694
+ })
67695
+ );
67696
+ const listJobs = deps.listJobsByVerifiedSenderImpl ?? listJobsByVerifiedSenderWithCapability;
67697
+ logger.info(
67698
+ LogEvent.SUBSCRIPTION_JOBS_QUERY_STARTED,
67699
+ buildSubscriptionInboundExtras({
67700
+ checkpoint: "inbound/subscription_jobs_query_started",
67701
+ userAgentId: agenticId,
67702
+ conversationId,
67703
+ messageId
67704
+ })
67705
+ );
67706
+ const listJobsResult = await listJobs({
67707
+ groupId: conversationId,
67708
+ senderInboxId,
67709
+ agenticId
67710
+ });
67711
+ logWithTimestamp(
67712
+ `[okx-agent-task:${deps.myXmtpAddress}] subscription queried status=${listJobsResult.status} jobs=${listJobsResult.jobs.length} invalid=${listJobsResult.invalidCount} conv=${conversationId} message=${shortenLogValue(messageId)}`
67713
+ );
67714
+ if (listJobsResult.status === "fail_closed") {
67715
+ logger.error(
67716
+ LogEvent.SUBSCRIPTION_JOBS_FAIL_CLOSED,
67717
+ new Error("Subscription inbound: listJobsByVerifiedSender fail-closed"),
67718
+ buildSubscriptionInboundExtras({
67719
+ checkpoint: "inbound/subscription_jobs_fail_closed",
67720
+ outcome: "blocked",
67721
+ userAgentId: agenticId,
67722
+ conversationId,
67723
+ messageId,
67724
+ senderInboxId: shortenLogValue(senderInboxId),
67725
+ reason: listJobsResult.reason ?? "unknown",
67726
+ errorCode: listJobsResult.errorCode
67727
+ })
67728
+ );
67729
+ return true;
67730
+ }
67731
+ if (listJobsResult.status === "empty") {
67732
+ logWithTimestamp(
67733
+ `[okx-agent-task:${deps.myXmtpAddress}] subscription empty: no verified jobs for conv=${conversationId} message=${shortenLogValue(messageId)}`
67734
+ );
67735
+ logger.info(
67736
+ LogEvent.SUBSCRIPTION_JOBS_EMPTY,
67737
+ buildSubscriptionInboundExtras({
67738
+ checkpoint: "inbound/subscription_jobs_empty",
67739
+ outcome: "ignored",
67740
+ userAgentId: agenticId,
67741
+ conversationId,
67742
+ messageId,
67743
+ reason: "jobs_empty",
67744
+ returnedCount: 0,
67745
+ invalidCount: listJobsResult.invalidCount
67746
+ })
67747
+ );
67748
+ return true;
67749
+ }
67750
+ logger.info(
67751
+ LogEvent.SUBSCRIPTION_JOBS_QUERY_SUCCEEDED,
67752
+ buildSubscriptionInboundExtras({
67753
+ checkpoint: "inbound/subscription_jobs_query_succeeded",
67754
+ userAgentId: agenticId,
67755
+ conversationId,
67756
+ messageId,
67757
+ returnedCount: listJobsResult.jobs.length,
67758
+ invalidCount: listJobsResult.invalidCount
67759
+ })
67760
+ );
67761
+ const ownership = partitionSubscriptionJobsByOwner({
67762
+ jobs: listJobsResult.jobs,
67763
+ localAgentId: agenticId
67764
+ });
67765
+ logWithTimestamp(
67766
+ `[okx-agent-task:${deps.myXmtpAddress}] subscription routed receiver=${agenticId} returned=${ownership.returnedCount} localOwned=${ownership.ownedCount} ignored=${ownership.ignoredCount} conv=${conversationId} message=${shortenLogValue(messageId)}`
67767
+ );
67768
+ logger.info(
67769
+ LogEvent.SUBSCRIPTION_INBOUND_OWNERSHIP_ROUTED,
67770
+ buildSubscriptionInboundExtras({
67771
+ checkpoint: "inbound/subscription_ownership_routed",
67772
+ outcome: ownership.ownedCount === 0 ? "ignored" : null,
67773
+ userAgentId: agenticId,
67774
+ conversationId,
67775
+ messageId,
67776
+ returnedCount: ownership.returnedCount,
67777
+ ownedCount: ownership.ownedCount,
67778
+ ignoredCount: ownership.ignoredCount
67779
+ })
67780
+ );
67781
+ if (ownership.ownedCount === 0) {
67782
+ return true;
67783
+ }
67784
+ const normalizedJobs = normalizeSubscriptionJobs({
67785
+ jobs: ownership.owned,
67786
+ envelope,
67787
+ conversationId,
67788
+ senderInboxId
67789
+ });
67790
+ logWithTimestamp(
67791
+ `[okx-agent-task:${deps.myXmtpAddress}] subscription expanded jobs=${normalizedJobs.length} conv=${conversationId} message=${shortenLogValue(messageId)}`
67792
+ );
67793
+ let senderXmtpAddress = null;
67794
+ try {
67795
+ const resolved = await ctx.getSenderAddress();
67796
+ senderXmtpAddress = resolved ? resolved : null;
67797
+ } catch (err) {
67798
+ logWithTimestamp(
67799
+ `[okx-agent-task:${deps.myXmtpAddress}] subscription sender address unresolved (degrading to null) conv=${conversationId} message=${shortenLogValue(messageId)}:`,
67800
+ err
67801
+ );
67802
+ }
67803
+ const fanoutResult = await fanOutSubscriptionJobs({
67804
+ jobs: normalizedJobs,
67805
+ myXmtpAddress: deps.myXmtpAddress,
67806
+ messageId,
67807
+ dispatch: async (job, idempotencyKey) => {
67808
+ const sessionKey = buildSessionKey({
67809
+ jobId: job.jobId,
67810
+ myAgentId: job.userAgentId,
67811
+ toAgentId: job.aspAgentId
67812
+ });
67813
+ deps.sessionStore?.upsertSession({
67814
+ sessionKey,
67815
+ jobId: job.jobId,
67816
+ myAgentId: job.userAgentId,
67817
+ toAgentId: job.aspAgentId,
67818
+ groupId: job.conversationId,
67819
+ myAgentXmtpAddress: deps.myXmtpAddress,
67820
+ toAgentXmtpAddress: senderXmtpAddress
67821
+ });
67822
+ return deps.onSessionMessage?.({
67823
+ sessionKey,
67824
+ content: JSON.stringify({
67825
+ msgType: job.msgType,
67826
+ content: job.content,
67827
+ ...job.deliveryId ? { deliveryId: job.deliveryId } : {},
67828
+ jobId: job.jobId,
67829
+ userAgentId: job.userAgentId,
67830
+ aspAgentId: job.aspAgentId,
67831
+ conversationId: job.conversationId,
67832
+ senderInboxId: job.senderInboxId,
67833
+ // Raw XMTP messageId preserved for sender/receiver telemetry join;
67834
+ // the durable dedup identity is the idempotencyKey passed as this
67835
+ // session-message's own `messageId` field below (M1 fix).
67836
+ xmtpMessageId: messageId
67837
+ }),
67838
+ messageId: idempotencyKey,
67839
+ // Durable exactly-once enqueue key (M2): the wiring persists via
67840
+ // CommandStore.submitIdempotent keyed on sessionKey+messageId so a
67841
+ // re-processed / replayed message never creates a second command.
67842
+ idempotencyKey,
67843
+ jobId: job.jobId,
67844
+ agentId: job.userAgentId
67845
+ });
67846
+ }
67847
+ });
67848
+ logWithTimestamp(
67849
+ `[okx-agent-task:${deps.myXmtpAddress}] subscription fan-out succeeded=${fanoutResult.started} failed=${fanoutResult.failed} skippedDuplicate=${fanoutResult.skippedDuplicate} total=${fanoutResult.total} capacityAnomaly=${fanoutResult.capacityAnomaly} conv=${conversationId} message=${shortenLogValue(messageId)}`
67850
+ );
67851
+ const normalizedJobsById = new Map(normalizedJobs.map((job) => [job.jobId, job]));
67852
+ for (const result of fanoutResult.results) {
67853
+ const job = normalizedJobsById.get(result.jobId);
67854
+ if (result.outcome === "started") {
67855
+ logger.info(
67856
+ LogEvent.SUBSCRIPTION_JOB_DISPATCHED,
67857
+ buildSubscriptionJobExtras({
67858
+ checkpoint: "dispatch/subscription_job_dispatched",
67859
+ outcome: "success",
67860
+ jobId: result.jobId,
67861
+ userAgentId: agenticId,
67862
+ aspAgentId: job?.aspAgentId,
67863
+ conversationId,
67864
+ deliveryId: envelope.deliveryId
67865
+ })
67866
+ );
67867
+ } else if (result.outcome === "duplicate") {
67868
+ logger.info(
67869
+ LogEvent.SUBSCRIPTION_JOB_DUPLICATE_IGNORED,
67870
+ buildSubscriptionJobExtras({
67871
+ checkpoint: "dispatch/subscription_job_duplicate_ignored",
67872
+ outcome: "ignored",
67873
+ jobId: result.jobId,
67874
+ userAgentId: agenticId,
67875
+ aspAgentId: job?.aspAgentId,
67876
+ conversationId,
67877
+ deliveryId: envelope.deliveryId,
67878
+ reason: "duplicate_delivery"
67879
+ })
67880
+ );
67881
+ } else {
67882
+ logger.error(
67883
+ LogEvent.SUBSCRIPTION_JOB_FAILED,
67884
+ toLoggableError(result.error),
67885
+ buildSubscriptionJobExtras({
67886
+ checkpoint: "dispatch/subscription_job_failed",
67887
+ outcome: "failed",
67888
+ jobId: result.jobId,
67889
+ userAgentId: agenticId,
67890
+ aspAgentId: job?.aspAgentId,
67891
+ conversationId,
67892
+ deliveryId: envelope.deliveryId,
67893
+ reason: "session_dispatch_failed"
67894
+ })
67895
+ );
67896
+ }
67897
+ }
67898
+ logger.info(
67899
+ LogEvent.SUBSCRIPTION_FANOUT_SUMMARY,
67900
+ buildSubscriptionJobExtras({
67901
+ checkpoint: "dispatch/subscription_fanout_summary",
67902
+ outcome: fanoutResult.failed === 0 ? "success" : fanoutResult.started > 0 || fanoutResult.skippedDuplicate > 0 ? "partial" : "failed",
67903
+ conversationId,
67904
+ userAgentId: agenticId,
67905
+ total: fanoutResult.total,
67906
+ started: fanoutResult.started,
67907
+ failed: fanoutResult.failed,
67908
+ skippedDuplicate: fanoutResult.skippedDuplicate
67909
+ })
67910
+ );
67911
+ return true;
67912
+ }
66672
67913
  async function processFileMessage(ctx, deps, options = {}) {
66673
67914
  const messageId = ctx.message.id ?? "";
66674
67915
  const timing = createInboundTimingTracker(extractXmtpSentAtMs2(ctx.message));
67916
+ const subscriptionPrecheckRawText = extractRawText(ctx.message.content);
67917
+ const subscriptionPrecheckParse = parseJson2(subscriptionPrecheckRawText);
67918
+ if (subscriptionPrecheckParse.ok && isSubscriptionEnvelope(subscriptionPrecheckParse.data)) {
67919
+ const { chatType: subscriptionChatType, conversationId: subscriptionConversationId } = getConversationInfo(ctx.conversation);
67920
+ const gateDecision = decideSubscriptionGate({
67921
+ // getConversationInfo's declared StoredChatType also lists "system",
67922
+ // but that value is only ever produced for stored-message bookkeeping
67923
+ // elsewhere in this file — the conversation-type branch above never
67924
+ // returns it, so this narrowing is safe.
67925
+ chatType: subscriptionChatType === "system" ? "unknown" : subscriptionChatType,
67926
+ payload: subscriptionPrecheckParse.data,
67927
+ senderInboxId: ctx.message.senderInboxId ?? ""
67928
+ });
67929
+ return processSubscriptionInbound(ctx, deps, {
67930
+ decision: gateDecision,
67931
+ conversationId: subscriptionConversationId,
67932
+ messageId: messageId || `subscription-${(0, import_node_crypto13.randomUUID)()}`
67933
+ });
67934
+ }
66675
67935
  if (messageId && !tryMarkProcessed(messageId)) {
66676
67936
  logWithTimestamp(`[okx-agent-task:${deps.myXmtpAddress}] duplicate message ignored: ${messageId}`);
66677
67937
  logger.info(LogEvent.INBOUND_IGNORED_DUPLICATE, timing.extras({
@@ -66694,19 +67954,6 @@ async function processFileMessage(ctx, deps, options = {}) {
66694
67954
  chatType,
66695
67955
  ...extra
66696
67956
  });
66697
- if (chatType === "dm") {
66698
- const dmTrustStartedAt = Date.now();
66699
- const trusted = await isTrustedDmSender({
66700
- myXmtpAddress: deps.myXmtpAddress,
66701
- senderInboxId: ctx.message.senderInboxId ?? "",
66702
- messageId,
66703
- conversationId
66704
- });
66705
- timing.mark("dmTrustCheck", dmTrustStartedAt);
66706
- if (!trusted) {
66707
- return true;
66708
- }
66709
- }
66710
67957
  const parseStartedAt = Date.now();
66711
67958
  const receivedRawText = extractRawText(ctx.message.content);
66712
67959
  const parseResult = parseJson2(receivedRawText);
@@ -66722,9 +67969,26 @@ async function processFileMessage(ctx, deps, options = {}) {
66722
67969
  }
66723
67970
  }
66724
67971
  timing.mark("payloadParse", parseStartedAt);
67972
+ const parsedDmData = parseResult.ok ? parseResult.data : null;
67973
+ const parsedDmMessage = isPlainObject5(parsedDmData) && isPlainObject5(parsedDmData.message) ? parsedDmData.message : null;
67974
+ const dmCarriesSystemMarkers = parsedDmMessage?.isDirectToUser === true || parsedDmMessage?.source === "system" || parsedDmMessage?.isDirectCommunication === true;
67975
+ const isA2ADm = chatType === "dm" && parseResult.ok && isA2AEnvelope(parseResult.data) && !dmCarriesSystemMarkers;
67976
+ if (chatType === "dm" && !isA2ADm) {
67977
+ const dmTrustStartedAt = Date.now();
67978
+ const trusted = await isTrustedDmSender({
67979
+ myXmtpAddress: deps.myXmtpAddress,
67980
+ senderInboxId: ctx.message.senderInboxId ?? "",
67981
+ messageId,
67982
+ conversationId
67983
+ });
67984
+ timing.mark("dmTrustCheck", dmTrustStartedAt);
67985
+ if (!trusted) {
67986
+ return true;
67987
+ }
67988
+ }
66725
67989
  const directToUser = chatType === "dm" && parseResult.ok ? extractDirectToUserNotification(parseResult.data) : { kind: "none" };
66726
67990
  if (directToUser.kind === "invalid") {
66727
- const droppedMessageId = messageId || `direct-to-user-${(0, import_node_crypto12.randomUUID)()}`;
67991
+ const droppedMessageId = messageId || `direct-to-user-${(0, import_node_crypto13.randomUUID)()}`;
66728
67992
  logger.error(
66729
67993
  LogEvent.INBOUND_DROP_DM_INVALID_PAYLOAD,
66730
67994
  new Error("Invalid direct-to-user system DM"),
@@ -66748,7 +68012,7 @@ async function processFileMessage(ctx, deps, options = {}) {
66748
68012
  await dispatchDirectToUserNotification({
66749
68013
  deps,
66750
68014
  notification: directToUser.notification,
66751
- messageId: messageId || `direct-to-user-${(0, import_node_crypto12.randomUUID)()}`,
68015
+ messageId: messageId || `direct-to-user-${(0, import_node_crypto13.randomUUID)()}`,
66752
68016
  timing,
66753
68017
  source: options.source ?? "live"
66754
68018
  });
@@ -66756,7 +68020,7 @@ async function processFileMessage(ctx, deps, options = {}) {
66756
68020
  }
66757
68021
  const systemNotification = chatType === "dm" && parseResult.ok ? extractSystemNotification(parseResult.data) : null;
66758
68022
  if (systemNotification) {
66759
- const systemMessageId = messageId || `system-${(0, import_node_crypto12.randomUUID)()}`;
68023
+ const systemMessageId = messageId || `system-${(0, import_node_crypto13.randomUUID)()}`;
66760
68024
  logWithTimestamp(
66761
68025
  `[okx-agent-task:${deps.myXmtpAddress}] xmtp_system_message_received agentId=${systemNotification.agentId ?? ""} msg=${shortenLogValue(systemMessageId)} event=${systemNotification.event ?? ""} job=${shortenLogValue(systemNotification.jobId)} conv=${conversationId} source=${options.source ?? "live"} rawBytes=${Buffer.byteLength(rawText, "utf8")} rawPreview=${previewRawEnvelope(rawText)}`
66762
68026
  );
@@ -66917,7 +68181,7 @@ async function processFileMessage(ctx, deps, options = {}) {
66917
68181
  timing.mark("routeResolve", routeStartedAt);
66918
68182
  if (route.route === "job" && parseResult.ok && isA2AEnvelope(parseResult.data) && !isValidExternalJobId(route.jobId)) {
66919
68183
  const payloadObject = parseResult.data;
66920
- const sender = isPlainObject3(payloadObject.sender) ? payloadObject.sender : null;
68184
+ const sender = isPlainObject5(payloadObject.sender) ? payloadObject.sender : null;
66921
68185
  logWithTimestamp(
66922
68186
  `[okx-agent-task:${deps.myXmtpAddress}] inbound A2A message has invalid jobId, dropping: jobLength=${route.jobId.length} group=${conversationId}`
66923
68187
  );
@@ -66946,7 +68210,32 @@ async function processFileMessage(ctx, deps, options = {}) {
66946
68210
  });
66947
68211
  return true;
66948
68212
  }
66949
- if (route.route === "job" && chatType !== "group") {
68213
+ if (isA2ADm && route.route !== "job") {
68214
+ const payloadObject = parseResult.data;
68215
+ const sender = isPlainObject5(payloadObject.sender) ? payloadObject.sender : null;
68216
+ recordInvalidXmtpMessageBestEffort({
68217
+ messageId,
68218
+ groupId: conversationId,
68219
+ jobId: null,
68220
+ agentId: readString3(sender?.agentId),
68221
+ localAgentId: XmtpService.getInstance().getAgentByAddress(deps.myXmtpAddress)?.agentId ?? null,
68222
+ senderInboxId: ctx.message.senderInboxId ?? "",
68223
+ reason: "dm_a2a_missing_job_id",
68224
+ stage: "inbound/job_id_validation",
68225
+ logTag: `[okx-agent-task:${deps.myXmtpAddress}]`
68226
+ });
68227
+ logger.info(LogEvent.INBOUND_DROP_INVALID_JOBID, {
68228
+ ...agentExtras({ walletAddress: deps.myXmtpAddress }),
68229
+ conversationId,
68230
+ messageId,
68231
+ chatType,
68232
+ peerInboxId: ctx.message.senderInboxId ?? "",
68233
+ ...inboundStageExtras("inbound/job_id_validation", "dropped"),
68234
+ reason: "dm_a2a_missing_job_id"
68235
+ });
68236
+ return true;
68237
+ }
68238
+ if (route.route === "job" && chatType !== "group" && !isA2ADm) {
66950
68239
  const providerBindStartedAt = Date.now();
66951
68240
  const providerGate = await bindMessageJobProviderToCurrentDefault(deps, route.jobId, "inbound-xmtp");
66952
68241
  timing.mark("providerBind", providerBindStartedAt);
@@ -66986,7 +68275,7 @@ async function processFileMessage(ctx, deps, options = {}) {
66986
68275
  );
66987
68276
  }
66988
68277
  if (route.route === "job" && chatType === "group") {
66989
- const payloadObject = isPlainObject3(parseResult.ok ? parseResult.data : null) ? parseResult.data : null;
68278
+ const payloadObject = isPlainObject5(parseResult.ok ? parseResult.data : null) ? parseResult.data : null;
66990
68279
  const service = XmtpService.getInstance();
66991
68280
  const trustedSystemSender = service.isTrustedSystemAccountSender({
66992
68281
  senderAddress,
@@ -67012,7 +68301,7 @@ async function processFileMessage(ctx, deps, options = {}) {
67012
68301
  });
67013
68302
  return true;
67014
68303
  }
67015
- const sender = isPlainObject3(payloadObject?.sender) ? payloadObject.sender : null;
68304
+ const sender = isPlainObject5(payloadObject?.sender) ? payloadObject.sender : null;
67016
68305
  const localAgent = service.getAgentByAddress(deps.myXmtpAddress);
67017
68306
  const myAgentId = localAgent?.agentId ?? readString3(payloadObject?.receiverAgentId) ?? sessionAgentId ?? null;
67018
68307
  const toAgentId = readString3(sender?.agentId);
@@ -67052,7 +68341,7 @@ async function processFileMessage(ctx, deps, options = {}) {
67052
68341
  }));
67053
68342
  return true;
67054
68343
  }
67055
- const routedMessageId = messageId || `group-${(0, import_node_crypto12.randomUUID)()}`;
68344
+ const routedMessageId = messageId || `group-${(0, import_node_crypto13.randomUUID)()}`;
67056
68345
  const sessionKey = ensureInboundGroupSession(deps, {
67057
68346
  jobId: route.jobId,
67058
68347
  myAgentId,
@@ -67117,8 +68406,102 @@ async function processFileMessage(ctx, deps, options = {}) {
67117
68406
  );
67118
68407
  return true;
67119
68408
  }
68409
+ if (route.route === "job" && isA2ADm) {
68410
+ const payloadObject = parseResult.data;
68411
+ const accepted = await verifyInboundA2AGroupMessage({
68412
+ payload: parseResult.data,
68413
+ myXmtpAddress: deps.myXmtpAddress,
68414
+ senderAddress,
68415
+ senderInboxId: ctx.message.senderInboxId ?? "",
68416
+ jobId: route.jobId,
68417
+ groupId: conversationId,
68418
+ messageId,
68419
+ consentState: void 0,
68420
+ trustedSystemSender: false,
68421
+ isOfflineReplay: options.isOfflineReplay ?? false,
68422
+ timing
68423
+ });
68424
+ if (!accepted) {
68425
+ return true;
68426
+ }
68427
+ const providerBindStartedAt = Date.now();
68428
+ const providerGate = await bindMessageJobProviderToCurrentDefault(deps, route.jobId, "inbound-xmtp");
68429
+ timing.mark("providerBind", providerBindStartedAt);
68430
+ if (!providerGate.allowed) {
68431
+ logger.info(LogEvent.INBOUND_IGNORED_NON_BUSINESS, timing.extras({
68432
+ ...buildInboundTerminalExtras({
68433
+ terminalState: "provider_gate_denied",
68434
+ myXmtpAddress: deps.myXmtpAddress,
68435
+ messageId,
68436
+ conversationId,
68437
+ chatType,
68438
+ jobId: route.jobId,
68439
+ route: route.route,
68440
+ reason: "job_provider_gate_denied"
68441
+ }),
68442
+ routeReason: route.routeReason,
68443
+ providerBinding: providerGate.provider ?? ""
68444
+ }));
68445
+ return true;
68446
+ }
68447
+ const myAgentId = XmtpService.getInstance().getAgentByAddress(deps.myXmtpAddress)?.agentId ?? readString3(payloadObject.receiverAgentId) ?? sessionAgentId ?? null;
68448
+ const sender = isPlainObject5(payloadObject.sender) ? payloadObject.sender : null;
68449
+ const toAgentId = readString3(sender?.agentId);
68450
+ const routedMessageId = messageId || `dm-${(0, import_node_crypto13.randomUUID)()}`;
68451
+ const sessionKey = ensureInboundGroupSession(deps, {
68452
+ jobId: route.jobId,
68453
+ myAgentId,
68454
+ toAgentId,
68455
+ groupId: null,
68456
+ toAgentXmtpAddress: senderAddress || readString3(payloadObject.fromXmtpAddress)
68457
+ });
68458
+ const dispatchStartedAt = Date.now();
68459
+ void Promise.resolve(deps.onSessionMessage?.({
68460
+ sessionKey,
68461
+ content: rawText,
68462
+ messageId: routedMessageId,
68463
+ jobId: route.jobId,
68464
+ agentId: myAgentId
68465
+ })).then(() => {
68466
+ timing.mark("sessionDispatch", dispatchStartedAt);
68467
+ logger.info(LogEvent.INBOUND_DELIVERED, commonDeliveryExtras({
68468
+ taskId: route.jobId,
68469
+ agentId: myAgentId ?? "",
68470
+ peerWalletAddress: senderAddress,
68471
+ peerInboxId: ctx.message.senderInboxId ?? "",
68472
+ peerAgentId: toAgentId ?? "",
68473
+ sessionKey,
68474
+ messageId: routedMessageId,
68475
+ route: "dm",
68476
+ ...inboundStageExtras("inbound/dm_session_dispatch", "success"),
68477
+ dispatchTarget: deps.onSessionMessage ? "session" : "none"
68478
+ }));
68479
+ }).catch((err) => {
68480
+ logWithTimestamp(`[okx-agent-task:${deps.myXmtpAddress}] onSessionMessage failed:`, err);
68481
+ logger.error(LogEvent.INBOUND_DISPATCH_FAILED, toLoggableError(err), timing.extras({
68482
+ ...buildInboundTerminalExtras({
68483
+ terminalState: "dispatch_failed",
68484
+ myXmtpAddress: deps.myXmtpAddress,
68485
+ messageId: routedMessageId,
68486
+ conversationId,
68487
+ chatType,
68488
+ jobId: route.jobId,
68489
+ sessionKey,
68490
+ route: "dm",
68491
+ reason: "session_dispatch_failed"
68492
+ }),
68493
+ checkpoint: "inbound/dm_session_dispatch_failed",
68494
+ agentId: myAgentId ?? "",
68495
+ peerAgentId: toAgentId ?? ""
68496
+ }));
68497
+ });
68498
+ logWithTimestamp(
68499
+ `[okx-agent-task:${deps.myXmtpAddress}] session dispatch queued route=dm session=${sessionKey} message=${shortenLogValue(routedMessageId)} ${summarizePayloadForLog(parseResult.data)}`
68500
+ );
68501
+ return true;
68502
+ }
67120
68503
  const stored = {
67121
- id: messageId || `local-${(0, import_node_crypto12.randomUUID)()}`,
68504
+ id: messageId || `local-${(0, import_node_crypto13.randomUUID)()}`,
67122
68505
  direction: "inbound",
67123
68506
  route: route.route,
67124
68507
  routeReason: route.routeReason,
@@ -67136,8 +68519,8 @@ async function processFileMessage(ctx, deps, options = {}) {
67136
68519
  await deps.store.append(route.jobId, stored, sessionAgentId);
67137
68520
  timing.mark("storeAppend", storeAppendStartedAt);
67138
68521
  if ((route.route === "job" || parseResult.ok && !isA2AEnvelope(stored.payload)) && !options.skipNotify) {
67139
- const payloadObject = isPlainObject3(stored.payload) ? stored.payload : null;
67140
- const sender = isPlainObject3(payloadObject?.sender) ? payloadObject.sender : null;
68522
+ const payloadObject = isPlainObject5(stored.payload) ? stored.payload : null;
68523
+ const sender = isPlainObject5(payloadObject?.sender) ? payloadObject.sender : null;
67141
68524
  const localAgent = XmtpService.getInstance().getAgentByAddress(deps.myXmtpAddress);
67142
68525
  const sessionKey = route.route === "job" ? buildSessionKey({
67143
68526
  jobId: route.jobId,
@@ -67155,8 +68538,8 @@ async function processFileMessage(ctx, deps, options = {}) {
67155
68538
  });
67156
68539
  }
67157
68540
  if (route.route === "job" && chatType === "group" && conversationId && senderAddress) {
67158
- const payloadObject = isPlainObject3(stored.payload) ? stored.payload : null;
67159
- const sender = isPlainObject3(payloadObject?.sender) ? payloadObject.sender : null;
68541
+ const payloadObject = isPlainObject5(stored.payload) ? stored.payload : null;
68542
+ const sender = isPlainObject5(payloadObject?.sender) ? payloadObject.sender : null;
67160
68543
  await deps.store.updateXmtpSession(route.jobId, {
67161
68544
  xmtpGroupId: conversationId,
67162
68545
  myXmtpAddress: deps.myXmtpAddress,
@@ -67299,7 +68682,7 @@ function processOfflineFromCoreDeps(store, ctx, deps, options) {
67299
68682
  function buildSystemStoredMessage(params) {
67300
68683
  const now = Date.now();
67301
68684
  return {
67302
- id: params.id ?? `system-${now}-${(0, import_node_crypto12.randomUUID)()}`,
68685
+ id: params.id ?? `system-${now}-${(0, import_node_crypto13.randomUUID)()}`,
67303
68686
  direction: "system",
67304
68687
  route: "backup",
67305
68688
  routeReason: params.reason,
@@ -67315,7 +68698,7 @@ function buildSystemStoredMessage(params) {
67315
68698
  };
67316
68699
  }
67317
68700
  function isA2AEnvelope(payload) {
67318
- return isPlainObject3(payload) && payload.msgType === A2A_MESSAGE_TYPE;
68701
+ return isPlainObject5(payload) && payload.msgType === A2A_MESSAGE_TYPE;
67319
68702
  }
67320
68703
 
67321
68704
  // src/listener.ts
@@ -67443,7 +68826,7 @@ async function enqueueAiJobMessageDispatch(params) {
67443
68826
  await commands.submit(command);
67444
68827
  return command;
67445
68828
  }
67446
- async function enqueueAiSessionMessageDispatch(params) {
68829
+ async function enqueueAiSessionMessageDispatchIdempotent(params) {
67447
68830
  const commands = params.commands ?? new CommandStore(params.homeDir);
67448
68831
  const messageId = params.event.messageId ?? `session-${Date.now()}`;
67449
68832
  const command = commands.createAiSessionMessageDispatchCommand({
@@ -67453,15 +68836,25 @@ async function enqueueAiSessionMessageDispatch(params) {
67453
68836
  jobId: params.event.jobId,
67454
68837
  agentId: params.event.agentId
67455
68838
  });
68839
+ const idempotencyKey = params.event.idempotencyKey?.trim();
68840
+ if (idempotencyKey) {
68841
+ const dbKey = `${command.sessionKey}
68842
+ ${command.messageId}`;
68843
+ const result = await commands.submitIdempotent(command, dbKey);
68844
+ return {
68845
+ command: result.created ? command : { ...command, id: result.commandId },
68846
+ created: result.created
68847
+ };
68848
+ }
67456
68849
  await commands.submit(command);
67457
- return command;
68850
+ return { command, created: true };
67458
68851
  }
67459
68852
 
67460
68853
  // src/listener.ts
67461
68854
  init_paths();
67462
68855
 
67463
68856
  // src/user-attention-watchers.ts
67464
- var import_node_crypto13 = require("node:crypto");
68857
+ var import_node_crypto14 = require("node:crypto");
67465
68858
  init_sentry_logger();
67466
68859
  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.";
67467
68860
  var USER_ATTENTION_WATCHER_SCAN_MS = 500;
@@ -67504,7 +68897,7 @@ function isOriginalParentProcessAlive(options) {
67504
68897
  }
67505
68898
  function registerUserAttentionWatcher(options) {
67506
68899
  return options.store.registerUserAttentionWatcher({
67507
- id: options.id ?? (0, import_node_crypto13.randomUUID)(),
68900
+ id: options.id ?? (0, import_node_crypto14.randomUUID)(),
67508
68901
  provider: options.provider,
67509
68902
  jobId: options.jobId,
67510
68903
  nowMs: options.nowMs ?? Date.now(),
@@ -67796,6 +69189,35 @@ var ListenerMaintenanceGate = class {
67796
69189
  }
67797
69190
  };
67798
69191
  var UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY = "system:onchainos-offline-replay-upgrade";
69192
+ var LIST_JOBS_UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY = "system:onchainos-list-jobs-by-verified-sender-upgrade";
69193
+ function buildUpgradeRecommendationNotice(input) {
69194
+ const capability = input.capability?.trim() ?? "";
69195
+ if (capability === MESSAGE_ELIGIBLE_OFFLINE_REPLAY_HELP_TOKEN) {
69196
+ return {
69197
+ title: "OnchainOS upgrade recommended",
69198
+ content: "The installed OnchainOS version does not support offline-replay preferences. Subscription messages will continue to replay normally. Upgrade OnchainOS to enable this capability.\n\nSuggested command: onchainos upgrade",
69199
+ idempotencyKey: UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY
69200
+ };
69201
+ }
69202
+ if (capability === LIST_JOBS_BY_VERIFIED_SENDER_HELP_TOKEN) {
69203
+ return {
69204
+ title: "OnchainOS upgrade required for Subscription Shared Group",
69205
+ content: "The installed OnchainOS version does not support the verified-sender task query required by Subscription Shared Group. Until OnchainOS is upgraded, Subscription Shared Group messages fail closed and are NOT routed to an AI Session. Upgrade OnchainOS to enable this capability.\n\nSuggested command: onchainos upgrade",
69206
+ idempotencyKey: LIST_JOBS_UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY
69207
+ };
69208
+ }
69209
+ const capabilitySlug = capability ? capability.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") : "";
69210
+ const idempotencyKey = capabilitySlug ? `system:onchainos-${capabilitySlug}-upgrade` : "system:onchainos-capability-upgrade";
69211
+ const capabilityLabel = capability || "a required capability";
69212
+ const reasonSuffix = input.reason?.trim() ? ` ${input.reason.trim()}` : "";
69213
+ return {
69214
+ title: "OnchainOS upgrade recommended",
69215
+ content: `The installed OnchainOS version does not support ${capabilityLabel}.${reasonSuffix} Upgrade OnchainOS to enable this capability.
69216
+
69217
+ Suggested command: onchainos upgrade`,
69218
+ idempotencyKey
69219
+ };
69220
+ }
67799
69221
  function resolveOfflineReplayIntervalSec(systemConfig) {
67800
69222
  const interval = systemConfig.offlineReplayInterval;
67801
69223
  if (typeof interval !== "number" || !Number.isFinite(interval) || interval <= 0) {
@@ -68024,8 +69446,12 @@ async function runListenerWithLock(options, paths) {
68024
69446
  onJobMessageStored: async (event) => {
68025
69447
  await enqueueAiJobMessageDispatch({ commands, event });
68026
69448
  },
69449
+ // Returns { created } so the V2 subscription fan-out can distinguish a
69450
+ // durable DB duplicate (idempotent success) from a fresh enqueue. V1
69451
+ // group/system callers ignore the return; their events carry no
69452
+ // idempotencyKey, so the plain submit path (unchanged) is used.
68027
69453
  onSessionMessage: async (event) => {
68028
- await enqueueAiSessionMessageDispatch({ commands, event });
69454
+ return enqueueAiSessionMessageDispatchIdempotent({ commands, event });
68029
69455
  }
68030
69456
  }),
68031
69457
  processOfflineMessage: (ctx, deps, replayOptions) => processOfflineFromCoreDeps(store, ctx, deps, {
@@ -68035,7 +69461,7 @@ async function runListenerWithLock(options, paths) {
68035
69461
  await enqueueAiJobMessageDispatch({ commands, event });
68036
69462
  },
68037
69463
  onSessionMessage: async (event) => {
68038
- await enqueueAiSessionMessageDispatch({ commands, event });
69464
+ return enqueueAiSessionMessageDispatchIdempotent({ commands, event });
68039
69465
  }
68040
69466
  }),
68041
69467
  notifySessionExpired: (command) => {
@@ -68053,12 +69479,12 @@ async function runListenerWithLock(options, paths) {
68053
69479
  });
68054
69480
  },
68055
69481
  notifyUpgradeRecommendation: (input) => {
68056
- const content = "The installed OnchainOS version does not support offline-replay preferences. Subscription messages will continue to replay normally. Upgrade OnchainOS to enable this capability.\n\nSuggested command: onchainos upgrade";
69482
+ const notice = buildUpgradeRecommendationNotice(input);
68057
69483
  void notifySystemMessageToUser({
68058
- title: "OnchainOS upgrade recommended",
68059
- content,
69484
+ title: notice.title,
69485
+ content: notice.content,
68060
69486
  store: sessionStore,
68061
- idempotencyKey: UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY
69487
+ idempotencyKey: notice.idempotencyKey
68062
69488
  }).catch((err) => {
68063
69489
  logWithTimestamp(
68064
69490
  `[okx-agent-task] upgrade recommendation notify failed component=${input.component} capability=${input.capability}:`,
@@ -68067,12 +69493,12 @@ async function runListenerWithLock(options, paths) {
68067
69493
  });
68068
69494
  }
68069
69495
  });
68070
- service.setPluginVersion("0.2.17");
69496
+ service.setPluginVersion("0.2.18-beta-4dd056b897-261015113839");
68071
69497
  await service.init();
68072
69498
  const pluginVersionStatus = service.pluginVersionStatus;
68073
69499
  if (pluginVersionStatus.unavailable) {
68074
69500
  throw new Error(
68075
- `@okxweb3/a2a-node v${"0.2.17"} is below the required minimum v${pluginVersionStatus.minVersion}`
69501
+ `@okxweb3/a2a-node v${"0.2.18-beta-4dd056b897-261015113839"} is below the required minimum v${pluginVersionStatus.minVersion}`
68076
69502
  );
68077
69503
  }
68078
69504
  const systemConfig = service.getSystemConfig();
@@ -68100,7 +69526,7 @@ async function runListenerWithLock(options, paths) {
68100
69526
  onchainosAgentId: "*",
68101
69527
  reason: "system-config missing sentryDsn",
68102
69528
  pluginId: "@okxweb3/a2a-node",
68103
- pluginVersion: "0.2.17"
69529
+ pluginVersion: "0.2.18-beta-4dd056b897-261015113839"
68104
69530
  });
68105
69531
  }
68106
69532
  logWithTimestamp(
@@ -69562,7 +70988,7 @@ var import_node_path34 = require("node:path");
69562
70988
  var import_jszip = __toESM(require_lib3());
69563
70989
 
69564
70990
  // src/logs-export-archive.ts
69565
- var import_node_crypto14 = require("node:crypto");
70991
+ var import_node_crypto15 = require("node:crypto");
69566
70992
  var import_node_fs24 = require("node:fs");
69567
70993
  var import_promises13 = require("node:fs/promises");
69568
70994
  var import_node_path31 = require("node:path");
@@ -70198,7 +71624,7 @@ async function writeArchiveAtomically(outputPath, archive, overwrite) {
70198
71624
  await (0, import_promises13.mkdir)((0, import_node_path31.dirname)(outputPath), { recursive: true });
70199
71625
  const temporaryPath = (0, import_node_path31.join)(
70200
71626
  (0, import_node_path31.dirname)(outputPath),
70201
- `.${(0, import_node_path31.basename)(outputPath)}.${(0, import_node_crypto14.randomUUID)()}.tmp`
71627
+ `.${(0, import_node_path31.basename)(outputPath)}.${(0, import_node_crypto15.randomUUID)()}.tmp`
70202
71628
  );
70203
71629
  try {
70204
71630
  await (0, import_promises13.writeFile)(temporaryPath, archive, { flag: "wx", mode: 384 });
@@ -70217,7 +71643,7 @@ async function writeArchiveAtomically(outputPath, archive, overwrite) {
70217
71643
  }
70218
71644
  }
70219
71645
  function hashDiagnosticFileContent(content) {
70220
- return (0, import_node_crypto14.createHash)("sha256").update(content).digest("hex");
71646
+ return (0, import_node_crypto15.createHash)("sha256").update(content).digest("hex");
70221
71647
  }
70222
71648
  function isUnavailableError(err) {
70223
71649
  return !!err && typeof err === "object" && "diagnosticUnavailable" in err;
@@ -70477,7 +71903,7 @@ function isProvider2(value) {
70477
71903
  }
70478
71904
 
70479
71905
  // src/logs-export-utils.ts
70480
- var import_node_crypto15 = require("node:crypto");
71906
+ var import_node_crypto16 = require("node:crypto");
70481
71907
  var import_node_fs26 = require("node:fs");
70482
71908
  var import_promises14 = require("node:fs/promises");
70483
71909
  var import_node_path33 = require("node:path");
@@ -70620,7 +72046,7 @@ async function assertRegularFile2(path2) {
70620
72046
  }
70621
72047
  async function inspectRegularFile(path2) {
70622
72048
  const file = await assertRegularFile2(path2);
70623
- const hash2 = (0, import_node_crypto15.createHash)("sha256");
72049
+ const hash2 = (0, import_node_crypto16.createHash)("sha256");
70624
72050
  for await (const chunk of (0, import_node_fs26.createReadStream)(path2)) {
70625
72051
  hash2.update(chunk);
70626
72052
  }
@@ -70873,7 +72299,7 @@ async function exportDiagnosticLogs(options) {
70873
72299
  node: process.version,
70874
72300
  platform: process.platform,
70875
72301
  arch: process.arch,
70876
- packageVersion: true ? "0.2.17" : "unknown",
72302
+ packageVersion: true ? "0.2.18-beta-4dd056b897-261015113839" : "unknown",
70877
72303
  sensitiveContentIncluded: options.includeSensitiveContent,
70878
72304
  listenerAndLlmContentIncluded: true,
70879
72305
  credentialsAlwaysRedacted: true,
@@ -72785,7 +74211,7 @@ async function runDoctor(options = {}) {
72785
74211
  platform: options.platform ?? process.platform,
72786
74212
  env: options.env ?? process.env,
72787
74213
  target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
72788
- cliVersion: options.cliVersion ?? (true ? "0.2.17" : "0.0.0"),
74214
+ cliVersion: options.cliVersion ?? (true ? "0.2.18-beta-4dd056b897-261015113839" : "0.0.0"),
72789
74215
  fixMode: options.fix === true,
72790
74216
  nonInteractive: options.nonInteractive === true,
72791
74217
  packageChanged: false,
@@ -73032,6 +74458,7 @@ init_autostart_windows();
73032
74458
  InboundReplayGate,
73033
74459
  InvalidXmtpMessageStore,
73034
74460
  JOB_PROVIDER_BINDING_SOURCES,
74461
+ LIST_JOBS_BY_VERIFIED_SENDER_HELP_TOKEN,
73035
74462
  ListenerDeferredTaskScheduler,
73036
74463
  ListenerMaintenanceGate,
73037
74464
  LogEvent,
@@ -73041,6 +74468,9 @@ init_autostart_windows();
73041
74468
  NATIVE_LAUNCHER_EXE_NAME,
73042
74469
  OPENCLAW_GATEWAY_ROUTE_GROUP_ID,
73043
74470
  ProviderNotReadyError,
74471
+ RUN_LOG_FILENAME_MAX_BYTES,
74472
+ SUBSCRIPTION_FANOUT_MAX,
74473
+ SUBSCRIPTION_MESSAGE_TYPE,
73044
74474
  SYSTEM_NOTIFICATION_SESSION_KEY,
73045
74475
  SessionBusyTracker,
73046
74476
  SessionStore,
@@ -73086,7 +74516,9 @@ init_autostart_windows();
73086
74516
  buildInboundTerminalExtras,
73087
74517
  buildLaunchdPlist,
73088
74518
  buildLauncherEntryJs,
74519
+ buildListJobsByVerifiedSenderArgs,
73089
74520
  buildMessageEligibleArgs,
74521
+ buildRunLogFileName,
73090
74522
  buildSchtasksCreateArgs,
73091
74523
  buildSchtasksDeleteArgs,
73092
74524
  buildSchtasksEndArgs,
@@ -73095,9 +74527,14 @@ init_autostart_windows();
73095
74527
  buildSeaConfig,
73096
74528
  buildServicePath,
73097
74529
  buildSessionKey,
74530
+ buildSubscriptionEnvelope,
74531
+ buildSubscriptionInboundExtras,
74532
+ buildSubscriptionJobExtras,
74533
+ buildSubscriptionSendExtras,
73098
74534
  buildSystemMessageNotice,
73099
74535
  buildSystemStoredMessage,
73100
74536
  buildSystemdUserService,
74537
+ buildUpgradeRecommendationNotice,
73101
74538
  buildWin32OnchainosCandidates,
73102
74539
  buildWindowsParentProcessProbe,
73103
74540
  buildXmtpMessageSentExtra,
@@ -73112,6 +74549,7 @@ init_autostart_windows();
73112
74549
  checkCodexReadiness,
73113
74550
  claimActiveDaemon,
73114
74551
  classifyJobBindingSource,
74552
+ classifyListJobsError,
73115
74553
  clearCodexReadinessCache,
73116
74554
  codexCommandResolvesWithoutOverride,
73117
74555
  codexReadinessCacheKey,
@@ -73123,10 +74561,12 @@ init_autostart_windows();
73123
74561
  createOutboundBehavior,
73124
74562
  createUserAttentionWatchParentMonitor,
73125
74563
  currentOpenClawGatewaySessionKey,
74564
+ decideSubscriptionGate,
73126
74565
  detectAiProviders,
73127
74566
  detectAiRuntimeSurface,
73128
74567
  detectCurrentAiProvider,
73129
74568
  detectGatewayInvocation,
74569
+ detectListJobsByVerifiedSenderSupport,
73130
74570
  detectMessageEligibleOfflineReplaySupport,
73131
74571
  detectRuntime,
73132
74572
  ensureDaemonReady,
@@ -73140,6 +74580,7 @@ init_autostart_windows();
73140
74580
  extractDirectToUserNotification,
73141
74581
  extractRateLimitEndpoint,
73142
74582
  extractXmtpSentAtMs,
74583
+ fanOutSubscriptionJobs,
73143
74584
  findWindowsNativeOkxA2aExe,
73144
74585
  followFile,
73145
74586
  formatDoctorReportForHumans,
@@ -73152,6 +74593,7 @@ init_autostart_windows();
73152
74593
  getXmtpCreationCooldown,
73153
74594
  handleCapabilitiesCommand,
73154
74595
  handleDoctorCommand,
74596
+ handleSubscriptionPushCommand,
73155
74597
  handleXmtpDebugCommand,
73156
74598
  handleXmtpSendCommand,
73157
74599
  handleXmtpTestCommand,
@@ -73166,6 +74608,7 @@ init_autostart_windows();
73166
74608
  invalidateResolvedOnchainosBinForTests,
73167
74609
  isAutostartManagerUnavailableError,
73168
74610
  isDefaultTaskHome,
74611
+ isFingerprintKey,
73169
74612
  isGatewayAvailableForHeartbeat,
73170
74613
  isHermesGatewayPluginEnabled,
73171
74614
  isInfoEventAllowlisted,
@@ -73176,6 +74619,7 @@ init_autostart_windows();
73176
74619
  isPrereleaseVersion,
73177
74620
  isRetryableOpenClawGatewayError,
73178
74621
  isSqliteBusyError,
74622
+ isSubscriptionEnvelope,
73179
74623
  isSystemdManagerUnavailableMessage,
73180
74624
  isTagKey,
73181
74625
  isValidExternalJobId,
@@ -73184,8 +74628,12 @@ init_autostart_windows();
73184
74628
  killProcessTree,
73185
74629
  launchdPlistHasCurrentRestartPolicy,
73186
74630
  listAllAgentsWithMetadata,
74631
+ listJobsByVerifiedSender,
74632
+ listJobsByVerifiedSenderHelpAdvertisesCommand,
74633
+ listJobsByVerifiedSenderWithCapability,
73187
74634
  logWinCompat,
73188
74635
  logXmtpMessageSent,
74636
+ logger,
73189
74637
  maybeRecommendOnchainosUpgrade,
73190
74638
  mergeA2AEnvelopeTips,
73191
74639
  messageEligibleHelpAdvertisesOfflineReplay,
@@ -73193,6 +74641,8 @@ init_autostart_windows();
73193
74641
  normalizeAiProvider,
73194
74642
  normalizeAiRuntimeProvider,
73195
74643
  normalizeHermesOkxA2aPluginConfig,
74644
+ normalizeListJobsResponse,
74645
+ normalizeSubscriptionJobs,
73196
74646
  notifyAgentMessageToUserAttention,
73197
74647
  notifyDirectToUserAttention,
73198
74648
  notifySystemMessageToUser,
@@ -73203,6 +74653,7 @@ init_autostart_windows();
73203
74653
  parsePluginYamlVersion,
73204
74654
  parseWalletLoginStatus,
73205
74655
  parseWindowsParentProcessJson,
74656
+ partitionSubscriptionJobsByOwner,
73206
74657
  performRuntimeSwitch,
73207
74658
  persistAiRuntimeSurfaceBestEffort,
73208
74659
  persistCurrentRuntimeSelectionForNewJob,
@@ -73212,12 +74663,14 @@ init_autostart_windows();
73212
74663
  printXmtpTestUsage,
73213
74664
  probeCodexAuthStatus,
73214
74665
  processFileMessage,
74666
+ processSubscriptionInbound,
73215
74667
  queryWalletLoginStatus,
73216
74668
  readAiProviderTimeoutMs,
73217
74669
  readAiRuntimeSurfaceBestEffort,
73218
74670
  readCachedCodexReadiness,
73219
74671
  readLastLines,
73220
74672
  readParentProcessCommandForPlatform,
74673
+ readSubscriptionEnvelope,
73221
74674
  readUserAttentionWatcherEvent,
73222
74675
  refreshAgentsAndWait,
73223
74676
  refreshOnchainosVersionMetadata,
@@ -73228,8 +74681,10 @@ init_autostart_windows();
73228
74681
  replayScanBackoffWithJitterMs,
73229
74682
  reportDoctorRunToSentry,
73230
74683
  reportUserNotificationFailure,
74684
+ resetListJobsByVerifiedSenderCapabilityForTests,
73231
74685
  resetMessageEligibleOfflineReplayCapabilityForTests,
73232
74686
  resetResolvedOnchainosBinForTests,
74687
+ resetSubscriptionTargetsForTests,
73233
74688
  resetXmtpCreationCooldownForTests,
73234
74689
  resolveAiPermissionPreset,
73235
74690
  resolveAiProviderCommand,
@@ -73283,6 +74738,8 @@ init_autostart_windows();
73283
74738
  stopOpenClawGateway,
73284
74739
  stopSystemdAutostart,
73285
74740
  subscribeUserAttentionEvents,
74741
+ subscriptionIdempotencyKey,
74742
+ summarizeSubscriptionPush,
73286
74743
  summarizeXmtpTestEvents,
73287
74744
  switchProvider,
73288
74745
  switchProviderWithReadinessGate,
@@ -73291,6 +74748,7 @@ init_autostart_windows();
73291
74748
  tailFile,
73292
74749
  toOpenClawGatewaySessionKey,
73293
74750
  toWindowsInvocation,
74751
+ tryMarkSubscriptionTarget,
73294
74752
  writeAiPermissionPresetToConfig
73295
74753
  });
73296
74754
  /*! Bundled license information: