@okxweb3/a2a-node 0.1.7-beta-482acfaf84-260707171501 → 0.1.7

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 +272 -228
  2. package/dist/index.js +846 -762
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -593,7 +593,7 @@ function readTextArray(value) {
593
593
  });
594
594
  return normalizeGatewayRouteAliases(values);
595
595
  }
596
- var import_node_crypto, import_node_fs2, import_node_path3, DatabaseSync, SYSTEM_NOTIFICATION_SESSION_KEY, NOTIFICATION_ATTENTION_KINDS, PROMPT_ATTENTION_KINDS, AI_PROVIDER_COMMAND_SETTING_PREFIX, SessionStore;
596
+ var import_node_crypto, import_node_fs2, import_node_path3, DatabaseSync, SYSTEM_NOTIFICATION_SESSION_KEY, AI_PROVIDER_COMMAND_SETTING_PREFIX, SessionStore;
597
597
  var init_session_store = __esm({
598
598
  "src/session-store.ts"() {
599
599
  "use strict";
@@ -603,8 +603,6 @@ var init_session_store = __esm({
603
603
  init_paths();
604
604
  ({ DatabaseSync } = loadSqlite());
605
605
  SYSTEM_NOTIFICATION_SESSION_KEY = "system-notification";
606
- NOTIFICATION_ATTENTION_KINDS = ["notification", "system_notification"];
607
- PROMPT_ATTENTION_KINDS = ["decision_request", "system_prompt"];
608
606
  AI_PROVIDER_COMMAND_SETTING_PREFIX = "ai_provider_command_";
609
607
  SessionStore = class {
610
608
  homeDir;
@@ -666,11 +664,34 @@ var init_session_store = __esm({
666
664
  CREATE INDEX IF NOT EXISTS idx_session_metadata_job_agents
667
665
  ON session_metadata(job_id, my_agent_id, to_agent_id)
668
666
  `);
669
- this.ensureUserAttentionSchema();
667
+ this.db.exec(`
668
+ CREATE TABLE IF NOT EXISTS user_attention (
669
+ id TEXT PRIMARY KEY,
670
+ kind TEXT NOT NULL CHECK (kind IN ('notification', 'decision_request')),
671
+ provider TEXT CHECK (provider IN ('codex', 'claude', 'hermes', 'openclaw') OR provider IS NULL),
672
+ status TEXT NOT NULL CHECK (status IN ('pending', 'handled')),
673
+ job_id TEXT,
674
+ session_key TEXT,
675
+ llm_content TEXT,
676
+ choices_json TEXT,
677
+ user_content TEXT NOT NULL,
678
+ idempotency_key TEXT UNIQUE,
679
+ expire_time INTEGER,
680
+ created_at TEXT NOT NULL,
681
+ handled_at TEXT,
682
+ deleted_at TEXT,
683
+ seen INTEGER NOT NULL DEFAULT 0 CHECK (seen IN (0, 1))
684
+ )
685
+ `);
670
686
  this.db.exec(`
671
687
  CREATE INDEX IF NOT EXISTS idx_user_attention_status_created
672
688
  ON user_attention(status, created_at)
673
689
  `);
690
+ this.ensureColumn("user_attention", "choices_json", "TEXT");
691
+ this.ensureColumn("user_attention", "deleted_at", "TEXT");
692
+ this.ensureColumn("user_attention", "seen", "INTEGER NOT NULL DEFAULT 0");
693
+ this.ensureColumn("user_attention", "provider", "TEXT CHECK (provider IN ('codex', 'claude', 'hermes', 'openclaw') OR provider IS NULL)");
694
+ this.ensureColumn("user_attention", "expire_time", "INTEGER");
674
695
  this.db.exec(`
675
696
  CREATE INDEX IF NOT EXISTS idx_user_attention_provider_status_created
676
697
  ON user_attention(provider, status, created_at)
@@ -736,58 +757,6 @@ var init_session_store = __esm({
736
757
  CREATE INDEX IF NOT EXISTS idx_pending_gateway_deliveries_provider_created
737
758
  ON pending_gateway_deliveries(provider, created_at)
738
759
  `);
739
- }
740
- ensureUserAttentionSchema() {
741
- this.db.exec(`
742
- CREATE TABLE IF NOT EXISTS user_attention (
743
- ${this.userAttentionTableColumnsSql()}
744
- )
745
- `);
746
- this.ensureColumn("user_attention", "choices_json", "TEXT");
747
- this.ensureColumn("user_attention", "deleted_at", "TEXT");
748
- this.ensureColumn("user_attention", "seen", "INTEGER NOT NULL DEFAULT 0");
749
- this.ensureColumn("user_attention", "provider", "TEXT CHECK (provider IN ('codex', 'claude', 'hermes', 'openclaw') OR provider IS NULL)");
750
- this.ensureColumn("user_attention", "expire_time", "INTEGER");
751
- const row = this.db.prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='user_attention'").get();
752
- if (row?.sql?.includes("system_notification") && row.sql.includes("system_prompt")) {
753
- return;
754
- }
755
- this.db.exec("ALTER TABLE user_attention RENAME TO user_attention_old");
756
- this.db.exec(`
757
- CREATE TABLE user_attention (
758
- ${this.userAttentionTableColumnsSql()}
759
- )
760
- `);
761
- this.db.exec(`
762
- INSERT INTO user_attention (
763
- id, kind, provider, status, job_id, session_key, llm_content, choices_json,
764
- user_content, idempotency_key, expire_time, created_at, handled_at, deleted_at, seen
765
- )
766
- SELECT
767
- id, kind, provider, status, job_id, session_key, llm_content, choices_json,
768
- user_content, idempotency_key, expire_time, created_at, handled_at, deleted_at, seen
769
- FROM user_attention_old
770
- `);
771
- this.db.exec("DROP TABLE user_attention_old");
772
- }
773
- userAttentionTableColumnsSql() {
774
- return `
775
- id TEXT PRIMARY KEY,
776
- kind TEXT NOT NULL CHECK (kind IN ('notification', 'decision_request', 'system_notification', 'system_prompt')),
777
- provider TEXT CHECK (provider IN ('codex', 'claude', 'hermes', 'openclaw') OR provider IS NULL),
778
- status TEXT NOT NULL CHECK (status IN ('pending', 'handled')),
779
- job_id TEXT,
780
- session_key TEXT,
781
- llm_content TEXT,
782
- choices_json TEXT,
783
- user_content TEXT NOT NULL,
784
- idempotency_key TEXT UNIQUE,
785
- expire_time INTEGER,
786
- created_at TEXT NOT NULL,
787
- handled_at TEXT,
788
- deleted_at TEXT,
789
- seen INTEGER NOT NULL DEFAULT 0 CHECK (seen IN (0, 1))
790
- `;
791
760
  }
792
761
  ensurePendingGatewayDeliveriesSchema() {
793
762
  const expectedKindCheck = this.pendingGatewayDeliveryKindCheck();
@@ -1132,11 +1101,11 @@ var init_session_store = __esm({
1132
1101
  return rows.map(mapJobProviderBindingRow);
1133
1102
  }
1134
1103
  createUserAttention(input) {
1135
- if (!NOTIFICATION_ATTENTION_KINDS.includes(input.kind) && !PROMPT_ATTENTION_KINDS.includes(input.kind)) {
1104
+ if (input.kind !== "notification" && input.kind !== "decision_request") {
1136
1105
  throw new Error(`Unsupported user_attention kind: ${String(input.kind)}`);
1137
1106
  }
1138
1107
  assertNonEmpty(input.userContent, "userContent");
1139
- if (PROMPT_ATTENTION_KINDS.includes(input.kind)) {
1108
+ if (input.kind === "decision_request") {
1140
1109
  assertNonEmpty(input.llmContent ?? "", "llmContent");
1141
1110
  }
1142
1111
  const provider = normalizeOptionalProvider(input.provider);
@@ -1151,8 +1120,8 @@ var init_session_store = __esm({
1151
1120
  }
1152
1121
  const id = this.idFactory();
1153
1122
  const createdAt = this.timestamp();
1154
- if (PROMPT_ATTENTION_KINDS.includes(input.kind) && input.jobId) {
1155
- this.softDeletePromptAttentionForJob(input.jobId, createdAt);
1123
+ if (input.kind === "decision_request" && input.jobId) {
1124
+ this.softDeleteDecisionRequestsForJob(input.jobId, createdAt);
1156
1125
  }
1157
1126
  const statement = input.idempotencyKey ? this.db.prepare(`
1158
1127
  INSERT OR IGNORE INTO user_attention (
@@ -1252,7 +1221,7 @@ var init_session_store = __esm({
1252
1221
  const watchFilter = buildWatchAttentionFilter(options);
1253
1222
  const decision = this.db.prepare(`
1254
1223
  SELECT * FROM user_attention
1255
- WHERE kind IN ('decision_request', 'system_prompt')
1224
+ WHERE kind = 'decision_request'
1256
1225
  AND status = 'pending'
1257
1226
  AND seen = 0
1258
1227
  AND deleted_at IS NULL
@@ -1263,7 +1232,7 @@ var init_session_store = __esm({
1263
1232
  `).get(this.currentUnixSeconds(), ...watchFilter.values);
1264
1233
  const notifications = this.db.prepare(`
1265
1234
  SELECT * FROM user_attention
1266
- WHERE kind IN ('notification', 'system_notification')
1235
+ WHERE kind = 'notification'
1267
1236
  AND status = 'pending'
1268
1237
  AND seen = 0
1269
1238
  AND deleted_at IS NULL
@@ -1494,7 +1463,7 @@ var init_session_store = __esm({
1494
1463
  const providerFilter = conditions.length > 0 ? `AND ${conditions.join(" AND ")}` : "";
1495
1464
  const rows = this.db.prepare(`
1496
1465
  SELECT * FROM user_attention
1497
- WHERE kind IN ('decision_request', 'system_prompt')
1466
+ WHERE kind = 'decision_request'
1498
1467
  AND status = 'pending'
1499
1468
  AND seen = 1
1500
1469
  AND deleted_at IS NULL
@@ -1672,14 +1641,11 @@ var init_session_store = __esm({
1672
1641
  const row = this.db.prepare("SELECT * FROM user_attention WHERE id = ?").get(id);
1673
1642
  return row ? mapAttentionRow(row) : null;
1674
1643
  }
1675
- // The task state machine allows at most one live action per job, so a new
1676
- // prompt-kind item (decision_request / system_prompt) supersedes every
1677
- // pending prompt for that job regardless of which side produced it.
1678
- softDeletePromptAttentionForJob(jobId, deletedAt) {
1644
+ softDeleteDecisionRequestsForJob(jobId, deletedAt) {
1679
1645
  this.db.prepare(`
1680
1646
  UPDATE user_attention
1681
1647
  SET deleted_at = ?, idempotency_key = NULL
1682
- WHERE kind IN ('decision_request', 'system_prompt')
1648
+ WHERE kind = 'decision_request'
1683
1649
  AND job_id = ?
1684
1650
  AND deleted_at IS NULL
1685
1651
  `).run(deletedAt, jobId);
@@ -8334,7 +8300,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
8334
8300
  client: {
8335
8301
  id: "gateway-client",
8336
8302
  displayName: "okx-a2a-node",
8337
- version: "0.1.7-beta-482acfaf84-260707171501",
8303
+ version: "0.1.7",
8338
8304
  platform: "node",
8339
8305
  mode: "backend",
8340
8306
  instanceId
@@ -8345,7 +8311,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
8345
8311
  commands: [],
8346
8312
  permissions: {},
8347
8313
  locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
8348
- userAgent: `okx-a2a-node/${"0.1.7-beta-482acfaf84-260707171501"}`,
8314
+ userAgent: `okx-a2a-node/${"0.1.7"}`,
8349
8315
  auth: {
8350
8316
  ...config.token ? { token: config.token } : {},
8351
8317
  ...config.password ? { password: config.password } : {}
@@ -24378,6 +24344,7 @@ var init_events = __esm({
24378
24344
  SYSTEM_NOTIFICATION_RECEIVED: "System notification received",
24379
24345
  SYSTEM_NOTIFICATION_ROUTED: "System notification routed",
24380
24346
  HERMES_SESSION_ROUTE_BINDING: "Hermes session route binding",
24347
+ DOCTOR_REPORT: "Doctor report",
24381
24348
  // ── error ─────────────────────────────────────────────────────
24382
24349
  XMTP_CONNECTION_FAILED: "XMTP connection failed",
24383
24350
  CONVERSATIONS_STREAM_FAILED: "conversations.stream failed",
@@ -24417,6 +24384,8 @@ var init_events = __esm({
24417
24384
  DAEMON_LIFECYCLE_FAILED: "Daemon lifecycle failed",
24418
24385
  DAEMON_TICK_FAILED: "Daemon tick failed",
24419
24386
  DIRECT_CLI_FAILED: "Direct CLI failed",
24387
+ DOCTOR_NOT_READY: "Doctor not ready",
24388
+ DOCTOR_CRASHED: "Doctor crashed",
24420
24389
  AI_RUN_FAILED: "AI run failed",
24421
24390
  AI_RUN_TIMEOUT: "AI run timeout",
24422
24391
  AI_RUN_TOOL_FAILED: "AI run tool failed",
@@ -24440,7 +24409,8 @@ function agentExtras(identity3) {
24440
24409
  return {
24441
24410
  walletAddress: identity3.walletAddress || UNKNOWN_FIELD,
24442
24411
  inboxId: identity3.inboxId || UNKNOWN_FIELD,
24443
- onchainosAgentId: identity3.onchainosAgentId || UNKNOWN_FIELD
24412
+ onchainosAgentId: identity3.onchainosAgentId || UNKNOWN_FIELD,
24413
+ role: identity3.role != null && identity3.role !== "" ? String(identity3.role) : UNKNOWN_FIELD
24444
24414
  };
24445
24415
  }
24446
24416
  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, SentryLogger, logger, initLogger, shutdown, UNKNOWN_FIELD;
@@ -24954,7 +24924,7 @@ var init_outbound_behavior = __esm({
24954
24924
  }
24955
24925
  async dispatchUser(input) {
24956
24926
  const item = this.store.createUserAttention({
24957
- kind: input.kind ?? "notification",
24927
+ kind: "notification",
24958
24928
  provider: this.provider,
24959
24929
  userContent: input.userContent,
24960
24930
  jobId: input.jobId ?? null,
@@ -24967,7 +24937,7 @@ var init_outbound_behavior = __esm({
24967
24937
  }
24968
24938
  async promptUser(input) {
24969
24939
  const item = this.store.createUserAttention({
24970
- kind: input.kind ?? "decision_request",
24940
+ kind: "decision_request",
24971
24941
  provider: this.provider,
24972
24942
  userContent: input.userContent,
24973
24943
  llmContent: input.llmContent,
@@ -25595,16 +25565,17 @@ var init_task_config = __esm({
25595
25565
  });
25596
25566
 
25597
25567
  // ../core/src/sentry-config.ts
25598
- var environment, SENTRY_CONFIG;
25568
+ var environment, SENTRY_CONFIG, FALLBACK_SENTRY_DSN;
25599
25569
  var init_sentry_config = __esm({
25600
25570
  "../core/src/sentry-config.ts"() {
25601
25571
  "use strict";
25602
25572
  environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
25603
25573
  SENTRY_CONFIG = {
25604
25574
  projectName: "okx/openclaw-okx-a2a-extension",
25605
- release: "0.1.7-beta-482acfaf84-260707171501",
25575
+ release: "0.1.7",
25606
25576
  environment
25607
25577
  };
25578
+ FALLBACK_SENTRY_DSN = "https://e20ff987c945887733de9ec6cca87aba@sentry.coinall.ltd/apmfe/70295";
25608
25579
  }
25609
25580
  });
25610
25581
 
@@ -86693,7 +86664,8 @@ var init_xmtp_sdk = __esm({
86693
86664
  const identity3 = {
86694
86665
  walletAddress: address,
86695
86666
  inboxId: agent.client?.inboxId,
86696
- onchainosAgentId: onchainosAgent?.agentId
86667
+ onchainosAgentId: onchainosAgent?.agentId,
86668
+ role: onchainosAgent?.role
86697
86669
  };
86698
86670
  try {
86699
86671
  await agent.client.conversations.syncAll([
@@ -86924,12 +86896,16 @@ var init_xmtp_sdk = __esm({
86924
86896
  ...agentExtras({
86925
86897
  walletAddress: address,
86926
86898
  inboxId: agent.client?.inboxId,
86927
- onchainosAgentId: this.getAgentByAddress(address)?.agentId
86899
+ onchainosAgentId: this.getAgentByAddress(address)?.agentId,
86900
+ role: this.getAgentByAddress(address)?.role
86928
86901
  }),
86929
86902
  ...jobIdExtras(msg.content),
86930
86903
  messageId: msg.id,
86931
86904
  conversationId: conv.id,
86932
- stage: "offlineReplay/handleMessage"
86905
+ stage: "offlineReplay/handleMessage",
86906
+ xmtpSentAtMs: String(msgSentMs),
86907
+ replayLagMs: String(Math.max(0, Date.now() - msgSentMs)),
86908
+ handleMs: String(handleMs)
86933
86909
  });
86934
86910
  } else {
86935
86911
  summary.skipped++;
@@ -88112,45 +88088,6 @@ async function notifySystemMessageToUser(input) {
88112
88088
  ownedStore?.close();
88113
88089
  }
88114
88090
  }
88115
- async function notifyDirectSystemMessageToUser(input) {
88116
- const ownedStore = input.store ? null : new SessionStore();
88117
- const store = input.store ?? ownedStore;
88118
- const idempotencyKey = input.idempotencyKey ?? buildDirectSystemMessageIdempotencyKey(input);
88119
- const llmContent = input.llmContent?.trim() || null;
88120
- try {
88121
- const provider = resolveOutboundProvider(store, {
88122
- jobId: input.jobId,
88123
- override: input.provider
88124
- });
88125
- const behavior = createOutboundBehavior(provider, { store });
88126
- const item = llmContent ? await behavior.promptUser({
88127
- kind: "system_prompt",
88128
- userContent: input.userContent,
88129
- llmContent,
88130
- jobId: input.jobId ?? null,
88131
- idempotencyKey
88132
- }) : await behavior.dispatchUser({
88133
- kind: "system_notification",
88134
- userContent: input.userContent,
88135
- jobId: input.jobId ?? null,
88136
- idempotencyKey
88137
- });
88138
- logWithTimestamp(
88139
- `[notifyDirectSystemMessageToUser] provider=${provider} kind=${llmContent ? "system_prompt" : "system_notification"} job=${input.jobId ?? "(none)"} item=${item?.id ?? "(gateway)"}`
88140
- );
88141
- return item;
88142
- } finally {
88143
- ownedStore?.close();
88144
- }
88145
- }
88146
- function buildDirectSystemMessageIdempotencyKey(input) {
88147
- const identity3 = input.messageId || stableHash([
88148
- input.jobId ?? "",
88149
- input.userContent,
88150
- input.llmContent ?? ""
88151
- ].join("\n"));
88152
- return `system-direct:${identity3}`;
88153
- }
88154
88091
  function buildAgentMessageIdempotencyKey(input) {
88155
88092
  const identity3 = input.messageId || stableHash([
88156
88093
  input.direction,
@@ -88202,6 +88139,23 @@ var init_agent_message_notice = __esm({
88202
88139
  });
88203
88140
 
88204
88141
  // src/xmtp-send.ts
88142
+ function logXmtpMessageSent(params) {
88143
+ logger.info(LogEvent.MESSAGE_SENT, {
88144
+ component: params.component,
88145
+ stage: "outbound/xmtp_send",
88146
+ taskId: params.jobId,
88147
+ messageId: typeof params.xmtpMessageId === "string" && params.xmtpMessageId.length > 0 ? params.xmtpMessageId : "unknown",
88148
+ conversationId: params.conversationId,
88149
+ chatType: params.chatType,
88150
+ walletAddress: params.myXmtpAddress,
88151
+ toXmtpAddress: params.toXmtpAddress ?? "unknown",
88152
+ senderAgentId: params.senderAgentId ?? "unknown",
88153
+ toAgentId: params.toAgentId ?? "unknown",
88154
+ role: params.role != null && params.role !== "" ? String(params.role) : "unknown",
88155
+ xmtpSentAtMs: String(Date.now()),
88156
+ sendDurationMs: String(params.sendDurationMs)
88157
+ });
88158
+ }
88205
88159
  function isPlainObject(value) {
88206
88160
  return !!value && typeof value === "object" && !Array.isArray(value);
88207
88161
  }
@@ -88699,7 +88653,21 @@ async function handleSqliteGroupSendCommand(params) {
88699
88653
  payload: resolveEnvelopePayload(command, command.replyToMessageId)
88700
88654
  });
88701
88655
  logWithTimestamp(`[okx-agent-task] xmtp envelope ${rawText}`);
88702
- await conversation.send(rawText);
88656
+ const sendStartMs = Date.now();
88657
+ const xmtpMessageId = await conversation.send(rawText);
88658
+ logXmtpMessageSent({
88659
+ xmtpMessageId,
88660
+ conversationId: conversation.id,
88661
+ jobId: command.jobId,
88662
+ chatType: "group",
88663
+ component: "node_xmtp_send",
88664
+ myXmtpAddress,
88665
+ toXmtpAddress: remote.toXmtpAddress,
88666
+ senderAgentId: senderAgent?.agentId ?? command.myAgentId,
88667
+ toAgentId: remote.remoteAgent?.agentId ?? remote.toAgentId ?? command.toAgentId,
88668
+ role: senderAgent?.role,
88669
+ sendDurationMs: Date.now() - sendStartMs
88670
+ });
88703
88671
  const messageId = `outbound-${(0, import_node_crypto8.randomUUID)()}`;
88704
88672
  await notifyAgentMessageToUserAttention({
88705
88673
  direction: "outbound" /* OUTBOUND */,
@@ -88836,7 +88804,21 @@ async function handleGroupSendCommand(params) {
88836
88804
  payload: resolveEnvelopePayload(command, command.replyToMessageId)
88837
88805
  });
88838
88806
  logWithTimestamp(`[okx-agent-task] xmtp envelope ${rawText}`);
88839
- await conversation.send(rawText);
88807
+ const sendStartMs = Date.now();
88808
+ const xmtpMessageId = await conversation.send(rawText);
88809
+ logXmtpMessageSent({
88810
+ xmtpMessageId,
88811
+ conversationId: session.xmtpGroupId,
88812
+ jobId: command.jobId,
88813
+ chatType: "group",
88814
+ component: "node_xmtp_send",
88815
+ myXmtpAddress: session.myXmtpAddress,
88816
+ toXmtpAddress: session.toXmtpAddress,
88817
+ senderAgentId: senderAgent?.agentId ?? session.myAgentId,
88818
+ toAgentId: remoteAgent?.agentId ?? session.toAgentId,
88819
+ role: senderAgent?.role,
88820
+ sendDurationMs: Date.now() - sendStartMs
88821
+ });
88840
88822
  const now = Date.now();
88841
88823
  const messageId = `outbound-${(0, import_node_crypto8.randomUUID)()}`;
88842
88824
  const stored = {
@@ -89045,7 +89027,20 @@ async function handleXmtpSendCommand(params) {
89045
89027
  }
89046
89028
  const localAgent = service.getAgentByAddress(target.myXmtpAddress);
89047
89029
  const rawText = target.chatType === "group" ? buildGroupReplyRaw(command, target, target.myXmtpAddress, localAgent) : buildDmReplyRaw(command, target, localAgent?.agentId ?? null);
89048
- await conversation.send(rawText);
89030
+ const sendStartMs = Date.now();
89031
+ const xmtpMessageId = await conversation.send(rawText);
89032
+ logXmtpMessageSent({
89033
+ xmtpMessageId,
89034
+ conversationId: target.conversationId,
89035
+ jobId: command.jobId,
89036
+ chatType: target.chatType,
89037
+ component: "node_xmtp_send",
89038
+ myXmtpAddress: target.myXmtpAddress,
89039
+ toXmtpAddress: target.senderAddress,
89040
+ senderAgentId: localAgent?.agentId,
89041
+ role: localAgent?.role,
89042
+ sendDurationMs: Date.now() - sendStartMs
89043
+ });
89049
89044
  const now = Date.now();
89050
89045
  const messageId = `outbound-${(0, import_node_crypto8.randomUUID)()}`;
89051
89046
  const stored = {
@@ -89098,6 +89093,7 @@ var init_xmtp_send = __esm({
89098
89093
  "src/xmtp-send.ts"() {
89099
89094
  "use strict";
89100
89095
  init_log();
89096
+ init_sentry_logger();
89101
89097
  import_node_crypto8 = require("node:crypto");
89102
89098
  init_dist4();
89103
89099
  init_envelope();
@@ -92198,7 +92194,21 @@ async function sendRejectContentToTarget(content3, target, params) {
92198
92194
  }
92199
92195
  });
92200
92196
  logWithTimestamp(`[okx-agent-task] task reject xmtp envelope ${rawText}`);
92201
- await conversation.send(rawText);
92197
+ const sendStartMs = Date.now();
92198
+ const xmtpMessageId = await conversation.send(rawText);
92199
+ logXmtpMessageSent({
92200
+ xmtpMessageId,
92201
+ conversationId: target.groupId,
92202
+ jobId,
92203
+ chatType: "group",
92204
+ component: "node_command_processor",
92205
+ myXmtpAddress: target.address,
92206
+ toXmtpAddress,
92207
+ senderAgentId: senderAgent?.agentId,
92208
+ toAgentId: receiverAgent?.agentId ?? target.toAgentId,
92209
+ role: senderAgent?.role,
92210
+ sendDurationMs: Date.now() - sendStartMs
92211
+ });
92202
92212
  }
92203
92213
  async function denyTargets(targets, params) {
92204
92214
  return await Promise.all(
@@ -92676,8 +92686,7 @@ function extractSystemNotification(payload) {
92676
92686
  }
92677
92687
  const message = isPlainObject3(payload.message) ? payload.message : null;
92678
92688
  const isDirectCommunication = message?.isDirectCommunication === true;
92679
- const isDirectToUser = message?.isDirectToUser === true;
92680
- if (message?.source !== "system" && !isDirectCommunication && !isDirectToUser) {
92689
+ if (message?.source !== "system" && !isDirectCommunication) {
92681
92690
  return null;
92682
92691
  }
92683
92692
  return {
@@ -92686,10 +92695,7 @@ function extractSystemNotification(payload) {
92686
92695
  providerAgentId: readString3(message.providerAgentId),
92687
92696
  clientAgentId: readString3(message.clientAgentId),
92688
92697
  event: readString3(message.event),
92689
- isDirectCommunication,
92690
- isDirectToUser,
92691
- userContent: readString3(message.userContent),
92692
- llmContent: readString3(message.llmContent)
92698
+ isDirectCommunication
92693
92699
  };
92694
92700
  }
92695
92701
  function resolveDirectCommunicationSessionTarget(notification) {
@@ -93296,85 +93302,6 @@ ${failureMessage}`,
93296
93302
  }
93297
93303
  return true;
93298
93304
  }
93299
- function processDirectToUserSystemNotification(params) {
93300
- const { deps, notification, messageId, timing } = params;
93301
- const notificationAgentId = notification.agentId ?? void 0;
93302
- const attentionKind = notification.llmContent ? "system_prompt" : "system_notification";
93303
- if (!notification.userContent) {
93304
- logger.info(LogEvent.DM_FALLBACK_TO_BACKUP, {
93305
- ...agentExtras({ walletAddress: deps.myXmtpAddress, onchainosAgentId: notificationAgentId }),
93306
- taskId: notification.jobId ?? "",
93307
- messageId,
93308
- systemEvent: notification.event ?? "",
93309
- stage: "inbound/payload_parse",
93310
- reason: "direct_to_user_missing_user_content"
93311
- });
93312
- logWithTimestamp(
93313
- `[okx-agent-task:${deps.myXmtpAddress}] direct-to-user system DM missing userContent, falling back to AI session routing message=${shortenLogValue(messageId)}`
93314
- );
93315
- return false;
93316
- }
93317
- const userContent = notification.userContent;
93318
- const providerBindStartedAt = Date.now();
93319
- const providerGate = bindMessageJobProviderToCurrentDefault(deps, notification.jobId, "system-direct-user");
93320
- timing.mark("providerBind", providerBindStartedAt);
93321
- if (!providerGate.allowed) {
93322
- return true;
93323
- }
93324
- logger.info(LogEvent.SYSTEM_NOTIFICATION_RECEIVED, {
93325
- ...agentExtras({ walletAddress: deps.myXmtpAddress, onchainosAgentId: notificationAgentId }),
93326
- taskId: notification.jobId ?? "",
93327
- agentId: notification.agentId ?? "",
93328
- providerAgentId: notification.providerAgentId ?? "",
93329
- clientAgentId: notification.clientAgentId ?? "",
93330
- messageId,
93331
- systemEvent: notification.event ?? "",
93332
- stage: "inbound/system_notification_received",
93333
- isDirectToUser: "true",
93334
- attentionKind,
93335
- providerBinding: providerGate.provider ?? "",
93336
- providerBindingCreated: String(providerGate.created)
93337
- });
93338
- const dispatchStartedAt = Date.now();
93339
- void notifyDirectSystemMessageToUser({
93340
- userContent,
93341
- llmContent: notification.llmContent ?? null,
93342
- jobId: notification.jobId ?? null,
93343
- messageId,
93344
- store: deps.sessionStore
93345
- }).then(() => {
93346
- timing.mark("userDispatch", dispatchStartedAt);
93347
- logger.info(LogEvent.SYSTEM_NOTIFICATION_ROUTED, timing.extras({
93348
- ...agentExtras({ walletAddress: deps.myXmtpAddress, onchainosAgentId: notificationAgentId }),
93349
- taskId: notification.jobId ?? "",
93350
- agentId: notification.agentId ?? "",
93351
- messageId,
93352
- route: "system/direct-user",
93353
- systemEvent: notification.event ?? "",
93354
- stage: "inbound/system_direct_user_delivered",
93355
- isDirectToUser: "true",
93356
- attentionKind
93357
- }));
93358
- }).catch((err2) => {
93359
- logger.error(LogEvent.USER_DISPATCH_FAILED, err2 instanceof Error ? err2 : new Error(String(err2)), {
93360
- ...agentExtras({ walletAddress: deps.myXmtpAddress, onchainosAgentId: notificationAgentId }),
93361
- taskId: notification.jobId ?? "",
93362
- messageId,
93363
- systemEvent: notification.event ?? "",
93364
- stage: "inbound/system_direct_user_delivery",
93365
- isDirectToUser: "true",
93366
- attentionKind
93367
- });
93368
- logWithTimestamp(
93369
- `[okx-agent-task:${deps.myXmtpAddress}] direct-to-user delivery failed message=${shortenLogValue(messageId)}:`,
93370
- err2
93371
- );
93372
- });
93373
- logWithTimestamp(
93374
- `[okx-agent-task:${deps.myXmtpAddress}] direct-to-user delivery queued kind=${attentionKind} job=${shortenLogValue(notification.jobId ?? "(none)")} message=${shortenLogValue(messageId)}`
93375
- );
93376
- return true;
93377
- }
93378
93305
  async function processFileMessage(ctx, deps, options = {}) {
93379
93306
  const messageId = ctx.message.id ?? "";
93380
93307
  const timing = createInboundTimingTracker(extractXmtpSentAtMs2(ctx.message));
@@ -93427,14 +93354,6 @@ async function processFileMessage(ctx, deps, options = {}) {
93427
93354
  );
93428
93355
  return true;
93429
93356
  }
93430
- if (systemNotification.isDirectToUser && processDirectToUserSystemNotification({
93431
- deps,
93432
- notification: systemNotification,
93433
- messageId: systemMessageId,
93434
- timing
93435
- })) {
93436
- return true;
93437
- }
93438
93357
  const directTarget = resolveDirectCommunicationSessionTarget(systemNotification);
93439
93358
  if (systemNotification.isDirectCommunication && !directTarget) {
93440
93359
  logger.error(
@@ -93459,7 +93378,7 @@ async function processFileMessage(ctx, deps, options = {}) {
93459
93378
  if (!providerGate.allowed) {
93460
93379
  return true;
93461
93380
  }
93462
- logger.info(LogEvent.SYSTEM_NOTIFICATION_RECEIVED, {
93381
+ logger.info(LogEvent.SYSTEM_NOTIFICATION_RECEIVED, timing.extras({
93463
93382
  ...agentExtras({ walletAddress: deps.myXmtpAddress, onchainosAgentId: systemNotification.agentId }),
93464
93383
  taskId: systemNotification.jobId ?? "",
93465
93384
  agentId: systemNotification.agentId ?? "",
@@ -93468,10 +93387,11 @@ async function processFileMessage(ctx, deps, options = {}) {
93468
93387
  messageId: systemMessageId,
93469
93388
  systemEvent: systemNotification.event ?? "",
93470
93389
  stage: "inbound/system_notification_received",
93390
+ source: options.source ?? "live",
93471
93391
  isDirectCommunication: String(systemNotification.isDirectCommunication),
93472
93392
  providerBinding: providerGate.provider ?? "",
93473
93393
  providerBindingCreated: String(providerGate.created)
93474
- });
93394
+ }));
93475
93395
  const routeResolveStartedAt = Date.now();
93476
93396
  const targets = directTarget ? [{
93477
93397
  sessionKey: directTarget.sessionKey,
@@ -93487,7 +93407,7 @@ async function processFileMessage(ctx, deps, options = {}) {
93487
93407
  );
93488
93408
  }
93489
93409
  const primaryTarget = targets[0];
93490
- logger.info(LogEvent.SYSTEM_NOTIFICATION_ROUTED, {
93410
+ logger.info(LogEvent.SYSTEM_NOTIFICATION_ROUTED, timing.extras({
93491
93411
  ...agentExtras({ walletAddress: deps.myXmtpAddress, onchainosAgentId: systemNotification.agentId }),
93492
93412
  taskId: systemNotification.jobId ?? "",
93493
93413
  agentId: primaryTarget?.agentId ?? systemNotification.agentId ?? "",
@@ -93499,8 +93419,9 @@ async function processFileMessage(ctx, deps, options = {}) {
93499
93419
  targetCount: String(targets.length),
93500
93420
  systemEvent: systemNotification.event ?? "",
93501
93421
  stage: "inbound/system_notification_routed",
93422
+ source: options.source ?? "live",
93502
93423
  isDirectCommunication: String(systemNotification.isDirectCommunication)
93503
- });
93424
+ }));
93504
93425
  if (!options.skipNotify) {
93505
93426
  maybeNotifyInboundAgentMessage({
93506
93427
  deps,
@@ -93831,7 +93752,7 @@ function processOfflineFromCoreDeps(store, ctx, deps, options) {
93831
93752
  allowGroup: deps.allowGroup,
93832
93753
  onJobMessageStored: options.onJobMessageStored,
93833
93754
  onSessionMessage: options.onSessionMessage
93834
- }, options);
93755
+ }, { ...options, source: "replay" });
93835
93756
  }
93836
93757
  function buildSystemStoredMessage(params) {
93837
93758
  const now = Date.now();
@@ -94250,12 +94171,12 @@ async function runListenerWithLock(options, paths) {
94250
94171
  }));
94251
94172
  }
94252
94173
  });
94253
- service.setPluginVersion("0.1.7-beta-482acfaf84-260707171501");
94174
+ service.setPluginVersion("0.1.7");
94254
94175
  await service.init();
94255
94176
  const pluginVersionStatus = service.pluginVersionStatus;
94256
94177
  if (pluginVersionStatus.unavailable) {
94257
94178
  throw new Error(
94258
- `@okxweb3/a2a-node v${"0.1.7-beta-482acfaf84-260707171501"} is below the required minimum v${pluginVersionStatus.minVersion}`
94179
+ `@okxweb3/a2a-node v${"0.1.7"} is below the required minimum v${pluginVersionStatus.minVersion}`
94259
94180
  );
94260
94181
  }
94261
94182
  const systemConfig = service.getSystemConfig();
@@ -94273,7 +94194,7 @@ async function runListenerWithLock(options, paths) {
94273
94194
  onchainosAgentId: "*",
94274
94195
  reason: "system-config missing sentryDsn",
94275
94196
  pluginId: "@okxweb3/a2a-node",
94276
- pluginVersion: "0.1.7-beta-482acfaf84-260707171501"
94197
+ pluginVersion: "0.1.7"
94277
94198
  });
94278
94199
  }
94279
94200
  logWithTimestamp(
@@ -98294,7 +98215,7 @@ async function getCurrentNodeCliVersion() {
98294
98215
  return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
98295
98216
  }
98296
98217
  function getBundledNodeCliVersion() {
98297
- return true ? "0.1.7-beta-482acfaf84-260707171501" : null;
98218
+ return true ? "0.1.7" : null;
98298
98219
  }
98299
98220
  function readConfiguredAiProvider() {
98300
98221
  const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
@@ -98504,7 +98425,7 @@ async function updateHermes(release, options) {
98504
98425
  }
98505
98426
  }
98506
98427
  async function installGatewayPluginForDoctor(target) {
98507
- const release = isPrereleaseVersion("0.1.7-beta-482acfaf84-260707171501") ? "beta" : "latest";
98428
+ const release = isPrereleaseVersion("0.1.7") ? "beta" : "latest";
98508
98429
  const insideTargetGateway = detectGatewayInvocation() === target;
98509
98430
  const options = {
98510
98431
  restart: !insideTargetGateway,
@@ -99302,6 +99223,106 @@ var init_daemon_ops = __esm({
99302
99223
  }
99303
99224
  });
99304
99225
 
99226
+ // src/doctor-sentry.ts
99227
+ var doctor_sentry_exports = {};
99228
+ __export(doctor_sentry_exports, {
99229
+ buildDoctorSentryExtra: () => buildDoctorSentryExtra,
99230
+ reportDoctorCrashToSentry: () => reportDoctorCrashToSentry,
99231
+ reportDoctorRunToSentry: () => reportDoctorRunToSentry
99232
+ });
99233
+ function initDoctorSentry() {
99234
+ if (sentryReady) {
99235
+ return true;
99236
+ }
99237
+ try {
99238
+ const dsn = process.env.OKX_A2A_SENTRY_DSN?.trim() || process.env.SENTRY_DSN?.trim() || FALLBACK_SENTRY_DSN;
99239
+ initLogger({
99240
+ dsn,
99241
+ ...SENTRY_CONFIG,
99242
+ agentPlatform: "node"
99243
+ });
99244
+ sentryReady = true;
99245
+ return true;
99246
+ } catch {
99247
+ return false;
99248
+ }
99249
+ }
99250
+ function buildDoctorSentryExtra(report, meta) {
99251
+ const failedDetails = report.checks.filter((check) => check.status === "fail").map((check) => `${check.id}: ${check.detail}`.slice(0, 160)).join(" | ").slice(0, 900);
99252
+ return {
99253
+ component: "node_direct_cli",
99254
+ source: "direct_cli",
99255
+ operation: "doctor",
99256
+ communicationClass: "node_cli_or_daemon_issue",
99257
+ fixMode: String(meta.fix),
99258
+ nonInteractive: String(meta.nonInteractive),
99259
+ durationMs: String(meta.durationMs),
99260
+ ready: String(report.ready),
99261
+ state: report.state,
99262
+ target: report.target,
99263
+ platform: report.platform,
99264
+ cliVersion: report.cliVersion,
99265
+ blockingFailures: String(report.blockingFailures),
99266
+ checks: report.checks.map((check) => `${check.id}=${check.status}`).join(";"),
99267
+ fixesApplied: report.fixesApplied.map((fixEntry) => `${fixEntry.checkId}=${fixEntry.applied}`).join(";"),
99268
+ ...failedDetails ? { failedDetails } : {},
99269
+ ...report.upgraded ? { upgradedFrom: report.upgraded.from, upgradedTo: report.upgraded.to } : {}
99270
+ };
99271
+ }
99272
+ async function reportDoctorRunToSentry(report, meta) {
99273
+ try {
99274
+ if (!initDoctorSentry()) {
99275
+ return;
99276
+ }
99277
+ const extra = buildDoctorSentryExtra(report, meta);
99278
+ logger.info(LogEvent.DOCTOR_REPORT, extra);
99279
+ if (!report.ready) {
99280
+ const blocking = report.checks.filter((check) => check.status === "fail" && check.severity !== "recommended").map((check) => check.id).join(",");
99281
+ logger.error(
99282
+ LogEvent.DOCTOR_NOT_READY,
99283
+ new Error(`doctor not ready: ${blocking || report.state}`),
99284
+ extra
99285
+ );
99286
+ }
99287
+ await flushBounded();
99288
+ } catch {
99289
+ }
99290
+ }
99291
+ async function reportDoctorCrashToSentry(error, meta) {
99292
+ try {
99293
+ if (!initDoctorSentry()) {
99294
+ return;
99295
+ }
99296
+ logger.error(LogEvent.DOCTOR_CRASHED, error instanceof Error ? error : new Error(String(error)), {
99297
+ component: "node_direct_cli",
99298
+ source: "direct_cli",
99299
+ operation: "doctor",
99300
+ communicationClass: "node_cli_or_daemon_issue",
99301
+ fixMode: String(meta.fix),
99302
+ nonInteractive: String(meta.nonInteractive),
99303
+ durationMs: String(meta.durationMs)
99304
+ });
99305
+ await flushBounded();
99306
+ } catch {
99307
+ }
99308
+ }
99309
+ async function flushBounded() {
99310
+ const timeout = new Promise((resolvePromise) => {
99311
+ const timer = setTimeout(() => resolvePromise(), 1500);
99312
+ timer.unref?.();
99313
+ });
99314
+ await Promise.race([shutdown().then(() => void 0), timeout]);
99315
+ }
99316
+ var sentryReady;
99317
+ var init_doctor_sentry = __esm({
99318
+ "src/doctor-sentry.ts"() {
99319
+ "use strict";
99320
+ init_sentry_config();
99321
+ init_sentry_logger();
99322
+ sentryReady = false;
99323
+ }
99324
+ });
99325
+
99305
99326
  // src/doctor-cli.ts
99306
99327
  var doctor_cli_exports = {};
99307
99328
  __export(doctor_cli_exports, {
@@ -99389,10 +99410,11 @@ async function runDoctor(options = {}) {
99389
99410
  platform: options.platform ?? process.platform,
99390
99411
  env: options.env ?? process.env,
99391
99412
  target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
99392
- cliVersion: options.cliVersion ?? (true ? "0.1.7-beta-482acfaf84-260707171501" : "0.0.0"),
99413
+ cliVersion: options.cliVersion ?? (true ? "0.1.7" : "0.0.0"),
99393
99414
  fixMode: options.fix === true,
99394
99415
  nonInteractive: options.nonInteractive === true,
99395
- packageChanged: false
99416
+ packageChanged: false,
99417
+ hermesGatewayRestartPending: false
99396
99418
  };
99397
99419
  const checkers = options.checkers ?? CHECKERS;
99398
99420
  const fixesApplied = [];
@@ -99554,6 +99576,7 @@ async function handleDoctorCommand(args) {
99554
99576
  setRedirectCommandStdoutToStderr(false);
99555
99577
  }
99556
99578
  };
99579
+ const startedAtMs = Date.now();
99557
99580
  let report;
99558
99581
  try {
99559
99582
  report = await runDoctor({ fix, nonInteractive, ...rawTarget ? { target: rawTarget } : {} });
@@ -99565,10 +99588,14 @@ async function handleDoctorCommand(args) {
99565
99588
  if (!json) {
99566
99589
  console.error(`doctor crashed: ${message}`);
99567
99590
  }
99591
+ const { reportDoctorCrashToSentry: reportDoctorCrashToSentry2 } = await Promise.resolve().then(() => (init_doctor_sentry(), doctor_sentry_exports));
99592
+ await reportDoctorCrashToSentry2(error, { fix, nonInteractive, durationMs: Date.now() - startedAtMs });
99568
99593
  await writeStdoutAndExit(out2, 2);
99569
99594
  return;
99570
99595
  }
99571
99596
  restoreStdout();
99597
+ const { reportDoctorRunToSentry: reportDoctorRunToSentry2 } = await Promise.resolve().then(() => (init_doctor_sentry(), doctor_sentry_exports));
99598
+ await reportDoctorRunToSentry2(report, { fix, nonInteractive, durationMs: Date.now() - startedAtMs });
99572
99599
  const out = json ? `${JSON.stringify(report)}
99573
99600
  ` : `${formatDoctorReportForHumans(report)}
99574
99601
  `;
@@ -99966,6 +99993,20 @@ var init_doctor_cli = __esm({
99966
99993
  const installed = await isGatewayPluginInstalled(ctx.target);
99967
99994
  const hermesPathSuffix = ctx.target === "hermes" ? ` (checked ${resolveHermesPluginYamlPath()})` : "";
99968
99995
  if (installed) {
99996
+ if (ctx.target === "hermes" && ctx.hermesGatewayRestartPending) {
99997
+ return {
99998
+ id: "gateway_plugin",
99999
+ title: "Gateway plugin installed",
100000
+ status: "fail",
100001
+ severity: "required",
100002
+ detail: "the Hermes okx-a2a plugin was just installed/updated in this run, but the running Hermes gateway has not loaded it yet",
100003
+ fix: {
100004
+ kind: "manual",
100005
+ description: "The Hermes okx-a2a plugin was just installed and takes effect after the Hermes gateway restarts \u2014 run /restart inside Hermes (or restart the Hermes app), then re-run okx-a2a doctor to confirm.",
100006
+ command: "/restart"
100007
+ }
100008
+ };
100009
+ }
99969
100010
  return {
99970
100011
  id: "gateway_plugin",
99971
100012
  title: "Gateway plugin installed",
@@ -99997,6 +100038,9 @@ var init_doctor_cli = __esm({
99997
100038
  }
99998
100039
  const { installGatewayPluginForDoctor: installGatewayPluginForDoctor2 } = await Promise.resolve().then(() => (init_update_cli(), update_cli_exports));
99999
100040
  const { gatewayRestarted } = await installGatewayPluginForDoctor2(ctx.target);
100041
+ if (ctx.target === "hermes" && !gatewayRestarted) {
100042
+ ctx.hermesGatewayRestartPending = true;
100043
+ }
100000
100044
  return gatewayRestarted ? `installed the ${ctx.target} okx-a2a plugin and restarted the gateway` : `installed the ${ctx.target} okx-a2a plugin; gateway restart was deferred because doctor is running inside the ${ctx.target} gateway (restarting now would kill this session). Restart the gateway to load the plugin.`;
100001
100045
  }
100002
100046
  };
@@ -100482,7 +100526,7 @@ init_sentry_logger();
100482
100526
  init_sentry_config();
100483
100527
  var CURRENT_GATEWAY_SESSION_KEYS_ENV4 = "OKX_A2A_CURRENT_GATEWAY_SESSION_KEYS";
100484
100528
  function printUsage2() {
100485
- console.log(`okx-a2a ${"0.1.7-beta-482acfaf84-260707171501"}
100529
+ console.log(`okx-a2a ${"0.1.7"}
100486
100530
 
100487
100531
  Usage:
100488
100532
  okx-a2a <command> [options]
@@ -100520,7 +100564,7 @@ Run \`okx-a2a <command> -h\` for command-specific help.
100520
100564
  `);
100521
100565
  }
100522
100566
  function printVersion() {
100523
- console.log("0.1.7-beta-482acfaf84-260707171501");
100567
+ console.log("0.1.7");
100524
100568
  }
100525
100569
  function printDaemonUsage() {
100526
100570
  console.log(`Usage: okx-a2a daemon <start|restart|stop|status|autostart> [options]