@okxweb3/a2a-node 0.1.4-beta-520175e226-260703171232 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +257 -56
- package/dist/index.js +53 -10
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -154,6 +154,20 @@ function buildSessionKey(input) {
|
|
|
154
154
|
encodeURIComponent(input.toAgentId || "unknown")
|
|
155
155
|
].join(":");
|
|
156
156
|
}
|
|
157
|
+
function isSqliteBusyError(err2) {
|
|
158
|
+
if (!(err2 instanceof Error)) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
const code2 = err2.errcode;
|
|
162
|
+
if (typeof code2 === "number" && ((code2 & 255) === 5 || (code2 & 255) === 6)) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
return /database is locked|database table is locked/i.test(err2.message);
|
|
166
|
+
}
|
|
167
|
+
function sleepSyncMs(ms) {
|
|
168
|
+
const buf = new Int32Array(new SharedArrayBuffer(4));
|
|
169
|
+
Atomics.wait(buf, 0, 0, ms);
|
|
170
|
+
}
|
|
157
171
|
function loadSqlite() {
|
|
158
172
|
const originalEmitWarning = process.emitWarning;
|
|
159
173
|
process.emitWarning = ((warning, ...args) => {
|
|
@@ -606,7 +620,28 @@ var init_session_store = __esm({
|
|
|
606
620
|
this.db = new DatabaseSync(this.dbPath);
|
|
607
621
|
this.ensureReady();
|
|
608
622
|
}
|
|
623
|
+
// Opening the store races other processes writing the same DB (daemon
|
|
624
|
+
// coordinator scans, other CLI watches). Two busy flavors both crash an
|
|
625
|
+
// unprotected open: schema DDL starving past busy_timeout, and the WAL
|
|
626
|
+
// journal-mode conversion which returns SQLITE_BUSY IMMEDIATELY under any
|
|
627
|
+
// concurrent writer (busy_timeout does not apply to it). Retry bounded with
|
|
628
|
+
// exponential backoff so the cumulative window (~7.75s) rides out real
|
|
629
|
+
// contention bursts instead of crashing on arrival.
|
|
609
630
|
ensureReady() {
|
|
631
|
+
const attempts = 6;
|
|
632
|
+
for (let attempt = 1; ; attempt += 1) {
|
|
633
|
+
try {
|
|
634
|
+
this.ensureReadyOnce();
|
|
635
|
+
return;
|
|
636
|
+
} catch (err2) {
|
|
637
|
+
if (!isSqliteBusyError(err2) || attempt >= attempts) {
|
|
638
|
+
throw err2;
|
|
639
|
+
}
|
|
640
|
+
sleepSyncMs(Math.min(250 * 2 ** (attempt - 1), 4e3));
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
ensureReadyOnce() {
|
|
610
645
|
this.db.exec("PRAGMA busy_timeout=5000");
|
|
611
646
|
this.db.exec("PRAGMA journal_mode=WAL");
|
|
612
647
|
this.db.exec("PRAGMA foreign_keys=ON");
|
|
@@ -1281,13 +1316,19 @@ var init_session_store = __esm({
|
|
|
1281
1316
|
};
|
|
1282
1317
|
});
|
|
1283
1318
|
}
|
|
1319
|
+
// Returns null when the watcher row no longer exists (e.g. TTL-expired after
|
|
1320
|
+
// heartbeats starved on a busy database) so the caller can re-register
|
|
1321
|
+
// instead of polling a row that will never receive events again.
|
|
1284
1322
|
heartbeatUserAttentionWatcher(watcher, nowMs) {
|
|
1285
1323
|
assertNonEmpty(watcher.id, "id");
|
|
1286
|
-
this.db.prepare(`
|
|
1324
|
+
const result = this.db.prepare(`
|
|
1287
1325
|
UPDATE user_attention_watchers
|
|
1288
1326
|
SET updated_at_ms = ?
|
|
1289
1327
|
WHERE id = ?
|
|
1290
1328
|
`).run(nowMs, watcher.id);
|
|
1329
|
+
if (Number(result.changes) === 0) {
|
|
1330
|
+
return null;
|
|
1331
|
+
}
|
|
1291
1332
|
return {
|
|
1292
1333
|
...watcher,
|
|
1293
1334
|
updatedAt: nowMs
|
|
@@ -8237,7 +8278,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
|
|
|
8237
8278
|
client: {
|
|
8238
8279
|
id: "gateway-client",
|
|
8239
8280
|
displayName: "okx-a2a-node",
|
|
8240
|
-
version: "0.1.4
|
|
8281
|
+
version: "0.1.4",
|
|
8241
8282
|
platform: "node",
|
|
8242
8283
|
mode: "backend",
|
|
8243
8284
|
instanceId
|
|
@@ -8248,7 +8289,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
|
|
|
8248
8289
|
commands: [],
|
|
8249
8290
|
permissions: {},
|
|
8250
8291
|
locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
|
|
8251
|
-
userAgent: `okx-a2a-node/${"0.1.4
|
|
8292
|
+
userAgent: `okx-a2a-node/${"0.1.4"}`,
|
|
8252
8293
|
auth: {
|
|
8253
8294
|
...config.token ? { token: config.token } : {},
|
|
8254
8295
|
...config.password ? { password: config.password } : {}
|
|
@@ -25504,7 +25545,7 @@ var init_sentry_config = __esm({
|
|
|
25504
25545
|
environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
|
|
25505
25546
|
SENTRY_CONFIG = {
|
|
25506
25547
|
projectName: "okx/openclaw-okx-a2a-extension",
|
|
25507
|
-
release: "0.1.4
|
|
25548
|
+
release: "0.1.4",
|
|
25508
25549
|
environment
|
|
25509
25550
|
};
|
|
25510
25551
|
}
|
|
@@ -94014,12 +94055,12 @@ async function runListenerWithLock(options, paths) {
|
|
|
94014
94055
|
}));
|
|
94015
94056
|
}
|
|
94016
94057
|
});
|
|
94017
|
-
service.setPluginVersion("0.1.4
|
|
94058
|
+
service.setPluginVersion("0.1.4");
|
|
94018
94059
|
await service.init();
|
|
94019
94060
|
const pluginVersionStatus = service.pluginVersionStatus;
|
|
94020
94061
|
if (pluginVersionStatus.unavailable) {
|
|
94021
94062
|
throw new Error(
|
|
94022
|
-
`@okxweb3/a2a-node v${"0.1.4
|
|
94063
|
+
`@okxweb3/a2a-node v${"0.1.4"} is below the required minimum v${pluginVersionStatus.minVersion}`
|
|
94023
94064
|
);
|
|
94024
94065
|
}
|
|
94025
94066
|
const systemConfig = service.getSystemConfig();
|
|
@@ -94037,7 +94078,7 @@ async function runListenerWithLock(options, paths) {
|
|
|
94037
94078
|
onchainosAgentId: "*",
|
|
94038
94079
|
reason: "system-config missing sentryDsn",
|
|
94039
94080
|
pluginId: "@okxweb3/a2a-node",
|
|
94040
|
-
pluginVersion: "0.1.4
|
|
94081
|
+
pluginVersion: "0.1.4"
|
|
94041
94082
|
});
|
|
94042
94083
|
}
|
|
94043
94084
|
logWithTimestamp(
|
|
@@ -95147,13 +95188,20 @@ async function watchUserAttentionLoop(store, parsed, json, options = {}) {
|
|
|
95147
95188
|
if (!parentMonitor.isAlive()) {
|
|
95148
95189
|
return;
|
|
95149
95190
|
}
|
|
95150
|
-
|
|
95151
|
-
|
|
95152
|
-
|
|
95153
|
-
|
|
95154
|
-
|
|
95155
|
-
|
|
95156
|
-
|
|
95191
|
+
let batch = null;
|
|
95192
|
+
try {
|
|
95193
|
+
batch = store.consumeUnseenUserAttentionForWatch(
|
|
95194
|
+
options.jobId || options.provider ? {
|
|
95195
|
+
...options.provider ? { provider: options.provider } : {},
|
|
95196
|
+
...options.jobId ? { jobId: options.jobId } : {}
|
|
95197
|
+
} : void 0
|
|
95198
|
+
);
|
|
95199
|
+
} catch (err2) {
|
|
95200
|
+
if (!isSqliteBusyError(err2)) {
|
|
95201
|
+
throw err2;
|
|
95202
|
+
}
|
|
95203
|
+
}
|
|
95204
|
+
if (batch && batch.items.length > 0) {
|
|
95157
95205
|
outputAttentionItems(json, batch.items, "User attention needed");
|
|
95158
95206
|
return;
|
|
95159
95207
|
}
|
|
@@ -95177,7 +95225,7 @@ async function watchUserAttentionViaDaemon(store, parsed, json, options) {
|
|
|
95177
95225
|
const timeoutMs = (readNumberOption(parsed, "timeout") ?? 0) * 1e3;
|
|
95178
95226
|
const pollMs = readNumberOption(parsed, "poll-ms") ?? 500;
|
|
95179
95227
|
const deadline = timeoutMs > 0 ? Date.now() + timeoutMs : null;
|
|
95180
|
-
const registration =
|
|
95228
|
+
const registration = await registerWatcherWithBusyRetry({
|
|
95181
95229
|
store,
|
|
95182
95230
|
provider: options.provider,
|
|
95183
95231
|
jobId: options.jobId
|
|
@@ -95205,7 +95253,14 @@ async function watchUserAttentionViaDaemon(store, parsed, json, options) {
|
|
|
95205
95253
|
if (!parentMonitor.isAlive()) {
|
|
95206
95254
|
return;
|
|
95207
95255
|
}
|
|
95208
|
-
|
|
95256
|
+
let event = null;
|
|
95257
|
+
try {
|
|
95258
|
+
event = readUserAttentionWatcherEvent(store, watcher.id);
|
|
95259
|
+
} catch (err2) {
|
|
95260
|
+
if (!isSqliteBusyError(err2)) {
|
|
95261
|
+
throw err2;
|
|
95262
|
+
}
|
|
95263
|
+
}
|
|
95209
95264
|
if (event) {
|
|
95210
95265
|
outputWatcherEvent(json, event);
|
|
95211
95266
|
return;
|
|
@@ -95220,7 +95275,23 @@ async function watchUserAttentionViaDaemon(store, parsed, json, options) {
|
|
|
95220
95275
|
return;
|
|
95221
95276
|
}
|
|
95222
95277
|
if (Date.now() >= nextHeartbeatAt) {
|
|
95223
|
-
|
|
95278
|
+
try {
|
|
95279
|
+
const next = heartbeatUserAttentionWatcher(store, watcher);
|
|
95280
|
+
if (next) {
|
|
95281
|
+
watcher = next;
|
|
95282
|
+
} else {
|
|
95283
|
+
watcher = registerUserAttentionWatcher({
|
|
95284
|
+
store,
|
|
95285
|
+
provider: options.provider,
|
|
95286
|
+
jobId: options.jobId,
|
|
95287
|
+
id: watcher.id
|
|
95288
|
+
}).watcher;
|
|
95289
|
+
}
|
|
95290
|
+
} catch (err2) {
|
|
95291
|
+
if (!isSqliteBusyError(err2)) {
|
|
95292
|
+
throw err2;
|
|
95293
|
+
}
|
|
95294
|
+
}
|
|
95224
95295
|
nextHeartbeatAt = Date.now() + Math.min(1e3, Math.max(100, pollMs));
|
|
95225
95296
|
}
|
|
95226
95297
|
const waitMs = deadline ? Math.max(0, Math.min(pollMs, USER_ATTENTION_WATCH_PARENT_CHECK_MS, deadline - Date.now())) : Math.min(pollMs, USER_ATTENTION_WATCH_PARENT_CHECK_MS);
|
|
@@ -95231,6 +95302,23 @@ async function watchUserAttentionViaDaemon(store, parsed, json, options) {
|
|
|
95231
95302
|
watcherCleanup.dispose();
|
|
95232
95303
|
}
|
|
95233
95304
|
}
|
|
95305
|
+
async function registerWatcherWithBusyRetry(options) {
|
|
95306
|
+
const attempts = 3;
|
|
95307
|
+
for (let attempt = 1; ; attempt += 1) {
|
|
95308
|
+
try {
|
|
95309
|
+
return registerUserAttentionWatcher({
|
|
95310
|
+
store: options.store,
|
|
95311
|
+
provider: options.provider,
|
|
95312
|
+
jobId: options.jobId
|
|
95313
|
+
});
|
|
95314
|
+
} catch (err2) {
|
|
95315
|
+
if (!isSqliteBusyError(err2) || attempt >= attempts) {
|
|
95316
|
+
throw err2;
|
|
95317
|
+
}
|
|
95318
|
+
await sleep3(250 * attempt);
|
|
95319
|
+
}
|
|
95320
|
+
}
|
|
95321
|
+
}
|
|
95234
95322
|
function installWatcherProcessCleanup(store, getWatcher) {
|
|
95235
95323
|
let cleaned = false;
|
|
95236
95324
|
const cleanup = () => {
|
|
@@ -95240,7 +95328,10 @@ function installWatcherProcessCleanup(store, getWatcher) {
|
|
|
95240
95328
|
cleaned = true;
|
|
95241
95329
|
const watcher = getWatcher();
|
|
95242
95330
|
if (watcher) {
|
|
95243
|
-
|
|
95331
|
+
try {
|
|
95332
|
+
removeUserAttentionWatcher(store, watcher.id);
|
|
95333
|
+
} catch {
|
|
95334
|
+
}
|
|
95244
95335
|
}
|
|
95245
95336
|
};
|
|
95246
95337
|
const onExit = () => {
|
|
@@ -96411,8 +96502,8 @@ function bindHermesSessionRouteIfAvailable(store, session) {
|
|
|
96411
96502
|
if (!jobId || process.env.OKX_A2A_GATEWAY_PROVIDER !== "hermes" && !hasHermesRuntimeMarker()) {
|
|
96412
96503
|
return;
|
|
96413
96504
|
}
|
|
96414
|
-
const
|
|
96415
|
-
if (
|
|
96505
|
+
const routes = currentHermesRoutesFromEnv2();
|
|
96506
|
+
if (routes.length === 0) {
|
|
96416
96507
|
logger.info(LogEvent.HERMES_SESSION_ROUTE_BINDING, sessionCliSentryExtra("hermes_session_route_binding", {
|
|
96417
96508
|
status: "skipped",
|
|
96418
96509
|
reason: "missing_route",
|
|
@@ -96430,26 +96521,53 @@ function bindHermesSessionRouteIfAvailable(store, session) {
|
|
|
96430
96521
|
const sessionKeys = /* @__PURE__ */ new Set();
|
|
96431
96522
|
sessionKeys.add(session.sessionKey);
|
|
96432
96523
|
sessionKeys.add(buildBackupJobSessionKey(jobId));
|
|
96433
|
-
|
|
96524
|
+
for (const route of routes) {
|
|
96525
|
+
persistHermesRouteBinding2(store, { jobId, route, sessionAliases: [...sessionKeys] });
|
|
96526
|
+
}
|
|
96434
96527
|
logger.info(LogEvent.HERMES_SESSION_ROUTE_BINDING, sessionCliSentryExtra("hermes_session_route_binding", {
|
|
96435
96528
|
status: "bound",
|
|
96436
96529
|
sessionKey: session.sessionKey,
|
|
96437
96530
|
backupSessionKey: buildBackupJobSessionKey(jobId),
|
|
96438
96531
|
jobId,
|
|
96439
|
-
gatewaySessionKey: route.gateway_session_key ?? route.session_key,
|
|
96440
|
-
gatewayPlatform: route.platform,
|
|
96441
|
-
gatewayChatId: route.chat_id,
|
|
96442
|
-
gatewayThreadId: route.thread_id,
|
|
96443
|
-
sessionKeyCount: String(sessionKeys.size)
|
|
96532
|
+
gatewaySessionKey: routes.map((route) => route.gateway_session_key ?? route.session_key).join(","),
|
|
96533
|
+
gatewayPlatform: routes.map((route) => route.platform).join(","),
|
|
96534
|
+
gatewayChatId: routes.map((route) => route.chat_id).join(","),
|
|
96535
|
+
gatewayThreadId: routes.map((route) => route.thread_id).join(","),
|
|
96536
|
+
sessionKeyCount: String(sessionKeys.size),
|
|
96537
|
+
routeCount: String(routes.length)
|
|
96444
96538
|
}));
|
|
96445
96539
|
}
|
|
96446
|
-
function
|
|
96447
|
-
const
|
|
96448
|
-
const
|
|
96540
|
+
function currentHermesRoutesFromEnv2(env = process.env) {
|
|
96541
|
+
const routes = [];
|
|
96542
|
+
const append = (route) => {
|
|
96543
|
+
if (!route) {
|
|
96544
|
+
return;
|
|
96545
|
+
}
|
|
96546
|
+
const key = `${route.platform}
|
|
96547
|
+
${route.chat_id}
|
|
96548
|
+
${route.thread_id}`;
|
|
96549
|
+
if (routes.some((existing) => `${existing.platform}
|
|
96550
|
+
${existing.chat_id}
|
|
96551
|
+
${existing.thread_id}` === key)) {
|
|
96552
|
+
return;
|
|
96553
|
+
}
|
|
96554
|
+
routes.push(route);
|
|
96555
|
+
};
|
|
96556
|
+
for (const sessionKey of readGatewaySessionKeysFromEnv2(env)) {
|
|
96557
|
+
append(routeFromHermesSessionKey2(sessionKey));
|
|
96558
|
+
}
|
|
96559
|
+
append(currentHermesRouteFromEnv2(env));
|
|
96560
|
+
append(routeFromHermesSessionEnv(env));
|
|
96561
|
+
append(routeFromHermesSessionKey2(env.HERMES_SESSION_KEY));
|
|
96562
|
+
return routes;
|
|
96563
|
+
}
|
|
96564
|
+
function currentHermesRouteFromEnv2(env = process.env) {
|
|
96565
|
+
const platform = normalizeOptionalText4(env.OKX_A2A_CURRENT_GATEWAY_PLATFORM);
|
|
96566
|
+
const chatId = normalizeOptionalText4(env.OKX_A2A_CURRENT_GATEWAY_CHAT_ID);
|
|
96449
96567
|
if (platform && chatId) {
|
|
96450
|
-
const sessionKey = normalizeOptionalText4(
|
|
96568
|
+
const sessionKey = normalizeOptionalText4(env.OKX_A2A_CURRENT_GATEWAY_SESSION_KEY);
|
|
96451
96569
|
const parsedGatewaySession = parseHermesGatewaySessionKey3(sessionKey);
|
|
96452
|
-
const threadId = normalizeOptionalText4(
|
|
96570
|
+
const threadId = normalizeOptionalText4(env.OKX_A2A_CURRENT_GATEWAY_THREAD_ID) ?? matchingParsedThreadId3(parsedGatewaySession, { platform, chatId });
|
|
96453
96571
|
return buildHermesRouteEntry({
|
|
96454
96572
|
platform,
|
|
96455
96573
|
chatId,
|
|
@@ -96457,11 +96575,15 @@ function currentHermesRouteFromEnv2() {
|
|
|
96457
96575
|
sessionKey
|
|
96458
96576
|
});
|
|
96459
96577
|
}
|
|
96460
|
-
return
|
|
96578
|
+
return null;
|
|
96461
96579
|
}
|
|
96462
96580
|
function buildHermesRouteEntry(input) {
|
|
96463
96581
|
const chatType = input.threadId ? "thread" : "dm";
|
|
96464
|
-
const gatewaySessionKey = input.sessionKey ?? (
|
|
96582
|
+
const gatewaySessionKey = input.sessionKey ?? hermesGatewaySessionKey2({
|
|
96583
|
+
platform: input.platform,
|
|
96584
|
+
chatId: input.chatId,
|
|
96585
|
+
threadId: input.threadId
|
|
96586
|
+
});
|
|
96465
96587
|
return {
|
|
96466
96588
|
platform: input.platform,
|
|
96467
96589
|
chat_id: input.chatId,
|
|
@@ -96474,19 +96596,19 @@ function buildHermesRouteEntry(input) {
|
|
|
96474
96596
|
gateway_session_key: gatewaySessionKey
|
|
96475
96597
|
};
|
|
96476
96598
|
}
|
|
96477
|
-
function routeFromHermesSessionEnv() {
|
|
96478
|
-
const platform = normalizeOptionalText4(
|
|
96479
|
-
const chatId = normalizeOptionalText4(
|
|
96599
|
+
function routeFromHermesSessionEnv(env = process.env) {
|
|
96600
|
+
const platform = normalizeOptionalText4(env.HERMES_SESSION_PLATFORM);
|
|
96601
|
+
const chatId = normalizeOptionalText4(env.HERMES_SESSION_CHAT_ID);
|
|
96480
96602
|
if (!platform || !chatId) {
|
|
96481
96603
|
return null;
|
|
96482
96604
|
}
|
|
96483
96605
|
return buildHermesRouteEntry({
|
|
96484
96606
|
platform,
|
|
96485
96607
|
chatId,
|
|
96486
|
-
sessionKey: normalizeOptionalText4(
|
|
96487
|
-
chatName: normalizeOptionalText4(
|
|
96488
|
-
userId: normalizeOptionalText4(
|
|
96489
|
-
userName: normalizeOptionalText4(
|
|
96608
|
+
sessionKey: normalizeOptionalText4(env.HERMES_SESSION_KEY),
|
|
96609
|
+
chatName: normalizeOptionalText4(env.HERMES_SESSION_CHAT_NAME),
|
|
96610
|
+
userId: normalizeOptionalText4(env.HERMES_SESSION_USER_ID),
|
|
96611
|
+
userName: normalizeOptionalText4(env.HERMES_SESSION_USER_NAME)
|
|
96490
96612
|
});
|
|
96491
96613
|
}
|
|
96492
96614
|
function routeFromHermesSessionKey2(value) {
|
|
@@ -96498,7 +96620,49 @@ function routeFromHermesSessionKey2(value) {
|
|
|
96498
96620
|
if (!parsed) {
|
|
96499
96621
|
return null;
|
|
96500
96622
|
}
|
|
96501
|
-
return buildHermesRouteEntry({
|
|
96623
|
+
return buildHermesRouteEntry({
|
|
96624
|
+
...parsed,
|
|
96625
|
+
sessionKey: hermesGatewaySessionKey2({
|
|
96626
|
+
platform: parsed.platform,
|
|
96627
|
+
chatId: parsed.chatId,
|
|
96628
|
+
threadId: parsed.threadId ?? ""
|
|
96629
|
+
})
|
|
96630
|
+
});
|
|
96631
|
+
}
|
|
96632
|
+
function readGatewaySessionKeysFromEnv2(env) {
|
|
96633
|
+
const keys = /* @__PURE__ */ new Set();
|
|
96634
|
+
const list = normalizeOptionalText4(env[CURRENT_GATEWAY_SESSION_KEYS_ENV3]);
|
|
96635
|
+
if (list) {
|
|
96636
|
+
try {
|
|
96637
|
+
const parsed = JSON.parse(list);
|
|
96638
|
+
if (Array.isArray(parsed)) {
|
|
96639
|
+
for (const item of parsed) {
|
|
96640
|
+
if (typeof item === "string" && item.trim()) {
|
|
96641
|
+
keys.add(item.trim());
|
|
96642
|
+
}
|
|
96643
|
+
}
|
|
96644
|
+
}
|
|
96645
|
+
} catch {
|
|
96646
|
+
for (const item of list.split(",")) {
|
|
96647
|
+
if (item.trim()) {
|
|
96648
|
+
keys.add(item.trim());
|
|
96649
|
+
}
|
|
96650
|
+
}
|
|
96651
|
+
}
|
|
96652
|
+
}
|
|
96653
|
+
const single = normalizeOptionalText4(env.OKX_A2A_CURRENT_GATEWAY_SESSION_KEY);
|
|
96654
|
+
if (single) {
|
|
96655
|
+
keys.add(single);
|
|
96656
|
+
}
|
|
96657
|
+
return [...keys];
|
|
96658
|
+
}
|
|
96659
|
+
function hermesGatewaySessionKey2(input) {
|
|
96660
|
+
const chatId = encodeURIComponent(input.chatId);
|
|
96661
|
+
const threadId = input.threadId ? encodeURIComponent(input.threadId) : "";
|
|
96662
|
+
if (input.platform === "telegram") {
|
|
96663
|
+
return threadId ? `agent:main:telegram:dm:${chatId}:${threadId}` : `agent:main:telegram:dm:${chatId}`;
|
|
96664
|
+
}
|
|
96665
|
+
return threadId ? `agent:main:${input.platform}:thread:${chatId}:${threadId}` : `agent:main:${input.platform}:dm:${chatId}`;
|
|
96502
96666
|
}
|
|
96503
96667
|
function parseHermesGatewaySessionKey3(sessionKey) {
|
|
96504
96668
|
const normalized = normalizeOptionalText4(sessionKey);
|
|
@@ -96506,18 +96670,25 @@ function parseHermesGatewaySessionKey3(sessionKey) {
|
|
|
96506
96670
|
return null;
|
|
96507
96671
|
}
|
|
96508
96672
|
const parts = normalized.startsWith("agent:") ? normalized.split(":").slice(2) : normalized.split(":");
|
|
96509
|
-
if (parts.length <
|
|
96673
|
+
if (parts.length < 2) {
|
|
96510
96674
|
return null;
|
|
96511
96675
|
}
|
|
96512
96676
|
const [platform, scope, ...rest] = parts;
|
|
96513
96677
|
if (!platform || platform === "okx-a2a" || platform === "backup" || platform === "job") {
|
|
96514
96678
|
return null;
|
|
96515
96679
|
}
|
|
96516
|
-
if (scope
|
|
96680
|
+
if (!isHermesGatewayScope2(scope)) {
|
|
96681
|
+
return {
|
|
96682
|
+
platform,
|
|
96683
|
+
chatId: safeDecodeURIComponent5(scope),
|
|
96684
|
+
...rest.length > 0 ? { threadId: safeDecodeURIComponent5(rest.join(":")) } : {}
|
|
96685
|
+
};
|
|
96686
|
+
}
|
|
96687
|
+
if ((scope === "dm" || scope === "direct" || scope === "channel") && rest[0]) {
|
|
96517
96688
|
return {
|
|
96518
96689
|
platform,
|
|
96519
96690
|
chatId: safeDecodeURIComponent5(rest[0]),
|
|
96520
|
-
...platform === "telegram" && rest[1] ? { threadId: safeDecodeURIComponent5(rest.slice(1)
|
|
96691
|
+
...platform === "telegram" && rest[1] ? { threadId: safeDecodeURIComponent5(parseTelegramTopicSuffix4(rest.slice(1))) } : {}
|
|
96521
96692
|
};
|
|
96522
96693
|
}
|
|
96523
96694
|
if (scope === "thread" && rest[0] && rest[1]) {
|
|
@@ -96527,8 +96698,31 @@ function parseHermesGatewaySessionKey3(sessionKey) {
|
|
|
96527
96698
|
threadId: safeDecodeURIComponent5(rest.slice(1).join(":"))
|
|
96528
96699
|
};
|
|
96529
96700
|
}
|
|
96701
|
+
if (platform === "telegram" && scope === "group" && rest[0]) {
|
|
96702
|
+
const threadId = parseTelegramTopicSuffix4(rest.slice(1));
|
|
96703
|
+
return {
|
|
96704
|
+
platform,
|
|
96705
|
+
chatId: safeDecodeURIComponent5(rest[0]),
|
|
96706
|
+
...threadId ? { threadId: safeDecodeURIComponent5(threadId) } : {}
|
|
96707
|
+
};
|
|
96708
|
+
}
|
|
96530
96709
|
return null;
|
|
96531
96710
|
}
|
|
96711
|
+
function isHermesGatewayScope2(value) {
|
|
96712
|
+
return value === "dm" || value === "direct" || value === "channel" || value === "thread" || value === "group";
|
|
96713
|
+
}
|
|
96714
|
+
function parseTelegramTopicSuffix4(parts) {
|
|
96715
|
+
if (parts.length === 0) {
|
|
96716
|
+
return "";
|
|
96717
|
+
}
|
|
96718
|
+
if (parts[0] === "topic") {
|
|
96719
|
+
return parts[1] ?? "";
|
|
96720
|
+
}
|
|
96721
|
+
if (parts[0] === "thread") {
|
|
96722
|
+
return parts.length >= 3 ? parts.slice(2).join(":") : parts[1] ?? "";
|
|
96723
|
+
}
|
|
96724
|
+
return parts.join(":");
|
|
96725
|
+
}
|
|
96532
96726
|
function matchingParsedThreadId3(parsed, expected) {
|
|
96533
96727
|
if (!parsed || parsed.platform !== expected.platform || parsed.chatId !== expected.chatId) {
|
|
96534
96728
|
return null;
|
|
@@ -96556,10 +96750,10 @@ function persistHermesRouteBinding2(store, input) {
|
|
|
96556
96750
|
store.upsertJobGatewayRoute({
|
|
96557
96751
|
jobId: input.jobId,
|
|
96558
96752
|
provider: "hermes",
|
|
96559
|
-
route: hermesRouteEntryToGatewayRoute2(input.route)
|
|
96753
|
+
route: hermesRouteEntryToGatewayRoute2(input.route, input.sessionAliases)
|
|
96560
96754
|
});
|
|
96561
96755
|
}
|
|
96562
|
-
function hermesRouteEntryToGatewayRoute2(route) {
|
|
96756
|
+
function hermesRouteEntryToGatewayRoute2(route, sessionAliases = []) {
|
|
96563
96757
|
return {
|
|
96564
96758
|
platform: route.platform,
|
|
96565
96759
|
chatId: route.chat_id,
|
|
@@ -96569,7 +96763,12 @@ function hermesRouteEntryToGatewayRoute2(route) {
|
|
|
96569
96763
|
userId: route.user_id,
|
|
96570
96764
|
userName: route.user_name,
|
|
96571
96765
|
sessionKey: route.session_key,
|
|
96572
|
-
gatewaySessionKey: route.gateway_session_key
|
|
96766
|
+
gatewaySessionKey: route.gateway_session_key,
|
|
96767
|
+
sessionAliases: [
|
|
96768
|
+
...new Set(
|
|
96769
|
+
[...route.session_aliases ?? [], ...sessionAliases].map((value) => value.trim()).filter(Boolean)
|
|
96770
|
+
)
|
|
96771
|
+
]
|
|
96573
96772
|
};
|
|
96574
96773
|
}
|
|
96575
96774
|
function hasHermesRuntimeMarker(env = process.env) {
|
|
@@ -96772,6 +96971,7 @@ function readNumberOption2(parsed, name2) {
|
|
|
96772
96971
|
}
|
|
96773
96972
|
return value;
|
|
96774
96973
|
}
|
|
96974
|
+
var CURRENT_GATEWAY_SESSION_KEYS_ENV3;
|
|
96775
96975
|
var init_session_cli = __esm({
|
|
96776
96976
|
"src/session-cli.ts"() {
|
|
96777
96977
|
"use strict";
|
|
@@ -96787,6 +96987,7 @@ var init_session_cli = __esm({
|
|
|
96787
96987
|
init_openclaw_gateway();
|
|
96788
96988
|
init_sentry_logger();
|
|
96789
96989
|
init_openclaw_gateway_config();
|
|
96990
|
+
CURRENT_GATEWAY_SESSION_KEYS_ENV3 = "OKX_A2A_CURRENT_GATEWAY_SESSION_KEYS";
|
|
96790
96991
|
}
|
|
96791
96992
|
});
|
|
96792
96993
|
|
|
@@ -97672,7 +97873,7 @@ async function getCurrentNodeCliVersion() {
|
|
|
97672
97873
|
return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
|
|
97673
97874
|
}
|
|
97674
97875
|
function getBundledNodeCliVersion() {
|
|
97675
|
-
return true ? "0.1.4
|
|
97876
|
+
return true ? "0.1.4" : null;
|
|
97676
97877
|
}
|
|
97677
97878
|
function readConfiguredAiProvider() {
|
|
97678
97879
|
const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
|
|
@@ -97863,7 +98064,7 @@ async function updateHermes(release, options) {
|
|
|
97863
98064
|
}
|
|
97864
98065
|
}
|
|
97865
98066
|
async function installGatewayPluginForDoctor(target) {
|
|
97866
|
-
const release = isPrereleaseVersion("0.1.4
|
|
98067
|
+
const release = isPrereleaseVersion("0.1.4") ? "beta" : "latest";
|
|
97867
98068
|
const insideTargetGateway = detectGatewayInvocation() === target;
|
|
97868
98069
|
const options = {
|
|
97869
98070
|
restart: !insideTargetGateway,
|
|
@@ -98936,7 +99137,7 @@ async function runDoctor(options = {}) {
|
|
|
98936
99137
|
platform: options.platform ?? process.platform,
|
|
98937
99138
|
env: options.env ?? process.env,
|
|
98938
99139
|
target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
|
|
98939
|
-
cliVersion: options.cliVersion ?? (true ? "0.1.4
|
|
99140
|
+
cliVersion: options.cliVersion ?? (true ? "0.1.4" : "0.0.0"),
|
|
98940
99141
|
fixMode: options.fix === true,
|
|
98941
99142
|
packageChanged: false
|
|
98942
99143
|
};
|
|
@@ -100006,9 +100207,9 @@ async function readFully(handle, buffer2, position) {
|
|
|
100006
100207
|
init_win_spawn();
|
|
100007
100208
|
init_sentry_logger();
|
|
100008
100209
|
init_sentry_config();
|
|
100009
|
-
var
|
|
100210
|
+
var CURRENT_GATEWAY_SESSION_KEYS_ENV4 = "OKX_A2A_CURRENT_GATEWAY_SESSION_KEYS";
|
|
100010
100211
|
function printUsage2() {
|
|
100011
|
-
console.log(`okx-a2a ${"0.1.4
|
|
100212
|
+
console.log(`okx-a2a ${"0.1.4"}
|
|
100012
100213
|
|
|
100013
100214
|
Usage:
|
|
100014
100215
|
okx-a2a <command> [options]
|
|
@@ -100046,7 +100247,7 @@ Run \`okx-a2a <command> -h\` for command-specific help.
|
|
|
100046
100247
|
`);
|
|
100047
100248
|
}
|
|
100048
100249
|
function printVersion() {
|
|
100049
|
-
console.log("0.1.4
|
|
100250
|
+
console.log("0.1.4");
|
|
100050
100251
|
}
|
|
100051
100252
|
function printDaemonUsage() {
|
|
100052
100253
|
console.log(`Usage: okx-a2a daemon <start|restart|stop|status|autostart> [options]
|
|
@@ -100454,7 +100655,7 @@ async function queueXmtpSend(args) {
|
|
|
100454
100655
|
myAgentId: target.myAgentId,
|
|
100455
100656
|
toAgentId: target.toAgentId,
|
|
100456
100657
|
toXmtpAddress: toXmtpAddress ?? target.toXmtpAddress,
|
|
100457
|
-
gatewaySessionKeys:
|
|
100658
|
+
gatewaySessionKeys: readGatewaySessionKeysFromEnv3(),
|
|
100458
100659
|
payload: payloadOverride
|
|
100459
100660
|
});
|
|
100460
100661
|
await commands.submit(command);
|
|
@@ -100489,9 +100690,9 @@ function parseXmtpSendPayloadOption(raw) {
|
|
|
100489
100690
|
return void 0;
|
|
100490
100691
|
}
|
|
100491
100692
|
}
|
|
100492
|
-
function
|
|
100693
|
+
function readGatewaySessionKeysFromEnv3(env = process.env) {
|
|
100493
100694
|
const keys = /* @__PURE__ */ new Set();
|
|
100494
|
-
const list = env[
|
|
100695
|
+
const list = env[CURRENT_GATEWAY_SESSION_KEYS_ENV4]?.trim();
|
|
100495
100696
|
if (list) {
|
|
100496
100697
|
try {
|
|
100497
100698
|
const parsed = JSON.parse(list);
|
package/dist/index.js
CHANGED
|
@@ -154,6 +154,20 @@ function buildSessionKey(input) {
|
|
|
154
154
|
encodeURIComponent(input.toAgentId || "unknown")
|
|
155
155
|
].join(":");
|
|
156
156
|
}
|
|
157
|
+
function isSqliteBusyError(err2) {
|
|
158
|
+
if (!(err2 instanceof Error)) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
const code2 = err2.errcode;
|
|
162
|
+
if (typeof code2 === "number" && ((code2 & 255) === 5 || (code2 & 255) === 6)) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
return /database is locked|database table is locked/i.test(err2.message);
|
|
166
|
+
}
|
|
167
|
+
function sleepSyncMs(ms) {
|
|
168
|
+
const buf = new Int32Array(new SharedArrayBuffer(4));
|
|
169
|
+
Atomics.wait(buf, 0, 0, ms);
|
|
170
|
+
}
|
|
157
171
|
function loadSqlite() {
|
|
158
172
|
const originalEmitWarning = process.emitWarning;
|
|
159
173
|
process.emitWarning = ((warning, ...args) => {
|
|
@@ -606,7 +620,28 @@ var init_session_store = __esm({
|
|
|
606
620
|
this.db = new DatabaseSync(this.dbPath);
|
|
607
621
|
this.ensureReady();
|
|
608
622
|
}
|
|
623
|
+
// Opening the store races other processes writing the same DB (daemon
|
|
624
|
+
// coordinator scans, other CLI watches). Two busy flavors both crash an
|
|
625
|
+
// unprotected open: schema DDL starving past busy_timeout, and the WAL
|
|
626
|
+
// journal-mode conversion which returns SQLITE_BUSY IMMEDIATELY under any
|
|
627
|
+
// concurrent writer (busy_timeout does not apply to it). Retry bounded with
|
|
628
|
+
// exponential backoff so the cumulative window (~7.75s) rides out real
|
|
629
|
+
// contention bursts instead of crashing on arrival.
|
|
609
630
|
ensureReady() {
|
|
631
|
+
const attempts = 6;
|
|
632
|
+
for (let attempt = 1; ; attempt += 1) {
|
|
633
|
+
try {
|
|
634
|
+
this.ensureReadyOnce();
|
|
635
|
+
return;
|
|
636
|
+
} catch (err2) {
|
|
637
|
+
if (!isSqliteBusyError(err2) || attempt >= attempts) {
|
|
638
|
+
throw err2;
|
|
639
|
+
}
|
|
640
|
+
sleepSyncMs(Math.min(250 * 2 ** (attempt - 1), 4e3));
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
ensureReadyOnce() {
|
|
610
645
|
this.db.exec("PRAGMA busy_timeout=5000");
|
|
611
646
|
this.db.exec("PRAGMA journal_mode=WAL");
|
|
612
647
|
this.db.exec("PRAGMA foreign_keys=ON");
|
|
@@ -1281,13 +1316,19 @@ var init_session_store = __esm({
|
|
|
1281
1316
|
};
|
|
1282
1317
|
});
|
|
1283
1318
|
}
|
|
1319
|
+
// Returns null when the watcher row no longer exists (e.g. TTL-expired after
|
|
1320
|
+
// heartbeats starved on a busy database) so the caller can re-register
|
|
1321
|
+
// instead of polling a row that will never receive events again.
|
|
1284
1322
|
heartbeatUserAttentionWatcher(watcher, nowMs) {
|
|
1285
1323
|
assertNonEmpty(watcher.id, "id");
|
|
1286
|
-
this.db.prepare(`
|
|
1324
|
+
const result = this.db.prepare(`
|
|
1287
1325
|
UPDATE user_attention_watchers
|
|
1288
1326
|
SET updated_at_ms = ?
|
|
1289
1327
|
WHERE id = ?
|
|
1290
1328
|
`).run(nowMs, watcher.id);
|
|
1329
|
+
if (Number(result.changes) === 0) {
|
|
1330
|
+
return null;
|
|
1331
|
+
}
|
|
1291
1332
|
return {
|
|
1292
1333
|
...watcher,
|
|
1293
1334
|
updatedAt: nowMs
|
|
@@ -71569,7 +71610,7 @@ async function getCurrentNodeCliVersion() {
|
|
|
71569
71610
|
return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
|
|
71570
71611
|
}
|
|
71571
71612
|
function getBundledNodeCliVersion() {
|
|
71572
|
-
return true ? "0.1.4
|
|
71613
|
+
return true ? "0.1.4" : null;
|
|
71573
71614
|
}
|
|
71574
71615
|
function readConfiguredAiProvider() {
|
|
71575
71616
|
const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
|
|
@@ -71760,7 +71801,7 @@ async function updateHermes(release, options) {
|
|
|
71760
71801
|
}
|
|
71761
71802
|
}
|
|
71762
71803
|
async function installGatewayPluginForDoctor(target) {
|
|
71763
|
-
const release = isPrereleaseVersion("0.1.4
|
|
71804
|
+
const release = isPrereleaseVersion("0.1.4") ? "beta" : "latest";
|
|
71764
71805
|
const insideTargetGateway = detectGatewayInvocation() === target;
|
|
71765
71806
|
const options = {
|
|
71766
71807
|
restart: !insideTargetGateway,
|
|
@@ -72776,6 +72817,7 @@ __export(index_exports, {
|
|
|
72776
72817
|
isOriginalParentProcessAlive: () => isOriginalParentProcessAlive,
|
|
72777
72818
|
isPrereleaseVersion: () => isPrereleaseVersion,
|
|
72778
72819
|
isRetryableOpenClawGatewayError: () => isRetryableOpenClawGatewayError,
|
|
72820
|
+
isSqliteBusyError: () => isSqliteBusyError,
|
|
72779
72821
|
isWindowsElevated: () => isWindowsElevated,
|
|
72780
72822
|
killProcessTree: () => killProcessTree,
|
|
72781
72823
|
logWinCompat: () => logWinCompat,
|
|
@@ -89263,7 +89305,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
|
|
|
89263
89305
|
client: {
|
|
89264
89306
|
id: "gateway-client",
|
|
89265
89307
|
displayName: "okx-a2a-node",
|
|
89266
|
-
version: "0.1.4
|
|
89308
|
+
version: "0.1.4",
|
|
89267
89309
|
platform: "node",
|
|
89268
89310
|
mode: "backend",
|
|
89269
89311
|
instanceId
|
|
@@ -89274,7 +89316,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
|
|
|
89274
89316
|
commands: [],
|
|
89275
89317
|
permissions: {},
|
|
89276
89318
|
locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
|
|
89277
|
-
userAgent: `okx-a2a-node/${"0.1.4
|
|
89319
|
+
userAgent: `okx-a2a-node/${"0.1.4"}`,
|
|
89278
89320
|
auth: {
|
|
89279
89321
|
...config.token ? { token: config.token } : {},
|
|
89280
89322
|
...config.password ? { password: config.password } : {}
|
|
@@ -93744,7 +93786,7 @@ init_ai_provider();
|
|
|
93744
93786
|
var environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
|
|
93745
93787
|
var SENTRY_CONFIG = {
|
|
93746
93788
|
projectName: "okx/openclaw-okx-a2a-extension",
|
|
93747
|
-
release: "0.1.4
|
|
93789
|
+
release: "0.1.4",
|
|
93748
93790
|
environment
|
|
93749
93791
|
};
|
|
93750
93792
|
|
|
@@ -93971,12 +94013,12 @@ async function runListenerWithLock(options, paths) {
|
|
|
93971
94013
|
}));
|
|
93972
94014
|
}
|
|
93973
94015
|
});
|
|
93974
|
-
service.setPluginVersion("0.1.4
|
|
94016
|
+
service.setPluginVersion("0.1.4");
|
|
93975
94017
|
await service.init();
|
|
93976
94018
|
const pluginVersionStatus = service.pluginVersionStatus;
|
|
93977
94019
|
if (pluginVersionStatus.unavailable) {
|
|
93978
94020
|
throw new Error(
|
|
93979
|
-
`@okxweb3/a2a-node v${"0.1.4
|
|
94021
|
+
`@okxweb3/a2a-node v${"0.1.4"} is below the required minimum v${pluginVersionStatus.minVersion}`
|
|
93980
94022
|
);
|
|
93981
94023
|
}
|
|
93982
94024
|
const systemConfig = service.getSystemConfig();
|
|
@@ -93994,7 +94036,7 @@ async function runListenerWithLock(options, paths) {
|
|
|
93994
94036
|
onchainosAgentId: "*",
|
|
93995
94037
|
reason: "system-config missing sentryDsn",
|
|
93996
94038
|
pluginId: "@okxweb3/a2a-node",
|
|
93997
|
-
pluginVersion: "0.1.4
|
|
94039
|
+
pluginVersion: "0.1.4"
|
|
93998
94040
|
});
|
|
93999
94041
|
}
|
|
94000
94042
|
logWithTimestamp(
|
|
@@ -95717,7 +95759,7 @@ async function runDoctor(options = {}) {
|
|
|
95717
95759
|
platform: options.platform ?? process.platform,
|
|
95718
95760
|
env: options.env ?? process.env,
|
|
95719
95761
|
target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
|
|
95720
|
-
cliVersion: options.cliVersion ?? (true ? "0.1.4
|
|
95762
|
+
cliVersion: options.cliVersion ?? (true ? "0.1.4" : "0.0.0"),
|
|
95721
95763
|
fixMode: options.fix === true,
|
|
95722
95764
|
packageChanged: false
|
|
95723
95765
|
};
|
|
@@ -96013,6 +96055,7 @@ init_win_native_launcher();
|
|
|
96013
96055
|
isOriginalParentProcessAlive,
|
|
96014
96056
|
isPrereleaseVersion,
|
|
96015
96057
|
isRetryableOpenClawGatewayError,
|
|
96058
|
+
isSqliteBusyError,
|
|
96016
96059
|
isWindowsElevated,
|
|
96017
96060
|
killProcessTree,
|
|
96018
96061
|
logWinCompat,
|
package/package.json
CHANGED