@okxweb3/a2a-node 0.1.10-beta-bf67773ad1-260723190921 → 0.1.10
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 +362 -31
- package/dist/index.js +352 -25
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -4418,6 +4418,274 @@ var init_openclaw_gateway_config = __esm({
|
|
|
4418
4418
|
}
|
|
4419
4419
|
});
|
|
4420
4420
|
|
|
4421
|
+
// src/session-busy-tracker.ts
|
|
4422
|
+
function getSessionBusyTracker() {
|
|
4423
|
+
if (!singleton) {
|
|
4424
|
+
singleton = new SessionBusyTracker();
|
|
4425
|
+
}
|
|
4426
|
+
return singleton;
|
|
4427
|
+
}
|
|
4428
|
+
var RING_MAX, DEFAULT_STALE_RUN_MS, DEFAULT_STREAM_STALE_MS, DEFAULT_WATCHDOG_INTERVAL_MS, LOG_PREFIX, SessionBusyTracker, singleton;
|
|
4429
|
+
var init_session_busy_tracker = __esm({
|
|
4430
|
+
"src/session-busy-tracker.ts"() {
|
|
4431
|
+
"use strict";
|
|
4432
|
+
init_log();
|
|
4433
|
+
RING_MAX = 256;
|
|
4434
|
+
DEFAULT_STALE_RUN_MS = 10 * 60 * 1e3;
|
|
4435
|
+
DEFAULT_STREAM_STALE_MS = 60 * 1e3;
|
|
4436
|
+
DEFAULT_WATCHDOG_INTERVAL_MS = 5 * 1e3;
|
|
4437
|
+
LOG_PREFIX = "[okx-a2a:session-gate]";
|
|
4438
|
+
SessionBusyTracker = class {
|
|
4439
|
+
now;
|
|
4440
|
+
staleRunMs;
|
|
4441
|
+
streamStaleMs;
|
|
4442
|
+
watchdogIntervalMs;
|
|
4443
|
+
/** runIds that reached a terminal state; guards against late/out-of-order deltas. */
|
|
4444
|
+
finalized = [];
|
|
4445
|
+
runWaiters = /* @__PURE__ */ new Map();
|
|
4446
|
+
/** sessionKey → (runId → lastSeenMs). */
|
|
4447
|
+
activeRuns = /* @__PURE__ */ new Map();
|
|
4448
|
+
idleWaiters = /* @__PURE__ */ new Map();
|
|
4449
|
+
lastEventAtMs;
|
|
4450
|
+
lastStreamStaleFireMs = 0;
|
|
4451
|
+
streamStaleHandler = null;
|
|
4452
|
+
pendingWaiters = 0;
|
|
4453
|
+
watchdogTimer = null;
|
|
4454
|
+
constructor(options = {}) {
|
|
4455
|
+
this.now = options.now ?? Date.now;
|
|
4456
|
+
this.staleRunMs = options.staleRunMs ?? DEFAULT_STALE_RUN_MS;
|
|
4457
|
+
this.streamStaleMs = options.streamStaleMs ?? DEFAULT_STREAM_STALE_MS;
|
|
4458
|
+
this.watchdogIntervalMs = options.watchdogIntervalMs ?? DEFAULT_WATCHDOG_INTERVAL_MS;
|
|
4459
|
+
this.lastEventAtMs = this.now();
|
|
4460
|
+
}
|
|
4461
|
+
/** Any event frame arrived (chat/agent/tick/health/...): the stream is alive. */
|
|
4462
|
+
noteEvent() {
|
|
4463
|
+
this.lastEventAtMs = this.now();
|
|
4464
|
+
}
|
|
4465
|
+
/** Reconnect hook invoked when the event stream goes silent while a wait is pending. */
|
|
4466
|
+
setStreamStaleHandler(handler) {
|
|
4467
|
+
this.streamStaleHandler = handler;
|
|
4468
|
+
}
|
|
4469
|
+
notifyChat(payload) {
|
|
4470
|
+
if (!payload || typeof payload !== "object") {
|
|
4471
|
+
return;
|
|
4472
|
+
}
|
|
4473
|
+
const frame = payload;
|
|
4474
|
+
const runId = typeof frame.runId === "string" ? frame.runId : "";
|
|
4475
|
+
const sessionKey = typeof frame.sessionKey === "string" ? frame.sessionKey : "";
|
|
4476
|
+
const state = typeof frame.state === "string" ? frame.state : "";
|
|
4477
|
+
if (!runId) {
|
|
4478
|
+
return;
|
|
4479
|
+
}
|
|
4480
|
+
if (state === "final" || state === "error" || state === "aborted") {
|
|
4481
|
+
this.markDone(sessionKey, runId, state);
|
|
4482
|
+
} else {
|
|
4483
|
+
this.markActive(sessionKey, runId);
|
|
4484
|
+
}
|
|
4485
|
+
}
|
|
4486
|
+
notifyAgent(payload) {
|
|
4487
|
+
if (!payload || typeof payload !== "object") {
|
|
4488
|
+
return;
|
|
4489
|
+
}
|
|
4490
|
+
const frame = payload;
|
|
4491
|
+
const runId = typeof frame.runId === "string" ? frame.runId : "";
|
|
4492
|
+
const sessionKey = typeof frame.sessionKey === "string" ? frame.sessionKey : "";
|
|
4493
|
+
const phase = frame.data && typeof frame.data === "object" ? frame.data.phase : void 0;
|
|
4494
|
+
if (!runId) {
|
|
4495
|
+
return;
|
|
4496
|
+
}
|
|
4497
|
+
if (frame.stream === "lifecycle" && (phase === "end" || phase === "error")) {
|
|
4498
|
+
this.markDone(sessionKey, runId, String(phase));
|
|
4499
|
+
} else {
|
|
4500
|
+
this.markActive(sessionKey, runId);
|
|
4501
|
+
}
|
|
4502
|
+
}
|
|
4503
|
+
isSessionBusy(sessionKey) {
|
|
4504
|
+
const runs = this.activeRuns.get(sessionKey);
|
|
4505
|
+
if (!runs) {
|
|
4506
|
+
return false;
|
|
4507
|
+
}
|
|
4508
|
+
const now = this.now();
|
|
4509
|
+
for (const [runId, lastSeen] of runs) {
|
|
4510
|
+
if (now - lastSeen > this.staleRunMs) {
|
|
4511
|
+
runs.delete(runId);
|
|
4512
|
+
}
|
|
4513
|
+
}
|
|
4514
|
+
if (runs.size === 0) {
|
|
4515
|
+
this.activeRuns.delete(sessionKey);
|
|
4516
|
+
return false;
|
|
4517
|
+
}
|
|
4518
|
+
return true;
|
|
4519
|
+
}
|
|
4520
|
+
waitForSessionIdle(sessionKey, timeoutMs) {
|
|
4521
|
+
if (!this.isSessionBusy(sessionKey)) {
|
|
4522
|
+
return Promise.resolve("idle");
|
|
4523
|
+
}
|
|
4524
|
+
return new Promise((resolve9) => {
|
|
4525
|
+
let waiters = this.idleWaiters.get(sessionKey);
|
|
4526
|
+
if (!waiters) {
|
|
4527
|
+
waiters = /* @__PURE__ */ new Set();
|
|
4528
|
+
this.idleWaiters.set(sessionKey, waiters);
|
|
4529
|
+
}
|
|
4530
|
+
this.beginWait();
|
|
4531
|
+
const entry = (state) => {
|
|
4532
|
+
clearTimeout(timer);
|
|
4533
|
+
this.endWait();
|
|
4534
|
+
resolve9(state);
|
|
4535
|
+
};
|
|
4536
|
+
const timer = setTimeout(() => {
|
|
4537
|
+
const cur = this.idleWaiters.get(sessionKey);
|
|
4538
|
+
if (cur) {
|
|
4539
|
+
cur.delete(entry);
|
|
4540
|
+
if (cur.size === 0) {
|
|
4541
|
+
this.idleWaiters.delete(sessionKey);
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
this.endWait();
|
|
4545
|
+
resolve9("timeout");
|
|
4546
|
+
}, timeoutMs);
|
|
4547
|
+
waiters.add(entry);
|
|
4548
|
+
});
|
|
4549
|
+
}
|
|
4550
|
+
waitForRunFinal(runId, timeoutMs) {
|
|
4551
|
+
if (this.finalized.includes(runId)) {
|
|
4552
|
+
return Promise.resolve("already-final");
|
|
4553
|
+
}
|
|
4554
|
+
return new Promise((resolve9) => {
|
|
4555
|
+
let waiters = this.runWaiters.get(runId);
|
|
4556
|
+
if (!waiters) {
|
|
4557
|
+
waiters = /* @__PURE__ */ new Set();
|
|
4558
|
+
this.runWaiters.set(runId, waiters);
|
|
4559
|
+
}
|
|
4560
|
+
this.beginWait();
|
|
4561
|
+
const entry = (state) => {
|
|
4562
|
+
clearTimeout(timer);
|
|
4563
|
+
this.endWait();
|
|
4564
|
+
resolve9(state);
|
|
4565
|
+
};
|
|
4566
|
+
const timer = setTimeout(() => {
|
|
4567
|
+
const cur = this.runWaiters.get(runId);
|
|
4568
|
+
if (cur) {
|
|
4569
|
+
cur.delete(entry);
|
|
4570
|
+
if (cur.size === 0) {
|
|
4571
|
+
this.runWaiters.delete(runId);
|
|
4572
|
+
}
|
|
4573
|
+
}
|
|
4574
|
+
this.endWait();
|
|
4575
|
+
resolve9("timeout");
|
|
4576
|
+
}, timeoutMs);
|
|
4577
|
+
waiters.add(entry);
|
|
4578
|
+
});
|
|
4579
|
+
}
|
|
4580
|
+
_debugSnapshot() {
|
|
4581
|
+
return {
|
|
4582
|
+
active: Array.from(this.activeRuns, ([key, runs]) => {
|
|
4583
|
+
return [key, Array.from(runs.keys())];
|
|
4584
|
+
}),
|
|
4585
|
+
finalizedTail: this.finalized.slice(-10)
|
|
4586
|
+
};
|
|
4587
|
+
}
|
|
4588
|
+
rememberFinalized(runId) {
|
|
4589
|
+
if (!this.finalized.includes(runId)) {
|
|
4590
|
+
this.finalized.push(runId);
|
|
4591
|
+
if (this.finalized.length > RING_MAX) {
|
|
4592
|
+
this.finalized.shift();
|
|
4593
|
+
}
|
|
4594
|
+
}
|
|
4595
|
+
}
|
|
4596
|
+
markActive(sessionKey, runId) {
|
|
4597
|
+
if (!sessionKey || !runId || this.finalized.includes(runId)) {
|
|
4598
|
+
return;
|
|
4599
|
+
}
|
|
4600
|
+
let runs = this.activeRuns.get(sessionKey);
|
|
4601
|
+
if (!runs) {
|
|
4602
|
+
runs = /* @__PURE__ */ new Map();
|
|
4603
|
+
this.activeRuns.set(sessionKey, runs);
|
|
4604
|
+
}
|
|
4605
|
+
runs.set(runId, this.now());
|
|
4606
|
+
}
|
|
4607
|
+
markDone(sessionKey, runId, state) {
|
|
4608
|
+
if (runId) {
|
|
4609
|
+
this.rememberFinalized(runId);
|
|
4610
|
+
const waiters = this.runWaiters.get(runId);
|
|
4611
|
+
if (waiters) {
|
|
4612
|
+
this.runWaiters.delete(runId);
|
|
4613
|
+
for (const fn of waiters) {
|
|
4614
|
+
fn(state);
|
|
4615
|
+
}
|
|
4616
|
+
}
|
|
4617
|
+
const runs = sessionKey ? this.activeRuns.get(sessionKey) : void 0;
|
|
4618
|
+
if (runs) {
|
|
4619
|
+
runs.delete(runId);
|
|
4620
|
+
if (runs.size === 0) {
|
|
4621
|
+
this.activeRuns.delete(sessionKey);
|
|
4622
|
+
}
|
|
4623
|
+
} else {
|
|
4624
|
+
for (const [key, sessionRuns] of this.activeRuns) {
|
|
4625
|
+
if (sessionRuns.delete(runId) && sessionRuns.size === 0) {
|
|
4626
|
+
this.activeRuns.delete(key);
|
|
4627
|
+
}
|
|
4628
|
+
}
|
|
4629
|
+
}
|
|
4630
|
+
}
|
|
4631
|
+
if (sessionKey) {
|
|
4632
|
+
this.releaseIdleWaiters(sessionKey);
|
|
4633
|
+
}
|
|
4634
|
+
}
|
|
4635
|
+
releaseIdleWaiters(sessionKey) {
|
|
4636
|
+
if (!sessionKey || this.isSessionBusy(sessionKey)) {
|
|
4637
|
+
return;
|
|
4638
|
+
}
|
|
4639
|
+
const waiters = this.idleWaiters.get(sessionKey);
|
|
4640
|
+
if (waiters) {
|
|
4641
|
+
this.idleWaiters.delete(sessionKey);
|
|
4642
|
+
for (const fn of waiters) {
|
|
4643
|
+
fn("idle");
|
|
4644
|
+
}
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4647
|
+
beginWait() {
|
|
4648
|
+
this.pendingWaiters += 1;
|
|
4649
|
+
if (this.pendingWaiters === 1 && !this.watchdogTimer) {
|
|
4650
|
+
const timer = setInterval(() => {
|
|
4651
|
+
this.checkStreamLiveness();
|
|
4652
|
+
}, this.watchdogIntervalMs);
|
|
4653
|
+
timer.unref?.();
|
|
4654
|
+
this.watchdogTimer = timer;
|
|
4655
|
+
}
|
|
4656
|
+
}
|
|
4657
|
+
endWait() {
|
|
4658
|
+
this.pendingWaiters = Math.max(0, this.pendingWaiters - 1);
|
|
4659
|
+
if (this.pendingWaiters === 0 && this.watchdogTimer) {
|
|
4660
|
+
clearInterval(this.watchdogTimer);
|
|
4661
|
+
this.watchdogTimer = null;
|
|
4662
|
+
}
|
|
4663
|
+
}
|
|
4664
|
+
checkStreamLiveness() {
|
|
4665
|
+
const now = this.now();
|
|
4666
|
+
if (now - this.lastEventAtMs <= this.streamStaleMs) {
|
|
4667
|
+
return;
|
|
4668
|
+
}
|
|
4669
|
+
if (now - this.lastStreamStaleFireMs <= this.streamStaleMs) {
|
|
4670
|
+
return;
|
|
4671
|
+
}
|
|
4672
|
+
this.lastStreamStaleFireMs = now;
|
|
4673
|
+
errorWithTimestamp(
|
|
4674
|
+
`${LOG_PREFIX} event stream stale (${now - this.lastEventAtMs}ms since last event, threshold=${this.streamStaleMs}ms), invoking recovery handler`
|
|
4675
|
+
);
|
|
4676
|
+
try {
|
|
4677
|
+
this.streamStaleHandler?.();
|
|
4678
|
+
} catch (err2) {
|
|
4679
|
+
errorWithTimestamp(
|
|
4680
|
+
`${LOG_PREFIX} stream recovery handler failed: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
4681
|
+
);
|
|
4682
|
+
}
|
|
4683
|
+
}
|
|
4684
|
+
};
|
|
4685
|
+
singleton = null;
|
|
4686
|
+
}
|
|
4687
|
+
});
|
|
4688
|
+
|
|
4421
4689
|
// ../../node_modules/ws/lib/constants.js
|
|
4422
4690
|
var require_constants = __commonJS({
|
|
4423
4691
|
"../../node_modules/ws/lib/constants.js"(exports2, module2) {
|
|
@@ -8107,6 +8375,17 @@ function createDefaultWebSocket(url) {
|
|
|
8107
8375
|
}
|
|
8108
8376
|
return new Ctor(url);
|
|
8109
8377
|
}
|
|
8378
|
+
function ensureStreamStaleHandlerRegistered() {
|
|
8379
|
+
if (streamStaleHandlerRegistered) {
|
|
8380
|
+
return;
|
|
8381
|
+
}
|
|
8382
|
+
streamStaleHandlerRegistered = true;
|
|
8383
|
+
getSessionBusyTracker().setStreamStaleHandler(() => {
|
|
8384
|
+
errorWithTimestamp(`${LOG_PREFIX2} [session-gate] event stream stale, forcing gateway reconnect`);
|
|
8385
|
+
clearClient();
|
|
8386
|
+
void isOpenClawA2aPluginAvailable();
|
|
8387
|
+
});
|
|
8388
|
+
}
|
|
8110
8389
|
function resolveOpenClawGatewayConfig(env = process.env) {
|
|
8111
8390
|
const synced = readSyncedGatewayConfig(env);
|
|
8112
8391
|
const explicitUrl = env.OKX_A2A_OPENCLAW_GATEWAY_URL?.trim() || void 0;
|
|
@@ -8123,12 +8402,13 @@ function resolveOpenClawGatewayConfig(env = process.env) {
|
|
|
8123
8402
|
}
|
|
8124
8403
|
function clearClient() {
|
|
8125
8404
|
if (sharedClient) {
|
|
8126
|
-
errorWithTimestamp(`${
|
|
8405
|
+
errorWithTimestamp(`${LOG_PREFIX2} clear client`);
|
|
8127
8406
|
sharedClient.close();
|
|
8128
8407
|
}
|
|
8129
8408
|
sharedClient = null;
|
|
8130
8409
|
}
|
|
8131
8410
|
async function ensureClient(timeoutMs) {
|
|
8411
|
+
ensureStreamStaleHandlerRegistered();
|
|
8132
8412
|
if (sharedClient?.isReady()) {
|
|
8133
8413
|
return sharedClient;
|
|
8134
8414
|
}
|
|
@@ -8152,7 +8432,7 @@ async function ensureClient(timeoutMs) {
|
|
|
8152
8432
|
const remainingMs = Math.max(1, timeoutMs - elapsedMs);
|
|
8153
8433
|
const fallbackProtocol = firstProtocol === PREFERRED_PROTOCOL_VERSION ? LEGACY_PROTOCOL_VERSION : PREFERRED_PROTOCOL_VERSION;
|
|
8154
8434
|
errorWithTimestamp(
|
|
8155
|
-
`${
|
|
8435
|
+
`${LOG_PREFIX2} protocol fallback from=${firstProtocol} to=${fallbackProtocol} remainingMs=${remainingMs}: ${formatErrorMessage(err2)}`
|
|
8156
8436
|
);
|
|
8157
8437
|
const fallbackClient = new MinimalGatewayClient(config, fallbackProtocol);
|
|
8158
8438
|
sharedClient = fallbackClient;
|
|
@@ -8163,7 +8443,7 @@ async function ensureClient(timeoutMs) {
|
|
|
8163
8443
|
}
|
|
8164
8444
|
function stopOpenClawGateway() {
|
|
8165
8445
|
if (!sharedClient) {
|
|
8166
|
-
errorWithTimestamp(`${
|
|
8446
|
+
errorWithTimestamp(`${LOG_PREFIX2} stop requested with no active client`);
|
|
8167
8447
|
return;
|
|
8168
8448
|
}
|
|
8169
8449
|
clearClient();
|
|
@@ -8171,12 +8451,12 @@ function stopOpenClawGateway() {
|
|
|
8171
8451
|
async function callOpenClawGateway(opts) {
|
|
8172
8452
|
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
8173
8453
|
const startedAt = Date.now();
|
|
8174
|
-
errorWithTimestamp(`${
|
|
8454
|
+
errorWithTimestamp(`${LOG_PREFIX2} rpc start method=${opts.method} timeoutMs=${timeoutMs}`);
|
|
8175
8455
|
for (let attempt = 0; ; attempt += 1) {
|
|
8176
8456
|
try {
|
|
8177
8457
|
const client = await ensureClient(timeoutMs);
|
|
8178
8458
|
const result = await client.request(opts.method, opts.params, { timeoutMs });
|
|
8179
|
-
errorWithTimestamp(`${
|
|
8459
|
+
errorWithTimestamp(`${LOG_PREFIX2} rpc ok method=${opts.method} durationMs=${Date.now() - startedAt} attempts=${attempt + 1}`);
|
|
8180
8460
|
return result;
|
|
8181
8461
|
} catch (err2) {
|
|
8182
8462
|
const message = err2 instanceof Error ? err2.message : String(err2);
|
|
@@ -8186,13 +8466,13 @@ async function callOpenClawGateway(opts) {
|
|
|
8186
8466
|
}
|
|
8187
8467
|
if (isGatewayStartingError(err2) && delayMs !== void 0 && Date.now() + delayMs - startedAt < timeoutMs) {
|
|
8188
8468
|
errorWithTimestamp(
|
|
8189
|
-
`${
|
|
8469
|
+
`${LOG_PREFIX2} rpc retry method=${opts.method} attempt=${attempt + 1} delayMs=${delayMs}: ${message}`
|
|
8190
8470
|
);
|
|
8191
8471
|
await sleep2(delayMs);
|
|
8192
8472
|
continue;
|
|
8193
8473
|
}
|
|
8194
8474
|
errorWithTimestamp(
|
|
8195
|
-
`${
|
|
8475
|
+
`${LOG_PREFIX2} rpc failed method=${opts.method} durationMs=${Date.now() - startedAt} attempts=${attempt + 1}: ${message}`
|
|
8196
8476
|
);
|
|
8197
8477
|
if (isGatewayStartingError(err2)) {
|
|
8198
8478
|
throw Object.assign(
|
|
@@ -8291,7 +8571,7 @@ function readSyncedGatewayConfig(env) {
|
|
|
8291
8571
|
token: synced.token
|
|
8292
8572
|
};
|
|
8293
8573
|
} catch (err2) {
|
|
8294
|
-
errorWithTimestamp(`${
|
|
8574
|
+
errorWithTimestamp(`${LOG_PREFIX2} failed to read synced gateway config: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
8295
8575
|
return null;
|
|
8296
8576
|
}
|
|
8297
8577
|
}
|
|
@@ -8302,7 +8582,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
|
|
|
8302
8582
|
client: {
|
|
8303
8583
|
id: "gateway-client",
|
|
8304
8584
|
displayName: "okx-a2a-node",
|
|
8305
|
-
version: "0.1.10
|
|
8585
|
+
version: "0.1.10",
|
|
8306
8586
|
platform: "node",
|
|
8307
8587
|
mode: "backend",
|
|
8308
8588
|
instanceId
|
|
@@ -8313,7 +8593,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
|
|
|
8313
8593
|
commands: [],
|
|
8314
8594
|
permissions: {},
|
|
8315
8595
|
locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
|
|
8316
|
-
userAgent: `okx-a2a-node/${"0.1.10
|
|
8596
|
+
userAgent: `okx-a2a-node/${"0.1.10"}`,
|
|
8317
8597
|
auth: {
|
|
8318
8598
|
...config.token ? { token: config.token } : {},
|
|
8319
8599
|
...config.password ? { password: config.password } : {}
|
|
@@ -8379,24 +8659,26 @@ function isSessionNotFound(err2) {
|
|
|
8379
8659
|
const msg = String(e?.message ?? "");
|
|
8380
8660
|
return (code2 === "INVALID_REQUEST" || code2 === "SESSION_NOT_FOUND") && msg.includes("session not found");
|
|
8381
8661
|
}
|
|
8382
|
-
var import_node_crypto3, DEFAULT_GATEWAY_PORT, DEFAULT_TIMEOUT_MS, DEFAULT_HEALTH_TIMEOUT_MS, PREFERRED_PROTOCOL_VERSION, LEGACY_PROTOCOL_VERSION, DEFAULT_SCOPES,
|
|
8662
|
+
var import_node_crypto3, DEFAULT_GATEWAY_PORT, DEFAULT_TIMEOUT_MS, DEFAULT_HEALTH_TIMEOUT_MS, PREFERRED_PROTOCOL_VERSION, LEGACY_PROTOCOL_VERSION, DEFAULT_SCOPES, LOG_PREFIX2, GATEWAY_STARTING_RETRY_DELAYS_MS, wsFactory, preferredGatewayProtocolVersion, sharedClient, streamStaleHandlerRegistered, isOpenClawGatewayAvailable, MinimalGatewayClient;
|
|
8383
8663
|
var init_openclaw_gateway = __esm({
|
|
8384
8664
|
"src/openclaw-gateway.ts"() {
|
|
8385
8665
|
"use strict";
|
|
8386
8666
|
init_log();
|
|
8387
8667
|
import_node_crypto3 = require("node:crypto");
|
|
8388
8668
|
init_openclaw_gateway_config();
|
|
8669
|
+
init_session_busy_tracker();
|
|
8389
8670
|
DEFAULT_GATEWAY_PORT = 18789;
|
|
8390
8671
|
DEFAULT_TIMEOUT_MS = 2e4;
|
|
8391
8672
|
DEFAULT_HEALTH_TIMEOUT_MS = 2e3;
|
|
8392
8673
|
PREFERRED_PROTOCOL_VERSION = 4;
|
|
8393
8674
|
LEGACY_PROTOCOL_VERSION = 3;
|
|
8394
8675
|
DEFAULT_SCOPES = ["operator.admin"];
|
|
8395
|
-
|
|
8676
|
+
LOG_PREFIX2 = "[okx-a2a:gateway]";
|
|
8396
8677
|
GATEWAY_STARTING_RETRY_DELAYS_MS = [300, 700, 1200, 2e3, 3e3];
|
|
8397
8678
|
wsFactory = createDefaultWebSocket;
|
|
8398
8679
|
preferredGatewayProtocolVersion = PREFERRED_PROTOCOL_VERSION;
|
|
8399
8680
|
sharedClient = null;
|
|
8681
|
+
streamStaleHandlerRegistered = false;
|
|
8400
8682
|
isOpenClawGatewayAvailable = isOpenClawA2aPluginAvailable;
|
|
8401
8683
|
MinimalGatewayClient = class {
|
|
8402
8684
|
config;
|
|
@@ -8416,7 +8698,7 @@ var init_openclaw_gateway = __esm({
|
|
|
8416
8698
|
}
|
|
8417
8699
|
async connect(timeoutMs) {
|
|
8418
8700
|
errorWithTimestamp(
|
|
8419
|
-
`${
|
|
8701
|
+
`${LOG_PREFIX2} connect url=${this.config.url} source=${this.config.source} instanceId=${this.instanceId} protocol=${this.protocolVersion} passwordConfigured=${!!this.config.password} tokenConfigured=${!!this.config.token} scopes=${DEFAULT_SCOPES.join(",")}`
|
|
8420
8702
|
);
|
|
8421
8703
|
const ws = wsFactory(this.config.url);
|
|
8422
8704
|
this.ws = ws;
|
|
@@ -8472,7 +8754,7 @@ var init_openclaw_gateway = __esm({
|
|
|
8472
8754
|
}
|
|
8473
8755
|
});
|
|
8474
8756
|
});
|
|
8475
|
-
errorWithTimestamp(`${
|
|
8757
|
+
errorWithTimestamp(`${LOG_PREFIX2} hello ok instanceId=${this.instanceId} protocol=${this.protocolVersion}`);
|
|
8476
8758
|
}
|
|
8477
8759
|
request(method, params, options = {}) {
|
|
8478
8760
|
if (method === "connect") {
|
|
@@ -8548,7 +8830,17 @@ var init_openclaw_gateway = __esm({
|
|
|
8548
8830
|
try {
|
|
8549
8831
|
frame = JSON.parse(String(raw));
|
|
8550
8832
|
} catch (err2) {
|
|
8551
|
-
errorWithTimestamp(`${
|
|
8833
|
+
errorWithTimestamp(`${LOG_PREFIX2} invalid frame: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
8834
|
+
return;
|
|
8835
|
+
}
|
|
8836
|
+
if (frame.type === "event") {
|
|
8837
|
+
const gate = getSessionBusyTracker();
|
|
8838
|
+
gate.noteEvent();
|
|
8839
|
+
if (frame.event === "chat") {
|
|
8840
|
+
gate.notifyChat(frame.payload);
|
|
8841
|
+
} else if (frame.event === "agent") {
|
|
8842
|
+
gate.notifyAgent(frame.payload);
|
|
8843
|
+
}
|
|
8552
8844
|
return;
|
|
8553
8845
|
}
|
|
8554
8846
|
if (frame.type !== "res") {
|
|
@@ -8570,7 +8862,7 @@ var init_openclaw_gateway = __esm({
|
|
|
8570
8862
|
pending.reject(toGatewayError(frame.error));
|
|
8571
8863
|
}
|
|
8572
8864
|
handleClose(code2, reason) {
|
|
8573
|
-
errorWithTimestamp(`${
|
|
8865
|
+
errorWithTimestamp(`${LOG_PREFIX2} closed instanceId=${this.instanceId} code=${code2 ?? 0} reason=${reason || "no reason"}`);
|
|
8574
8866
|
this.ready = false;
|
|
8575
8867
|
for (const [id, pending] of this.pending) {
|
|
8576
8868
|
clearTimeout(pending.timer);
|
|
@@ -9328,8 +9620,8 @@ var require_worldwide = __commonJS({
|
|
|
9328
9620
|
function getGlobalSingleton(name2, creator, obj) {
|
|
9329
9621
|
const gbl = obj || GLOBAL_OBJ;
|
|
9330
9622
|
const __SENTRY__ = gbl.__SENTRY__ = gbl.__SENTRY__ || {};
|
|
9331
|
-
const
|
|
9332
|
-
return
|
|
9623
|
+
const singleton2 = __SENTRY__[name2] || (__SENTRY__[name2] = creator());
|
|
9624
|
+
return singleton2;
|
|
9333
9625
|
}
|
|
9334
9626
|
exports2.GLOBAL_OBJ = GLOBAL_OBJ;
|
|
9335
9627
|
exports2.getGlobalObject = getGlobalObject;
|
|
@@ -24824,6 +25116,13 @@ var init_sentry_logger = __esm({
|
|
|
24824
25116
|
});
|
|
24825
25117
|
|
|
24826
25118
|
// src/outbound-behavior.ts
|
|
25119
|
+
function resolveSessionGateFallbackMs(env = process.env) {
|
|
25120
|
+
const raw = Number(env.OKX_A2A_SESSION_GATE_FALLBACK_MS ?? "");
|
|
25121
|
+
if (Number.isFinite(raw) && raw > 0) {
|
|
25122
|
+
return raw;
|
|
25123
|
+
}
|
|
25124
|
+
return DEFAULT_SESSION_GATE_FALLBACK_MS;
|
|
25125
|
+
}
|
|
24827
25126
|
function resolveUserDeliveryId(input) {
|
|
24828
25127
|
return input.idempotencyKey?.trim() || (0, import_node_crypto5.randomUUID)();
|
|
24829
25128
|
}
|
|
@@ -24884,7 +25183,7 @@ function createOutboundBehavior(provider, deps) {
|
|
|
24884
25183
|
}
|
|
24885
25184
|
return new SqliteOutboundBehavior(provider, deps);
|
|
24886
25185
|
}
|
|
24887
|
-
var import_node_crypto5, SqliteOutboundBehavior, DEFAULT_GATEWAY_PORT2, GATEWAY_OUTBOUND_LOG_PREFIX, GatewayOutboundBehavior;
|
|
25186
|
+
var import_node_crypto5, SqliteOutboundBehavior, DEFAULT_GATEWAY_PORT2, GATEWAY_OUTBOUND_LOG_PREFIX, DEFAULT_SESSION_GATE_FALLBACK_MS, GatewayOutboundBehavior;
|
|
24888
25187
|
var init_outbound_behavior = __esm({
|
|
24889
25188
|
"src/outbound-behavior.ts"() {
|
|
24890
25189
|
"use strict";
|
|
@@ -24893,6 +25192,7 @@ var init_outbound_behavior = __esm({
|
|
|
24893
25192
|
init_user_attention_ipc();
|
|
24894
25193
|
init_openclaw_gateway();
|
|
24895
25194
|
init_openclaw_session_key();
|
|
25195
|
+
init_session_busy_tracker();
|
|
24896
25196
|
init_openclaw_route();
|
|
24897
25197
|
init_sentry_logger();
|
|
24898
25198
|
SqliteOutboundBehavior = class {
|
|
@@ -24968,15 +25268,25 @@ var init_outbound_behavior = __esm({
|
|
|
24968
25268
|
callPromptUserToLatestSessions
|
|
24969
25269
|
};
|
|
24970
25270
|
GATEWAY_OUTBOUND_LOG_PREFIX = "[okx-a2a:gateway-outbound]";
|
|
25271
|
+
DEFAULT_SESSION_GATE_FALLBACK_MS = 3e5;
|
|
24971
25272
|
GatewayOutboundBehavior = class {
|
|
24972
25273
|
provider = "openclaw";
|
|
24973
25274
|
gateway;
|
|
24974
25275
|
store;
|
|
24975
25276
|
sessionMetaStore;
|
|
25277
|
+
/** `undefined` = default (resolve the shared tracker lazily on first dispatch); `null` = disabled. */
|
|
25278
|
+
sessionGateOption;
|
|
24976
25279
|
constructor(options = {}) {
|
|
24977
25280
|
this.gateway = options.gateway ?? DEFAULT_GATEWAY_PORT2;
|
|
24978
25281
|
this.store = options.store;
|
|
24979
25282
|
this.sessionMetaStore = options.store;
|
|
25283
|
+
this.sessionGateOption = options.sessionGate;
|
|
25284
|
+
}
|
|
25285
|
+
resolveSessionGate() {
|
|
25286
|
+
if (this.sessionGateOption === void 0) {
|
|
25287
|
+
return getSessionBusyTracker();
|
|
25288
|
+
}
|
|
25289
|
+
return this.sessionGateOption;
|
|
24980
25290
|
}
|
|
24981
25291
|
async createSession(input) {
|
|
24982
25292
|
const gatewaySessionKey = this.resolveGatewaySessionKey(input);
|
|
@@ -25029,8 +25339,19 @@ var init_outbound_behavior = __esm({
|
|
|
25029
25339
|
errorWithTimestamp(
|
|
25030
25340
|
`${GATEWAY_OUTBOUND_LOG_PREFIX} dispatchSessionMessage sessionKey=${input.sessionKey} gatewaySessionKey=${gatewaySessionKey} jobId=${input.jobId ?? "(none)"} agentId=${input.agentId ?? "(none)"} messageId=${input.messageId ?? "(none)"}`
|
|
25031
25341
|
);
|
|
25342
|
+
const sessionGate = this.resolveSessionGate();
|
|
25343
|
+
const gateFallbackMs = resolveSessionGateFallbackMs();
|
|
25344
|
+
if (sessionGate?.isSessionBusy(gatewaySessionKey)) {
|
|
25345
|
+
errorWithTimestamp(
|
|
25346
|
+
`${GATEWAY_OUTBOUND_LOG_PREFIX} [session-gate] busy, waiting idle sessionKey=${input.sessionKey} gatewaySessionKey=${gatewaySessionKey} (fallbackMs=${gateFallbackMs})`
|
|
25347
|
+
);
|
|
25348
|
+
const idleState = await sessionGate.waitForSessionIdle(gatewaySessionKey, gateFallbackMs);
|
|
25349
|
+
errorWithTimestamp(
|
|
25350
|
+
`${GATEWAY_OUTBOUND_LOG_PREFIX} [session-gate] idle wait done sessionKey=${input.sessionKey} gatewaySessionKey=${gatewaySessionKey} result=${idleState}`
|
|
25351
|
+
);
|
|
25352
|
+
}
|
|
25032
25353
|
try {
|
|
25033
|
-
await this.gateway.callSessionsSend({
|
|
25354
|
+
const sendResult = await this.gateway.callSessionsSend({
|
|
25034
25355
|
key: gatewaySessionKey,
|
|
25035
25356
|
message: input.content,
|
|
25036
25357
|
...input.messageId ? { idempotencyKey: input.messageId } : {}
|
|
@@ -25045,6 +25366,16 @@ var init_outbound_behavior = __esm({
|
|
|
25045
25366
|
messageId: input.messageId ?? "",
|
|
25046
25367
|
status: "delivered"
|
|
25047
25368
|
}));
|
|
25369
|
+
const gateRunId = sendResult && typeof sendResult === "object" && typeof sendResult.runId === "string" ? sendResult.runId : input.messageId;
|
|
25370
|
+
if (sessionGate && typeof gateRunId === "string" && gateRunId) {
|
|
25371
|
+
errorWithTimestamp(
|
|
25372
|
+
`${GATEWAY_OUTBOUND_LOG_PREFIX} [session-gate] holding sessionKey=${input.sessionKey} gatewaySessionKey=${gatewaySessionKey} runId=${gateRunId} until run final/error (fallbackMs=${gateFallbackMs})`
|
|
25373
|
+
);
|
|
25374
|
+
const gateState = await sessionGate.waitForRunFinal(gateRunId, gateFallbackMs);
|
|
25375
|
+
errorWithTimestamp(
|
|
25376
|
+
`${GATEWAY_OUTBOUND_LOG_PREFIX} [session-gate] released sessionKey=${input.sessionKey} gatewaySessionKey=${gatewaySessionKey} runId=${gateRunId} state=${gateState}`
|
|
25377
|
+
);
|
|
25378
|
+
}
|
|
25048
25379
|
} catch (err2) {
|
|
25049
25380
|
if (!this.store || !isRetryableOpenClawGatewayError(err2)) {
|
|
25050
25381
|
logger.error(LogEvent.GATEWAY_REQUEST_FAILED, err2 instanceof Error ? err2 : new Error(String(err2)), gatewayOutboundExtra("sessions.send", {
|
|
@@ -25584,7 +25915,7 @@ var init_sentry_config = __esm({
|
|
|
25584
25915
|
environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
|
|
25585
25916
|
SENTRY_CONFIG = {
|
|
25586
25917
|
projectName: "okx/openclaw-okx-a2a-extension",
|
|
25587
|
-
release: "0.1.10
|
|
25918
|
+
release: "0.1.10",
|
|
25588
25919
|
environment,
|
|
25589
25920
|
runtimeContainer: normalizeRuntimeContainer(process.env.OKX_A2A_RUNTIME_CONTAINER)
|
|
25590
25921
|
};
|
|
@@ -94318,12 +94649,12 @@ async function runListenerWithLock(options, paths) {
|
|
|
94318
94649
|
});
|
|
94319
94650
|
}
|
|
94320
94651
|
});
|
|
94321
|
-
service.setPluginVersion("0.1.10
|
|
94652
|
+
service.setPluginVersion("0.1.10");
|
|
94322
94653
|
await service.init();
|
|
94323
94654
|
const pluginVersionStatus = service.pluginVersionStatus;
|
|
94324
94655
|
if (pluginVersionStatus.unavailable) {
|
|
94325
94656
|
throw new Error(
|
|
94326
|
-
`@okxweb3/a2a-node v${"0.1.10
|
|
94657
|
+
`@okxweb3/a2a-node v${"0.1.10"} is below the required minimum v${pluginVersionStatus.minVersion}`
|
|
94327
94658
|
);
|
|
94328
94659
|
}
|
|
94329
94660
|
const systemConfig = service.getSystemConfig();
|
|
@@ -94341,7 +94672,7 @@ async function runListenerWithLock(options, paths) {
|
|
|
94341
94672
|
onchainosAgentId: "*",
|
|
94342
94673
|
reason: "system-config missing sentryDsn",
|
|
94343
94674
|
pluginId: "@okxweb3/a2a-node",
|
|
94344
|
-
pluginVersion: "0.1.10
|
|
94675
|
+
pluginVersion: "0.1.10"
|
|
94345
94676
|
});
|
|
94346
94677
|
}
|
|
94347
94678
|
logWithTimestamp(
|
|
@@ -98363,7 +98694,7 @@ async function getCurrentNodeCliVersion() {
|
|
|
98363
98694
|
return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
|
|
98364
98695
|
}
|
|
98365
98696
|
function getBundledNodeCliVersion() {
|
|
98366
|
-
return true ? "0.1.10
|
|
98697
|
+
return true ? "0.1.10" : null;
|
|
98367
98698
|
}
|
|
98368
98699
|
function readConfiguredAiProvider() {
|
|
98369
98700
|
const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
|
|
@@ -98573,7 +98904,7 @@ async function updateHermes(release, options) {
|
|
|
98573
98904
|
}
|
|
98574
98905
|
}
|
|
98575
98906
|
async function installGatewayPluginForDoctor(target) {
|
|
98576
|
-
const release = isPrereleaseVersion("0.1.10
|
|
98907
|
+
const release = isPrereleaseVersion("0.1.10") ? "beta" : "latest";
|
|
98577
98908
|
const insideTargetGateway = detectGatewayInvocation() === target;
|
|
98578
98909
|
const options = {
|
|
98579
98910
|
restart: !insideTargetGateway,
|
|
@@ -99561,7 +99892,7 @@ async function runDoctor(options = {}) {
|
|
|
99561
99892
|
platform: options.platform ?? process.platform,
|
|
99562
99893
|
env: options.env ?? process.env,
|
|
99563
99894
|
target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
|
|
99564
|
-
cliVersion: options.cliVersion ?? (true ? "0.1.10
|
|
99895
|
+
cliVersion: options.cliVersion ?? (true ? "0.1.10" : "0.0.0"),
|
|
99565
99896
|
fixMode: options.fix === true,
|
|
99566
99897
|
nonInteractive: options.nonInteractive === true,
|
|
99567
99898
|
packageChanged: false,
|
|
@@ -100693,7 +101024,7 @@ init_sentry_logger();
|
|
|
100693
101024
|
init_sentry_config();
|
|
100694
101025
|
var CURRENT_GATEWAY_SESSION_KEYS_ENV4 = "OKX_A2A_CURRENT_GATEWAY_SESSION_KEYS";
|
|
100695
101026
|
function printUsage2() {
|
|
100696
|
-
console.log(`okx-a2a ${"0.1.10
|
|
101027
|
+
console.log(`okx-a2a ${"0.1.10"}
|
|
100697
101028
|
|
|
100698
101029
|
Usage:
|
|
100699
101030
|
okx-a2a <command> [options]
|
|
@@ -100731,7 +101062,7 @@ Run \`okx-a2a <command> -h\` for command-specific help.
|
|
|
100731
101062
|
`);
|
|
100732
101063
|
}
|
|
100733
101064
|
function printVersion() {
|
|
100734
|
-
console.log("0.1.10
|
|
101065
|
+
console.log("0.1.10");
|
|
100735
101066
|
}
|
|
100736
101067
|
function printDaemonUsage() {
|
|
100737
101068
|
console.log(`Usage: okx-a2a daemon <start|restart|stop|status|autostart> [options]
|
|
@@ -101977,9 +102308,9 @@ function assertSupportedNodeVersion() {
|
|
|
101977
102308
|
const major = Number(majorRaw);
|
|
101978
102309
|
const minor = Number(minorRaw);
|
|
101979
102310
|
const patch = Number(patchRaw);
|
|
101980
|
-
const supported = major > 22 || major === 22 && (minor >
|
|
102311
|
+
const supported = major > 22 || major === 22 && (minor > 14 || minor === 14 && patch >= 0);
|
|
101981
102312
|
if (!supported) {
|
|
101982
|
-
throw new Error(`okx-a2a requires Node.js >= 22.
|
|
102313
|
+
throw new Error(`okx-a2a requires Node.js >= 22.14.0, current=${process.version}`);
|
|
101983
102314
|
}
|
|
101984
102315
|
}
|
|
101985
102316
|
var cliSentryInitAttempted = false;
|
package/dist/index.js
CHANGED
|
@@ -3816,8 +3816,8 @@ var require_worldwide = __commonJS({
|
|
|
3816
3816
|
function getGlobalSingleton(name2, creator, obj) {
|
|
3817
3817
|
const gbl = obj || GLOBAL_OBJ;
|
|
3818
3818
|
const __SENTRY__ = gbl.__SENTRY__ = gbl.__SENTRY__ || {};
|
|
3819
|
-
const
|
|
3820
|
-
return
|
|
3819
|
+
const singleton2 = __SENTRY__[name2] || (__SENTRY__[name2] = creator());
|
|
3820
|
+
return singleton2;
|
|
3821
3821
|
}
|
|
3822
3822
|
exports2.GLOBAL_OBJ = GLOBAL_OBJ;
|
|
3823
3823
|
exports2.getGlobalObject = getGlobalObject;
|
|
@@ -71981,7 +71981,7 @@ var init_sentry_config = __esm({
|
|
|
71981
71981
|
environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
|
|
71982
71982
|
SENTRY_CONFIG = {
|
|
71983
71983
|
projectName: "okx/openclaw-okx-a2a-extension",
|
|
71984
|
-
release: "0.1.10
|
|
71984
|
+
release: "0.1.10",
|
|
71985
71985
|
environment,
|
|
71986
71986
|
runtimeContainer: normalizeRuntimeContainer(process.env.OKX_A2A_RUNTIME_CONTAINER)
|
|
71987
71987
|
};
|
|
@@ -72911,7 +72911,7 @@ async function getCurrentNodeCliVersion() {
|
|
|
72911
72911
|
return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
|
|
72912
72912
|
}
|
|
72913
72913
|
function getBundledNodeCliVersion() {
|
|
72914
|
-
return true ? "0.1.10
|
|
72914
|
+
return true ? "0.1.10" : null;
|
|
72915
72915
|
}
|
|
72916
72916
|
function readConfiguredAiProvider() {
|
|
72917
72917
|
const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
|
|
@@ -73121,7 +73121,7 @@ async function updateHermes(release, options) {
|
|
|
73121
73121
|
}
|
|
73122
73122
|
}
|
|
73123
73123
|
async function installGatewayPluginForDoctor(target) {
|
|
73124
|
-
const release = isPrereleaseVersion("0.1.10
|
|
73124
|
+
const release = isPrereleaseVersion("0.1.10") ? "beta" : "latest";
|
|
73125
73125
|
const insideTargetGateway = detectGatewayInvocation() === target;
|
|
73126
73126
|
const options = {
|
|
73127
73127
|
restart: !insideTargetGateway,
|
|
@@ -74005,6 +74005,7 @@ __export(index_exports, {
|
|
|
74005
74005
|
NATIVE_LAUNCHER_EXE_NAME: () => NATIVE_LAUNCHER_EXE_NAME,
|
|
74006
74006
|
OPENCLAW_GATEWAY_ROUTE_GROUP_ID: () => OPENCLAW_GATEWAY_ROUTE_GROUP_ID,
|
|
74007
74007
|
SYSTEM_NOTIFICATION_SESSION_KEY: () => SYSTEM_NOTIFICATION_SESSION_KEY,
|
|
74008
|
+
SessionBusyTracker: () => SessionBusyTracker,
|
|
74008
74009
|
SessionStore: () => SessionStore,
|
|
74009
74010
|
SqliteOutboundBehavior: () => SqliteOutboundBehavior,
|
|
74010
74011
|
TASK_NAME: () => TASK_NAME,
|
|
@@ -74070,6 +74071,7 @@ __export(index_exports, {
|
|
|
74070
74071
|
formatDoctorReportForHumans: () => formatDoctorReportForHumans,
|
|
74071
74072
|
getDaemonStatus: () => getDaemonStatus,
|
|
74072
74073
|
getHermesGatewayPluginStatus: () => getHermesGatewayPluginStatus,
|
|
74074
|
+
getSessionBusyTracker: () => getSessionBusyTracker,
|
|
74073
74075
|
handleDoctorCommand: () => handleDoctorCommand,
|
|
74074
74076
|
handleXmtpSendCommand: () => handleXmtpSendCommand,
|
|
74075
74077
|
hasAiRuntimeMarker: () => hasAiRuntimeMarker,
|
|
@@ -89244,6 +89246,268 @@ function readSyncedOpenClawGatewayConfig(homeDir = resolveA2aTaskHome()) {
|
|
|
89244
89246
|
};
|
|
89245
89247
|
}
|
|
89246
89248
|
|
|
89249
|
+
// src/session-busy-tracker.ts
|
|
89250
|
+
init_log();
|
|
89251
|
+
var RING_MAX = 256;
|
|
89252
|
+
var DEFAULT_STALE_RUN_MS = 10 * 60 * 1e3;
|
|
89253
|
+
var DEFAULT_STREAM_STALE_MS = 60 * 1e3;
|
|
89254
|
+
var DEFAULT_WATCHDOG_INTERVAL_MS = 5 * 1e3;
|
|
89255
|
+
var LOG_PREFIX = "[okx-a2a:session-gate]";
|
|
89256
|
+
var SessionBusyTracker = class {
|
|
89257
|
+
now;
|
|
89258
|
+
staleRunMs;
|
|
89259
|
+
streamStaleMs;
|
|
89260
|
+
watchdogIntervalMs;
|
|
89261
|
+
/** runIds that reached a terminal state; guards against late/out-of-order deltas. */
|
|
89262
|
+
finalized = [];
|
|
89263
|
+
runWaiters = /* @__PURE__ */ new Map();
|
|
89264
|
+
/** sessionKey → (runId → lastSeenMs). */
|
|
89265
|
+
activeRuns = /* @__PURE__ */ new Map();
|
|
89266
|
+
idleWaiters = /* @__PURE__ */ new Map();
|
|
89267
|
+
lastEventAtMs;
|
|
89268
|
+
lastStreamStaleFireMs = 0;
|
|
89269
|
+
streamStaleHandler = null;
|
|
89270
|
+
pendingWaiters = 0;
|
|
89271
|
+
watchdogTimer = null;
|
|
89272
|
+
constructor(options = {}) {
|
|
89273
|
+
this.now = options.now ?? Date.now;
|
|
89274
|
+
this.staleRunMs = options.staleRunMs ?? DEFAULT_STALE_RUN_MS;
|
|
89275
|
+
this.streamStaleMs = options.streamStaleMs ?? DEFAULT_STREAM_STALE_MS;
|
|
89276
|
+
this.watchdogIntervalMs = options.watchdogIntervalMs ?? DEFAULT_WATCHDOG_INTERVAL_MS;
|
|
89277
|
+
this.lastEventAtMs = this.now();
|
|
89278
|
+
}
|
|
89279
|
+
/** Any event frame arrived (chat/agent/tick/health/...): the stream is alive. */
|
|
89280
|
+
noteEvent() {
|
|
89281
|
+
this.lastEventAtMs = this.now();
|
|
89282
|
+
}
|
|
89283
|
+
/** Reconnect hook invoked when the event stream goes silent while a wait is pending. */
|
|
89284
|
+
setStreamStaleHandler(handler) {
|
|
89285
|
+
this.streamStaleHandler = handler;
|
|
89286
|
+
}
|
|
89287
|
+
notifyChat(payload) {
|
|
89288
|
+
if (!payload || typeof payload !== "object") {
|
|
89289
|
+
return;
|
|
89290
|
+
}
|
|
89291
|
+
const frame = payload;
|
|
89292
|
+
const runId = typeof frame.runId === "string" ? frame.runId : "";
|
|
89293
|
+
const sessionKey = typeof frame.sessionKey === "string" ? frame.sessionKey : "";
|
|
89294
|
+
const state = typeof frame.state === "string" ? frame.state : "";
|
|
89295
|
+
if (!runId) {
|
|
89296
|
+
return;
|
|
89297
|
+
}
|
|
89298
|
+
if (state === "final" || state === "error" || state === "aborted") {
|
|
89299
|
+
this.markDone(sessionKey, runId, state);
|
|
89300
|
+
} else {
|
|
89301
|
+
this.markActive(sessionKey, runId);
|
|
89302
|
+
}
|
|
89303
|
+
}
|
|
89304
|
+
notifyAgent(payload) {
|
|
89305
|
+
if (!payload || typeof payload !== "object") {
|
|
89306
|
+
return;
|
|
89307
|
+
}
|
|
89308
|
+
const frame = payload;
|
|
89309
|
+
const runId = typeof frame.runId === "string" ? frame.runId : "";
|
|
89310
|
+
const sessionKey = typeof frame.sessionKey === "string" ? frame.sessionKey : "";
|
|
89311
|
+
const phase = frame.data && typeof frame.data === "object" ? frame.data.phase : void 0;
|
|
89312
|
+
if (!runId) {
|
|
89313
|
+
return;
|
|
89314
|
+
}
|
|
89315
|
+
if (frame.stream === "lifecycle" && (phase === "end" || phase === "error")) {
|
|
89316
|
+
this.markDone(sessionKey, runId, String(phase));
|
|
89317
|
+
} else {
|
|
89318
|
+
this.markActive(sessionKey, runId);
|
|
89319
|
+
}
|
|
89320
|
+
}
|
|
89321
|
+
isSessionBusy(sessionKey) {
|
|
89322
|
+
const runs = this.activeRuns.get(sessionKey);
|
|
89323
|
+
if (!runs) {
|
|
89324
|
+
return false;
|
|
89325
|
+
}
|
|
89326
|
+
const now = this.now();
|
|
89327
|
+
for (const [runId, lastSeen] of runs) {
|
|
89328
|
+
if (now - lastSeen > this.staleRunMs) {
|
|
89329
|
+
runs.delete(runId);
|
|
89330
|
+
}
|
|
89331
|
+
}
|
|
89332
|
+
if (runs.size === 0) {
|
|
89333
|
+
this.activeRuns.delete(sessionKey);
|
|
89334
|
+
return false;
|
|
89335
|
+
}
|
|
89336
|
+
return true;
|
|
89337
|
+
}
|
|
89338
|
+
waitForSessionIdle(sessionKey, timeoutMs) {
|
|
89339
|
+
if (!this.isSessionBusy(sessionKey)) {
|
|
89340
|
+
return Promise.resolve("idle");
|
|
89341
|
+
}
|
|
89342
|
+
return new Promise((resolve6) => {
|
|
89343
|
+
let waiters = this.idleWaiters.get(sessionKey);
|
|
89344
|
+
if (!waiters) {
|
|
89345
|
+
waiters = /* @__PURE__ */ new Set();
|
|
89346
|
+
this.idleWaiters.set(sessionKey, waiters);
|
|
89347
|
+
}
|
|
89348
|
+
this.beginWait();
|
|
89349
|
+
const entry = (state) => {
|
|
89350
|
+
clearTimeout(timer);
|
|
89351
|
+
this.endWait();
|
|
89352
|
+
resolve6(state);
|
|
89353
|
+
};
|
|
89354
|
+
const timer = setTimeout(() => {
|
|
89355
|
+
const cur = this.idleWaiters.get(sessionKey);
|
|
89356
|
+
if (cur) {
|
|
89357
|
+
cur.delete(entry);
|
|
89358
|
+
if (cur.size === 0) {
|
|
89359
|
+
this.idleWaiters.delete(sessionKey);
|
|
89360
|
+
}
|
|
89361
|
+
}
|
|
89362
|
+
this.endWait();
|
|
89363
|
+
resolve6("timeout");
|
|
89364
|
+
}, timeoutMs);
|
|
89365
|
+
waiters.add(entry);
|
|
89366
|
+
});
|
|
89367
|
+
}
|
|
89368
|
+
waitForRunFinal(runId, timeoutMs) {
|
|
89369
|
+
if (this.finalized.includes(runId)) {
|
|
89370
|
+
return Promise.resolve("already-final");
|
|
89371
|
+
}
|
|
89372
|
+
return new Promise((resolve6) => {
|
|
89373
|
+
let waiters = this.runWaiters.get(runId);
|
|
89374
|
+
if (!waiters) {
|
|
89375
|
+
waiters = /* @__PURE__ */ new Set();
|
|
89376
|
+
this.runWaiters.set(runId, waiters);
|
|
89377
|
+
}
|
|
89378
|
+
this.beginWait();
|
|
89379
|
+
const entry = (state) => {
|
|
89380
|
+
clearTimeout(timer);
|
|
89381
|
+
this.endWait();
|
|
89382
|
+
resolve6(state);
|
|
89383
|
+
};
|
|
89384
|
+
const timer = setTimeout(() => {
|
|
89385
|
+
const cur = this.runWaiters.get(runId);
|
|
89386
|
+
if (cur) {
|
|
89387
|
+
cur.delete(entry);
|
|
89388
|
+
if (cur.size === 0) {
|
|
89389
|
+
this.runWaiters.delete(runId);
|
|
89390
|
+
}
|
|
89391
|
+
}
|
|
89392
|
+
this.endWait();
|
|
89393
|
+
resolve6("timeout");
|
|
89394
|
+
}, timeoutMs);
|
|
89395
|
+
waiters.add(entry);
|
|
89396
|
+
});
|
|
89397
|
+
}
|
|
89398
|
+
_debugSnapshot() {
|
|
89399
|
+
return {
|
|
89400
|
+
active: Array.from(this.activeRuns, ([key, runs]) => {
|
|
89401
|
+
return [key, Array.from(runs.keys())];
|
|
89402
|
+
}),
|
|
89403
|
+
finalizedTail: this.finalized.slice(-10)
|
|
89404
|
+
};
|
|
89405
|
+
}
|
|
89406
|
+
rememberFinalized(runId) {
|
|
89407
|
+
if (!this.finalized.includes(runId)) {
|
|
89408
|
+
this.finalized.push(runId);
|
|
89409
|
+
if (this.finalized.length > RING_MAX) {
|
|
89410
|
+
this.finalized.shift();
|
|
89411
|
+
}
|
|
89412
|
+
}
|
|
89413
|
+
}
|
|
89414
|
+
markActive(sessionKey, runId) {
|
|
89415
|
+
if (!sessionKey || !runId || this.finalized.includes(runId)) {
|
|
89416
|
+
return;
|
|
89417
|
+
}
|
|
89418
|
+
let runs = this.activeRuns.get(sessionKey);
|
|
89419
|
+
if (!runs) {
|
|
89420
|
+
runs = /* @__PURE__ */ new Map();
|
|
89421
|
+
this.activeRuns.set(sessionKey, runs);
|
|
89422
|
+
}
|
|
89423
|
+
runs.set(runId, this.now());
|
|
89424
|
+
}
|
|
89425
|
+
markDone(sessionKey, runId, state) {
|
|
89426
|
+
if (runId) {
|
|
89427
|
+
this.rememberFinalized(runId);
|
|
89428
|
+
const waiters = this.runWaiters.get(runId);
|
|
89429
|
+
if (waiters) {
|
|
89430
|
+
this.runWaiters.delete(runId);
|
|
89431
|
+
for (const fn of waiters) {
|
|
89432
|
+
fn(state);
|
|
89433
|
+
}
|
|
89434
|
+
}
|
|
89435
|
+
const runs = sessionKey ? this.activeRuns.get(sessionKey) : void 0;
|
|
89436
|
+
if (runs) {
|
|
89437
|
+
runs.delete(runId);
|
|
89438
|
+
if (runs.size === 0) {
|
|
89439
|
+
this.activeRuns.delete(sessionKey);
|
|
89440
|
+
}
|
|
89441
|
+
} else {
|
|
89442
|
+
for (const [key, sessionRuns] of this.activeRuns) {
|
|
89443
|
+
if (sessionRuns.delete(runId) && sessionRuns.size === 0) {
|
|
89444
|
+
this.activeRuns.delete(key);
|
|
89445
|
+
}
|
|
89446
|
+
}
|
|
89447
|
+
}
|
|
89448
|
+
}
|
|
89449
|
+
if (sessionKey) {
|
|
89450
|
+
this.releaseIdleWaiters(sessionKey);
|
|
89451
|
+
}
|
|
89452
|
+
}
|
|
89453
|
+
releaseIdleWaiters(sessionKey) {
|
|
89454
|
+
if (!sessionKey || this.isSessionBusy(sessionKey)) {
|
|
89455
|
+
return;
|
|
89456
|
+
}
|
|
89457
|
+
const waiters = this.idleWaiters.get(sessionKey);
|
|
89458
|
+
if (waiters) {
|
|
89459
|
+
this.idleWaiters.delete(sessionKey);
|
|
89460
|
+
for (const fn of waiters) {
|
|
89461
|
+
fn("idle");
|
|
89462
|
+
}
|
|
89463
|
+
}
|
|
89464
|
+
}
|
|
89465
|
+
beginWait() {
|
|
89466
|
+
this.pendingWaiters += 1;
|
|
89467
|
+
if (this.pendingWaiters === 1 && !this.watchdogTimer) {
|
|
89468
|
+
const timer = setInterval(() => {
|
|
89469
|
+
this.checkStreamLiveness();
|
|
89470
|
+
}, this.watchdogIntervalMs);
|
|
89471
|
+
timer.unref?.();
|
|
89472
|
+
this.watchdogTimer = timer;
|
|
89473
|
+
}
|
|
89474
|
+
}
|
|
89475
|
+
endWait() {
|
|
89476
|
+
this.pendingWaiters = Math.max(0, this.pendingWaiters - 1);
|
|
89477
|
+
if (this.pendingWaiters === 0 && this.watchdogTimer) {
|
|
89478
|
+
clearInterval(this.watchdogTimer);
|
|
89479
|
+
this.watchdogTimer = null;
|
|
89480
|
+
}
|
|
89481
|
+
}
|
|
89482
|
+
checkStreamLiveness() {
|
|
89483
|
+
const now = this.now();
|
|
89484
|
+
if (now - this.lastEventAtMs <= this.streamStaleMs) {
|
|
89485
|
+
return;
|
|
89486
|
+
}
|
|
89487
|
+
if (now - this.lastStreamStaleFireMs <= this.streamStaleMs) {
|
|
89488
|
+
return;
|
|
89489
|
+
}
|
|
89490
|
+
this.lastStreamStaleFireMs = now;
|
|
89491
|
+
errorWithTimestamp(
|
|
89492
|
+
`${LOG_PREFIX} event stream stale (${now - this.lastEventAtMs}ms since last event, threshold=${this.streamStaleMs}ms), invoking recovery handler`
|
|
89493
|
+
);
|
|
89494
|
+
try {
|
|
89495
|
+
this.streamStaleHandler?.();
|
|
89496
|
+
} catch (err2) {
|
|
89497
|
+
errorWithTimestamp(
|
|
89498
|
+
`${LOG_PREFIX} stream recovery handler failed: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
89499
|
+
);
|
|
89500
|
+
}
|
|
89501
|
+
}
|
|
89502
|
+
};
|
|
89503
|
+
var singleton = null;
|
|
89504
|
+
function getSessionBusyTracker() {
|
|
89505
|
+
if (!singleton) {
|
|
89506
|
+
singleton = new SessionBusyTracker();
|
|
89507
|
+
}
|
|
89508
|
+
return singleton;
|
|
89509
|
+
}
|
|
89510
|
+
|
|
89247
89511
|
// src/openclaw-gateway.ts
|
|
89248
89512
|
var DEFAULT_GATEWAY_PORT = 18789;
|
|
89249
89513
|
var DEFAULT_TIMEOUT_MS = 2e4;
|
|
@@ -89251,7 +89515,7 @@ var DEFAULT_HEALTH_TIMEOUT_MS = 2e3;
|
|
|
89251
89515
|
var PREFERRED_PROTOCOL_VERSION = 4;
|
|
89252
89516
|
var LEGACY_PROTOCOL_VERSION = 3;
|
|
89253
89517
|
var DEFAULT_SCOPES = ["operator.admin"];
|
|
89254
|
-
var
|
|
89518
|
+
var LOG_PREFIX2 = "[okx-a2a:gateway]";
|
|
89255
89519
|
var GATEWAY_STARTING_RETRY_DELAYS_MS = [300, 700, 1200, 2e3, 3e3];
|
|
89256
89520
|
var wsFactory = createDefaultWebSocket;
|
|
89257
89521
|
var preferredGatewayProtocolVersion = PREFERRED_PROTOCOL_VERSION;
|
|
@@ -89303,6 +89567,18 @@ function createDefaultWebSocket(url) {
|
|
|
89303
89567
|
return new Ctor(url);
|
|
89304
89568
|
}
|
|
89305
89569
|
var sharedClient = null;
|
|
89570
|
+
var streamStaleHandlerRegistered = false;
|
|
89571
|
+
function ensureStreamStaleHandlerRegistered() {
|
|
89572
|
+
if (streamStaleHandlerRegistered) {
|
|
89573
|
+
return;
|
|
89574
|
+
}
|
|
89575
|
+
streamStaleHandlerRegistered = true;
|
|
89576
|
+
getSessionBusyTracker().setStreamStaleHandler(() => {
|
|
89577
|
+
errorWithTimestamp(`${LOG_PREFIX2} [session-gate] event stream stale, forcing gateway reconnect`);
|
|
89578
|
+
clearClient();
|
|
89579
|
+
void isOpenClawA2aPluginAvailable();
|
|
89580
|
+
});
|
|
89581
|
+
}
|
|
89306
89582
|
function resolveOpenClawGatewayConfig(env = process.env) {
|
|
89307
89583
|
const synced = readSyncedGatewayConfig(env);
|
|
89308
89584
|
const explicitUrl = env.OKX_A2A_OPENCLAW_GATEWAY_URL?.trim() || void 0;
|
|
@@ -89324,12 +89600,13 @@ function setOpenClawWebSocketFactoryForTests(factory) {
|
|
|
89324
89600
|
}
|
|
89325
89601
|
function clearClient() {
|
|
89326
89602
|
if (sharedClient) {
|
|
89327
|
-
errorWithTimestamp(`${
|
|
89603
|
+
errorWithTimestamp(`${LOG_PREFIX2} clear client`);
|
|
89328
89604
|
sharedClient.close();
|
|
89329
89605
|
}
|
|
89330
89606
|
sharedClient = null;
|
|
89331
89607
|
}
|
|
89332
89608
|
async function ensureClient(timeoutMs) {
|
|
89609
|
+
ensureStreamStaleHandlerRegistered();
|
|
89333
89610
|
if (sharedClient?.isReady()) {
|
|
89334
89611
|
return sharedClient;
|
|
89335
89612
|
}
|
|
@@ -89353,7 +89630,7 @@ async function ensureClient(timeoutMs) {
|
|
|
89353
89630
|
const remainingMs = Math.max(1, timeoutMs - elapsedMs);
|
|
89354
89631
|
const fallbackProtocol = firstProtocol === PREFERRED_PROTOCOL_VERSION ? LEGACY_PROTOCOL_VERSION : PREFERRED_PROTOCOL_VERSION;
|
|
89355
89632
|
errorWithTimestamp(
|
|
89356
|
-
`${
|
|
89633
|
+
`${LOG_PREFIX2} protocol fallback from=${firstProtocol} to=${fallbackProtocol} remainingMs=${remainingMs}: ${formatErrorMessage(err2)}`
|
|
89357
89634
|
);
|
|
89358
89635
|
const fallbackClient = new MinimalGatewayClient(config, fallbackProtocol);
|
|
89359
89636
|
sharedClient = fallbackClient;
|
|
@@ -89364,7 +89641,7 @@ async function ensureClient(timeoutMs) {
|
|
|
89364
89641
|
}
|
|
89365
89642
|
function stopOpenClawGateway() {
|
|
89366
89643
|
if (!sharedClient) {
|
|
89367
|
-
errorWithTimestamp(`${
|
|
89644
|
+
errorWithTimestamp(`${LOG_PREFIX2} stop requested with no active client`);
|
|
89368
89645
|
return;
|
|
89369
89646
|
}
|
|
89370
89647
|
clearClient();
|
|
@@ -89372,12 +89649,12 @@ function stopOpenClawGateway() {
|
|
|
89372
89649
|
async function callOpenClawGateway(opts) {
|
|
89373
89650
|
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
89374
89651
|
const startedAt = Date.now();
|
|
89375
|
-
errorWithTimestamp(`${
|
|
89652
|
+
errorWithTimestamp(`${LOG_PREFIX2} rpc start method=${opts.method} timeoutMs=${timeoutMs}`);
|
|
89376
89653
|
for (let attempt = 0; ; attempt += 1) {
|
|
89377
89654
|
try {
|
|
89378
89655
|
const client = await ensureClient(timeoutMs);
|
|
89379
89656
|
const result = await client.request(opts.method, opts.params, { timeoutMs });
|
|
89380
|
-
errorWithTimestamp(`${
|
|
89657
|
+
errorWithTimestamp(`${LOG_PREFIX2} rpc ok method=${opts.method} durationMs=${Date.now() - startedAt} attempts=${attempt + 1}`);
|
|
89381
89658
|
return result;
|
|
89382
89659
|
} catch (err2) {
|
|
89383
89660
|
const message = err2 instanceof Error ? err2.message : String(err2);
|
|
@@ -89387,13 +89664,13 @@ async function callOpenClawGateway(opts) {
|
|
|
89387
89664
|
}
|
|
89388
89665
|
if (isGatewayStartingError(err2) && delayMs !== void 0 && Date.now() + delayMs - startedAt < timeoutMs) {
|
|
89389
89666
|
errorWithTimestamp(
|
|
89390
|
-
`${
|
|
89667
|
+
`${LOG_PREFIX2} rpc retry method=${opts.method} attempt=${attempt + 1} delayMs=${delayMs}: ${message}`
|
|
89391
89668
|
);
|
|
89392
89669
|
await sleep2(delayMs);
|
|
89393
89670
|
continue;
|
|
89394
89671
|
}
|
|
89395
89672
|
errorWithTimestamp(
|
|
89396
|
-
`${
|
|
89673
|
+
`${LOG_PREFIX2} rpc failed method=${opts.method} durationMs=${Date.now() - startedAt} attempts=${attempt + 1}: ${message}`
|
|
89397
89674
|
);
|
|
89398
89675
|
if (isGatewayStartingError(err2)) {
|
|
89399
89676
|
throw Object.assign(
|
|
@@ -89502,7 +89779,7 @@ var MinimalGatewayClient = class {
|
|
|
89502
89779
|
}
|
|
89503
89780
|
async connect(timeoutMs) {
|
|
89504
89781
|
errorWithTimestamp(
|
|
89505
|
-
`${
|
|
89782
|
+
`${LOG_PREFIX2} connect url=${this.config.url} source=${this.config.source} instanceId=${this.instanceId} protocol=${this.protocolVersion} passwordConfigured=${!!this.config.password} tokenConfigured=${!!this.config.token} scopes=${DEFAULT_SCOPES.join(",")}`
|
|
89506
89783
|
);
|
|
89507
89784
|
const ws = wsFactory(this.config.url);
|
|
89508
89785
|
this.ws = ws;
|
|
@@ -89558,7 +89835,7 @@ var MinimalGatewayClient = class {
|
|
|
89558
89835
|
}
|
|
89559
89836
|
});
|
|
89560
89837
|
});
|
|
89561
|
-
errorWithTimestamp(`${
|
|
89838
|
+
errorWithTimestamp(`${LOG_PREFIX2} hello ok instanceId=${this.instanceId} protocol=${this.protocolVersion}`);
|
|
89562
89839
|
}
|
|
89563
89840
|
request(method, params, options = {}) {
|
|
89564
89841
|
if (method === "connect") {
|
|
@@ -89634,7 +89911,17 @@ var MinimalGatewayClient = class {
|
|
|
89634
89911
|
try {
|
|
89635
89912
|
frame = JSON.parse(String(raw));
|
|
89636
89913
|
} catch (err2) {
|
|
89637
|
-
errorWithTimestamp(`${
|
|
89914
|
+
errorWithTimestamp(`${LOG_PREFIX2} invalid frame: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
89915
|
+
return;
|
|
89916
|
+
}
|
|
89917
|
+
if (frame.type === "event") {
|
|
89918
|
+
const gate = getSessionBusyTracker();
|
|
89919
|
+
gate.noteEvent();
|
|
89920
|
+
if (frame.event === "chat") {
|
|
89921
|
+
gate.notifyChat(frame.payload);
|
|
89922
|
+
} else if (frame.event === "agent") {
|
|
89923
|
+
gate.notifyAgent(frame.payload);
|
|
89924
|
+
}
|
|
89638
89925
|
return;
|
|
89639
89926
|
}
|
|
89640
89927
|
if (frame.type !== "res") {
|
|
@@ -89656,7 +89943,7 @@ var MinimalGatewayClient = class {
|
|
|
89656
89943
|
pending.reject(toGatewayError(frame.error));
|
|
89657
89944
|
}
|
|
89658
89945
|
handleClose(code2, reason) {
|
|
89659
|
-
errorWithTimestamp(`${
|
|
89946
|
+
errorWithTimestamp(`${LOG_PREFIX2} closed instanceId=${this.instanceId} code=${code2 ?? 0} reason=${reason || "no reason"}`);
|
|
89660
89947
|
this.ready = false;
|
|
89661
89948
|
for (const [id, pending] of this.pending) {
|
|
89662
89949
|
clearTimeout(pending.timer);
|
|
@@ -89680,7 +89967,7 @@ function readSyncedGatewayConfig(env) {
|
|
|
89680
89967
|
token: synced.token
|
|
89681
89968
|
};
|
|
89682
89969
|
} catch (err2) {
|
|
89683
|
-
errorWithTimestamp(`${
|
|
89970
|
+
errorWithTimestamp(`${LOG_PREFIX2} failed to read synced gateway config: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
89684
89971
|
return null;
|
|
89685
89972
|
}
|
|
89686
89973
|
}
|
|
@@ -89691,7 +89978,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
|
|
|
89691
89978
|
client: {
|
|
89692
89979
|
id: "gateway-client",
|
|
89693
89980
|
displayName: "okx-a2a-node",
|
|
89694
|
-
version: "0.1.10
|
|
89981
|
+
version: "0.1.10",
|
|
89695
89982
|
platform: "node",
|
|
89696
89983
|
mode: "backend",
|
|
89697
89984
|
instanceId
|
|
@@ -89702,7 +89989,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
|
|
|
89702
89989
|
commands: [],
|
|
89703
89990
|
permissions: {},
|
|
89704
89991
|
locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
|
|
89705
|
-
userAgent: `okx-a2a-node/${"0.1.10
|
|
89992
|
+
userAgent: `okx-a2a-node/${"0.1.10"}`,
|
|
89706
89993
|
auth: {
|
|
89707
89994
|
...config.token ? { token: config.token } : {},
|
|
89708
89995
|
...config.password ? { password: config.password } : {}
|
|
@@ -90295,6 +90582,14 @@ var DEFAULT_GATEWAY_PORT2 = {
|
|
|
90295
90582
|
callPromptUserToLatestSessions
|
|
90296
90583
|
};
|
|
90297
90584
|
var GATEWAY_OUTBOUND_LOG_PREFIX = "[okx-a2a:gateway-outbound]";
|
|
90585
|
+
var DEFAULT_SESSION_GATE_FALLBACK_MS = 3e5;
|
|
90586
|
+
function resolveSessionGateFallbackMs(env = process.env) {
|
|
90587
|
+
const raw = Number(env.OKX_A2A_SESSION_GATE_FALLBACK_MS ?? "");
|
|
90588
|
+
if (Number.isFinite(raw) && raw > 0) {
|
|
90589
|
+
return raw;
|
|
90590
|
+
}
|
|
90591
|
+
return DEFAULT_SESSION_GATE_FALLBACK_MS;
|
|
90592
|
+
}
|
|
90298
90593
|
function resolveUserDeliveryId(input) {
|
|
90299
90594
|
return input.idempotencyKey?.trim() || (0, import_node_crypto7.randomUUID)();
|
|
90300
90595
|
}
|
|
@@ -90351,10 +90646,19 @@ var GatewayOutboundBehavior = class {
|
|
|
90351
90646
|
gateway;
|
|
90352
90647
|
store;
|
|
90353
90648
|
sessionMetaStore;
|
|
90649
|
+
/** `undefined` = default (resolve the shared tracker lazily on first dispatch); `null` = disabled. */
|
|
90650
|
+
sessionGateOption;
|
|
90354
90651
|
constructor(options = {}) {
|
|
90355
90652
|
this.gateway = options.gateway ?? DEFAULT_GATEWAY_PORT2;
|
|
90356
90653
|
this.store = options.store;
|
|
90357
90654
|
this.sessionMetaStore = options.store;
|
|
90655
|
+
this.sessionGateOption = options.sessionGate;
|
|
90656
|
+
}
|
|
90657
|
+
resolveSessionGate() {
|
|
90658
|
+
if (this.sessionGateOption === void 0) {
|
|
90659
|
+
return getSessionBusyTracker();
|
|
90660
|
+
}
|
|
90661
|
+
return this.sessionGateOption;
|
|
90358
90662
|
}
|
|
90359
90663
|
async createSession(input) {
|
|
90360
90664
|
const gatewaySessionKey = this.resolveGatewaySessionKey(input);
|
|
@@ -90407,8 +90711,19 @@ var GatewayOutboundBehavior = class {
|
|
|
90407
90711
|
errorWithTimestamp(
|
|
90408
90712
|
`${GATEWAY_OUTBOUND_LOG_PREFIX} dispatchSessionMessage sessionKey=${input.sessionKey} gatewaySessionKey=${gatewaySessionKey} jobId=${input.jobId ?? "(none)"} agentId=${input.agentId ?? "(none)"} messageId=${input.messageId ?? "(none)"}`
|
|
90409
90713
|
);
|
|
90714
|
+
const sessionGate = this.resolveSessionGate();
|
|
90715
|
+
const gateFallbackMs = resolveSessionGateFallbackMs();
|
|
90716
|
+
if (sessionGate?.isSessionBusy(gatewaySessionKey)) {
|
|
90717
|
+
errorWithTimestamp(
|
|
90718
|
+
`${GATEWAY_OUTBOUND_LOG_PREFIX} [session-gate] busy, waiting idle sessionKey=${input.sessionKey} gatewaySessionKey=${gatewaySessionKey} (fallbackMs=${gateFallbackMs})`
|
|
90719
|
+
);
|
|
90720
|
+
const idleState = await sessionGate.waitForSessionIdle(gatewaySessionKey, gateFallbackMs);
|
|
90721
|
+
errorWithTimestamp(
|
|
90722
|
+
`${GATEWAY_OUTBOUND_LOG_PREFIX} [session-gate] idle wait done sessionKey=${input.sessionKey} gatewaySessionKey=${gatewaySessionKey} result=${idleState}`
|
|
90723
|
+
);
|
|
90724
|
+
}
|
|
90410
90725
|
try {
|
|
90411
|
-
await this.gateway.callSessionsSend({
|
|
90726
|
+
const sendResult = await this.gateway.callSessionsSend({
|
|
90412
90727
|
key: gatewaySessionKey,
|
|
90413
90728
|
message: input.content,
|
|
90414
90729
|
...input.messageId ? { idempotencyKey: input.messageId } : {}
|
|
@@ -90423,6 +90738,16 @@ var GatewayOutboundBehavior = class {
|
|
|
90423
90738
|
messageId: input.messageId ?? "",
|
|
90424
90739
|
status: "delivered"
|
|
90425
90740
|
}));
|
|
90741
|
+
const gateRunId = sendResult && typeof sendResult === "object" && typeof sendResult.runId === "string" ? sendResult.runId : input.messageId;
|
|
90742
|
+
if (sessionGate && typeof gateRunId === "string" && gateRunId) {
|
|
90743
|
+
errorWithTimestamp(
|
|
90744
|
+
`${GATEWAY_OUTBOUND_LOG_PREFIX} [session-gate] holding sessionKey=${input.sessionKey} gatewaySessionKey=${gatewaySessionKey} runId=${gateRunId} until run final/error (fallbackMs=${gateFallbackMs})`
|
|
90745
|
+
);
|
|
90746
|
+
const gateState = await sessionGate.waitForRunFinal(gateRunId, gateFallbackMs);
|
|
90747
|
+
errorWithTimestamp(
|
|
90748
|
+
`${GATEWAY_OUTBOUND_LOG_PREFIX} [session-gate] released sessionKey=${input.sessionKey} gatewaySessionKey=${gatewaySessionKey} runId=${gateRunId} state=${gateState}`
|
|
90749
|
+
);
|
|
90750
|
+
}
|
|
90426
90751
|
} catch (err2) {
|
|
90427
90752
|
if (!this.store || !isRetryableOpenClawGatewayError(err2)) {
|
|
90428
90753
|
logger.error(LogEvent.GATEWAY_REQUEST_FAILED, err2 instanceof Error ? err2 : new Error(String(err2)), gatewayOutboundExtra("sessions.send", {
|
|
@@ -94498,12 +94823,12 @@ async function runListenerWithLock(options, paths) {
|
|
|
94498
94823
|
});
|
|
94499
94824
|
}
|
|
94500
94825
|
});
|
|
94501
|
-
service.setPluginVersion("0.1.10
|
|
94826
|
+
service.setPluginVersion("0.1.10");
|
|
94502
94827
|
await service.init();
|
|
94503
94828
|
const pluginVersionStatus = service.pluginVersionStatus;
|
|
94504
94829
|
if (pluginVersionStatus.unavailable) {
|
|
94505
94830
|
throw new Error(
|
|
94506
|
-
`@okxweb3/a2a-node v${"0.1.10
|
|
94831
|
+
`@okxweb3/a2a-node v${"0.1.10"} is below the required minimum v${pluginVersionStatus.minVersion}`
|
|
94507
94832
|
);
|
|
94508
94833
|
}
|
|
94509
94834
|
const systemConfig = service.getSystemConfig();
|
|
@@ -94521,7 +94846,7 @@ async function runListenerWithLock(options, paths) {
|
|
|
94521
94846
|
onchainosAgentId: "*",
|
|
94522
94847
|
reason: "system-config missing sentryDsn",
|
|
94523
94848
|
pluginId: "@okxweb3/a2a-node",
|
|
94524
|
-
pluginVersion: "0.1.10
|
|
94849
|
+
pluginVersion: "0.1.10"
|
|
94525
94850
|
});
|
|
94526
94851
|
}
|
|
94527
94852
|
logWithTimestamp(
|
|
@@ -96290,7 +96615,7 @@ async function runDoctor(options = {}) {
|
|
|
96290
96615
|
platform: options.platform ?? process.platform,
|
|
96291
96616
|
env: options.env ?? process.env,
|
|
96292
96617
|
target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
|
|
96293
|
-
cliVersion: options.cliVersion ?? (true ? "0.1.10
|
|
96618
|
+
cliVersion: options.cliVersion ?? (true ? "0.1.10" : "0.0.0"),
|
|
96294
96619
|
fixMode: options.fix === true,
|
|
96295
96620
|
nonInteractive: options.nonInteractive === true,
|
|
96296
96621
|
packageChanged: false,
|
|
@@ -96526,6 +96851,7 @@ init_win_native_launcher();
|
|
|
96526
96851
|
NATIVE_LAUNCHER_EXE_NAME,
|
|
96527
96852
|
OPENCLAW_GATEWAY_ROUTE_GROUP_ID,
|
|
96528
96853
|
SYSTEM_NOTIFICATION_SESSION_KEY,
|
|
96854
|
+
SessionBusyTracker,
|
|
96529
96855
|
SessionStore,
|
|
96530
96856
|
SqliteOutboundBehavior,
|
|
96531
96857
|
TASK_NAME,
|
|
@@ -96591,6 +96917,7 @@ init_win_native_launcher();
|
|
|
96591
96917
|
formatDoctorReportForHumans,
|
|
96592
96918
|
getDaemonStatus,
|
|
96593
96919
|
getHermesGatewayPluginStatus,
|
|
96920
|
+
getSessionBusyTracker,
|
|
96594
96921
|
handleDoctorCommand,
|
|
96595
96922
|
handleXmtpSendCommand,
|
|
96596
96923
|
hasAiRuntimeMarker,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@okxweb3/a2a-node",
|
|
3
|
-
"version": "0.1.10
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Host-agnostic Node CLI for E2E encrypted agent-to-agent communication via XMTP",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"dist"
|
|
11
11
|
],
|
|
12
12
|
"engines": {
|
|
13
|
-
"node": ">=22.
|
|
13
|
+
"node": ">=22.14.0"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
16
|
"preinstall": "node dist/check-node-version.js",
|