@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.
- package/dist/cli.js +1682 -124
- package/dist/index.js +1585 -127
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3788,6 +3788,10 @@ function isDaemonCommand(value) {
|
|
|
3788
3788
|
if (parsed.type === "xmtp-send") {
|
|
3789
3789
|
return typeof parsed.jobId === "string" && typeof parsed.message === "string";
|
|
3790
3790
|
}
|
|
3791
|
+
if (parsed.type === "xmtp-subscription-push") {
|
|
3792
|
+
const command = parsed;
|
|
3793
|
+
return typeof command.myAgentId === "string" && typeof command.content === "string" && Array.isArray(command.conversationIds) && command.conversationIds.every((item) => typeof item === "string");
|
|
3794
|
+
}
|
|
3791
3795
|
if (parsed.type === "xmtp-get-pending-list") {
|
|
3792
3796
|
return true;
|
|
3793
3797
|
}
|
|
@@ -3843,6 +3847,7 @@ var init_command_store = __esm({
|
|
|
3843
3847
|
import_node_fs8 = require("node:fs");
|
|
3844
3848
|
import_node_path11 = require("node:path");
|
|
3845
3849
|
init_paths();
|
|
3850
|
+
init_session_store();
|
|
3846
3851
|
({ DatabaseSync: DatabaseSync2 } = loadSqlite2());
|
|
3847
3852
|
XMTP_DEBUG_RESULT_TTL_MS = 5 * 6e4;
|
|
3848
3853
|
CommandStore = class {
|
|
@@ -3872,6 +3877,17 @@ var init_command_store = __esm({
|
|
|
3872
3877
|
createdAt: Date.now()
|
|
3873
3878
|
};
|
|
3874
3879
|
}
|
|
3880
|
+
createXmtpSubscriptionPushCommand(params) {
|
|
3881
|
+
return {
|
|
3882
|
+
id: (0, import_node_crypto2.randomUUID)(),
|
|
3883
|
+
type: "xmtp-subscription-push",
|
|
3884
|
+
myAgentId: params.myAgentId,
|
|
3885
|
+
content: params.content,
|
|
3886
|
+
conversationIds: params.conversationIds,
|
|
3887
|
+
deliveryId: params.deliveryId,
|
|
3888
|
+
createdAt: Date.now()
|
|
3889
|
+
};
|
|
3890
|
+
}
|
|
3875
3891
|
createXmtpGetPendingListCommand() {
|
|
3876
3892
|
return {
|
|
3877
3893
|
id: (0, import_node_crypto2.randomUUID)(),
|
|
@@ -3965,6 +3981,65 @@ var init_command_store = __esm({
|
|
|
3965
3981
|
);
|
|
3966
3982
|
return this.commandPath(command.id);
|
|
3967
3983
|
}
|
|
3984
|
+
/**
|
|
3985
|
+
* Atomic idempotent submit keyed on a business `idempotencyKey` (DEXMARKET-9035,
|
|
3986
|
+
* M2). The FIRST caller for a given key inserts its command and gets
|
|
3987
|
+
* `created: true`; every later caller with the SAME key — including after a
|
|
3988
|
+
* daemon / CommandStore rebuild — gets the ALREADY-persisted command back with
|
|
3989
|
+
* `created: false` and NO new row. Concurrency-safe: correctness rests on the
|
|
3990
|
+
* partial UNIQUE index on `idempotency_key`, not a check-then-insert (which
|
|
3991
|
+
* races), so a `INSERT ... ON CONFLICT DO NOTHING` collapses concurrent
|
|
3992
|
+
* duplicates to exactly one row. Recoverable SQLITE_BUSY/LOCKED errors reuse
|
|
3993
|
+
* the repo's bounded exponential backoff. This never changes the plain
|
|
3994
|
+
* `submit` path used by `xmtp-send` and every other daemon command.
|
|
3995
|
+
*/
|
|
3996
|
+
async submitIdempotent(command, idempotencyKey) {
|
|
3997
|
+
if (!idempotencyKey) {
|
|
3998
|
+
throw new Error("submitIdempotent requires a non-empty idempotencyKey");
|
|
3999
|
+
}
|
|
4000
|
+
return this.withBusyRetry(
|
|
4001
|
+
() => this.transaction(() => {
|
|
4002
|
+
const now = Date.now();
|
|
4003
|
+
const insert = this.db.prepare(`
|
|
4004
|
+
INSERT INTO command_queue (
|
|
4005
|
+
id, type, status, command_json, result_json,
|
|
4006
|
+
created_at_ms, updated_at_ms, processing_started_at_ms, completed_at_ms,
|
|
4007
|
+
idempotency_key
|
|
4008
|
+
)
|
|
4009
|
+
VALUES (?, ?, 'pending', ?, NULL, ?, ?, NULL, NULL, ?)
|
|
4010
|
+
ON CONFLICT(idempotency_key) WHERE idempotency_key IS NOT NULL DO NOTHING
|
|
4011
|
+
`).run(
|
|
4012
|
+
command.id,
|
|
4013
|
+
command.type,
|
|
4014
|
+
stringifyForStorage(command),
|
|
4015
|
+
normalizeCreatedAt(command.createdAt, now),
|
|
4016
|
+
now,
|
|
4017
|
+
idempotencyKey
|
|
4018
|
+
);
|
|
4019
|
+
if (Number(insert.changes ?? 0) > 0) {
|
|
4020
|
+
return { path: this.commandPath(command.id), commandId: command.id, created: true };
|
|
4021
|
+
}
|
|
4022
|
+
const existing = this.db.prepare(`
|
|
4023
|
+
SELECT id FROM command_queue WHERE idempotency_key = ?
|
|
4024
|
+
`).get(idempotencyKey);
|
|
4025
|
+
const existingId = existing?.id ?? command.id;
|
|
4026
|
+
return { path: this.commandPath(existingId), commandId: existingId, created: false };
|
|
4027
|
+
})
|
|
4028
|
+
);
|
|
4029
|
+
}
|
|
4030
|
+
async withBusyRetry(operation) {
|
|
4031
|
+
const attempts = 6;
|
|
4032
|
+
for (let attempt = 1; ; attempt += 1) {
|
|
4033
|
+
try {
|
|
4034
|
+
return operation();
|
|
4035
|
+
} catch (err2) {
|
|
4036
|
+
if (!isSqliteBusyError(err2) || attempt >= attempts) {
|
|
4037
|
+
throw err2;
|
|
4038
|
+
}
|
|
4039
|
+
await new Promise((resolve14) => setTimeout(resolve14, Math.min(50 * 2 ** (attempt - 1), 1e3)));
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4042
|
+
}
|
|
3968
4043
|
async listPending() {
|
|
3969
4044
|
return (await this.listPendingEntries()).map((entry) => entry.command);
|
|
3970
4045
|
}
|
|
@@ -4030,10 +4105,25 @@ var init_command_store = __esm({
|
|
|
4030
4105
|
this.db.exec(`
|
|
4031
4106
|
CREATE INDEX IF NOT EXISTS idx_command_queue_status_created
|
|
4032
4107
|
ON command_queue(status, created_at_ms, id)
|
|
4108
|
+
`);
|
|
4109
|
+
this.ensureColumn("command_queue", "idempotency_key", "TEXT");
|
|
4110
|
+
this.db.exec(`
|
|
4111
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_command_queue_idempotency_key
|
|
4112
|
+
ON command_queue(idempotency_key)
|
|
4113
|
+
WHERE idempotency_key IS NOT NULL
|
|
4033
4114
|
`);
|
|
4034
4115
|
this.purgeExpiredXmtpDebugResults();
|
|
4035
4116
|
this.importLegacyFileCommands();
|
|
4036
4117
|
}
|
|
4118
|
+
ensureColumn(table, column, definition) {
|
|
4119
|
+
this.transaction(() => {
|
|
4120
|
+
const rows = this.db.prepare(`PRAGMA table_info(${table})`).all();
|
|
4121
|
+
if (rows.some((row) => row.name === column)) {
|
|
4122
|
+
return;
|
|
4123
|
+
}
|
|
4124
|
+
this.db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
|
|
4125
|
+
});
|
|
4126
|
+
}
|
|
4037
4127
|
purgeExpiredXmtpDebugResults() {
|
|
4038
4128
|
this.db.prepare(`
|
|
4039
4129
|
DELETE FROM command_queue
|
|
@@ -4687,7 +4777,7 @@ var require_is = __commonJS({
|
|
|
4687
4777
|
function isPrimitive(wat) {
|
|
4688
4778
|
return wat === null || typeof wat !== "object" && typeof wat !== "function";
|
|
4689
4779
|
}
|
|
4690
|
-
function
|
|
4780
|
+
function isPlainObject6(wat) {
|
|
4691
4781
|
return isBuiltin(wat, "Object");
|
|
4692
4782
|
}
|
|
4693
4783
|
function isEvent(wat) {
|
|
@@ -4703,7 +4793,7 @@ var require_is = __commonJS({
|
|
|
4703
4793
|
return Boolean(wat && wat.then && typeof wat.then === "function");
|
|
4704
4794
|
}
|
|
4705
4795
|
function isSyntheticEvent(wat) {
|
|
4706
|
-
return
|
|
4796
|
+
return isPlainObject6(wat) && "nativeEvent" in wat && "preventDefault" in wat && "stopPropagation" in wat;
|
|
4707
4797
|
}
|
|
4708
4798
|
function isNaN2(wat) {
|
|
4709
4799
|
return typeof wat === "number" && wat !== wat;
|
|
@@ -4726,7 +4816,7 @@ var require_is = __commonJS({
|
|
|
4726
4816
|
exports2.isEvent = isEvent;
|
|
4727
4817
|
exports2.isInstanceOf = isInstanceOf;
|
|
4728
4818
|
exports2.isNaN = isNaN2;
|
|
4729
|
-
exports2.isPlainObject =
|
|
4819
|
+
exports2.isPlainObject = isPlainObject6;
|
|
4730
4820
|
exports2.isPrimitive = isPrimitive;
|
|
4731
4821
|
exports2.isRegExp = isRegExp;
|
|
4732
4822
|
exports2.isString = isString;
|
|
@@ -19989,6 +20079,23 @@ var init_events = __esm({
|
|
|
19989
20079
|
XMTP_RATE_LIMIT_CREATE_SUPPRESSED: "XMTP rate limit create suppressed",
|
|
19990
20080
|
XMTP_RATE_LIMIT_PROBE: "XMTP rate limit probe",
|
|
19991
20081
|
XMTP_RATE_LIMIT_RECOVERED: "XMTP rate limit recovered",
|
|
20082
|
+
// ── subscription observability info (DEXMARKET-9096) ───────────
|
|
20083
|
+
// All of the following logger.info checkpoints MUST also be listed in
|
|
20084
|
+
// SENTRY_INFO_ALLOWLIST (index.ts): info() returns early for an unlisted
|
|
20085
|
+
// event, which ships a checkpoint that looks implemented but emits nothing.
|
|
20086
|
+
SUBSCRIPTION_PUSH_STARTED: "Subscription push started",
|
|
20087
|
+
SUBSCRIPTION_PUSH_TARGETS_RESOLVED: "Subscription push targets resolved",
|
|
20088
|
+
SUBSCRIPTION_PUSH_EMPTY_TARGETS: "Subscription push empty targets",
|
|
20089
|
+
SUBSCRIPTION_PUSH_SUMMARY: "Subscription push summary",
|
|
20090
|
+
SUBSCRIPTION_INBOUND_RECEIVED: "Subscription inbound received",
|
|
20091
|
+
SUBSCRIPTION_INBOUND_GATE_DROPPED: "Subscription inbound gate dropped",
|
|
20092
|
+
SUBSCRIPTION_JOBS_QUERY_STARTED: "Subscription jobs query started",
|
|
20093
|
+
SUBSCRIPTION_JOBS_QUERY_SUCCEEDED: "Subscription jobs query succeeded",
|
|
20094
|
+
SUBSCRIPTION_JOBS_EMPTY: "Subscription jobs empty",
|
|
20095
|
+
SUBSCRIPTION_INBOUND_OWNERSHIP_ROUTED: "Subscription inbound ownership routed",
|
|
20096
|
+
SUBSCRIPTION_JOB_DISPATCHED: "Subscription job dispatched",
|
|
20097
|
+
SUBSCRIPTION_JOB_DUPLICATE_IGNORED: "Subscription job duplicate ignored",
|
|
20098
|
+
SUBSCRIPTION_FANOUT_SUMMARY: "Subscription fan-out summary",
|
|
19992
20099
|
// ── error ─────────────────────────────────────────────────────
|
|
19993
20100
|
XMTP_CONNECTION_FAILED: "XMTP connection failed",
|
|
19994
20101
|
CONVERSATIONS_STREAM_FAILED: "conversations.stream failed",
|
|
@@ -20055,6 +20162,13 @@ var init_events = __esm({
|
|
|
20055
20162
|
AGENT_INSTALLATION_LIMIT_NEAR: "Agent installation limit near",
|
|
20056
20163
|
XMTP_HISTORY_SYNC_REQUEST_FAILED: "XMTP history sync request failed",
|
|
20057
20164
|
XMTP_DEBUG_SYNC_FAILED: "XMTP debug sync failed",
|
|
20165
|
+
// ── subscription observability error (DEXMARKET-9096) ──────────
|
|
20166
|
+
// error-level: always emitted (no allowlist gate). Error objects are
|
|
20167
|
+
// classified by buildErrorDiagnostics — never attach raw Error.message.
|
|
20168
|
+
SUBSCRIPTION_PUSH_TARGET_FAILED: "Subscription push target failed",
|
|
20169
|
+
SUBSCRIPTION_INBOUND_AGENTIC_ID_MISSING: "Subscription inbound agenticId missing",
|
|
20170
|
+
SUBSCRIPTION_JOBS_FAIL_CLOSED: "Subscription jobs fail closed",
|
|
20171
|
+
SUBSCRIPTION_JOB_FAILED: "Subscription job failed",
|
|
20058
20172
|
// Underlying XMTP SDK client close failed during recycle/removal/shutdown
|
|
20059
20173
|
// (DEXMARKET-9116). Error-level → NOT added to SENTRY_INFO_ALLOWLIST.
|
|
20060
20174
|
XMTP_CLIENT_CLOSE_FAILED: "XMTP client close failed"
|
|
@@ -20730,6 +20844,13 @@ var init_sentry_logger = __esm({
|
|
|
20730
20844
|
]);
|
|
20731
20845
|
SENTRY_TAG_KEYS = /* @__PURE__ */ new Set([
|
|
20732
20846
|
"agentId",
|
|
20847
|
+
// Subscription correlation agent ids (DEXMARKET-9096). Bounded-cardinality,
|
|
20848
|
+
// same class as agentId/senderAgentId/onchainosAgentId — promoted to indexed
|
|
20849
|
+
// tags for Sentry filtering. NOT added to SENTRY_FINGERPRINT_KEYS, so the
|
|
20850
|
+
// global issue fingerprint is unchanged. High-cardinality ids
|
|
20851
|
+
// (conversationId/messageId/deliveryId) are deliberately NOT here.
|
|
20852
|
+
"aspAgentId",
|
|
20853
|
+
"userAgentId",
|
|
20733
20854
|
"agentPlatform",
|
|
20734
20855
|
"aiProvider",
|
|
20735
20856
|
"cacheName",
|
|
@@ -20897,6 +21018,22 @@ var init_sentry_logger = __esm({
|
|
|
20897
21018
|
LogEvent.SESSION_KEY_DERIVED,
|
|
20898
21019
|
LogEvent.SESSIONS_QUERIED,
|
|
20899
21020
|
LogEvent.SYNC_TICK_COMPLETED,
|
|
21021
|
+
// Subscription observability info checkpoints (DEXMARKET-9096). Each is a
|
|
21022
|
+
// logger.info event; omitting any makes info() drop it silently so the whole
|
|
21023
|
+
// subscription trace would look implemented and emit nothing in production.
|
|
21024
|
+
LogEvent.SUBSCRIPTION_PUSH_STARTED,
|
|
21025
|
+
LogEvent.SUBSCRIPTION_PUSH_TARGETS_RESOLVED,
|
|
21026
|
+
LogEvent.SUBSCRIPTION_PUSH_EMPTY_TARGETS,
|
|
21027
|
+
LogEvent.SUBSCRIPTION_PUSH_SUMMARY,
|
|
21028
|
+
LogEvent.SUBSCRIPTION_INBOUND_RECEIVED,
|
|
21029
|
+
LogEvent.SUBSCRIPTION_INBOUND_GATE_DROPPED,
|
|
21030
|
+
LogEvent.SUBSCRIPTION_JOBS_QUERY_STARTED,
|
|
21031
|
+
LogEvent.SUBSCRIPTION_JOBS_QUERY_SUCCEEDED,
|
|
21032
|
+
LogEvent.SUBSCRIPTION_JOBS_EMPTY,
|
|
21033
|
+
LogEvent.SUBSCRIPTION_INBOUND_OWNERSHIP_ROUTED,
|
|
21034
|
+
LogEvent.SUBSCRIPTION_JOB_DISPATCHED,
|
|
21035
|
+
LogEvent.SUBSCRIPTION_JOB_DUPLICATE_IGNORED,
|
|
21036
|
+
LogEvent.SUBSCRIPTION_FANOUT_SUMMARY,
|
|
20900
21037
|
// XMTP creation rate-limit cooldown checkpoints (DEXMARKET-9116). info() drops
|
|
20901
21038
|
// any event not listed here, so these must stay registered.
|
|
20902
21039
|
LogEvent.XMTP_RATE_LIMIT_COOLDOWN_STARTED,
|
|
@@ -25263,7 +25400,7 @@ var require_websocket2 = __commonJS({
|
|
|
25263
25400
|
var http2 = require("http");
|
|
25264
25401
|
var net = require("net");
|
|
25265
25402
|
var tls = require("tls");
|
|
25266
|
-
var { randomBytes: randomBytes4, createHash:
|
|
25403
|
+
var { randomBytes: randomBytes4, createHash: createHash7 } = require("crypto");
|
|
25267
25404
|
var { Duplex, Readable } = require("stream");
|
|
25268
25405
|
var { URL: URL2 } = require("url");
|
|
25269
25406
|
var PerMessageDeflate = require_permessage_deflate();
|
|
@@ -25923,7 +26060,7 @@ var require_websocket2 = __commonJS({
|
|
|
25923
26060
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
25924
26061
|
return;
|
|
25925
26062
|
}
|
|
25926
|
-
const digest =
|
|
26063
|
+
const digest = createHash7("sha1").update(key + GUID).digest("base64");
|
|
25927
26064
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
25928
26065
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
25929
26066
|
return;
|
|
@@ -26290,7 +26427,7 @@ var require_websocket_server = __commonJS({
|
|
|
26290
26427
|
var EventEmitter2 = require("events");
|
|
26291
26428
|
var http2 = require("http");
|
|
26292
26429
|
var { Duplex } = require("stream");
|
|
26293
|
-
var { createHash:
|
|
26430
|
+
var { createHash: createHash7 } = require("crypto");
|
|
26294
26431
|
var extension = require_extension();
|
|
26295
26432
|
var PerMessageDeflate = require_permessage_deflate();
|
|
26296
26433
|
var subprotocol = require_subprotocol();
|
|
@@ -26591,7 +26728,7 @@ var require_websocket_server = __commonJS({
|
|
|
26591
26728
|
);
|
|
26592
26729
|
}
|
|
26593
26730
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
26594
|
-
const digest =
|
|
26731
|
+
const digest = createHash7("sha1").update(key + GUID).digest("base64");
|
|
26595
26732
|
const headers = [
|
|
26596
26733
|
"HTTP/1.1 101 Switching Protocols",
|
|
26597
26734
|
"Upgrade: websocket",
|
|
@@ -27018,7 +27155,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
|
|
|
27018
27155
|
client: {
|
|
27019
27156
|
id: "gateway-client",
|
|
27020
27157
|
displayName: "okx-a2a-node",
|
|
27021
|
-
version: "0.2.
|
|
27158
|
+
version: "0.2.18-beta-4dd056b897-261015113839",
|
|
27022
27159
|
platform: "node",
|
|
27023
27160
|
mode: "backend",
|
|
27024
27161
|
instanceId
|
|
@@ -27029,7 +27166,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
|
|
|
27029
27166
|
commands: [],
|
|
27030
27167
|
permissions: {},
|
|
27031
27168
|
locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
|
|
27032
|
-
userAgent: `okx-a2a-node/${"0.2.
|
|
27169
|
+
userAgent: `okx-a2a-node/${"0.2.18-beta-4dd056b897-261015113839"}`,
|
|
27033
27170
|
auth: {
|
|
27034
27171
|
...config.token ? { token: config.token } : {},
|
|
27035
27172
|
...config.password ? { password: config.password } : {}
|
|
@@ -29089,7 +29226,7 @@ var init_sentry_config = __esm({
|
|
|
29089
29226
|
environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
|
|
29090
29227
|
SENTRY_CONFIG = {
|
|
29091
29228
|
projectName: "okx/openclaw-okx-a2a-extension",
|
|
29092
|
-
release: "0.2.
|
|
29229
|
+
release: "0.2.18-beta-4dd056b897-261015113839",
|
|
29093
29230
|
environment,
|
|
29094
29231
|
runtimeContainer: normalizeRuntimeContainer(process.env.OKX_A2A_RUNTIME_CONTAINER)
|
|
29095
29232
|
};
|
|
@@ -40259,7 +40396,7 @@ async function exportDiagnosticLogs(options) {
|
|
|
40259
40396
|
node: process.version,
|
|
40260
40397
|
platform: process.platform,
|
|
40261
40398
|
arch: process.arch,
|
|
40262
|
-
packageVersion: true ? "0.2.
|
|
40399
|
+
packageVersion: true ? "0.2.18-beta-4dd056b897-261015113839" : "unknown",
|
|
40263
40400
|
sensitiveContentIncluded: options.includeSensitiveContent,
|
|
40264
40401
|
listenerAndLlmContentIncluded: true,
|
|
40265
40402
|
credentialsAlwaysRedacted: true,
|
|
@@ -61990,6 +62127,247 @@ var init_onchainos = __esm({
|
|
|
61990
62127
|
}
|
|
61991
62128
|
});
|
|
61992
62129
|
|
|
62130
|
+
// ../core/src/xmtp-sdk/onchainos/list-jobs-by-verified-sender.ts
|
|
62131
|
+
function isPlainObject(value) {
|
|
62132
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
62133
|
+
}
|
|
62134
|
+
function isNonEmptyString(value) {
|
|
62135
|
+
return typeof value === "string" && value.length > 0;
|
|
62136
|
+
}
|
|
62137
|
+
function redactLogValue(value, left = 6, right = 4) {
|
|
62138
|
+
if (!value) {
|
|
62139
|
+
return "(none)";
|
|
62140
|
+
}
|
|
62141
|
+
if (value.length <= left + right + 1) {
|
|
62142
|
+
return "(redacted)";
|
|
62143
|
+
}
|
|
62144
|
+
return `${value.slice(0, left)}\u2026${value.slice(-right)}`;
|
|
62145
|
+
}
|
|
62146
|
+
function guardSessionExpired3(stdout, command) {
|
|
62147
|
+
if (isSessionExpired(stdout)) {
|
|
62148
|
+
reportSessionExpired(command);
|
|
62149
|
+
}
|
|
62150
|
+
}
|
|
62151
|
+
function guardCatchSessionExpired3(err2, command) {
|
|
62152
|
+
const stdout = String(err2?.stdout ?? "");
|
|
62153
|
+
if (stdout && isSessionExpired(stdout)) {
|
|
62154
|
+
reportSessionExpired(command);
|
|
62155
|
+
}
|
|
62156
|
+
}
|
|
62157
|
+
function buildListJobsByVerifiedSenderArgs(params) {
|
|
62158
|
+
return [
|
|
62159
|
+
"agent",
|
|
62160
|
+
"list-jobs-by-verified-sender",
|
|
62161
|
+
"--group-id",
|
|
62162
|
+
params.groupId,
|
|
62163
|
+
"--sender-inbox-id",
|
|
62164
|
+
params.senderInboxId,
|
|
62165
|
+
"--agentic-id",
|
|
62166
|
+
params.agenticId
|
|
62167
|
+
];
|
|
62168
|
+
}
|
|
62169
|
+
function extractErrorText(errorLike) {
|
|
62170
|
+
if (typeof errorLike === "string") {
|
|
62171
|
+
return errorLike;
|
|
62172
|
+
}
|
|
62173
|
+
if (typeof errorLike === "number") {
|
|
62174
|
+
return String(errorLike);
|
|
62175
|
+
}
|
|
62176
|
+
if (errorLike && typeof errorLike === "object") {
|
|
62177
|
+
const anyErr = errorLike;
|
|
62178
|
+
return [anyErr.code, anyErr.message, anyErr.stdout, anyErr.stderr].filter((value) => typeof value === "string" || typeof value === "number").map(String).join(" ");
|
|
62179
|
+
}
|
|
62180
|
+
return errorLike == null ? "" : String(errorLike);
|
|
62181
|
+
}
|
|
62182
|
+
function classifyListJobsError(errorLike) {
|
|
62183
|
+
const text = extractErrorText(errorLike);
|
|
62184
|
+
for (const [code, reason] of Object.entries(KNOWN_ERROR_CODES2)) {
|
|
62185
|
+
if (text.includes(code)) {
|
|
62186
|
+
return { reason, errorCode: code };
|
|
62187
|
+
}
|
|
62188
|
+
}
|
|
62189
|
+
if (/\b401\b/.test(text)) {
|
|
62190
|
+
return { reason: "auth_error", errorCode: "401" };
|
|
62191
|
+
}
|
|
62192
|
+
if (/\b403\b/.test(text)) {
|
|
62193
|
+
return { reason: "auth_error", errorCode: "403" };
|
|
62194
|
+
}
|
|
62195
|
+
return { reason: "invalid_response" };
|
|
62196
|
+
}
|
|
62197
|
+
function normalizeListJobsResponse(data) {
|
|
62198
|
+
const rawJobs = isPlainObject(data) && Array.isArray(data.jobs) ? data.jobs : [];
|
|
62199
|
+
const seen = /* @__PURE__ */ new Set();
|
|
62200
|
+
const jobs = [];
|
|
62201
|
+
let invalidCount = 0;
|
|
62202
|
+
for (const item of rawJobs) {
|
|
62203
|
+
if (!isPlainObject(item) || !isNonEmptyString(item.jobId) || !isNonEmptyString(item.userAgentId) || !isNonEmptyString(item.aspAgentId)) {
|
|
62204
|
+
invalidCount += 1;
|
|
62205
|
+
continue;
|
|
62206
|
+
}
|
|
62207
|
+
const key = `${item.jobId}|${item.userAgentId}|${item.aspAgentId}`;
|
|
62208
|
+
if (seen.has(key)) {
|
|
62209
|
+
continue;
|
|
62210
|
+
}
|
|
62211
|
+
seen.add(key);
|
|
62212
|
+
jobs.push({ jobId: item.jobId, userAgentId: item.userAgentId, aspAgentId: item.aspAgentId });
|
|
62213
|
+
}
|
|
62214
|
+
return { jobs, invalidCount };
|
|
62215
|
+
}
|
|
62216
|
+
async function listJobsByVerifiedSender(params, execFn = exec) {
|
|
62217
|
+
logWithTimestamp(
|
|
62218
|
+
`[onchainos] listing jobs by verified sender: group=${params.groupId} sender=${redactLogValue(params.senderInboxId)} agentic=${params.agenticId}`
|
|
62219
|
+
);
|
|
62220
|
+
let stdout;
|
|
62221
|
+
let stderr;
|
|
62222
|
+
try {
|
|
62223
|
+
({ stdout, stderr } = await execFn(buildListJobsByVerifiedSenderArgs(params)));
|
|
62224
|
+
} catch (err2) {
|
|
62225
|
+
guardCatchSessionExpired3(err2, "list-jobs-by-verified-sender");
|
|
62226
|
+
const classified = classifyListJobsError(err2);
|
|
62227
|
+
const reason = classified.reason === "invalid_response" ? "network_error" : classified.reason;
|
|
62228
|
+
warnWithTimestamp(
|
|
62229
|
+
`[onchainos] list-jobs-by-verified-sender exec failed (group=${params.groupId} sender=${redactLogValue(params.senderInboxId)}); fail-closed reason=${reason}`
|
|
62230
|
+
);
|
|
62231
|
+
return { status: "fail_closed", jobs: [], invalidCount: 0, reason, errorCode: classified.errorCode };
|
|
62232
|
+
}
|
|
62233
|
+
if (stderr) {
|
|
62234
|
+
logWithTimestamp(`[onchainos] stderr (list-jobs-by-verified-sender): ${stderr}`);
|
|
62235
|
+
}
|
|
62236
|
+
let res;
|
|
62237
|
+
try {
|
|
62238
|
+
res = parseCliJson(stdout, "list-jobs-by-verified-sender", {
|
|
62239
|
+
groupId: params.groupId,
|
|
62240
|
+
agenticId: params.agenticId
|
|
62241
|
+
});
|
|
62242
|
+
} catch {
|
|
62243
|
+
return { status: "fail_closed", jobs: [], invalidCount: 0, reason: "invalid_response" };
|
|
62244
|
+
}
|
|
62245
|
+
if (!res.ok) {
|
|
62246
|
+
guardSessionExpired3(stdout, "list-jobs-by-verified-sender");
|
|
62247
|
+
const classified = classifyListJobsError(res.error);
|
|
62248
|
+
warnWithTimestamp(
|
|
62249
|
+
`[onchainos] list-jobs-by-verified-sender ok=false (group=${params.groupId}); fail-closed reason=${classified.reason}`
|
|
62250
|
+
);
|
|
62251
|
+
logger.error(
|
|
62252
|
+
LogEvent.ONCHAINOS_CLI_ERROR,
|
|
62253
|
+
new Error("list-jobs-by-verified-sender ok=false"),
|
|
62254
|
+
cliOkFalseExtras(stdout, "list-jobs-by-verified-sender", {
|
|
62255
|
+
groupId: params.groupId,
|
|
62256
|
+
agenticId: params.agenticId,
|
|
62257
|
+
reason: classified.reason
|
|
62258
|
+
})
|
|
62259
|
+
);
|
|
62260
|
+
return { status: "fail_closed", jobs: [], invalidCount: 0, reason: classified.reason, errorCode: classified.errorCode };
|
|
62261
|
+
}
|
|
62262
|
+
const { jobs, invalidCount } = normalizeListJobsResponse(res.data);
|
|
62263
|
+
if (jobs.length === 0) {
|
|
62264
|
+
logWithTimestamp(
|
|
62265
|
+
`[onchainos] list-jobs-by-verified-sender: empty (group=${params.groupId} invalidCount=${invalidCount})`
|
|
62266
|
+
);
|
|
62267
|
+
return { status: "empty", jobs, invalidCount };
|
|
62268
|
+
}
|
|
62269
|
+
logWithTimestamp(
|
|
62270
|
+
`[onchainos] list-jobs-by-verified-sender: ok (group=${params.groupId} jobs=${jobs.length} invalidCount=${invalidCount})`
|
|
62271
|
+
);
|
|
62272
|
+
return { status: "ok", jobs, invalidCount };
|
|
62273
|
+
}
|
|
62274
|
+
function listJobsByVerifiedSenderHelpAdvertisesCommand(helpText) {
|
|
62275
|
+
if (typeof helpText !== "string" || helpText.length === 0) {
|
|
62276
|
+
return false;
|
|
62277
|
+
}
|
|
62278
|
+
const lower = helpText.toLowerCase();
|
|
62279
|
+
if (/unknown command|unrecognized|not a valid command|no such (sub)?command|command not found/.test(lower)) {
|
|
62280
|
+
return false;
|
|
62281
|
+
}
|
|
62282
|
+
return lower.includes(LIST_JOBS_BY_VERIFIED_SENDER_HELP_TOKEN);
|
|
62283
|
+
}
|
|
62284
|
+
function maybeRecommendListJobsUpgrade(capability) {
|
|
62285
|
+
if (capability.supported || capabilityRecommendedPairs.has(CAPABILITY_UPGRADE_PAIR_KEY)) {
|
|
62286
|
+
return;
|
|
62287
|
+
}
|
|
62288
|
+
warnWithTimestamp(
|
|
62289
|
+
`[onchainos] list-jobs-by-verified-sender unsupported (reason=${capability.reason}); ${CAPABILITY_UPGRADE_REASON}`
|
|
62290
|
+
);
|
|
62291
|
+
const hook = XmtpService.getInstance().tools?.notifyUpgradeRecommendation;
|
|
62292
|
+
if (!hook) {
|
|
62293
|
+
return;
|
|
62294
|
+
}
|
|
62295
|
+
capabilityRecommendedPairs.add(CAPABILITY_UPGRADE_PAIR_KEY);
|
|
62296
|
+
try {
|
|
62297
|
+
void Promise.resolve(
|
|
62298
|
+
hook({
|
|
62299
|
+
component: "onchainos",
|
|
62300
|
+
capability: LIST_JOBS_BY_VERIFIED_SENDER_HELP_TOKEN,
|
|
62301
|
+
reason: CAPABILITY_UPGRADE_REASON
|
|
62302
|
+
})
|
|
62303
|
+
).catch((err2) => {
|
|
62304
|
+
warnWithTimestamp("[onchainos] list-jobs-by-verified-sender upgrade notice async delivery failed:", err2);
|
|
62305
|
+
});
|
|
62306
|
+
} catch (err2) {
|
|
62307
|
+
warnWithTimestamp("[onchainos] list-jobs-by-verified-sender upgrade notice threw:", err2);
|
|
62308
|
+
}
|
|
62309
|
+
}
|
|
62310
|
+
function detectListJobsByVerifiedSenderSupport(execFn = exec) {
|
|
62311
|
+
if (!capabilityProbe2) {
|
|
62312
|
+
capabilityProbe2 = (async () => {
|
|
62313
|
+
try {
|
|
62314
|
+
const { stdout, stderr } = await execFn([
|
|
62315
|
+
"agent",
|
|
62316
|
+
"list-jobs-by-verified-sender",
|
|
62317
|
+
"--help"
|
|
62318
|
+
]);
|
|
62319
|
+
const supported = listJobsByVerifiedSenderHelpAdvertisesCommand(`${stdout}
|
|
62320
|
+
${stderr}`);
|
|
62321
|
+
logWithTimestamp(
|
|
62322
|
+
`[onchainos] list-jobs-by-verified-sender capability: ${supported ? "supported" : "unsupported_cli_capability"}`
|
|
62323
|
+
);
|
|
62324
|
+
return supported ? { supported: true } : { supported: false, reason: "unsupported_cli_capability" };
|
|
62325
|
+
} catch (err2) {
|
|
62326
|
+
logWithTimestamp(
|
|
62327
|
+
"[onchainos] list-jobs-by-verified-sender --help probe failed; treating as onchainos_upgrade_required:",
|
|
62328
|
+
err2
|
|
62329
|
+
);
|
|
62330
|
+
return { supported: false, reason: "onchainos_upgrade_required" };
|
|
62331
|
+
}
|
|
62332
|
+
})().then((capability) => {
|
|
62333
|
+
maybeRecommendListJobsUpgrade(capability);
|
|
62334
|
+
return capability;
|
|
62335
|
+
});
|
|
62336
|
+
}
|
|
62337
|
+
return capabilityProbe2;
|
|
62338
|
+
}
|
|
62339
|
+
async function listJobsByVerifiedSenderWithCapability(params, execFn = exec) {
|
|
62340
|
+
const capability = await detectListJobsByVerifiedSenderSupport(execFn);
|
|
62341
|
+
if (!capability.supported) {
|
|
62342
|
+
warnWithTimestamp(
|
|
62343
|
+
`[onchainos] list-jobs-by-verified-sender skipped: CLI capability unavailable (reason=${capability.reason}) group=${params.groupId} sender=${redactLogValue(params.senderInboxId)}`
|
|
62344
|
+
);
|
|
62345
|
+
return { status: "fail_closed", jobs: [], invalidCount: 0, reason: capability.reason };
|
|
62346
|
+
}
|
|
62347
|
+
return listJobsByVerifiedSender(params, execFn);
|
|
62348
|
+
}
|
|
62349
|
+
var KNOWN_ERROR_CODES2, LIST_JOBS_BY_VERIFIED_SENDER_HELP_TOKEN, CAPABILITY_UPGRADE_PAIR_KEY, CAPABILITY_UPGRADE_REASON, capabilityProbe2, capabilityRecommendedPairs;
|
|
62350
|
+
var init_list_jobs_by_verified_sender = __esm({
|
|
62351
|
+
"../core/src/xmtp-sdk/onchainos/list-jobs-by-verified-sender.ts"() {
|
|
62352
|
+
"use strict";
|
|
62353
|
+
init_log();
|
|
62354
|
+
init_sentry_logger();
|
|
62355
|
+
init_bin();
|
|
62356
|
+
init_cli_response();
|
|
62357
|
+
init_session_expired();
|
|
62358
|
+
init_xmtp_sdk();
|
|
62359
|
+
KNOWN_ERROR_CODES2 = {
|
|
62360
|
+
"130100079": "sender_not_authorized",
|
|
62361
|
+
"130100073": "sender_not_eligible"
|
|
62362
|
+
};
|
|
62363
|
+
LIST_JOBS_BY_VERIFIED_SENDER_HELP_TOKEN = "list-jobs-by-verified-sender";
|
|
62364
|
+
CAPABILITY_UPGRADE_PAIR_KEY = "onchainos:list-jobs-by-verified-sender";
|
|
62365
|
+
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.";
|
|
62366
|
+
capabilityProbe2 = null;
|
|
62367
|
+
capabilityRecommendedPairs = /* @__PURE__ */ new Set();
|
|
62368
|
+
}
|
|
62369
|
+
});
|
|
62370
|
+
|
|
61993
62371
|
// ../core/src/xmtp-sdk/onchainos/signer.ts
|
|
61994
62372
|
async function onchainosSign(agentId, keyUuid, walletAddress, message) {
|
|
61995
62373
|
logWithTimestamp(
|
|
@@ -62659,7 +63037,7 @@ function buildXmtpMessageSentExtra(params) {
|
|
|
62659
63037
|
function logXmtpMessageSent(params) {
|
|
62660
63038
|
logger.info(LogEvent.MESSAGE_SENT, buildXmtpMessageSentExtra(params));
|
|
62661
63039
|
}
|
|
62662
|
-
function
|
|
63040
|
+
function isPlainObject2(value) {
|
|
62663
63041
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
62664
63042
|
}
|
|
62665
63043
|
function readString3(value) {
|
|
@@ -62845,8 +63223,8 @@ function buildDmReplyRaw(command, target, localAgentId) {
|
|
|
62845
63223
|
});
|
|
62846
63224
|
}
|
|
62847
63225
|
function buildGroupReplyRaw(command, target, myXmtpAddress, localAgent) {
|
|
62848
|
-
const payload =
|
|
62849
|
-
const sender =
|
|
63226
|
+
const payload = isPlainObject2(target.payload) ? target.payload : null;
|
|
63227
|
+
const sender = isPlainObject2(payload?.sender) ? payload.sender : null;
|
|
62850
63228
|
return buildSendEnvelope({
|
|
62851
63229
|
content: command.message,
|
|
62852
63230
|
myXmtpAddress,
|
|
@@ -63443,8 +63821,8 @@ async function handleXmtpSendCommand(params) {
|
|
|
63443
63821
|
payload: parseJson(rawText)
|
|
63444
63822
|
};
|
|
63445
63823
|
await store.append(command.jobId, stored, sessionAgentId);
|
|
63446
|
-
const payloadObject =
|
|
63447
|
-
const sender =
|
|
63824
|
+
const payloadObject = isPlainObject2(target.payload) ? target.payload : null;
|
|
63825
|
+
const sender = isPlainObject2(payloadObject?.sender) ? payloadObject.sender : null;
|
|
63448
63826
|
const remoteAgentId = readString3(sender?.agentId);
|
|
63449
63827
|
await notifyAgentMessageToUserAttention({
|
|
63450
63828
|
direction: "outbound" /* OUTBOUND */,
|
|
@@ -63497,6 +63875,438 @@ var init_xmtp_send = __esm({
|
|
|
63497
63875
|
}
|
|
63498
63876
|
});
|
|
63499
63877
|
|
|
63878
|
+
// ../core/src/a2a/subscription-types.ts
|
|
63879
|
+
var SUBSCRIPTION_MESSAGE_TYPE;
|
|
63880
|
+
var init_subscription_types = __esm({
|
|
63881
|
+
"../core/src/a2a/subscription-types.ts"() {
|
|
63882
|
+
"use strict";
|
|
63883
|
+
SUBSCRIPTION_MESSAGE_TYPE = "a2a-subscription-push";
|
|
63884
|
+
}
|
|
63885
|
+
});
|
|
63886
|
+
|
|
63887
|
+
// ../core/src/a2a/subscription-envelope.ts
|
|
63888
|
+
function isPlainObject3(value) {
|
|
63889
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
63890
|
+
}
|
|
63891
|
+
function buildSubscriptionEnvelope(params) {
|
|
63892
|
+
const envelope = {
|
|
63893
|
+
msgType: SUBSCRIPTION_MESSAGE_TYPE,
|
|
63894
|
+
content: params.content,
|
|
63895
|
+
senderAgentId: params.senderAgentId
|
|
63896
|
+
};
|
|
63897
|
+
if (params.deliveryId) {
|
|
63898
|
+
envelope.deliveryId = params.deliveryId;
|
|
63899
|
+
}
|
|
63900
|
+
return JSON.stringify(envelope);
|
|
63901
|
+
}
|
|
63902
|
+
function isSubscriptionEnvelope(payload) {
|
|
63903
|
+
return isPlainObject3(payload) && payload.msgType === SUBSCRIPTION_MESSAGE_TYPE;
|
|
63904
|
+
}
|
|
63905
|
+
function isNonEmptyString2(value) {
|
|
63906
|
+
return typeof value === "string" && value.length > 0;
|
|
63907
|
+
}
|
|
63908
|
+
function readSubscriptionEnvelope(payload) {
|
|
63909
|
+
if (!isSubscriptionEnvelope(payload)) {
|
|
63910
|
+
return { ok: false, reason: "not_subscription" };
|
|
63911
|
+
}
|
|
63912
|
+
const record = payload;
|
|
63913
|
+
if (!isNonEmptyString2(record.content)) {
|
|
63914
|
+
return { ok: false, reason: "missing_content" };
|
|
63915
|
+
}
|
|
63916
|
+
const envelope = {
|
|
63917
|
+
msgType: SUBSCRIPTION_MESSAGE_TYPE,
|
|
63918
|
+
content: record.content,
|
|
63919
|
+
senderAgentId: isNonEmptyString2(record.senderAgentId) ? record.senderAgentId : ""
|
|
63920
|
+
};
|
|
63921
|
+
if (isNonEmptyString2(record.deliveryId)) {
|
|
63922
|
+
envelope.deliveryId = record.deliveryId;
|
|
63923
|
+
}
|
|
63924
|
+
return { ok: true, envelope };
|
|
63925
|
+
}
|
|
63926
|
+
var init_subscription_envelope = __esm({
|
|
63927
|
+
"../core/src/a2a/subscription-envelope.ts"() {
|
|
63928
|
+
"use strict";
|
|
63929
|
+
init_subscription_types();
|
|
63930
|
+
}
|
|
63931
|
+
});
|
|
63932
|
+
|
|
63933
|
+
// src/subscription-telemetry.ts
|
|
63934
|
+
function definedExtras(input) {
|
|
63935
|
+
return Object.entries(input).reduce((out, [key, value]) => {
|
|
63936
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
63937
|
+
out[key] = value.trim();
|
|
63938
|
+
}
|
|
63939
|
+
return out;
|
|
63940
|
+
}, {});
|
|
63941
|
+
}
|
|
63942
|
+
function countExtras(input) {
|
|
63943
|
+
return Object.entries(input).reduce((out, [key, value]) => {
|
|
63944
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
63945
|
+
out[key] = String(value);
|
|
63946
|
+
}
|
|
63947
|
+
return out;
|
|
63948
|
+
}, {});
|
|
63949
|
+
}
|
|
63950
|
+
function buildSubscriptionSendExtras(input) {
|
|
63951
|
+
return {
|
|
63952
|
+
stage: input.checkpoint,
|
|
63953
|
+
...logFieldExtras({
|
|
63954
|
+
checkpoint: input.checkpoint,
|
|
63955
|
+
outcome: input.outcome ?? null,
|
|
63956
|
+
transport: SUBSCRIPTION_TRANSPORT,
|
|
63957
|
+
eventFamily: "outbound",
|
|
63958
|
+
deliveryId: input.deliveryId ?? null
|
|
63959
|
+
}),
|
|
63960
|
+
...definedExtras({
|
|
63961
|
+
aspAgentId: input.aspAgentId,
|
|
63962
|
+
conversationId: input.conversationId,
|
|
63963
|
+
reason: input.reason
|
|
63964
|
+
}),
|
|
63965
|
+
...countExtras({
|
|
63966
|
+
targetCount: input.targetCount,
|
|
63967
|
+
sentCount: input.sentCount,
|
|
63968
|
+
failedCount: input.failedCount,
|
|
63969
|
+
notGroupCount: input.notGroupCount
|
|
63970
|
+
})
|
|
63971
|
+
};
|
|
63972
|
+
}
|
|
63973
|
+
function buildSubscriptionInboundExtras(input) {
|
|
63974
|
+
return {
|
|
63975
|
+
stage: input.checkpoint,
|
|
63976
|
+
...logFieldExtras({
|
|
63977
|
+
checkpoint: input.checkpoint,
|
|
63978
|
+
outcome: input.outcome ?? null,
|
|
63979
|
+
transport: SUBSCRIPTION_TRANSPORT,
|
|
63980
|
+
eventFamily: "inbound",
|
|
63981
|
+
deliveryId: input.deliveryId ?? null
|
|
63982
|
+
}),
|
|
63983
|
+
...definedExtras({
|
|
63984
|
+
userAgentId: input.userAgentId,
|
|
63985
|
+
conversationId: input.conversationId,
|
|
63986
|
+
messageId: input.messageId,
|
|
63987
|
+
senderInboxId: input.senderInboxId,
|
|
63988
|
+
reason: input.reason,
|
|
63989
|
+
errorCode: input.errorCode
|
|
63990
|
+
}),
|
|
63991
|
+
...countExtras({
|
|
63992
|
+
returnedCount: input.returnedCount,
|
|
63993
|
+
invalidCount: input.invalidCount,
|
|
63994
|
+
ownedCount: input.ownedCount,
|
|
63995
|
+
ignoredCount: input.ignoredCount
|
|
63996
|
+
})
|
|
63997
|
+
};
|
|
63998
|
+
}
|
|
63999
|
+
function buildSubscriptionJobExtras(input) {
|
|
64000
|
+
return {
|
|
64001
|
+
stage: input.checkpoint,
|
|
64002
|
+
...logFieldExtras({
|
|
64003
|
+
checkpoint: input.checkpoint,
|
|
64004
|
+
outcome: input.outcome,
|
|
64005
|
+
transport: SUBSCRIPTION_TRANSPORT,
|
|
64006
|
+
eventFamily: "dispatch",
|
|
64007
|
+
deliveryId: input.deliveryId ?? null
|
|
64008
|
+
}),
|
|
64009
|
+
...definedExtras({
|
|
64010
|
+
jobId: input.jobId,
|
|
64011
|
+
userAgentId: input.userAgentId,
|
|
64012
|
+
aspAgentId: input.aspAgentId,
|
|
64013
|
+
conversationId: input.conversationId,
|
|
64014
|
+
reason: input.reason
|
|
64015
|
+
}),
|
|
64016
|
+
...countExtras({
|
|
64017
|
+
total: input.total,
|
|
64018
|
+
started: input.started,
|
|
64019
|
+
failed: input.failed,
|
|
64020
|
+
skippedDuplicate: input.skippedDuplicate
|
|
64021
|
+
})
|
|
64022
|
+
};
|
|
64023
|
+
}
|
|
64024
|
+
var SUBSCRIPTION_TRANSPORT;
|
|
64025
|
+
var init_subscription_telemetry = __esm({
|
|
64026
|
+
"src/subscription-telemetry.ts"() {
|
|
64027
|
+
"use strict";
|
|
64028
|
+
init_log_fields();
|
|
64029
|
+
SUBSCRIPTION_TRANSPORT = "xmtp";
|
|
64030
|
+
}
|
|
64031
|
+
});
|
|
64032
|
+
|
|
64033
|
+
// src/subscription-push.ts
|
|
64034
|
+
function describeError(err2) {
|
|
64035
|
+
if (err2 instanceof Error) {
|
|
64036
|
+
return err2.message;
|
|
64037
|
+
}
|
|
64038
|
+
if (typeof err2 === "string" && err2.length > 0) {
|
|
64039
|
+
return err2;
|
|
64040
|
+
}
|
|
64041
|
+
return "unknown error";
|
|
64042
|
+
}
|
|
64043
|
+
async function requireXmtpClient2(service, address) {
|
|
64044
|
+
const existing = service.getClientByAddress(address);
|
|
64045
|
+
if (existing) {
|
|
64046
|
+
return existing;
|
|
64047
|
+
}
|
|
64048
|
+
await service.refreshAgents();
|
|
64049
|
+
const refreshed = service.getClientByAddress(address);
|
|
64050
|
+
if (!refreshed) {
|
|
64051
|
+
throw new Error(`no XMTP client found for ${address}`);
|
|
64052
|
+
}
|
|
64053
|
+
return refreshed;
|
|
64054
|
+
}
|
|
64055
|
+
function resolveLocalAddress(service, myAgentId) {
|
|
64056
|
+
const address = service.getAddressByAgentId(myAgentId);
|
|
64057
|
+
if (!address) {
|
|
64058
|
+
throw new Error(`No local communication address found for myAgentId=${myAgentId}`);
|
|
64059
|
+
}
|
|
64060
|
+
return address;
|
|
64061
|
+
}
|
|
64062
|
+
async function syncConversationsOnLocalMiss2(agent) {
|
|
64063
|
+
const conversations = agent.client.conversations;
|
|
64064
|
+
const existing = conversationSyncPromises2.get(conversations);
|
|
64065
|
+
if (existing) {
|
|
64066
|
+
return existing;
|
|
64067
|
+
}
|
|
64068
|
+
const pending = conversations.sync();
|
|
64069
|
+
conversationSyncPromises2.set(conversations, pending);
|
|
64070
|
+
try {
|
|
64071
|
+
await pending;
|
|
64072
|
+
} finally {
|
|
64073
|
+
if (conversationSyncPromises2.get(conversations) === pending) {
|
|
64074
|
+
conversationSyncPromises2.delete(conversations);
|
|
64075
|
+
}
|
|
64076
|
+
}
|
|
64077
|
+
}
|
|
64078
|
+
async function findGroupConversation2(agent, conversationId) {
|
|
64079
|
+
let conversation = await agent.client.conversations.getConversationById(conversationId);
|
|
64080
|
+
if (!(conversation instanceof Group)) {
|
|
64081
|
+
await syncConversationsOnLocalMiss2(agent);
|
|
64082
|
+
conversation = await agent.client.conversations.getConversationById(conversationId);
|
|
64083
|
+
}
|
|
64084
|
+
return conversation instanceof Group ? conversation : null;
|
|
64085
|
+
}
|
|
64086
|
+
async function sendSubscriptionToGroup(params) {
|
|
64087
|
+
const { agent, conversationId, command, myXmtpAddress, senderRole } = params;
|
|
64088
|
+
let conversation;
|
|
64089
|
+
try {
|
|
64090
|
+
conversation = await findGroupConversation2(agent, conversationId);
|
|
64091
|
+
} catch (err2) {
|
|
64092
|
+
return { conversationId, status: "not_group", error: describeError(err2) };
|
|
64093
|
+
}
|
|
64094
|
+
if (!conversation) {
|
|
64095
|
+
return {
|
|
64096
|
+
conversationId,
|
|
64097
|
+
status: "not_group",
|
|
64098
|
+
error: `conversationId=${conversationId} is not a Group (DM or unknown conversation)`
|
|
64099
|
+
};
|
|
64100
|
+
}
|
|
64101
|
+
const envelope = buildSubscriptionEnvelope({
|
|
64102
|
+
content: command.content,
|
|
64103
|
+
senderAgentId: command.myAgentId,
|
|
64104
|
+
deliveryId: command.deliveryId
|
|
64105
|
+
});
|
|
64106
|
+
const sendStartMs = Date.now();
|
|
64107
|
+
try {
|
|
64108
|
+
const xmtpMessageId = await conversation.sendText(envelope);
|
|
64109
|
+
logXmtpMessageSent({
|
|
64110
|
+
xmtpMessageId,
|
|
64111
|
+
conversationId,
|
|
64112
|
+
// V2 has no job dimension (FR-1) — deliveryId (or a fixed marker)
|
|
64113
|
+
// stands in for the telemetry taxonomy's jobId slot.
|
|
64114
|
+
jobId: command.deliveryId ?? "subscription-push",
|
|
64115
|
+
chatType: "group",
|
|
64116
|
+
component: "node_xmtp_subscription_push",
|
|
64117
|
+
myXmtpAddress,
|
|
64118
|
+
senderAgentId: command.myAgentId,
|
|
64119
|
+
role: senderRole,
|
|
64120
|
+
sendDurationMs: Date.now() - sendStartMs
|
|
64121
|
+
});
|
|
64122
|
+
const messageId = typeof xmtpMessageId === "string" && xmtpMessageId.length > 0 ? xmtpMessageId : String(xmtpMessageId);
|
|
64123
|
+
logWithTimestamp(
|
|
64124
|
+
`[okx-agent-task] subscription-push sent conversationId=${conversationId} deliveryId=${command.deliveryId ?? "(none)"}`
|
|
64125
|
+
);
|
|
64126
|
+
return { conversationId, status: "sent", messageId };
|
|
64127
|
+
} catch (err2) {
|
|
64128
|
+
logWithTimestamp(
|
|
64129
|
+
`[okx-agent-task] subscription-push failed conversationId=${conversationId} deliveryId=${command.deliveryId ?? "(none)"}`
|
|
64130
|
+
);
|
|
64131
|
+
return { conversationId, status: "failed", error: describeError(err2) };
|
|
64132
|
+
}
|
|
64133
|
+
}
|
|
64134
|
+
function summarizeSubscriptionPush(results) {
|
|
64135
|
+
let sentCount = 0;
|
|
64136
|
+
let failedCount = 0;
|
|
64137
|
+
for (const result of results) {
|
|
64138
|
+
if (result.status === "sent") {
|
|
64139
|
+
sentCount++;
|
|
64140
|
+
} else {
|
|
64141
|
+
failedCount++;
|
|
64142
|
+
}
|
|
64143
|
+
}
|
|
64144
|
+
return { conversationCount: results.length, sentCount, failedCount };
|
|
64145
|
+
}
|
|
64146
|
+
async function handleSubscriptionPushCommand(params) {
|
|
64147
|
+
const { command, service } = params;
|
|
64148
|
+
const aspAgentId = command.myAgentId;
|
|
64149
|
+
const deliveryId = command.deliveryId;
|
|
64150
|
+
const conversationIds = command.conversationIds ?? [];
|
|
64151
|
+
logger.info(
|
|
64152
|
+
LogEvent.SUBSCRIPTION_PUSH_STARTED,
|
|
64153
|
+
buildSubscriptionSendExtras({
|
|
64154
|
+
checkpoint: "outbound/subscription_push_started",
|
|
64155
|
+
aspAgentId,
|
|
64156
|
+
deliveryId,
|
|
64157
|
+
targetCount: conversationIds.length
|
|
64158
|
+
})
|
|
64159
|
+
);
|
|
64160
|
+
if (conversationIds.length === 0) {
|
|
64161
|
+
logger.info(
|
|
64162
|
+
LogEvent.SUBSCRIPTION_PUSH_EMPTY_TARGETS,
|
|
64163
|
+
buildSubscriptionSendExtras({
|
|
64164
|
+
checkpoint: "outbound/subscription_push_empty_targets",
|
|
64165
|
+
outcome: "ignored",
|
|
64166
|
+
aspAgentId,
|
|
64167
|
+
deliveryId,
|
|
64168
|
+
targetCount: 0,
|
|
64169
|
+
reason: "empty_targets"
|
|
64170
|
+
})
|
|
64171
|
+
);
|
|
64172
|
+
return { conversationCount: 0, sentCount: 0, failedCount: 0, results: [] };
|
|
64173
|
+
}
|
|
64174
|
+
const myXmtpAddress = resolveLocalAddress(service, command.myAgentId);
|
|
64175
|
+
const agent = await requireXmtpClient2(service, myXmtpAddress);
|
|
64176
|
+
const senderRole = service.getAgentByAddress?.(myXmtpAddress)?.role;
|
|
64177
|
+
logger.info(
|
|
64178
|
+
LogEvent.SUBSCRIPTION_PUSH_TARGETS_RESOLVED,
|
|
64179
|
+
buildSubscriptionSendExtras({
|
|
64180
|
+
checkpoint: "outbound/subscription_push_targets_resolved",
|
|
64181
|
+
aspAgentId,
|
|
64182
|
+
deliveryId,
|
|
64183
|
+
targetCount: conversationIds.length
|
|
64184
|
+
})
|
|
64185
|
+
);
|
|
64186
|
+
const settled = await parallelMap(
|
|
64187
|
+
conversationIds,
|
|
64188
|
+
(conversationId) => sendSubscriptionToGroup({
|
|
64189
|
+
agent,
|
|
64190
|
+
conversationId,
|
|
64191
|
+
command,
|
|
64192
|
+
myXmtpAddress,
|
|
64193
|
+
senderRole
|
|
64194
|
+
}),
|
|
64195
|
+
DEFAULT_CONCURRENCY
|
|
64196
|
+
);
|
|
64197
|
+
const results = settled.map((outcome, index2) => {
|
|
64198
|
+
if (outcome.status === "fulfilled") {
|
|
64199
|
+
return outcome.value;
|
|
64200
|
+
}
|
|
64201
|
+
return {
|
|
64202
|
+
conversationId: conversationIds[index2],
|
|
64203
|
+
status: "failed",
|
|
64204
|
+
error: describeError(outcome.reason)
|
|
64205
|
+
};
|
|
64206
|
+
});
|
|
64207
|
+
for (const result of results) {
|
|
64208
|
+
if (result.status === "sent") {
|
|
64209
|
+
continue;
|
|
64210
|
+
}
|
|
64211
|
+
logger.error(
|
|
64212
|
+
LogEvent.SUBSCRIPTION_PUSH_TARGET_FAILED,
|
|
64213
|
+
void 0,
|
|
64214
|
+
buildSubscriptionSendExtras({
|
|
64215
|
+
checkpoint: "outbound/subscription_push_target_failed",
|
|
64216
|
+
outcome: "failed",
|
|
64217
|
+
aspAgentId,
|
|
64218
|
+
deliveryId,
|
|
64219
|
+
conversationId: result.conversationId,
|
|
64220
|
+
reason: result.status
|
|
64221
|
+
})
|
|
64222
|
+
);
|
|
64223
|
+
}
|
|
64224
|
+
const summary = summarizeSubscriptionPush(results);
|
|
64225
|
+
const summaryOutcome = summary.failedCount === 0 ? "success" : summary.sentCount > 0 ? "partial" : "failed";
|
|
64226
|
+
logger.info(
|
|
64227
|
+
LogEvent.SUBSCRIPTION_PUSH_SUMMARY,
|
|
64228
|
+
buildSubscriptionSendExtras({
|
|
64229
|
+
checkpoint: "outbound/subscription_push_summary",
|
|
64230
|
+
outcome: summaryOutcome,
|
|
64231
|
+
aspAgentId,
|
|
64232
|
+
deliveryId,
|
|
64233
|
+
targetCount: summary.conversationCount,
|
|
64234
|
+
sentCount: summary.sentCount,
|
|
64235
|
+
failedCount: summary.failedCount
|
|
64236
|
+
})
|
|
64237
|
+
);
|
|
64238
|
+
return { ...summary, results };
|
|
64239
|
+
}
|
|
64240
|
+
var DEFAULT_CONCURRENCY, conversationSyncPromises2;
|
|
64241
|
+
var init_subscription_push = __esm({
|
|
64242
|
+
"src/subscription-push.ts"() {
|
|
64243
|
+
"use strict";
|
|
64244
|
+
init_log();
|
|
64245
|
+
init_sentry_logger();
|
|
64246
|
+
init_dist2();
|
|
64247
|
+
init_subscription_envelope();
|
|
64248
|
+
init_concurrency();
|
|
64249
|
+
init_xmtp_send();
|
|
64250
|
+
init_subscription_telemetry();
|
|
64251
|
+
DEFAULT_CONCURRENCY = 20;
|
|
64252
|
+
conversationSyncPromises2 = /* @__PURE__ */ new WeakMap();
|
|
64253
|
+
}
|
|
64254
|
+
});
|
|
64255
|
+
|
|
64256
|
+
// src/ai-run-log-path.ts
|
|
64257
|
+
function buildRunLogFileName(request) {
|
|
64258
|
+
const source = request.source;
|
|
64259
|
+
const sessionKey = request.sessionKey;
|
|
64260
|
+
const messageId = request.messageId;
|
|
64261
|
+
const jobId = request.jobId;
|
|
64262
|
+
const safeMessageId = encodeURIComponent(messageId);
|
|
64263
|
+
const prefix = source === "job-dispatch" ? "ai-" : "ai-session-";
|
|
64264
|
+
const encodedContext = source === "job-dispatch" ? encodeURIComponent(jobId ?? "unknown") : encodeURIComponent(sessionKey);
|
|
64265
|
+
const readable = `${prefix}${encodedContext}-${safeMessageId}.log`;
|
|
64266
|
+
if (Buffer.byteLength(readable, "utf8") <= RUN_LOG_FILENAME_MAX_BYTES) {
|
|
64267
|
+
return readable;
|
|
64268
|
+
}
|
|
64269
|
+
const readableWithoutExt = readable.slice(0, -".log".length);
|
|
64270
|
+
const digest = (0, import_node_crypto13.createHash)("sha256").update(readableWithoutExt).digest("hex").slice(0, 24);
|
|
64271
|
+
const suffix = `-${digest}.log`;
|
|
64272
|
+
const budgetForContext = RUN_LOG_FILENAME_MAX_BYTES - Buffer.byteLength(prefix, "utf8") - Buffer.byteLength(suffix, "utf8");
|
|
64273
|
+
const contextHead = truncateToUtf8ByteBudgetSafe(encodedContext, Math.max(budgetForContext, 0));
|
|
64274
|
+
return `${prefix}${contextHead}${suffix}`;
|
|
64275
|
+
}
|
|
64276
|
+
function truncateToUtf8ByteBudgetSafe(encoded, maxBytes) {
|
|
64277
|
+
if (maxBytes <= 0) {
|
|
64278
|
+
return "";
|
|
64279
|
+
}
|
|
64280
|
+
if (Buffer.byteLength(encoded, "utf8") <= maxBytes) {
|
|
64281
|
+
return encoded;
|
|
64282
|
+
}
|
|
64283
|
+
let candidateLength = Math.min(maxBytes, encoded.length);
|
|
64284
|
+
while (candidateLength > 0) {
|
|
64285
|
+
const candidate = encoded.slice(0, candidateLength);
|
|
64286
|
+
if (!endsWithSplitEscape(candidate)) {
|
|
64287
|
+
return candidate;
|
|
64288
|
+
}
|
|
64289
|
+
candidateLength -= 1;
|
|
64290
|
+
}
|
|
64291
|
+
return "";
|
|
64292
|
+
}
|
|
64293
|
+
function endsWithSplitEscape(value) {
|
|
64294
|
+
const percentIndex = value.lastIndexOf("%");
|
|
64295
|
+
if (percentIndex === -1) {
|
|
64296
|
+
return false;
|
|
64297
|
+
}
|
|
64298
|
+
const tail = value.length - percentIndex - 1;
|
|
64299
|
+
return tail < 2;
|
|
64300
|
+
}
|
|
64301
|
+
var import_node_crypto13, RUN_LOG_FILENAME_MAX_BYTES;
|
|
64302
|
+
var init_ai_run_log_path = __esm({
|
|
64303
|
+
"src/ai-run-log-path.ts"() {
|
|
64304
|
+
"use strict";
|
|
64305
|
+
import_node_crypto13 = require("node:crypto");
|
|
64306
|
+
RUN_LOG_FILENAME_MAX_BYTES = 240;
|
|
64307
|
+
}
|
|
64308
|
+
});
|
|
64309
|
+
|
|
63500
64310
|
// src/ai-adapter.ts
|
|
63501
64311
|
function buildClaudeAllowedToolsArgs() {
|
|
63502
64312
|
return ["--allowedTools", ...CLAUDE_ALLOWED_TOOLS];
|
|
@@ -65344,7 +66154,7 @@ function normalizeAttentionProvider(provider) {
|
|
|
65344
66154
|
return provider === "unknown" ? null : provider;
|
|
65345
66155
|
}
|
|
65346
66156
|
function stableHash2(value) {
|
|
65347
|
-
return (0,
|
|
66157
|
+
return (0, import_node_crypto14.createHash)("sha256").update(value).digest("hex").slice(0, 24);
|
|
65348
66158
|
}
|
|
65349
66159
|
function formatCommand(args) {
|
|
65350
66160
|
return args.map(shellQuote).join(" ");
|
|
@@ -65368,17 +66178,18 @@ function shortenJobId2(jobId) {
|
|
|
65368
66178
|
}
|
|
65369
66179
|
return `${jobId.slice(0, 6)}\u2026${jobId.slice(-4)}`;
|
|
65370
66180
|
}
|
|
65371
|
-
var
|
|
66181
|
+
var import_node_crypto14, import_node_fs26, import_promises12, import_node_os9, import_node_path31, AiRunner, CODEX_TOOL_FAILURE_MARKER;
|
|
65372
66182
|
var init_ai_runner = __esm({
|
|
65373
66183
|
"src/ai-runner.ts"() {
|
|
65374
66184
|
"use strict";
|
|
65375
66185
|
init_log();
|
|
65376
|
-
|
|
66186
|
+
import_node_crypto14 = require("node:crypto");
|
|
65377
66187
|
import_node_fs26 = require("node:fs");
|
|
65378
66188
|
import_promises12 = require("node:fs/promises");
|
|
65379
66189
|
import_node_os9 = require("node:os");
|
|
65380
66190
|
import_node_path31 = require("node:path");
|
|
65381
66191
|
init_ai_command();
|
|
66192
|
+
init_ai_run_log_path();
|
|
65382
66193
|
init_paths();
|
|
65383
66194
|
init_file_store();
|
|
65384
66195
|
init_ai_provider();
|
|
@@ -66006,13 +66817,15 @@ var init_ai_runner = __esm({
|
|
|
66006
66817
|
);
|
|
66007
66818
|
}
|
|
66008
66819
|
buildRunLogPath(request) {
|
|
66009
|
-
|
|
66010
|
-
|
|
66011
|
-
|
|
66012
|
-
|
|
66013
|
-
|
|
66014
|
-
|
|
66015
|
-
|
|
66820
|
+
return (0, import_node_path31.join)(
|
|
66821
|
+
this.logsDir,
|
|
66822
|
+
buildRunLogFileName({
|
|
66823
|
+
source: request.source,
|
|
66824
|
+
sessionKey: request.sessionKey,
|
|
66825
|
+
messageId: request.messageId,
|
|
66826
|
+
jobId: request.jobId
|
|
66827
|
+
})
|
|
66828
|
+
);
|
|
66016
66829
|
}
|
|
66017
66830
|
readRunAiSessionId(provider, request, file, sessionMeta) {
|
|
66018
66831
|
if (request.source === "job-dispatch" && request.jobId) {
|
|
@@ -67037,6 +67850,9 @@ function commandSentryExtra(command, extra = {}) {
|
|
|
67037
67850
|
base.myAgentId = command.myAgentId ?? "";
|
|
67038
67851
|
base.toAgentId = command.toAgentId ?? "";
|
|
67039
67852
|
base.toXmtpAddress = command.toXmtpAddress ?? "";
|
|
67853
|
+
} else if (command.type === "xmtp-subscription-push") {
|
|
67854
|
+
base.myAgentId = command.myAgentId;
|
|
67855
|
+
base.conversationCount = command.conversationIds.length;
|
|
67040
67856
|
} else if (command.type === "xmtp-deny-pending-conversation") {
|
|
67041
67857
|
base.groupId = command.groupId;
|
|
67042
67858
|
base.jobId = command.jobId ?? "";
|
|
@@ -67392,6 +68208,10 @@ async function handleDaemonCommand(command, params) {
|
|
|
67392
68208
|
});
|
|
67393
68209
|
return { ok: true, messageId: result.messageId };
|
|
67394
68210
|
}
|
|
68211
|
+
if (command.type === "xmtp-subscription-push") {
|
|
68212
|
+
const result = await handleSubscriptionPushCommand({ command, service: params.service });
|
|
68213
|
+
return { ok: true, payload: result };
|
|
68214
|
+
}
|
|
67395
68215
|
if (command.type === "xmtp-get-pending-list") {
|
|
67396
68216
|
return { ok: true, payload: await listPendingTaskRequests(params) };
|
|
67397
68217
|
}
|
|
@@ -67474,12 +68294,12 @@ async function listPendingTaskRequests(params) {
|
|
|
67474
68294
|
}
|
|
67475
68295
|
async function denyPendingConversationsByJobId(jobId, params, content2) {
|
|
67476
68296
|
const pending = await listPendingTaskRequests(params);
|
|
67477
|
-
const matched = pending.filter((item) =>
|
|
68297
|
+
const matched = pending.filter((item) => isPlainObject4(item) && readString4(item.jobId) === jobId);
|
|
67478
68298
|
const clientAddresses = [...params.service.getClients().keys()];
|
|
67479
68299
|
const targetsByKey = collectDenyTargetsFromPending(matched, clientAddresses);
|
|
67480
68300
|
const groupIds = /* @__PURE__ */ new Set();
|
|
67481
68301
|
for (const item of matched) {
|
|
67482
|
-
if (!
|
|
68302
|
+
if (!isPlainObject4(item)) {
|
|
67483
68303
|
continue;
|
|
67484
68304
|
}
|
|
67485
68305
|
const groupId = readString4(item.groupId);
|
|
@@ -67506,7 +68326,7 @@ async function denyPendingConversationsByJobId(jobId, params, content2) {
|
|
|
67506
68326
|
function collectDenyTargetsFromPending(pending, fallbackAddresses) {
|
|
67507
68327
|
const targetsByKey = /* @__PURE__ */ new Map();
|
|
67508
68328
|
for (const item of pending) {
|
|
67509
|
-
if (!
|
|
68329
|
+
if (!isPlainObject4(item)) {
|
|
67510
68330
|
continue;
|
|
67511
68331
|
}
|
|
67512
68332
|
const groupId = readString4(item.groupId);
|
|
@@ -67531,7 +68351,7 @@ ${groupId}`, {
|
|
|
67531
68351
|
async function resolvePendingTargetsByGroupId(groupId, addresses, params) {
|
|
67532
68352
|
const addressSet = addresses ? new Set(addresses) : null;
|
|
67533
68353
|
const pending = (await listPendingTaskRequests(params)).filter((item) => {
|
|
67534
|
-
if (!
|
|
68354
|
+
if (!isPlainObject4(item) || readString4(item.groupId) !== groupId) {
|
|
67535
68355
|
return false;
|
|
67536
68356
|
}
|
|
67537
68357
|
const address = readString4(item.myXmtpAddress);
|
|
@@ -67651,7 +68471,7 @@ function filterKnownPendingGroups(items, sessionStore) {
|
|
|
67651
68471
|
return items;
|
|
67652
68472
|
}
|
|
67653
68473
|
return items.filter((item) => {
|
|
67654
|
-
if (!
|
|
68474
|
+
if (!isPlainObject4(item)) {
|
|
67655
68475
|
return true;
|
|
67656
68476
|
}
|
|
67657
68477
|
const jobId = readString4(item.jobId);
|
|
@@ -67662,7 +68482,7 @@ function filterKnownPendingGroups(items, sessionStore) {
|
|
|
67662
68482
|
return sessionStore.querySessions({ jobId, toAgentId, limit: 1 }).length === 0;
|
|
67663
68483
|
});
|
|
67664
68484
|
}
|
|
67665
|
-
function
|
|
68485
|
+
function isPlainObject4(value) {
|
|
67666
68486
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
67667
68487
|
}
|
|
67668
68488
|
function readString4(value) {
|
|
@@ -67796,6 +68616,10 @@ function formatCommandCompleted(command, result) {
|
|
|
67796
68616
|
if (command.type === "xmtp-send") {
|
|
67797
68617
|
return `[okx-agent-task] xmtp-send command completed id=${command.id} job=${command.jobId} messageId=${result.messageId}`;
|
|
67798
68618
|
}
|
|
68619
|
+
if (command.type === "xmtp-subscription-push") {
|
|
68620
|
+
const payload = isPlainObject4(result.payload) ? result.payload : {};
|
|
68621
|
+
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}`;
|
|
68622
|
+
}
|
|
67799
68623
|
if (command.type === "xmtp-get-pending-list") {
|
|
67800
68624
|
return `[okx-agent-task] xmtp-get-pending-list command completed id=${command.id}`;
|
|
67801
68625
|
}
|
|
@@ -67816,8 +68640,8 @@ function formatCommandCompleted(command, result) {
|
|
|
67816
68640
|
return `[okx-agent-task] xmtp-refresh-agents command completed id=${command.id}`;
|
|
67817
68641
|
}
|
|
67818
68642
|
function formatXmtpDebugCompleted(command, payload) {
|
|
67819
|
-
const record =
|
|
67820
|
-
const summary =
|
|
68643
|
+
const record = isPlainObject4(payload) ? payload : {};
|
|
68644
|
+
const summary = isPlainObject4(record.summary) ? record.summary : {};
|
|
67821
68645
|
const count = command.action === "group-list" ? record.groupCount ?? 0 : command.action === "group-inspect" ? record.conversationFound ? 1 : 0 : summary.matchedCount ?? 0;
|
|
67822
68646
|
return `[okx-agent-task] xmtp-debug command completed id=${command.id} action=${command.action} rows=${String(count)}`;
|
|
67823
68647
|
}
|
|
@@ -67978,6 +68802,7 @@ var init_command_processor = __esm({
|
|
|
67978
68802
|
init_command_store();
|
|
67979
68803
|
init_invalid_message_store();
|
|
67980
68804
|
init_xmtp_send();
|
|
68805
|
+
init_subscription_push();
|
|
67981
68806
|
init_ai_runner();
|
|
67982
68807
|
init_session_store();
|
|
67983
68808
|
init_ai_provider();
|
|
@@ -68005,7 +68830,7 @@ async function enqueueAiJobMessageDispatch(params) {
|
|
|
68005
68830
|
await commands.submit(command);
|
|
68006
68831
|
return command;
|
|
68007
68832
|
}
|
|
68008
|
-
async function
|
|
68833
|
+
async function enqueueAiSessionMessageDispatchIdempotent(params) {
|
|
68009
68834
|
const commands = params.commands ?? new CommandStore(params.homeDir);
|
|
68010
68835
|
const messageId = params.event.messageId ?? `session-${Date.now()}`;
|
|
68011
68836
|
const command = commands.createAiSessionMessageDispatchCommand({
|
|
@@ -68015,7 +68840,21 @@ async function enqueueAiSessionMessageDispatch(params) {
|
|
|
68015
68840
|
jobId: params.event.jobId,
|
|
68016
68841
|
agentId: params.event.agentId
|
|
68017
68842
|
});
|
|
68843
|
+
const idempotencyKey = params.event.idempotencyKey?.trim();
|
|
68844
|
+
if (idempotencyKey) {
|
|
68845
|
+
const dbKey = `${command.sessionKey}
|
|
68846
|
+
${command.messageId}`;
|
|
68847
|
+
const result = await commands.submitIdempotent(command, dbKey);
|
|
68848
|
+
return {
|
|
68849
|
+
command: result.created ? command : { ...command, id: result.commandId },
|
|
68850
|
+
created: result.created
|
|
68851
|
+
};
|
|
68852
|
+
}
|
|
68018
68853
|
await commands.submit(command);
|
|
68854
|
+
return { command, created: true };
|
|
68855
|
+
}
|
|
68856
|
+
async function enqueueAiSessionMessageDispatch(params) {
|
|
68857
|
+
const { command } = await enqueueAiSessionMessageDispatchIdempotent(params);
|
|
68019
68858
|
return command;
|
|
68020
68859
|
}
|
|
68021
68860
|
var init_ai_dispatch_queue = __esm({
|
|
@@ -68025,6 +68864,156 @@ var init_ai_dispatch_queue = __esm({
|
|
|
68025
68864
|
}
|
|
68026
68865
|
});
|
|
68027
68866
|
|
|
68867
|
+
// src/subscription-inbound.ts
|
|
68868
|
+
function decideSubscriptionGate(input) {
|
|
68869
|
+
if (!isSubscriptionEnvelope(input.payload)) {
|
|
68870
|
+
return { kind: "not_subscription" };
|
|
68871
|
+
}
|
|
68872
|
+
if (input.chatType === "dm") {
|
|
68873
|
+
return { kind: "drop", reason: "dm_subscription" };
|
|
68874
|
+
}
|
|
68875
|
+
if (input.chatType === "unknown") {
|
|
68876
|
+
return { kind: "drop", reason: "unknown_conversation_subscription" };
|
|
68877
|
+
}
|
|
68878
|
+
const read = readSubscriptionEnvelope(input.payload);
|
|
68879
|
+
if (!read.ok) {
|
|
68880
|
+
return { kind: "drop", reason: "invalid_envelope", detail: read.reason };
|
|
68881
|
+
}
|
|
68882
|
+
if (!input.senderInboxId) {
|
|
68883
|
+
return { kind: "drop", reason: "missing_sender_inbox_id" };
|
|
68884
|
+
}
|
|
68885
|
+
return { kind: "v2", envelope: read.envelope };
|
|
68886
|
+
}
|
|
68887
|
+
function partitionSubscriptionJobsByOwner(input) {
|
|
68888
|
+
const owned = [];
|
|
68889
|
+
for (const job of input.jobs) {
|
|
68890
|
+
if (job.userAgentId === input.localAgentId) {
|
|
68891
|
+
owned.push(job);
|
|
68892
|
+
}
|
|
68893
|
+
}
|
|
68894
|
+
return {
|
|
68895
|
+
owned,
|
|
68896
|
+
returnedCount: input.jobs.length,
|
|
68897
|
+
ownedCount: owned.length,
|
|
68898
|
+
ignoredCount: input.jobs.length - owned.length
|
|
68899
|
+
};
|
|
68900
|
+
}
|
|
68901
|
+
function normalizeSubscriptionJobs(input) {
|
|
68902
|
+
const seen = /* @__PURE__ */ new Set();
|
|
68903
|
+
const normalized = [];
|
|
68904
|
+
for (const job of input.jobs) {
|
|
68905
|
+
const dedupKey = `${job.jobId}|${job.userAgentId}|${job.aspAgentId}`;
|
|
68906
|
+
if (seen.has(dedupKey)) {
|
|
68907
|
+
continue;
|
|
68908
|
+
}
|
|
68909
|
+
seen.add(dedupKey);
|
|
68910
|
+
normalized.push({
|
|
68911
|
+
jobId: job.jobId,
|
|
68912
|
+
userAgentId: job.userAgentId,
|
|
68913
|
+
aspAgentId: job.aspAgentId,
|
|
68914
|
+
msgType: SUBSCRIPTION_MESSAGE_TYPE,
|
|
68915
|
+
content: input.envelope.content,
|
|
68916
|
+
...input.envelope.deliveryId ? { deliveryId: input.envelope.deliveryId } : {},
|
|
68917
|
+
conversationId: input.conversationId,
|
|
68918
|
+
senderInboxId: input.senderInboxId
|
|
68919
|
+
});
|
|
68920
|
+
}
|
|
68921
|
+
return normalized;
|
|
68922
|
+
}
|
|
68923
|
+
function subscriptionIdempotencyKey(input) {
|
|
68924
|
+
const messageDimension = input.deliveryId || input.messageId;
|
|
68925
|
+
return `${input.myXmtpAddress}|${messageDimension}|${input.jobId}`;
|
|
68926
|
+
}
|
|
68927
|
+
function tryMarkSubscriptionTarget(key) {
|
|
68928
|
+
if (subscriptionTargets.has(key)) {
|
|
68929
|
+
return false;
|
|
68930
|
+
}
|
|
68931
|
+
subscriptionTargets.set(key, Date.now());
|
|
68932
|
+
while (subscriptionTargets.size > SUBSCRIPTION_TARGETS_MAX) {
|
|
68933
|
+
const oldest = subscriptionTargets.keys().next().value;
|
|
68934
|
+
if (oldest === void 0) {
|
|
68935
|
+
break;
|
|
68936
|
+
}
|
|
68937
|
+
subscriptionTargets.delete(oldest);
|
|
68938
|
+
}
|
|
68939
|
+
return true;
|
|
68940
|
+
}
|
|
68941
|
+
function redactSenderInboxId(senderInboxId, left = 8, right = 6) {
|
|
68942
|
+
if (!senderInboxId) {
|
|
68943
|
+
return "(none)";
|
|
68944
|
+
}
|
|
68945
|
+
if (senderInboxId.length <= left + right + 1) {
|
|
68946
|
+
return senderInboxId;
|
|
68947
|
+
}
|
|
68948
|
+
return `${senderInboxId.slice(0, left)}\u2026${senderInboxId.slice(-right)}`;
|
|
68949
|
+
}
|
|
68950
|
+
async function fanOutSubscriptionJobs(input) {
|
|
68951
|
+
const { jobs, myXmtpAddress, messageId, dispatch, concurrency } = input;
|
|
68952
|
+
const total = jobs.length;
|
|
68953
|
+
const capacityAnomaly = total > SUBSCRIPTION_FANOUT_MAX;
|
|
68954
|
+
if (capacityAnomaly) {
|
|
68955
|
+
logWithTimestamp(
|
|
68956
|
+
`[okx-agent-task:${myXmtpAddress}] subscription fan-out capacity anomaly: jobs=${total} max=${SUBSCRIPTION_FANOUT_MAX} message=${messageId}`
|
|
68957
|
+
);
|
|
68958
|
+
}
|
|
68959
|
+
const settled = await parallelMap(
|
|
68960
|
+
jobs,
|
|
68961
|
+
async (job) => {
|
|
68962
|
+
const idempotencyKey = subscriptionIdempotencyKey({
|
|
68963
|
+
myXmtpAddress,
|
|
68964
|
+
deliveryId: job.deliveryId,
|
|
68965
|
+
messageId,
|
|
68966
|
+
jobId: job.jobId
|
|
68967
|
+
});
|
|
68968
|
+
if (subscriptionTargets.has(idempotencyKey)) {
|
|
68969
|
+
return { key: idempotencyKey, outcome: "duplicate" };
|
|
68970
|
+
}
|
|
68971
|
+
const dispatchOutcome = await dispatch(job, idempotencyKey);
|
|
68972
|
+
const isDurableDuplicate = !!dispatchOutcome && dispatchOutcome.created === false;
|
|
68973
|
+
return { key: idempotencyKey, outcome: isDurableDuplicate ? "duplicate" : "started" };
|
|
68974
|
+
},
|
|
68975
|
+
concurrency ?? 20
|
|
68976
|
+
);
|
|
68977
|
+
let started = 0;
|
|
68978
|
+
let failed = 0;
|
|
68979
|
+
let skippedDuplicate = 0;
|
|
68980
|
+
const results = [];
|
|
68981
|
+
settled.forEach((result, idx) => {
|
|
68982
|
+
const job = jobs[idx];
|
|
68983
|
+
if (result.status === "rejected") {
|
|
68984
|
+
failed += 1;
|
|
68985
|
+
results.push({ jobId: job?.jobId ?? "(unknown)", outcome: "failed", error: result.reason });
|
|
68986
|
+
logWithTimestamp(
|
|
68987
|
+
`[okx-agent-task:${myXmtpAddress}] subscription dispatch failed message=${messageId} job=${job?.jobId ?? "(unknown)"} sender=${redactSenderInboxId(job?.senderInboxId)}:`,
|
|
68988
|
+
result.reason
|
|
68989
|
+
);
|
|
68990
|
+
return;
|
|
68991
|
+
}
|
|
68992
|
+
tryMarkSubscriptionTarget(result.value.key);
|
|
68993
|
+
if (result.value.outcome === "duplicate") {
|
|
68994
|
+
skippedDuplicate += 1;
|
|
68995
|
+
results.push({ jobId: job?.jobId ?? "(unknown)", outcome: "duplicate" });
|
|
68996
|
+
} else {
|
|
68997
|
+
started += 1;
|
|
68998
|
+
results.push({ jobId: job?.jobId ?? "(unknown)", outcome: "started" });
|
|
68999
|
+
}
|
|
69000
|
+
});
|
|
69001
|
+
return { total, started, failed, skippedDuplicate, capacityAnomaly, results };
|
|
69002
|
+
}
|
|
69003
|
+
var SUBSCRIPTION_TARGETS_MAX, subscriptionTargets, SUBSCRIPTION_FANOUT_MAX;
|
|
69004
|
+
var init_subscription_inbound = __esm({
|
|
69005
|
+
"src/subscription-inbound.ts"() {
|
|
69006
|
+
"use strict";
|
|
69007
|
+
init_log();
|
|
69008
|
+
init_concurrency();
|
|
69009
|
+
init_subscription_types();
|
|
69010
|
+
init_subscription_envelope();
|
|
69011
|
+
SUBSCRIPTION_TARGETS_MAX = 2e3;
|
|
69012
|
+
subscriptionTargets = /* @__PURE__ */ new Map();
|
|
69013
|
+
SUBSCRIPTION_FANOUT_MAX = 250;
|
|
69014
|
+
}
|
|
69015
|
+
});
|
|
69016
|
+
|
|
68028
69017
|
// src/message-handler.ts
|
|
68029
69018
|
function tryMarkProcessed(messageId) {
|
|
68030
69019
|
if (processedMessageIds.has(messageId)) {
|
|
@@ -68040,7 +69029,7 @@ function tryMarkProcessed(messageId) {
|
|
|
68040
69029
|
}
|
|
68041
69030
|
return true;
|
|
68042
69031
|
}
|
|
68043
|
-
function
|
|
69032
|
+
function isPlainObject5(value) {
|
|
68044
69033
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
68045
69034
|
}
|
|
68046
69035
|
function safeStringify(value) {
|
|
@@ -68100,9 +69089,9 @@ function readNumber(value) {
|
|
|
68100
69089
|
}
|
|
68101
69090
|
function resolveSessionAgentId(params) {
|
|
68102
69091
|
const { chatType, payload, myXmtpAddress } = params;
|
|
68103
|
-
const payloadObject =
|
|
68104
|
-
const sender =
|
|
68105
|
-
const message =
|
|
69092
|
+
const payloadObject = isPlainObject5(payload) ? payload : null;
|
|
69093
|
+
const sender = isPlainObject5(payloadObject?.sender) ? payloadObject.sender : null;
|
|
69094
|
+
const message = isPlainObject5(payloadObject?.message) ? payloadObject.message : null;
|
|
68106
69095
|
const localAgentId = XmtpService.getInstance().getAgentByAddress(myXmtpAddress)?.agentId ?? null;
|
|
68107
69096
|
if (chatType === "group") {
|
|
68108
69097
|
return readString5(sender?.agentId) ?? readString5(payloadObject?.receiverAgentId) ?? localAgentId;
|
|
@@ -68113,7 +69102,7 @@ function resolveSessionAgentId(params) {
|
|
|
68113
69102
|
return localAgentId;
|
|
68114
69103
|
}
|
|
68115
69104
|
function routeMessage(chatType, parsed, payload) {
|
|
68116
|
-
if (!parsed || !
|
|
69105
|
+
if (!parsed || !isPlainObject5(payload)) {
|
|
68117
69106
|
return {
|
|
68118
69107
|
jobId: BACKUP_JOB_ID,
|
|
68119
69108
|
route: "backup",
|
|
@@ -68125,7 +69114,7 @@ function routeMessage(chatType, parsed, payload) {
|
|
|
68125
69114
|
return jobId ? { jobId, route: "job", routeReason: "group-job-id" } : { jobId: BACKUP_JOB_ID, route: "backup", routeReason: "group-missing-job-id" };
|
|
68126
69115
|
}
|
|
68127
69116
|
if (chatType === "dm") {
|
|
68128
|
-
const message =
|
|
69117
|
+
const message = isPlainObject5(payload.message) ? payload.message : null;
|
|
68129
69118
|
const nestedJobId = readString5(message?.jobId);
|
|
68130
69119
|
const directJobId = readString5(payload.jobId);
|
|
68131
69120
|
const jobId = nestedJobId ?? directJobId;
|
|
@@ -68138,10 +69127,10 @@ function routeMessage(chatType, parsed, payload) {
|
|
|
68138
69127
|
return { jobId: BACKUP_JOB_ID, route: "backup", routeReason: "unknown-conversation" };
|
|
68139
69128
|
}
|
|
68140
69129
|
function extractDirectToUserNotification(payload) {
|
|
68141
|
-
if (!
|
|
69130
|
+
if (!isPlainObject5(payload)) {
|
|
68142
69131
|
return { kind: "none" };
|
|
68143
69132
|
}
|
|
68144
|
-
const message =
|
|
69133
|
+
const message = isPlainObject5(payload.message) ? payload.message : null;
|
|
68145
69134
|
if (message?.isDirectToUser !== true) {
|
|
68146
69135
|
return { kind: "none" };
|
|
68147
69136
|
}
|
|
@@ -68165,10 +69154,10 @@ function extractDirectToUserNotification(payload) {
|
|
|
68165
69154
|
};
|
|
68166
69155
|
}
|
|
68167
69156
|
function extractSystemNotification(payload) {
|
|
68168
|
-
if (!
|
|
69157
|
+
if (!isPlainObject5(payload)) {
|
|
68169
69158
|
return null;
|
|
68170
69159
|
}
|
|
68171
|
-
const message =
|
|
69160
|
+
const message = isPlainObject5(payload.message) ? payload.message : null;
|
|
68172
69161
|
const isDirectCommunication = message?.isDirectCommunication === true;
|
|
68173
69162
|
if (message?.source !== "system" && !isDirectCommunication) {
|
|
68174
69163
|
return null;
|
|
@@ -68394,7 +69383,7 @@ function inboundStageExtras(stage, outcome) {
|
|
|
68394
69383
|
})
|
|
68395
69384
|
};
|
|
68396
69385
|
}
|
|
68397
|
-
function
|
|
69386
|
+
function definedExtras2(input) {
|
|
68398
69387
|
return Object.entries(input).reduce((out, [key, value]) => {
|
|
68399
69388
|
const text = readString5(value);
|
|
68400
69389
|
if (text) {
|
|
@@ -68426,7 +69415,7 @@ function buildInboundTerminalExtras(input) {
|
|
|
68426
69415
|
originPlatform: classifyOriginPlatform({ env: process.env }),
|
|
68427
69416
|
deliveryId: resolveDeliveryId({ messageId, jobId, sessionKey })
|
|
68428
69417
|
}),
|
|
68429
|
-
...
|
|
69418
|
+
...definedExtras2({
|
|
68430
69419
|
messageId,
|
|
68431
69420
|
conversationId,
|
|
68432
69421
|
chatType,
|
|
@@ -68460,7 +69449,7 @@ function maybeNotifyInboundAgentMessage(params) {
|
|
|
68460
69449
|
return;
|
|
68461
69450
|
}
|
|
68462
69451
|
const content2 = payloadObject.content;
|
|
68463
|
-
const sender =
|
|
69452
|
+
const sender = isPlainObject5(payloadObject.sender) ? payloadObject.sender : null;
|
|
68464
69453
|
const localAgent = XmtpService.getInstance().getAgentByAddress(params.deps.myXmtpAddress);
|
|
68465
69454
|
void notifyAgentMessageToUserAttention({
|
|
68466
69455
|
direction: "inbound" /* INBOUND */,
|
|
@@ -68491,11 +69480,11 @@ function stringifySystemPayload(payload) {
|
|
|
68491
69480
|
}
|
|
68492
69481
|
}
|
|
68493
69482
|
function summarizePayloadForLog(payload) {
|
|
68494
|
-
if (!
|
|
69483
|
+
if (!isPlainObject5(payload)) {
|
|
68495
69484
|
return "payload=non-object";
|
|
68496
69485
|
}
|
|
68497
|
-
const message =
|
|
68498
|
-
const sender =
|
|
69486
|
+
const message = isPlainObject5(payload.message) ? payload.message : null;
|
|
69487
|
+
const sender = isPlainObject5(payload.sender) ? payload.sender : null;
|
|
68499
69488
|
const jobId = readString5(payload.jobId) ?? readString5(message?.jobId);
|
|
68500
69489
|
const parts = [
|
|
68501
69490
|
readString5(payload.msgType) ? `type=${readString5(payload.msgType)}` : null,
|
|
@@ -68764,7 +69753,7 @@ async function verifyInboundA2AGroupMessage(params) {
|
|
|
68764
69753
|
messageId,
|
|
68765
69754
|
groupId,
|
|
68766
69755
|
jobId,
|
|
68767
|
-
agentId: readString5(
|
|
69756
|
+
agentId: readString5(isPlainObject5(payload.sender) ? payload.sender.agentId : null),
|
|
68768
69757
|
localAgentId: myAgent?.agentId ?? null,
|
|
68769
69758
|
senderAddress,
|
|
68770
69759
|
senderInboxId,
|
|
@@ -68790,7 +69779,7 @@ async function verifyInboundA2AGroupMessage(params) {
|
|
|
68790
69779
|
});
|
|
68791
69780
|
return false;
|
|
68792
69781
|
}
|
|
68793
|
-
const sender =
|
|
69782
|
+
const sender = isPlainObject5(payload.sender) ? payload.sender : null;
|
|
68794
69783
|
const senderAgentId = readString5(sender?.agentId);
|
|
68795
69784
|
const senderRole = readNumber(sender?.role);
|
|
68796
69785
|
if (!senderAgentId || !myAgent) {
|
|
@@ -68959,9 +69948,302 @@ ${failureMessage}`,
|
|
|
68959
69948
|
}
|
|
68960
69949
|
return true;
|
|
68961
69950
|
}
|
|
69951
|
+
async function processSubscriptionInbound(ctx, deps, input) {
|
|
69952
|
+
const { decision, conversationId, messageId } = input;
|
|
69953
|
+
const senderInboxId = ctx.message.senderInboxId ?? "";
|
|
69954
|
+
if (decision.kind === "drop") {
|
|
69955
|
+
logger.info(
|
|
69956
|
+
LogEvent.SUBSCRIPTION_INBOUND_GATE_DROPPED,
|
|
69957
|
+
buildSubscriptionInboundExtras({
|
|
69958
|
+
checkpoint: "inbound/subscription_gate_dropped",
|
|
69959
|
+
outcome: "dropped",
|
|
69960
|
+
conversationId,
|
|
69961
|
+
messageId,
|
|
69962
|
+
senderInboxId: shortenLogValue(senderInboxId),
|
|
69963
|
+
reason: decision.reason
|
|
69964
|
+
})
|
|
69965
|
+
);
|
|
69966
|
+
logWithTimestamp(
|
|
69967
|
+
`[okx-agent-task:${deps.myXmtpAddress}] subscription message dropped reason=${decision.reason}${decision.detail ? ` detail=${decision.detail}` : ""} conv=${conversationId} message=${shortenLogValue(messageId)} sender=${shortenLogValue(senderInboxId)}`
|
|
69968
|
+
);
|
|
69969
|
+
return true;
|
|
69970
|
+
}
|
|
69971
|
+
if (decision.kind === "not_subscription") {
|
|
69972
|
+
return true;
|
|
69973
|
+
}
|
|
69974
|
+
const { envelope } = decision;
|
|
69975
|
+
const agenticId = XmtpService.getInstance().getAgentByAddress(deps.myXmtpAddress)?.agentId;
|
|
69976
|
+
if (!agenticId) {
|
|
69977
|
+
logWithTimestamp(
|
|
69978
|
+
`[okx-agent-task:${deps.myXmtpAddress}] subscription fail-closed: no local agenticId for ${deps.myXmtpAddress}, conv=${conversationId} message=${shortenLogValue(messageId)}`
|
|
69979
|
+
);
|
|
69980
|
+
logger.error(
|
|
69981
|
+
LogEvent.SUBSCRIPTION_INBOUND_AGENTIC_ID_MISSING,
|
|
69982
|
+
new Error("Subscription inbound: local agenticId not resolved"),
|
|
69983
|
+
buildSubscriptionInboundExtras({
|
|
69984
|
+
checkpoint: "inbound/subscription_agentic_id",
|
|
69985
|
+
outcome: "blocked",
|
|
69986
|
+
conversationId,
|
|
69987
|
+
messageId,
|
|
69988
|
+
senderInboxId: shortenLogValue(senderInboxId),
|
|
69989
|
+
reason: "missing_agentic_id"
|
|
69990
|
+
})
|
|
69991
|
+
);
|
|
69992
|
+
return true;
|
|
69993
|
+
}
|
|
69994
|
+
logWithTimestamp(
|
|
69995
|
+
`[okx-agent-task:${deps.myXmtpAddress}] subscription received msgType=${envelope.msgType} conv=${conversationId} message=${shortenLogValue(messageId)} sender=${shortenLogValue(senderInboxId)}`
|
|
69996
|
+
);
|
|
69997
|
+
logger.info(
|
|
69998
|
+
LogEvent.SUBSCRIPTION_INBOUND_RECEIVED,
|
|
69999
|
+
buildSubscriptionInboundExtras({
|
|
70000
|
+
checkpoint: "inbound/subscription_received",
|
|
70001
|
+
userAgentId: agenticId,
|
|
70002
|
+
conversationId,
|
|
70003
|
+
messageId,
|
|
70004
|
+
deliveryId: envelope.deliveryId,
|
|
70005
|
+
senderInboxId: shortenLogValue(senderInboxId)
|
|
70006
|
+
})
|
|
70007
|
+
);
|
|
70008
|
+
const listJobs = deps.listJobsByVerifiedSenderImpl ?? listJobsByVerifiedSenderWithCapability;
|
|
70009
|
+
logger.info(
|
|
70010
|
+
LogEvent.SUBSCRIPTION_JOBS_QUERY_STARTED,
|
|
70011
|
+
buildSubscriptionInboundExtras({
|
|
70012
|
+
checkpoint: "inbound/subscription_jobs_query_started",
|
|
70013
|
+
userAgentId: agenticId,
|
|
70014
|
+
conversationId,
|
|
70015
|
+
messageId
|
|
70016
|
+
})
|
|
70017
|
+
);
|
|
70018
|
+
const listJobsResult = await listJobs({
|
|
70019
|
+
groupId: conversationId,
|
|
70020
|
+
senderInboxId,
|
|
70021
|
+
agenticId
|
|
70022
|
+
});
|
|
70023
|
+
logWithTimestamp(
|
|
70024
|
+
`[okx-agent-task:${deps.myXmtpAddress}] subscription queried status=${listJobsResult.status} jobs=${listJobsResult.jobs.length} invalid=${listJobsResult.invalidCount} conv=${conversationId} message=${shortenLogValue(messageId)}`
|
|
70025
|
+
);
|
|
70026
|
+
if (listJobsResult.status === "fail_closed") {
|
|
70027
|
+
logger.error(
|
|
70028
|
+
LogEvent.SUBSCRIPTION_JOBS_FAIL_CLOSED,
|
|
70029
|
+
new Error("Subscription inbound: listJobsByVerifiedSender fail-closed"),
|
|
70030
|
+
buildSubscriptionInboundExtras({
|
|
70031
|
+
checkpoint: "inbound/subscription_jobs_fail_closed",
|
|
70032
|
+
outcome: "blocked",
|
|
70033
|
+
userAgentId: agenticId,
|
|
70034
|
+
conversationId,
|
|
70035
|
+
messageId,
|
|
70036
|
+
senderInboxId: shortenLogValue(senderInboxId),
|
|
70037
|
+
reason: listJobsResult.reason ?? "unknown",
|
|
70038
|
+
errorCode: listJobsResult.errorCode
|
|
70039
|
+
})
|
|
70040
|
+
);
|
|
70041
|
+
return true;
|
|
70042
|
+
}
|
|
70043
|
+
if (listJobsResult.status === "empty") {
|
|
70044
|
+
logWithTimestamp(
|
|
70045
|
+
`[okx-agent-task:${deps.myXmtpAddress}] subscription empty: no verified jobs for conv=${conversationId} message=${shortenLogValue(messageId)}`
|
|
70046
|
+
);
|
|
70047
|
+
logger.info(
|
|
70048
|
+
LogEvent.SUBSCRIPTION_JOBS_EMPTY,
|
|
70049
|
+
buildSubscriptionInboundExtras({
|
|
70050
|
+
checkpoint: "inbound/subscription_jobs_empty",
|
|
70051
|
+
outcome: "ignored",
|
|
70052
|
+
userAgentId: agenticId,
|
|
70053
|
+
conversationId,
|
|
70054
|
+
messageId,
|
|
70055
|
+
reason: "jobs_empty",
|
|
70056
|
+
returnedCount: 0,
|
|
70057
|
+
invalidCount: listJobsResult.invalidCount
|
|
70058
|
+
})
|
|
70059
|
+
);
|
|
70060
|
+
return true;
|
|
70061
|
+
}
|
|
70062
|
+
logger.info(
|
|
70063
|
+
LogEvent.SUBSCRIPTION_JOBS_QUERY_SUCCEEDED,
|
|
70064
|
+
buildSubscriptionInboundExtras({
|
|
70065
|
+
checkpoint: "inbound/subscription_jobs_query_succeeded",
|
|
70066
|
+
userAgentId: agenticId,
|
|
70067
|
+
conversationId,
|
|
70068
|
+
messageId,
|
|
70069
|
+
returnedCount: listJobsResult.jobs.length,
|
|
70070
|
+
invalidCount: listJobsResult.invalidCount
|
|
70071
|
+
})
|
|
70072
|
+
);
|
|
70073
|
+
const ownership = partitionSubscriptionJobsByOwner({
|
|
70074
|
+
jobs: listJobsResult.jobs,
|
|
70075
|
+
localAgentId: agenticId
|
|
70076
|
+
});
|
|
70077
|
+
logWithTimestamp(
|
|
70078
|
+
`[okx-agent-task:${deps.myXmtpAddress}] subscription routed receiver=${agenticId} returned=${ownership.returnedCount} localOwned=${ownership.ownedCount} ignored=${ownership.ignoredCount} conv=${conversationId} message=${shortenLogValue(messageId)}`
|
|
70079
|
+
);
|
|
70080
|
+
logger.info(
|
|
70081
|
+
LogEvent.SUBSCRIPTION_INBOUND_OWNERSHIP_ROUTED,
|
|
70082
|
+
buildSubscriptionInboundExtras({
|
|
70083
|
+
checkpoint: "inbound/subscription_ownership_routed",
|
|
70084
|
+
outcome: ownership.ownedCount === 0 ? "ignored" : null,
|
|
70085
|
+
userAgentId: agenticId,
|
|
70086
|
+
conversationId,
|
|
70087
|
+
messageId,
|
|
70088
|
+
returnedCount: ownership.returnedCount,
|
|
70089
|
+
ownedCount: ownership.ownedCount,
|
|
70090
|
+
ignoredCount: ownership.ignoredCount
|
|
70091
|
+
})
|
|
70092
|
+
);
|
|
70093
|
+
if (ownership.ownedCount === 0) {
|
|
70094
|
+
return true;
|
|
70095
|
+
}
|
|
70096
|
+
const normalizedJobs = normalizeSubscriptionJobs({
|
|
70097
|
+
jobs: ownership.owned,
|
|
70098
|
+
envelope,
|
|
70099
|
+
conversationId,
|
|
70100
|
+
senderInboxId
|
|
70101
|
+
});
|
|
70102
|
+
logWithTimestamp(
|
|
70103
|
+
`[okx-agent-task:${deps.myXmtpAddress}] subscription expanded jobs=${normalizedJobs.length} conv=${conversationId} message=${shortenLogValue(messageId)}`
|
|
70104
|
+
);
|
|
70105
|
+
let senderXmtpAddress = null;
|
|
70106
|
+
try {
|
|
70107
|
+
const resolved = await ctx.getSenderAddress();
|
|
70108
|
+
senderXmtpAddress = resolved ? resolved : null;
|
|
70109
|
+
} catch (err2) {
|
|
70110
|
+
logWithTimestamp(
|
|
70111
|
+
`[okx-agent-task:${deps.myXmtpAddress}] subscription sender address unresolved (degrading to null) conv=${conversationId} message=${shortenLogValue(messageId)}:`,
|
|
70112
|
+
err2
|
|
70113
|
+
);
|
|
70114
|
+
}
|
|
70115
|
+
const fanoutResult = await fanOutSubscriptionJobs({
|
|
70116
|
+
jobs: normalizedJobs,
|
|
70117
|
+
myXmtpAddress: deps.myXmtpAddress,
|
|
70118
|
+
messageId,
|
|
70119
|
+
dispatch: async (job, idempotencyKey) => {
|
|
70120
|
+
const sessionKey = buildSessionKey({
|
|
70121
|
+
jobId: job.jobId,
|
|
70122
|
+
myAgentId: job.userAgentId,
|
|
70123
|
+
toAgentId: job.aspAgentId
|
|
70124
|
+
});
|
|
70125
|
+
deps.sessionStore?.upsertSession({
|
|
70126
|
+
sessionKey,
|
|
70127
|
+
jobId: job.jobId,
|
|
70128
|
+
myAgentId: job.userAgentId,
|
|
70129
|
+
toAgentId: job.aspAgentId,
|
|
70130
|
+
groupId: job.conversationId,
|
|
70131
|
+
myAgentXmtpAddress: deps.myXmtpAddress,
|
|
70132
|
+
toAgentXmtpAddress: senderXmtpAddress
|
|
70133
|
+
});
|
|
70134
|
+
return deps.onSessionMessage?.({
|
|
70135
|
+
sessionKey,
|
|
70136
|
+
content: JSON.stringify({
|
|
70137
|
+
msgType: job.msgType,
|
|
70138
|
+
content: job.content,
|
|
70139
|
+
...job.deliveryId ? { deliveryId: job.deliveryId } : {},
|
|
70140
|
+
jobId: job.jobId,
|
|
70141
|
+
userAgentId: job.userAgentId,
|
|
70142
|
+
aspAgentId: job.aspAgentId,
|
|
70143
|
+
conversationId: job.conversationId,
|
|
70144
|
+
senderInboxId: job.senderInboxId,
|
|
70145
|
+
// Raw XMTP messageId preserved for sender/receiver telemetry join;
|
|
70146
|
+
// the durable dedup identity is the idempotencyKey passed as this
|
|
70147
|
+
// session-message's own `messageId` field below (M1 fix).
|
|
70148
|
+
xmtpMessageId: messageId
|
|
70149
|
+
}),
|
|
70150
|
+
messageId: idempotencyKey,
|
|
70151
|
+
// Durable exactly-once enqueue key (M2): the wiring persists via
|
|
70152
|
+
// CommandStore.submitIdempotent keyed on sessionKey+messageId so a
|
|
70153
|
+
// re-processed / replayed message never creates a second command.
|
|
70154
|
+
idempotencyKey,
|
|
70155
|
+
jobId: job.jobId,
|
|
70156
|
+
agentId: job.userAgentId
|
|
70157
|
+
});
|
|
70158
|
+
}
|
|
70159
|
+
});
|
|
70160
|
+
logWithTimestamp(
|
|
70161
|
+
`[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)}`
|
|
70162
|
+
);
|
|
70163
|
+
const normalizedJobsById = new Map(normalizedJobs.map((job) => [job.jobId, job]));
|
|
70164
|
+
for (const result of fanoutResult.results) {
|
|
70165
|
+
const job = normalizedJobsById.get(result.jobId);
|
|
70166
|
+
if (result.outcome === "started") {
|
|
70167
|
+
logger.info(
|
|
70168
|
+
LogEvent.SUBSCRIPTION_JOB_DISPATCHED,
|
|
70169
|
+
buildSubscriptionJobExtras({
|
|
70170
|
+
checkpoint: "dispatch/subscription_job_dispatched",
|
|
70171
|
+
outcome: "success",
|
|
70172
|
+
jobId: result.jobId,
|
|
70173
|
+
userAgentId: agenticId,
|
|
70174
|
+
aspAgentId: job?.aspAgentId,
|
|
70175
|
+
conversationId,
|
|
70176
|
+
deliveryId: envelope.deliveryId
|
|
70177
|
+
})
|
|
70178
|
+
);
|
|
70179
|
+
} else if (result.outcome === "duplicate") {
|
|
70180
|
+
logger.info(
|
|
70181
|
+
LogEvent.SUBSCRIPTION_JOB_DUPLICATE_IGNORED,
|
|
70182
|
+
buildSubscriptionJobExtras({
|
|
70183
|
+
checkpoint: "dispatch/subscription_job_duplicate_ignored",
|
|
70184
|
+
outcome: "ignored",
|
|
70185
|
+
jobId: result.jobId,
|
|
70186
|
+
userAgentId: agenticId,
|
|
70187
|
+
aspAgentId: job?.aspAgentId,
|
|
70188
|
+
conversationId,
|
|
70189
|
+
deliveryId: envelope.deliveryId,
|
|
70190
|
+
reason: "duplicate_delivery"
|
|
70191
|
+
})
|
|
70192
|
+
);
|
|
70193
|
+
} else {
|
|
70194
|
+
logger.error(
|
|
70195
|
+
LogEvent.SUBSCRIPTION_JOB_FAILED,
|
|
70196
|
+
toLoggableError(result.error),
|
|
70197
|
+
buildSubscriptionJobExtras({
|
|
70198
|
+
checkpoint: "dispatch/subscription_job_failed",
|
|
70199
|
+
outcome: "failed",
|
|
70200
|
+
jobId: result.jobId,
|
|
70201
|
+
userAgentId: agenticId,
|
|
70202
|
+
aspAgentId: job?.aspAgentId,
|
|
70203
|
+
conversationId,
|
|
70204
|
+
deliveryId: envelope.deliveryId,
|
|
70205
|
+
reason: "session_dispatch_failed"
|
|
70206
|
+
})
|
|
70207
|
+
);
|
|
70208
|
+
}
|
|
70209
|
+
}
|
|
70210
|
+
logger.info(
|
|
70211
|
+
LogEvent.SUBSCRIPTION_FANOUT_SUMMARY,
|
|
70212
|
+
buildSubscriptionJobExtras({
|
|
70213
|
+
checkpoint: "dispatch/subscription_fanout_summary",
|
|
70214
|
+
outcome: fanoutResult.failed === 0 ? "success" : fanoutResult.started > 0 || fanoutResult.skippedDuplicate > 0 ? "partial" : "failed",
|
|
70215
|
+
conversationId,
|
|
70216
|
+
userAgentId: agenticId,
|
|
70217
|
+
total: fanoutResult.total,
|
|
70218
|
+
started: fanoutResult.started,
|
|
70219
|
+
failed: fanoutResult.failed,
|
|
70220
|
+
skippedDuplicate: fanoutResult.skippedDuplicate
|
|
70221
|
+
})
|
|
70222
|
+
);
|
|
70223
|
+
return true;
|
|
70224
|
+
}
|
|
68962
70225
|
async function processFileMessage(ctx, deps, options = {}) {
|
|
68963
70226
|
const messageId = ctx.message.id ?? "";
|
|
68964
70227
|
const timing = createInboundTimingTracker(extractXmtpSentAtMs2(ctx.message));
|
|
70228
|
+
const subscriptionPrecheckRawText = extractRawText(ctx.message.content);
|
|
70229
|
+
const subscriptionPrecheckParse = parseJson2(subscriptionPrecheckRawText);
|
|
70230
|
+
if (subscriptionPrecheckParse.ok && isSubscriptionEnvelope(subscriptionPrecheckParse.data)) {
|
|
70231
|
+
const { chatType: subscriptionChatType, conversationId: subscriptionConversationId } = getConversationInfo(ctx.conversation);
|
|
70232
|
+
const gateDecision = decideSubscriptionGate({
|
|
70233
|
+
// getConversationInfo's declared StoredChatType also lists "system",
|
|
70234
|
+
// but that value is only ever produced for stored-message bookkeeping
|
|
70235
|
+
// elsewhere in this file — the conversation-type branch above never
|
|
70236
|
+
// returns it, so this narrowing is safe.
|
|
70237
|
+
chatType: subscriptionChatType === "system" ? "unknown" : subscriptionChatType,
|
|
70238
|
+
payload: subscriptionPrecheckParse.data,
|
|
70239
|
+
senderInboxId: ctx.message.senderInboxId ?? ""
|
|
70240
|
+
});
|
|
70241
|
+
return processSubscriptionInbound(ctx, deps, {
|
|
70242
|
+
decision: gateDecision,
|
|
70243
|
+
conversationId: subscriptionConversationId,
|
|
70244
|
+
messageId: messageId || `subscription-${(0, import_node_crypto15.randomUUID)()}`
|
|
70245
|
+
});
|
|
70246
|
+
}
|
|
68965
70247
|
if (messageId && !tryMarkProcessed(messageId)) {
|
|
68966
70248
|
logWithTimestamp(`[okx-agent-task:${deps.myXmtpAddress}] duplicate message ignored: ${messageId}`);
|
|
68967
70249
|
logger.info(LogEvent.INBOUND_IGNORED_DUPLICATE, timing.extras({
|
|
@@ -68984,19 +70266,6 @@ async function processFileMessage(ctx, deps, options = {}) {
|
|
|
68984
70266
|
chatType,
|
|
68985
70267
|
...extra
|
|
68986
70268
|
});
|
|
68987
|
-
if (chatType === "dm") {
|
|
68988
|
-
const dmTrustStartedAt = Date.now();
|
|
68989
|
-
const trusted = await isTrustedDmSender({
|
|
68990
|
-
myXmtpAddress: deps.myXmtpAddress,
|
|
68991
|
-
senderInboxId: ctx.message.senderInboxId ?? "",
|
|
68992
|
-
messageId,
|
|
68993
|
-
conversationId
|
|
68994
|
-
});
|
|
68995
|
-
timing.mark("dmTrustCheck", dmTrustStartedAt);
|
|
68996
|
-
if (!trusted) {
|
|
68997
|
-
return true;
|
|
68998
|
-
}
|
|
68999
|
-
}
|
|
69000
70269
|
const parseStartedAt = Date.now();
|
|
69001
70270
|
const receivedRawText = extractRawText(ctx.message.content);
|
|
69002
70271
|
const parseResult = parseJson2(receivedRawText);
|
|
@@ -69012,9 +70281,26 @@ async function processFileMessage(ctx, deps, options = {}) {
|
|
|
69012
70281
|
}
|
|
69013
70282
|
}
|
|
69014
70283
|
timing.mark("payloadParse", parseStartedAt);
|
|
70284
|
+
const parsedDmData = parseResult.ok ? parseResult.data : null;
|
|
70285
|
+
const parsedDmMessage = isPlainObject5(parsedDmData) && isPlainObject5(parsedDmData.message) ? parsedDmData.message : null;
|
|
70286
|
+
const dmCarriesSystemMarkers = parsedDmMessage?.isDirectToUser === true || parsedDmMessage?.source === "system" || parsedDmMessage?.isDirectCommunication === true;
|
|
70287
|
+
const isA2ADm = chatType === "dm" && parseResult.ok && isA2AEnvelope(parseResult.data) && !dmCarriesSystemMarkers;
|
|
70288
|
+
if (chatType === "dm" && !isA2ADm) {
|
|
70289
|
+
const dmTrustStartedAt = Date.now();
|
|
70290
|
+
const trusted = await isTrustedDmSender({
|
|
70291
|
+
myXmtpAddress: deps.myXmtpAddress,
|
|
70292
|
+
senderInboxId: ctx.message.senderInboxId ?? "",
|
|
70293
|
+
messageId,
|
|
70294
|
+
conversationId
|
|
70295
|
+
});
|
|
70296
|
+
timing.mark("dmTrustCheck", dmTrustStartedAt);
|
|
70297
|
+
if (!trusted) {
|
|
70298
|
+
return true;
|
|
70299
|
+
}
|
|
70300
|
+
}
|
|
69015
70301
|
const directToUser = chatType === "dm" && parseResult.ok ? extractDirectToUserNotification(parseResult.data) : { kind: "none" };
|
|
69016
70302
|
if (directToUser.kind === "invalid") {
|
|
69017
|
-
const droppedMessageId = messageId || `direct-to-user-${(0,
|
|
70303
|
+
const droppedMessageId = messageId || `direct-to-user-${(0, import_node_crypto15.randomUUID)()}`;
|
|
69018
70304
|
logger.error(
|
|
69019
70305
|
LogEvent.INBOUND_DROP_DM_INVALID_PAYLOAD,
|
|
69020
70306
|
new Error("Invalid direct-to-user system DM"),
|
|
@@ -69038,7 +70324,7 @@ async function processFileMessage(ctx, deps, options = {}) {
|
|
|
69038
70324
|
await dispatchDirectToUserNotification({
|
|
69039
70325
|
deps,
|
|
69040
70326
|
notification: directToUser.notification,
|
|
69041
|
-
messageId: messageId || `direct-to-user-${(0,
|
|
70327
|
+
messageId: messageId || `direct-to-user-${(0, import_node_crypto15.randomUUID)()}`,
|
|
69042
70328
|
timing,
|
|
69043
70329
|
source: options.source ?? "live"
|
|
69044
70330
|
});
|
|
@@ -69046,7 +70332,7 @@ async function processFileMessage(ctx, deps, options = {}) {
|
|
|
69046
70332
|
}
|
|
69047
70333
|
const systemNotification = chatType === "dm" && parseResult.ok ? extractSystemNotification(parseResult.data) : null;
|
|
69048
70334
|
if (systemNotification) {
|
|
69049
|
-
const systemMessageId = messageId || `system-${(0,
|
|
70335
|
+
const systemMessageId = messageId || `system-${(0, import_node_crypto15.randomUUID)()}`;
|
|
69050
70336
|
logWithTimestamp(
|
|
69051
70337
|
`[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)}`
|
|
69052
70338
|
);
|
|
@@ -69207,7 +70493,7 @@ async function processFileMessage(ctx, deps, options = {}) {
|
|
|
69207
70493
|
timing.mark("routeResolve", routeStartedAt);
|
|
69208
70494
|
if (route.route === "job" && parseResult.ok && isA2AEnvelope(parseResult.data) && !isValidExternalJobId(route.jobId)) {
|
|
69209
70495
|
const payloadObject = parseResult.data;
|
|
69210
|
-
const sender =
|
|
70496
|
+
const sender = isPlainObject5(payloadObject.sender) ? payloadObject.sender : null;
|
|
69211
70497
|
logWithTimestamp(
|
|
69212
70498
|
`[okx-agent-task:${deps.myXmtpAddress}] inbound A2A message has invalid jobId, dropping: jobLength=${route.jobId.length} group=${conversationId}`
|
|
69213
70499
|
);
|
|
@@ -69236,7 +70522,32 @@ async function processFileMessage(ctx, deps, options = {}) {
|
|
|
69236
70522
|
});
|
|
69237
70523
|
return true;
|
|
69238
70524
|
}
|
|
69239
|
-
if (route.route
|
|
70525
|
+
if (isA2ADm && route.route !== "job") {
|
|
70526
|
+
const payloadObject = parseResult.data;
|
|
70527
|
+
const sender = isPlainObject5(payloadObject.sender) ? payloadObject.sender : null;
|
|
70528
|
+
recordInvalidXmtpMessageBestEffort({
|
|
70529
|
+
messageId,
|
|
70530
|
+
groupId: conversationId,
|
|
70531
|
+
jobId: null,
|
|
70532
|
+
agentId: readString5(sender?.agentId),
|
|
70533
|
+
localAgentId: XmtpService.getInstance().getAgentByAddress(deps.myXmtpAddress)?.agentId ?? null,
|
|
70534
|
+
senderInboxId: ctx.message.senderInboxId ?? "",
|
|
70535
|
+
reason: "dm_a2a_missing_job_id",
|
|
70536
|
+
stage: "inbound/job_id_validation",
|
|
70537
|
+
logTag: `[okx-agent-task:${deps.myXmtpAddress}]`
|
|
70538
|
+
});
|
|
70539
|
+
logger.info(LogEvent.INBOUND_DROP_INVALID_JOBID, {
|
|
70540
|
+
...agentExtras({ walletAddress: deps.myXmtpAddress }),
|
|
70541
|
+
conversationId,
|
|
70542
|
+
messageId,
|
|
70543
|
+
chatType,
|
|
70544
|
+
peerInboxId: ctx.message.senderInboxId ?? "",
|
|
70545
|
+
...inboundStageExtras("inbound/job_id_validation", "dropped"),
|
|
70546
|
+
reason: "dm_a2a_missing_job_id"
|
|
70547
|
+
});
|
|
70548
|
+
return true;
|
|
70549
|
+
}
|
|
70550
|
+
if (route.route === "job" && chatType !== "group" && !isA2ADm) {
|
|
69240
70551
|
const providerBindStartedAt = Date.now();
|
|
69241
70552
|
const providerGate = await bindMessageJobProviderToCurrentDefault(deps, route.jobId, "inbound-xmtp");
|
|
69242
70553
|
timing.mark("providerBind", providerBindStartedAt);
|
|
@@ -69276,7 +70587,7 @@ async function processFileMessage(ctx, deps, options = {}) {
|
|
|
69276
70587
|
);
|
|
69277
70588
|
}
|
|
69278
70589
|
if (route.route === "job" && chatType === "group") {
|
|
69279
|
-
const payloadObject =
|
|
70590
|
+
const payloadObject = isPlainObject5(parseResult.ok ? parseResult.data : null) ? parseResult.data : null;
|
|
69280
70591
|
const service = XmtpService.getInstance();
|
|
69281
70592
|
const trustedSystemSender = service.isTrustedSystemAccountSender({
|
|
69282
70593
|
senderAddress,
|
|
@@ -69302,7 +70613,7 @@ async function processFileMessage(ctx, deps, options = {}) {
|
|
|
69302
70613
|
});
|
|
69303
70614
|
return true;
|
|
69304
70615
|
}
|
|
69305
|
-
const sender =
|
|
70616
|
+
const sender = isPlainObject5(payloadObject?.sender) ? payloadObject.sender : null;
|
|
69306
70617
|
const localAgent = service.getAgentByAddress(deps.myXmtpAddress);
|
|
69307
70618
|
const myAgentId = localAgent?.agentId ?? readString5(payloadObject?.receiverAgentId) ?? sessionAgentId ?? null;
|
|
69308
70619
|
const toAgentId = readString5(sender?.agentId);
|
|
@@ -69342,7 +70653,7 @@ async function processFileMessage(ctx, deps, options = {}) {
|
|
|
69342
70653
|
}));
|
|
69343
70654
|
return true;
|
|
69344
70655
|
}
|
|
69345
|
-
const routedMessageId = messageId || `group-${(0,
|
|
70656
|
+
const routedMessageId = messageId || `group-${(0, import_node_crypto15.randomUUID)()}`;
|
|
69346
70657
|
const sessionKey = ensureInboundGroupSession(deps, {
|
|
69347
70658
|
jobId: route.jobId,
|
|
69348
70659
|
myAgentId,
|
|
@@ -69407,8 +70718,102 @@ async function processFileMessage(ctx, deps, options = {}) {
|
|
|
69407
70718
|
);
|
|
69408
70719
|
return true;
|
|
69409
70720
|
}
|
|
70721
|
+
if (route.route === "job" && isA2ADm) {
|
|
70722
|
+
const payloadObject = parseResult.data;
|
|
70723
|
+
const accepted = await verifyInboundA2AGroupMessage({
|
|
70724
|
+
payload: parseResult.data,
|
|
70725
|
+
myXmtpAddress: deps.myXmtpAddress,
|
|
70726
|
+
senderAddress,
|
|
70727
|
+
senderInboxId: ctx.message.senderInboxId ?? "",
|
|
70728
|
+
jobId: route.jobId,
|
|
70729
|
+
groupId: conversationId,
|
|
70730
|
+
messageId,
|
|
70731
|
+
consentState: void 0,
|
|
70732
|
+
trustedSystemSender: false,
|
|
70733
|
+
isOfflineReplay: options.isOfflineReplay ?? false,
|
|
70734
|
+
timing
|
|
70735
|
+
});
|
|
70736
|
+
if (!accepted) {
|
|
70737
|
+
return true;
|
|
70738
|
+
}
|
|
70739
|
+
const providerBindStartedAt = Date.now();
|
|
70740
|
+
const providerGate = await bindMessageJobProviderToCurrentDefault(deps, route.jobId, "inbound-xmtp");
|
|
70741
|
+
timing.mark("providerBind", providerBindStartedAt);
|
|
70742
|
+
if (!providerGate.allowed) {
|
|
70743
|
+
logger.info(LogEvent.INBOUND_IGNORED_NON_BUSINESS, timing.extras({
|
|
70744
|
+
...buildInboundTerminalExtras({
|
|
70745
|
+
terminalState: "provider_gate_denied",
|
|
70746
|
+
myXmtpAddress: deps.myXmtpAddress,
|
|
70747
|
+
messageId,
|
|
70748
|
+
conversationId,
|
|
70749
|
+
chatType,
|
|
70750
|
+
jobId: route.jobId,
|
|
70751
|
+
route: route.route,
|
|
70752
|
+
reason: "job_provider_gate_denied"
|
|
70753
|
+
}),
|
|
70754
|
+
routeReason: route.routeReason,
|
|
70755
|
+
providerBinding: providerGate.provider ?? ""
|
|
70756
|
+
}));
|
|
70757
|
+
return true;
|
|
70758
|
+
}
|
|
70759
|
+
const myAgentId = XmtpService.getInstance().getAgentByAddress(deps.myXmtpAddress)?.agentId ?? readString5(payloadObject.receiverAgentId) ?? sessionAgentId ?? null;
|
|
70760
|
+
const sender = isPlainObject5(payloadObject.sender) ? payloadObject.sender : null;
|
|
70761
|
+
const toAgentId = readString5(sender?.agentId);
|
|
70762
|
+
const routedMessageId = messageId || `dm-${(0, import_node_crypto15.randomUUID)()}`;
|
|
70763
|
+
const sessionKey = ensureInboundGroupSession(deps, {
|
|
70764
|
+
jobId: route.jobId,
|
|
70765
|
+
myAgentId,
|
|
70766
|
+
toAgentId,
|
|
70767
|
+
groupId: null,
|
|
70768
|
+
toAgentXmtpAddress: senderAddress || readString5(payloadObject.fromXmtpAddress)
|
|
70769
|
+
});
|
|
70770
|
+
const dispatchStartedAt = Date.now();
|
|
70771
|
+
void Promise.resolve(deps.onSessionMessage?.({
|
|
70772
|
+
sessionKey,
|
|
70773
|
+
content: rawText,
|
|
70774
|
+
messageId: routedMessageId,
|
|
70775
|
+
jobId: route.jobId,
|
|
70776
|
+
agentId: myAgentId
|
|
70777
|
+
})).then(() => {
|
|
70778
|
+
timing.mark("sessionDispatch", dispatchStartedAt);
|
|
70779
|
+
logger.info(LogEvent.INBOUND_DELIVERED, commonDeliveryExtras({
|
|
70780
|
+
taskId: route.jobId,
|
|
70781
|
+
agentId: myAgentId ?? "",
|
|
70782
|
+
peerWalletAddress: senderAddress,
|
|
70783
|
+
peerInboxId: ctx.message.senderInboxId ?? "",
|
|
70784
|
+
peerAgentId: toAgentId ?? "",
|
|
70785
|
+
sessionKey,
|
|
70786
|
+
messageId: routedMessageId,
|
|
70787
|
+
route: "dm",
|
|
70788
|
+
...inboundStageExtras("inbound/dm_session_dispatch", "success"),
|
|
70789
|
+
dispatchTarget: deps.onSessionMessage ? "session" : "none"
|
|
70790
|
+
}));
|
|
70791
|
+
}).catch((err2) => {
|
|
70792
|
+
logWithTimestamp(`[okx-agent-task:${deps.myXmtpAddress}] onSessionMessage failed:`, err2);
|
|
70793
|
+
logger.error(LogEvent.INBOUND_DISPATCH_FAILED, toLoggableError(err2), timing.extras({
|
|
70794
|
+
...buildInboundTerminalExtras({
|
|
70795
|
+
terminalState: "dispatch_failed",
|
|
70796
|
+
myXmtpAddress: deps.myXmtpAddress,
|
|
70797
|
+
messageId: routedMessageId,
|
|
70798
|
+
conversationId,
|
|
70799
|
+
chatType,
|
|
70800
|
+
jobId: route.jobId,
|
|
70801
|
+
sessionKey,
|
|
70802
|
+
route: "dm",
|
|
70803
|
+
reason: "session_dispatch_failed"
|
|
70804
|
+
}),
|
|
70805
|
+
checkpoint: "inbound/dm_session_dispatch_failed",
|
|
70806
|
+
agentId: myAgentId ?? "",
|
|
70807
|
+
peerAgentId: toAgentId ?? ""
|
|
70808
|
+
}));
|
|
70809
|
+
});
|
|
70810
|
+
logWithTimestamp(
|
|
70811
|
+
`[okx-agent-task:${deps.myXmtpAddress}] session dispatch queued route=dm session=${sessionKey} message=${shortenLogValue(routedMessageId)} ${summarizePayloadForLog(parseResult.data)}`
|
|
70812
|
+
);
|
|
70813
|
+
return true;
|
|
70814
|
+
}
|
|
69410
70815
|
const stored = {
|
|
69411
|
-
id: messageId || `local-${(0,
|
|
70816
|
+
id: messageId || `local-${(0, import_node_crypto15.randomUUID)()}`,
|
|
69412
70817
|
direction: "inbound",
|
|
69413
70818
|
route: route.route,
|
|
69414
70819
|
routeReason: route.routeReason,
|
|
@@ -69426,8 +70831,8 @@ async function processFileMessage(ctx, deps, options = {}) {
|
|
|
69426
70831
|
await deps.store.append(route.jobId, stored, sessionAgentId);
|
|
69427
70832
|
timing.mark("storeAppend", storeAppendStartedAt);
|
|
69428
70833
|
if ((route.route === "job" || parseResult.ok && !isA2AEnvelope(stored.payload)) && !options.skipNotify) {
|
|
69429
|
-
const payloadObject =
|
|
69430
|
-
const sender =
|
|
70834
|
+
const payloadObject = isPlainObject5(stored.payload) ? stored.payload : null;
|
|
70835
|
+
const sender = isPlainObject5(payloadObject?.sender) ? payloadObject.sender : null;
|
|
69431
70836
|
const localAgent = XmtpService.getInstance().getAgentByAddress(deps.myXmtpAddress);
|
|
69432
70837
|
const sessionKey = route.route === "job" ? buildSessionKey({
|
|
69433
70838
|
jobId: route.jobId,
|
|
@@ -69445,8 +70850,8 @@ async function processFileMessage(ctx, deps, options = {}) {
|
|
|
69445
70850
|
});
|
|
69446
70851
|
}
|
|
69447
70852
|
if (route.route === "job" && chatType === "group" && conversationId && senderAddress) {
|
|
69448
|
-
const payloadObject =
|
|
69449
|
-
const sender =
|
|
70853
|
+
const payloadObject = isPlainObject5(stored.payload) ? stored.payload : null;
|
|
70854
|
+
const sender = isPlainObject5(payloadObject?.sender) ? payloadObject.sender : null;
|
|
69450
70855
|
await deps.store.updateXmtpSession(route.jobId, {
|
|
69451
70856
|
xmtpGroupId: conversationId,
|
|
69452
70857
|
myXmtpAddress: deps.myXmtpAddress,
|
|
@@ -69589,7 +70994,7 @@ function processOfflineFromCoreDeps(store, ctx, deps, options) {
|
|
|
69589
70994
|
function buildSystemStoredMessage(params) {
|
|
69590
70995
|
const now = Date.now();
|
|
69591
70996
|
return {
|
|
69592
|
-
id: params.id ?? `system-${now}-${(0,
|
|
70997
|
+
id: params.id ?? `system-${now}-${(0, import_node_crypto15.randomUUID)()}`,
|
|
69593
70998
|
direction: "system",
|
|
69594
70999
|
route: "backup",
|
|
69595
71000
|
routeReason: params.reason,
|
|
@@ -69605,14 +71010,14 @@ function buildSystemStoredMessage(params) {
|
|
|
69605
71010
|
};
|
|
69606
71011
|
}
|
|
69607
71012
|
function isA2AEnvelope(payload) {
|
|
69608
|
-
return
|
|
71013
|
+
return isPlainObject5(payload) && payload.msgType === A2A_MESSAGE_TYPE;
|
|
69609
71014
|
}
|
|
69610
|
-
var
|
|
71015
|
+
var import_node_crypto15, PROCESSED_IDS_MAX, processedMessageIds, EXTERNAL_JOB_ID_PATTERN, INBOUND_TRANSPORT, INBOUND_EVENT_FAMILY, INBOUND_TERMINAL_FIELDS;
|
|
69611
71016
|
var init_message_handler = __esm({
|
|
69612
71017
|
"src/message-handler.ts"() {
|
|
69613
71018
|
"use strict";
|
|
69614
71019
|
init_log();
|
|
69615
|
-
|
|
71020
|
+
import_node_crypto15 = require("node:crypto");
|
|
69616
71021
|
init_dist2();
|
|
69617
71022
|
init_a2a();
|
|
69618
71023
|
init_envelope_shared();
|
|
@@ -69627,6 +71032,10 @@ var init_message_handler = __esm({
|
|
|
69627
71032
|
init_session_store();
|
|
69628
71033
|
init_agent_message_notice();
|
|
69629
71034
|
init_ai_provider();
|
|
71035
|
+
init_subscription_envelope();
|
|
71036
|
+
init_subscription_inbound();
|
|
71037
|
+
init_list_jobs_by_verified_sender();
|
|
71038
|
+
init_subscription_telemetry();
|
|
69630
71039
|
PROCESSED_IDS_MAX = 1e3;
|
|
69631
71040
|
processedMessageIds = /* @__PURE__ */ new Map();
|
|
69632
71041
|
EXTERNAL_JOB_ID_PATTERN = /^0x[0-9a-fA-F]{64}$/;
|
|
@@ -69680,7 +71089,7 @@ function isOriginalParentProcessAlive(options) {
|
|
|
69680
71089
|
}
|
|
69681
71090
|
function registerUserAttentionWatcher(options) {
|
|
69682
71091
|
return options.store.registerUserAttentionWatcher({
|
|
69683
|
-
id: options.id ?? (0,
|
|
71092
|
+
id: options.id ?? (0, import_node_crypto16.randomUUID)(),
|
|
69684
71093
|
provider: options.provider,
|
|
69685
71094
|
jobId: options.jobId,
|
|
69686
71095
|
nowMs: options.nowMs ?? Date.now(),
|
|
@@ -69759,11 +71168,11 @@ function userWatchEventDeliveredSentryExtra(event) {
|
|
|
69759
71168
|
hasDecision: String(event.hasDecision)
|
|
69760
71169
|
};
|
|
69761
71170
|
}
|
|
69762
|
-
var
|
|
71171
|
+
var import_node_crypto16, USER_ATTENTION_WATCH_REPLACED_MESSAGE, USER_ATTENTION_WATCHER_SCAN_MS, USER_ATTENTION_WATCHER_TTL_MS, USER_ATTENTION_WATCH_PARENT_CHECK_MS;
|
|
69763
71172
|
var init_user_attention_watchers = __esm({
|
|
69764
71173
|
"src/user-attention-watchers.ts"() {
|
|
69765
71174
|
"use strict";
|
|
69766
|
-
|
|
71175
|
+
import_node_crypto16 = require("node:crypto");
|
|
69767
71176
|
init_sentry_logger();
|
|
69768
71177
|
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.";
|
|
69769
71178
|
USER_ATTENTION_WATCHER_SCAN_MS = 500;
|
|
@@ -69785,6 +71194,7 @@ __export(listener_exports, {
|
|
|
69785
71194
|
ListenerDeferredTaskScheduler: () => ListenerDeferredTaskScheduler,
|
|
69786
71195
|
ListenerMaintenanceGate: () => ListenerMaintenanceGate,
|
|
69787
71196
|
XMTP_CLIENT_RECYCLE_INTERVAL_ENV: () => XMTP_CLIENT_RECYCLE_INTERVAL_ENV,
|
|
71197
|
+
buildUpgradeRecommendationNotice: () => buildUpgradeRecommendationNotice,
|
|
69788
71198
|
getHermesGatewayPluginStatus: () => getHermesGatewayPluginStatus,
|
|
69789
71199
|
hermesConfigEnablesOkxA2a: () => hermesConfigEnablesOkxA2a,
|
|
69790
71200
|
isGatewayAvailableForHeartbeat: () => isGatewayAvailableForHeartbeat,
|
|
@@ -69801,6 +71211,34 @@ async function runHeartbeatRefreshCycle(options) {
|
|
|
69801
71211
|
const refresh = options.refresh && refreshAllowed ? await timeSettled(options.refresh) : void 0;
|
|
69802
71212
|
return { heartbeat, versionRefresh, refresh };
|
|
69803
71213
|
}
|
|
71214
|
+
function buildUpgradeRecommendationNotice(input) {
|
|
71215
|
+
const capability = input.capability?.trim() ?? "";
|
|
71216
|
+
if (capability === MESSAGE_ELIGIBLE_OFFLINE_REPLAY_HELP_TOKEN) {
|
|
71217
|
+
return {
|
|
71218
|
+
title: "OnchainOS upgrade recommended",
|
|
71219
|
+
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",
|
|
71220
|
+
idempotencyKey: UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY
|
|
71221
|
+
};
|
|
71222
|
+
}
|
|
71223
|
+
if (capability === LIST_JOBS_BY_VERIFIED_SENDER_HELP_TOKEN) {
|
|
71224
|
+
return {
|
|
71225
|
+
title: "OnchainOS upgrade required for Subscription Shared Group",
|
|
71226
|
+
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",
|
|
71227
|
+
idempotencyKey: LIST_JOBS_UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY
|
|
71228
|
+
};
|
|
71229
|
+
}
|
|
71230
|
+
const capabilitySlug = capability ? capability.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") : "";
|
|
71231
|
+
const idempotencyKey = capabilitySlug ? `system:onchainos-${capabilitySlug}-upgrade` : "system:onchainos-capability-upgrade";
|
|
71232
|
+
const capabilityLabel = capability || "a required capability";
|
|
71233
|
+
const reasonSuffix = input.reason?.trim() ? ` ${input.reason.trim()}` : "";
|
|
71234
|
+
return {
|
|
71235
|
+
title: "OnchainOS upgrade recommended",
|
|
71236
|
+
content: `The installed OnchainOS version does not support ${capabilityLabel}.${reasonSuffix} Upgrade OnchainOS to enable this capability.
|
|
71237
|
+
|
|
71238
|
+
Suggested command: onchainos upgrade`,
|
|
71239
|
+
idempotencyKey
|
|
71240
|
+
};
|
|
71241
|
+
}
|
|
69804
71242
|
function resolveOfflineReplayIntervalSec(systemConfig) {
|
|
69805
71243
|
const interval = systemConfig.offlineReplayInterval;
|
|
69806
71244
|
if (typeof interval !== "number" || !Number.isFinite(interval) || interval <= 0) {
|
|
@@ -70028,8 +71466,12 @@ async function runListenerWithLock(options, paths) {
|
|
|
70028
71466
|
onJobMessageStored: async (event) => {
|
|
70029
71467
|
await enqueueAiJobMessageDispatch({ commands, event });
|
|
70030
71468
|
},
|
|
71469
|
+
// Returns { created } so the V2 subscription fan-out can distinguish a
|
|
71470
|
+
// durable DB duplicate (idempotent success) from a fresh enqueue. V1
|
|
71471
|
+
// group/system callers ignore the return; their events carry no
|
|
71472
|
+
// idempotencyKey, so the plain submit path (unchanged) is used.
|
|
70031
71473
|
onSessionMessage: async (event) => {
|
|
70032
|
-
|
|
71474
|
+
return enqueueAiSessionMessageDispatchIdempotent({ commands, event });
|
|
70033
71475
|
}
|
|
70034
71476
|
}),
|
|
70035
71477
|
processOfflineMessage: (ctx, deps, replayOptions) => processOfflineFromCoreDeps(store, ctx, deps, {
|
|
@@ -70039,7 +71481,7 @@ async function runListenerWithLock(options, paths) {
|
|
|
70039
71481
|
await enqueueAiJobMessageDispatch({ commands, event });
|
|
70040
71482
|
},
|
|
70041
71483
|
onSessionMessage: async (event) => {
|
|
70042
|
-
|
|
71484
|
+
return enqueueAiSessionMessageDispatchIdempotent({ commands, event });
|
|
70043
71485
|
}
|
|
70044
71486
|
}),
|
|
70045
71487
|
notifySessionExpired: (command) => {
|
|
@@ -70057,12 +71499,12 @@ async function runListenerWithLock(options, paths) {
|
|
|
70057
71499
|
});
|
|
70058
71500
|
},
|
|
70059
71501
|
notifyUpgradeRecommendation: (input) => {
|
|
70060
|
-
const
|
|
71502
|
+
const notice = buildUpgradeRecommendationNotice(input);
|
|
70061
71503
|
void notifySystemMessageToUser({
|
|
70062
|
-
title:
|
|
70063
|
-
content:
|
|
71504
|
+
title: notice.title,
|
|
71505
|
+
content: notice.content,
|
|
70064
71506
|
store: sessionStore,
|
|
70065
|
-
idempotencyKey:
|
|
71507
|
+
idempotencyKey: notice.idempotencyKey
|
|
70066
71508
|
}).catch((err2) => {
|
|
70067
71509
|
logWithTimestamp(
|
|
70068
71510
|
`[okx-agent-task] upgrade recommendation notify failed component=${input.component} capability=${input.capability}:`,
|
|
@@ -70071,12 +71513,12 @@ async function runListenerWithLock(options, paths) {
|
|
|
70071
71513
|
});
|
|
70072
71514
|
}
|
|
70073
71515
|
});
|
|
70074
|
-
service.setPluginVersion("0.2.
|
|
71516
|
+
service.setPluginVersion("0.2.18-beta-4dd056b897-261015113839");
|
|
70075
71517
|
await service.init();
|
|
70076
71518
|
const pluginVersionStatus = service.pluginVersionStatus;
|
|
70077
71519
|
if (pluginVersionStatus.unavailable) {
|
|
70078
71520
|
throw new Error(
|
|
70079
|
-
`@okxweb3/a2a-node v${"0.2.
|
|
71521
|
+
`@okxweb3/a2a-node v${"0.2.18-beta-4dd056b897-261015113839"} is below the required minimum v${pluginVersionStatus.minVersion}`
|
|
70080
71522
|
);
|
|
70081
71523
|
}
|
|
70082
71524
|
const systemConfig = service.getSystemConfig();
|
|
@@ -70104,7 +71546,7 @@ async function runListenerWithLock(options, paths) {
|
|
|
70104
71546
|
onchainosAgentId: "*",
|
|
70105
71547
|
reason: "system-config missing sentryDsn",
|
|
70106
71548
|
pluginId: "@okxweb3/a2a-node",
|
|
70107
|
-
pluginVersion: "0.2.
|
|
71549
|
+
pluginVersion: "0.2.18-beta-4dd056b897-261015113839"
|
|
70108
71550
|
});
|
|
70109
71551
|
}
|
|
70110
71552
|
logWithTimestamp(
|
|
@@ -70454,7 +71896,7 @@ async function timeSettled(fn) {
|
|
|
70454
71896
|
return { durationMs: Date.now() - startedAt, error };
|
|
70455
71897
|
}
|
|
70456
71898
|
}
|
|
70457
|
-
var import_node_fs27, import_promises13, import_node_os10, import_node_path32, DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC, DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC, XMTP_CLIENT_RECYCLE_INTERVAL_ENV, HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS, AUTH_RECOVERY_PROBE_INTERVAL_MS, AUTH_RECOVERY_REFRESH_BACKOFF_MS, AgentRefreshAuthGate, AgentRefreshCoordinator, ListenerDeferredTaskScheduler, ListenerMaintenanceGate, UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY, SHUTDOWN_FORCE_RESOLVE_MS;
|
|
71899
|
+
var import_node_fs27, import_promises13, import_node_os10, import_node_path32, DEFAULT_OFFLINE_REPLAY_INTERVAL_SEC, DEFAULT_XMTP_CLIENT_RECYCLE_INTERVAL_SEC, XMTP_CLIENT_RECYCLE_INTERVAL_ENV, HEARTBEAT_GATEWAY_CHECK_TIMEOUT_MS, AUTH_RECOVERY_PROBE_INTERVAL_MS, AUTH_RECOVERY_REFRESH_BACKOFF_MS, AgentRefreshAuthGate, AgentRefreshCoordinator, ListenerDeferredTaskScheduler, ListenerMaintenanceGate, UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY, LIST_JOBS_UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY, SHUTDOWN_FORCE_RESOLVE_MS;
|
|
70458
71900
|
var init_listener = __esm({
|
|
70459
71901
|
"src/listener.ts"() {
|
|
70460
71902
|
"use strict";
|
|
@@ -70467,6 +71909,7 @@ var init_listener = __esm({
|
|
|
70467
71909
|
init_onchainos();
|
|
70468
71910
|
init_system_config();
|
|
70469
71911
|
init_offline_replay_capability();
|
|
71912
|
+
init_list_jobs_by_verified_sender();
|
|
70470
71913
|
init_signer();
|
|
70471
71914
|
init_bin();
|
|
70472
71915
|
init_xmtp_sdk();
|
|
@@ -70647,6 +72090,7 @@ var init_listener = __esm({
|
|
|
70647
72090
|
}
|
|
70648
72091
|
};
|
|
70649
72092
|
UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY = "system:onchainos-offline-replay-upgrade";
|
|
72093
|
+
LIST_JOBS_UPGRADE_RECOMMENDATION_IDEMPOTENCY_KEY = "system:onchainos-list-jobs-by-verified-sender-upgrade";
|
|
70650
72094
|
SHUTDOWN_FORCE_RESOLVE_MS = 5e3;
|
|
70651
72095
|
}
|
|
70652
72096
|
});
|
|
@@ -88736,7 +90180,7 @@ var require_fetch_pb = __commonJS({
|
|
|
88736
90180
|
}
|
|
88737
90181
|
});
|
|
88738
90182
|
}
|
|
88739
|
-
function
|
|
90183
|
+
function isPlainObject6(value) {
|
|
88740
90184
|
const isObject = Object.prototype.toString.call(value).slice(8, -1) === "Object";
|
|
88741
90185
|
const isObjLike = value !== null && isObject;
|
|
88742
90186
|
if (!isObjLike || !isObject) {
|
|
@@ -88759,7 +90203,7 @@ var require_fetch_pb = __commonJS({
|
|
|
88759
90203
|
const isNonEmptyPrimitiveArray = Array.isArray(value) && value.every((v) => isPrimitive(v)) && value.length > 0;
|
|
88760
90204
|
const isNonZeroValuePrimitive = isPrimitive(value) && !isZeroValuePrimitive(value);
|
|
88761
90205
|
let objectToMerge = {};
|
|
88762
|
-
if (
|
|
90206
|
+
if (isPlainObject6(value)) {
|
|
88763
90207
|
objectToMerge = flattenRequestPayload(value, newPath);
|
|
88764
90208
|
} else if (isNonZeroValuePrimitive || isNonEmptyPrimitiveArray) {
|
|
88765
90209
|
objectToMerge = { [newPath]: value };
|
|
@@ -114328,10 +115772,10 @@ var require_node4 = __commonJS({
|
|
|
114328
115772
|
|
|
114329
115773
|
// ../../node_modules/@xmtp/content-type-remote-attachment/dist/index.js
|
|
114330
115774
|
async function encrypt(plain, secret, additionalData) {
|
|
114331
|
-
const salt =
|
|
114332
|
-
const nonce =
|
|
115775
|
+
const salt = import_node_crypto17.webcrypto.getRandomValues(new Uint8Array(KDFSaltSize));
|
|
115776
|
+
const nonce = import_node_crypto17.webcrypto.getRandomValues(new Uint8Array(AESGCMNonceSize));
|
|
114333
115777
|
const key = await hkdf(secret, salt);
|
|
114334
|
-
const encrypted = await
|
|
115778
|
+
const encrypted = await import_node_crypto17.webcrypto.subtle.encrypt(aesGcmParams(nonce), key, plain);
|
|
114335
115779
|
return new Ciphertext({
|
|
114336
115780
|
aes256GcmHkdfSha256: {
|
|
114337
115781
|
payload: new Uint8Array(encrypted),
|
|
@@ -114345,7 +115789,7 @@ async function decrypt(encrypted, secret, additionalData) {
|
|
|
114345
115789
|
throw new Error("invalid payload ciphertext");
|
|
114346
115790
|
}
|
|
114347
115791
|
const key = await hkdf(secret, encrypted.aes256GcmHkdfSha256.hkdfSalt);
|
|
114348
|
-
const decrypted = await
|
|
115792
|
+
const decrypted = await import_node_crypto17.webcrypto.subtle.decrypt(aesGcmParams(encrypted.aes256GcmHkdfSha256.gcmNonce), key, encrypted.aes256GcmHkdfSha256.payload);
|
|
114349
115793
|
return new Uint8Array(decrypted);
|
|
114350
115794
|
}
|
|
114351
115795
|
function aesGcmParams(nonce, additionalData) {
|
|
@@ -114356,18 +115800,18 @@ function aesGcmParams(nonce, additionalData) {
|
|
|
114356
115800
|
return spec;
|
|
114357
115801
|
}
|
|
114358
115802
|
async function hkdf(secret, salt) {
|
|
114359
|
-
const key = await
|
|
115803
|
+
const key = await import_node_crypto17.webcrypto.subtle.importKey("raw", secret, "HKDF", false, [
|
|
114360
115804
|
"deriveKey"
|
|
114361
115805
|
]);
|
|
114362
|
-
return
|
|
115806
|
+
return import_node_crypto17.webcrypto.subtle.deriveKey({ name: "HKDF", hash: "SHA-256", salt, info: hkdfNoInfo }, key, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]);
|
|
114363
115807
|
}
|
|
114364
|
-
var import_proto,
|
|
115808
|
+
var import_proto, import_node_crypto17, ContentTypeAttachment, AttachmentCodec, KDFSaltSize, AESGCMNonceSize, AESGCMTagLength, Ciphertext, hkdfNoInfo, ContentTypeRemoteAttachment, RemoteAttachmentCodec;
|
|
114365
115809
|
var init_dist6 = __esm({
|
|
114366
115810
|
"../../node_modules/@xmtp/content-type-remote-attachment/dist/index.js"() {
|
|
114367
115811
|
init_dist5();
|
|
114368
115812
|
init_secp256k12();
|
|
114369
115813
|
import_proto = __toESM(require_node4(), 1);
|
|
114370
|
-
|
|
115814
|
+
import_node_crypto17 = require("node:crypto");
|
|
114371
115815
|
ContentTypeAttachment = new ContentTypeId({
|
|
114372
115816
|
authorityId: "xmtp.org",
|
|
114373
115817
|
typeId: "attachment",
|
|
@@ -114447,7 +115891,7 @@ var init_dist6 = __esm({
|
|
|
114447
115891
|
if (payload.length === 0) {
|
|
114448
115892
|
throw new Error(`no payload for remote attachment at ${remoteAttachment.url}`);
|
|
114449
115893
|
}
|
|
114450
|
-
const digestBytes = new Uint8Array(await
|
|
115894
|
+
const digestBytes = new Uint8Array(await import_node_crypto17.webcrypto.subtle.digest("SHA-256", payload));
|
|
114451
115895
|
const digest = etc.bytesToHex(digestBytes);
|
|
114452
115896
|
if (digest !== remoteAttachment.contentDigest) {
|
|
114453
115897
|
throw new Error("content digest does not match");
|
|
@@ -114471,7 +115915,7 @@ var init_dist6 = __esm({
|
|
|
114471
115915
|
return codec.decode(encodedContent, codecRegistry);
|
|
114472
115916
|
}
|
|
114473
115917
|
static async encodeEncrypted(content$1, codec) {
|
|
114474
|
-
const secret =
|
|
115918
|
+
const secret = import_node_crypto17.webcrypto.getRandomValues(new Uint8Array(32));
|
|
114475
115919
|
const encodedContent = import_proto.content.EncodedContent.encode(codec.encode(content$1, {
|
|
114476
115920
|
codecFor() {
|
|
114477
115921
|
return void 0;
|
|
@@ -114484,7 +115928,7 @@ var init_dist6 = __esm({
|
|
|
114484
115928
|
if (!salt || !nonce || !payload) {
|
|
114485
115929
|
throw new Error("missing encryption key");
|
|
114486
115930
|
}
|
|
114487
|
-
const digestBytes = new Uint8Array(await
|
|
115931
|
+
const digestBytes = new Uint8Array(await import_node_crypto17.webcrypto.subtle.digest("SHA-256", payload));
|
|
114488
115932
|
const digest = etc.bytesToHex(digestBytes);
|
|
114489
115933
|
return {
|
|
114490
115934
|
digest,
|
|
@@ -114702,7 +116146,7 @@ async function uploadFile(params) {
|
|
|
114702
116146
|
const attachment = { filename, mimeType, data: new Uint8Array(data) };
|
|
114703
116147
|
const encrypted = await RemoteAttachmentCodec.encodeEncrypted(attachment, new AttachmentCodec());
|
|
114704
116148
|
ensureFileDirs();
|
|
114705
|
-
const encryptedPath = (0, import_node_path35.resolve)(FILE_WORK_DIR, `${(0,
|
|
116149
|
+
const encryptedPath = (0, import_node_path35.resolve)(FILE_WORK_DIR, `${(0, import_node_crypto18.randomUUID)()}.enc`);
|
|
114706
116150
|
(0, import_node_fs29.writeFileSync)(encryptedPath, encrypted.payload);
|
|
114707
116151
|
try {
|
|
114708
116152
|
const stdout = runOnchainos([
|
|
@@ -114746,7 +116190,7 @@ async function uploadFile(params) {
|
|
|
114746
116190
|
}
|
|
114747
116191
|
async function downloadFile(params) {
|
|
114748
116192
|
ensureFileDirs();
|
|
114749
|
-
const encryptedPath = (0, import_node_path35.resolve)(FILE_WORK_DIR, `${(0,
|
|
116193
|
+
const encryptedPath = (0, import_node_path35.resolve)(FILE_WORK_DIR, `${(0, import_node_crypto18.randomUUID)()}.enc`);
|
|
114750
116194
|
try {
|
|
114751
116195
|
const stdout = runOnchainos([
|
|
114752
116196
|
"agent",
|
|
@@ -114771,7 +116215,7 @@ async function downloadFile(params) {
|
|
|
114771
116215
|
throw new Error(`file download failed: ${stdout}`);
|
|
114772
116216
|
}
|
|
114773
116217
|
const payload = new Uint8Array((0, import_node_fs29.readFileSync)(encryptedPath));
|
|
114774
|
-
const digestBytes = new Uint8Array(await
|
|
116218
|
+
const digestBytes = new Uint8Array(await import_node_crypto18.webcrypto.subtle.digest("SHA-256", payload));
|
|
114775
116219
|
const actualDigest = Array.from(digestBytes).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
114776
116220
|
if (actualDigest !== params.digest) {
|
|
114777
116221
|
throw new Error(`file download digest verification failed: expected=${params.digest}, actual=${actualDigest}`);
|
|
@@ -114779,7 +116223,7 @@ async function downloadFile(params) {
|
|
|
114779
116223
|
const decryptedBytes = await decryptAttachmentPayload(payload, params);
|
|
114780
116224
|
const encodedContent = import_proto2.content.EncodedContent.decode(decryptedBytes);
|
|
114781
116225
|
const attachment = new AttachmentCodec().decode(encodedContent);
|
|
114782
|
-
const outputFilename = params.filename || attachment.filename || `${(0,
|
|
116226
|
+
const outputFilename = params.filename || attachment.filename || `${(0, import_node_crypto18.randomUUID)()}.bin`;
|
|
114783
116227
|
const outputDir = DOWNLOADS_DIR;
|
|
114784
116228
|
ensureA2aTaskDir(outputDir);
|
|
114785
116229
|
const outputPath = (0, import_node_path35.resolve)(outputDir, (0, import_node_path35.basename)(outputFilename));
|
|
@@ -114796,15 +116240,15 @@ async function decryptAttachmentPayload(payload, params) {
|
|
|
114796
116240
|
const secretBytes = new Uint8Array(Buffer.from(params.secret, "base64"));
|
|
114797
116241
|
const saltBytes = new Uint8Array(Buffer.from(params.salt, "base64"));
|
|
114798
116242
|
const nonceBytes = new Uint8Array(Buffer.from(params.nonce, "base64"));
|
|
114799
|
-
const hkdfKey = await
|
|
114800
|
-
const aesKey = await
|
|
116243
|
+
const hkdfKey = await import_node_crypto18.webcrypto.subtle.importKey("raw", secretBytes, "HKDF", false, ["deriveKey"]);
|
|
116244
|
+
const aesKey = await import_node_crypto18.webcrypto.subtle.deriveKey(
|
|
114801
116245
|
{ name: "HKDF", hash: "SHA-256", salt: saltBytes, info: new Uint8Array().buffer },
|
|
114802
116246
|
hkdfKey,
|
|
114803
116247
|
{ name: "AES-GCM", length: 256 },
|
|
114804
116248
|
false,
|
|
114805
116249
|
["decrypt"]
|
|
114806
116250
|
);
|
|
114807
|
-
return new Uint8Array(await
|
|
116251
|
+
return new Uint8Array(await import_node_crypto18.webcrypto.subtle.decrypt({ name: "AES-GCM", iv: nonceBytes }, aesKey, toArrayBuffer(payload)));
|
|
114808
116252
|
}
|
|
114809
116253
|
function toArrayBuffer(bytes) {
|
|
114810
116254
|
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
@@ -114944,12 +116388,12 @@ function readRequiredOption(args, name) {
|
|
|
114944
116388
|
}
|
|
114945
116389
|
return value;
|
|
114946
116390
|
}
|
|
114947
|
-
var
|
|
116391
|
+
var import_node_crypto18, import_node_fs29, import_node_path35, import_proto2, OKX_A2A_PATHS, OKX_A2A_HOME_DIR, FILE_WORK_DIR, DOWNLOADS_DIR, SYSTEM_CONFIG_PATH;
|
|
114948
116392
|
var init_file_cli = __esm({
|
|
114949
116393
|
"src/file-cli.ts"() {
|
|
114950
116394
|
"use strict";
|
|
114951
116395
|
init_win_spawn();
|
|
114952
|
-
|
|
116396
|
+
import_node_crypto18 = require("node:crypto");
|
|
114953
116397
|
import_node_fs29 = require("node:fs");
|
|
114954
116398
|
import_node_path35 = require("node:path");
|
|
114955
116399
|
init_dist6();
|
|
@@ -118447,7 +119891,7 @@ async function getCurrentNodeCliVersion() {
|
|
|
118447
119891
|
return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
|
|
118448
119892
|
}
|
|
118449
119893
|
function getBundledNodeCliVersion() {
|
|
118450
|
-
return true ? "0.2.
|
|
119894
|
+
return true ? "0.2.18-beta-4dd056b897-261015113839" : null;
|
|
118451
119895
|
}
|
|
118452
119896
|
function readConfiguredAiProvider() {
|
|
118453
119897
|
const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
|
|
@@ -118657,7 +120101,7 @@ async function updateHermes(release, options) {
|
|
|
118657
120101
|
}
|
|
118658
120102
|
}
|
|
118659
120103
|
async function installGatewayPluginForDoctor(target) {
|
|
118660
|
-
const release = isPrereleaseVersion("0.2.
|
|
120104
|
+
const release = isPrereleaseVersion("0.2.18-beta-4dd056b897-261015113839") ? "beta" : "latest";
|
|
118661
120105
|
const insideTargetGateway = detectGatewayInvocation() === target;
|
|
118662
120106
|
const options = {
|
|
118663
120107
|
restart: !insideTargetGateway,
|
|
@@ -119710,7 +121154,7 @@ async function runDoctor(options = {}) {
|
|
|
119710
121154
|
platform: options.platform ?? process.platform,
|
|
119711
121155
|
env: options.env ?? process.env,
|
|
119712
121156
|
target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
|
|
119713
|
-
cliVersion: options.cliVersion ?? (true ? "0.2.
|
|
121157
|
+
cliVersion: options.cliVersion ?? (true ? "0.2.18-beta-4dd056b897-261015113839" : "0.0.0"),
|
|
119714
121158
|
fixMode: options.fix === true,
|
|
119715
121159
|
nonInteractive: options.nonInteractive === true,
|
|
119716
121160
|
packageChanged: false,
|
|
@@ -120817,7 +122261,7 @@ init_sentry_config();
|
|
|
120817
122261
|
init_runtime_metadata();
|
|
120818
122262
|
var CURRENT_GATEWAY_SESSION_KEYS_ENV4 = "OKX_A2A_CURRENT_GATEWAY_SESSION_KEYS";
|
|
120819
122263
|
function printUsage3() {
|
|
120820
|
-
console.log(`okx-a2a ${"0.2.
|
|
122264
|
+
console.log(`okx-a2a ${"0.2.18-beta-4dd056b897-261015113839"}
|
|
120821
122265
|
|
|
120822
122266
|
Usage:
|
|
120823
122267
|
okx-a2a <command> [options]
|
|
@@ -120847,6 +122291,8 @@ Commands:
|
|
|
120847
122291
|
Alias for runtime switch-current
|
|
120848
122292
|
job-provider Manage job-to-provider bindings
|
|
120849
122293
|
xmtp-send Queue an XMTP message through the running daemon
|
|
122294
|
+
subscription-push
|
|
122295
|
+
Queue a V2 subscription push to one or more XMTP Group conversations
|
|
120850
122296
|
trade-records
|
|
120851
122297
|
Insert, query, and soft-delete local business trade records
|
|
120852
122298
|
capabilities Print machine-readable A2A capability negotiation status (used by OnchainOS)
|
|
@@ -120859,7 +122305,7 @@ Run \`okx-a2a <command> -h\` for command-specific help.
|
|
|
120859
122305
|
`);
|
|
120860
122306
|
}
|
|
120861
122307
|
function printVersion() {
|
|
120862
|
-
console.log("0.2.
|
|
122308
|
+
console.log("0.2.18-beta-4dd056b897-261015113839");
|
|
120863
122309
|
}
|
|
120864
122310
|
function printDaemonUsage() {
|
|
120865
122311
|
console.log(`Usage: okx-a2a daemon <start|restart|stop|status|autostart> [options]
|
|
@@ -120956,6 +122402,18 @@ Options:
|
|
|
120956
122402
|
--json Print machine-readable output with ok boolean
|
|
120957
122403
|
`);
|
|
120958
122404
|
}
|
|
122405
|
+
function printSubscriptionPushUsage() {
|
|
122406
|
+
console.log(`Usage: okx-a2a subscription-push --my-agent-id <id> --message <text> (--conversation-id <id> ... | --conversation-ids <id,id,...>) [options]
|
|
122407
|
+
|
|
122408
|
+
Options:
|
|
122409
|
+
--my-agent-id <id> Local sender agent id used to resolve the XMTP client
|
|
122410
|
+
--message <text> Subscription content
|
|
122411
|
+
--conversation-id <id> Target Group conversationId (repeatable)
|
|
122412
|
+
--conversation-ids <id,id> Comma-separated list of target Group conversationIds
|
|
122413
|
+
--delivery-id <id> Optional deliveryId carried in the V2 envelope
|
|
122414
|
+
--json Print machine-readable output with ok boolean
|
|
122415
|
+
`);
|
|
122416
|
+
}
|
|
120959
122417
|
function printCommandUsage(command) {
|
|
120960
122418
|
if (command === "daemon" || command === "start" || command === "restart" || command === "stop" || command === "status") {
|
|
120961
122419
|
printDaemonUsage();
|
|
@@ -121025,6 +122483,10 @@ function printCommandUsage(command) {
|
|
|
121025
122483
|
printXmtpSendUsage();
|
|
121026
122484
|
return true;
|
|
121027
122485
|
}
|
|
122486
|
+
if (command === "subscription-push") {
|
|
122487
|
+
printSubscriptionPushUsage();
|
|
122488
|
+
return true;
|
|
122489
|
+
}
|
|
121028
122490
|
if (command === "trade-records") {
|
|
121029
122491
|
printTradeRecordsUsageProxy();
|
|
121030
122492
|
return true;
|
|
@@ -121352,6 +122814,79 @@ async function queueXmtpSend(args) {
|
|
|
121352
122814
|
commands.close();
|
|
121353
122815
|
}
|
|
121354
122816
|
}
|
|
122817
|
+
async function queueXmtpSubscriptionPush(args) {
|
|
122818
|
+
if (hasHelpFlag5(args)) {
|
|
122819
|
+
printSubscriptionPushUsage();
|
|
122820
|
+
return;
|
|
122821
|
+
}
|
|
122822
|
+
assertOnlyKnownOptions(args, {
|
|
122823
|
+
command: "subscription-push",
|
|
122824
|
+
options: /* @__PURE__ */ new Set([
|
|
122825
|
+
"--my-agent-id",
|
|
122826
|
+
"--message",
|
|
122827
|
+
"--conversation-id",
|
|
122828
|
+
"--conversation-ids",
|
|
122829
|
+
"--delivery-id"
|
|
122830
|
+
]),
|
|
122831
|
+
flags: /* @__PURE__ */ new Set(["--json"])
|
|
122832
|
+
});
|
|
122833
|
+
const json = hasFlag2(args, "--json");
|
|
122834
|
+
const myAgentId = readOption5(args, "--my-agent-id");
|
|
122835
|
+
const content2 = readOption5(args, "--message");
|
|
122836
|
+
const deliveryId = readOption5(args, "--delivery-id");
|
|
122837
|
+
const conversationIds = readSubscriptionPushConversationIds(args);
|
|
122838
|
+
if (!myAgentId || !content2) {
|
|
122839
|
+
throw new Error("subscription-push requires --my-agent-id and --message");
|
|
122840
|
+
}
|
|
122841
|
+
await assertDaemonRunningForQueuedCommand2("subscription-push");
|
|
122842
|
+
const commands = new CommandStore();
|
|
122843
|
+
try {
|
|
122844
|
+
const command = commands.createXmtpSubscriptionPushCommand({
|
|
122845
|
+
myAgentId,
|
|
122846
|
+
content: content2,
|
|
122847
|
+
conversationIds,
|
|
122848
|
+
deliveryId
|
|
122849
|
+
});
|
|
122850
|
+
await commands.submit(command);
|
|
122851
|
+
const result = await commands.waitForResult(command.id, Number.POSITIVE_INFINITY);
|
|
122852
|
+
if (!result) {
|
|
122853
|
+
printSubscriptionPushCommandResult(json, {
|
|
122854
|
+
id: command.id,
|
|
122855
|
+
ok: false,
|
|
122856
|
+
completedAt: Date.now(),
|
|
122857
|
+
error: "subscription-push finished without result"
|
|
122858
|
+
});
|
|
122859
|
+
process.exitCode = 1;
|
|
122860
|
+
return;
|
|
122861
|
+
}
|
|
122862
|
+
if (!result.ok) {
|
|
122863
|
+
printSubscriptionPushCommandResult(json, result);
|
|
122864
|
+
process.exitCode = 1;
|
|
122865
|
+
return;
|
|
122866
|
+
}
|
|
122867
|
+
printSubscriptionPushCommandResult(json, result);
|
|
122868
|
+
} finally {
|
|
122869
|
+
commands.close();
|
|
122870
|
+
}
|
|
122871
|
+
}
|
|
122872
|
+
function readSubscriptionPushConversationIds(args) {
|
|
122873
|
+
const ids = /* @__PURE__ */ new Set();
|
|
122874
|
+
for (let i = 0; i < args.length; i++) {
|
|
122875
|
+
if (args[i] === "--conversation-id" && args[i + 1]) {
|
|
122876
|
+
ids.add(args[i + 1]);
|
|
122877
|
+
}
|
|
122878
|
+
}
|
|
122879
|
+
const commaList = readOption5(args, "--conversation-ids");
|
|
122880
|
+
if (commaList) {
|
|
122881
|
+
for (const item of commaList.split(",")) {
|
|
122882
|
+
const trimmed = item.trim();
|
|
122883
|
+
if (trimmed) {
|
|
122884
|
+
ids.add(trimmed);
|
|
122885
|
+
}
|
|
122886
|
+
}
|
|
122887
|
+
}
|
|
122888
|
+
return [...ids];
|
|
122889
|
+
}
|
|
121355
122890
|
function parseXmtpSendPayloadOption(raw) {
|
|
121356
122891
|
const trimmed = raw?.trim();
|
|
121357
122892
|
if (!trimmed) {
|
|
@@ -121661,6 +123196,23 @@ function printXmtpSendCommandResult(json, result) {
|
|
|
121661
123196
|
}
|
|
121662
123197
|
console.log(`ok=false xmtp-send failed command=${result.id} error=${result.error ?? "unknown error"}`);
|
|
121663
123198
|
}
|
|
123199
|
+
function printSubscriptionPushCommandResult(json, result) {
|
|
123200
|
+
const payload = result.payload;
|
|
123201
|
+
if (json) {
|
|
123202
|
+
console.log(JSON.stringify({
|
|
123203
|
+
ok: result.ok,
|
|
123204
|
+
commandId: result.id,
|
|
123205
|
+
payload: result.payload ?? null,
|
|
123206
|
+
error: result.error ?? null
|
|
123207
|
+
}));
|
|
123208
|
+
return;
|
|
123209
|
+
}
|
|
123210
|
+
if (result.ok) {
|
|
123211
|
+
console.log(`ok=true subscription-push command=${result.id} conversationCount=${payload?.conversationCount ?? 0} sentCount=${payload?.sentCount ?? 0} failedCount=${payload?.failedCount ?? 0}`);
|
|
123212
|
+
return;
|
|
123213
|
+
}
|
|
123214
|
+
console.log(`ok=false subscription-push failed command=${result.id} error=${result.error ?? "unknown error"}`);
|
|
123215
|
+
}
|
|
121664
123216
|
function formatDaemonCommandResult(type, result) {
|
|
121665
123217
|
if (!result.ok) {
|
|
121666
123218
|
return `ok=false ${type} command=${result.id} error=${result.error ?? "unknown error"}`;
|
|
@@ -122354,7 +123906,7 @@ async function main() {
|
|
|
122354
123906
|
if (command === "xmtp-test") {
|
|
122355
123907
|
const { handleXmtpTestCommand: handleXmtpTestCommand2 } = await Promise.resolve().then(() => (init_xmtp_test_cli(), xmtp_test_cli_exports));
|
|
122356
123908
|
await handleXmtpTestCommand2(process.argv.slice(3), {
|
|
122357
|
-
packageVersion: "0.2.
|
|
123909
|
+
packageVersion: "0.2.18-beta-4dd056b897-261015113839",
|
|
122358
123910
|
agentSdkVersion: "2.3.0",
|
|
122359
123911
|
nodeSdkVersion: "6.1.0",
|
|
122360
123912
|
nodeBindingsVersion: "1.11.0"
|
|
@@ -122367,6 +123919,12 @@ async function main() {
|
|
|
122367
123919
|
await flushDirectCliSentry();
|
|
122368
123920
|
return;
|
|
122369
123921
|
}
|
|
123922
|
+
if (command === "subscription-push") {
|
|
123923
|
+
await initDirectCliSentry();
|
|
123924
|
+
await queueXmtpSubscriptionPush(process.argv.slice(3));
|
|
123925
|
+
await flushDirectCliSentry();
|
|
123926
|
+
return;
|
|
123927
|
+
}
|
|
122370
123928
|
if (command === "task") {
|
|
122371
123929
|
await initDirectCliSentry();
|
|
122372
123930
|
await handleTaskCommand(process.argv.slice(3));
|