@okxweb3/a2a-node 0.2.17 → 0.2.18
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 +597 -180
- package/dist/index.js +587 -170
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -22179,7 +22179,7 @@ var require_retry_promise = __commonJS({
|
|
|
22179
22179
|
return true;
|
|
22180
22180
|
}
|
|
22181
22181
|
};
|
|
22182
|
-
function
|
|
22182
|
+
function wait2(ms) {
|
|
22183
22183
|
return __awaiter(this, void 0, void 0, function() {
|
|
22184
22184
|
return __generator(this, function(_a) {
|
|
22185
22185
|
return [2, new Promise(function(resolve11) {
|
|
@@ -22188,7 +22188,7 @@ var require_retry_promise = __commonJS({
|
|
|
22188
22188
|
});
|
|
22189
22189
|
});
|
|
22190
22190
|
}
|
|
22191
|
-
exports2.wait =
|
|
22191
|
+
exports2.wait = wait2;
|
|
22192
22192
|
function retry2(f, config) {
|
|
22193
22193
|
return __awaiter(this, void 0, void 0, function() {
|
|
22194
22194
|
var effectiveConfig;
|
|
@@ -22278,7 +22278,7 @@ var require_retry_promise = __commonJS({
|
|
|
22278
22278
|
return [3, 5];
|
|
22279
22279
|
case 5:
|
|
22280
22280
|
millisToWait = delay(i + 1, config.delay);
|
|
22281
|
-
return [4,
|
|
22281
|
+
return [4, wait2(millisToWait > config.maxBackOff ? config.maxBackOff : millisToWait)];
|
|
22282
22282
|
case 6:
|
|
22283
22283
|
_a.sent();
|
|
22284
22284
|
if (done()) {
|
|
@@ -28761,7 +28761,7 @@ var init_withResolvers = __esm({
|
|
|
28761
28761
|
});
|
|
28762
28762
|
|
|
28763
28763
|
// ../../node_modules/viem/_esm/utils/promise/createBatchScheduler.js
|
|
28764
|
-
function createBatchScheduler({ fn, id, shouldSplitBatch, wait:
|
|
28764
|
+
function createBatchScheduler({ fn, id, shouldSplitBatch, wait: wait2 = 0, sort }) {
|
|
28765
28765
|
const exec2 = async () => {
|
|
28766
28766
|
const scheduler = getScheduler();
|
|
28767
28767
|
flush2();
|
|
@@ -28799,7 +28799,7 @@ function createBatchScheduler({ fn, id, shouldSplitBatch, wait: wait3 = 0, sort
|
|
|
28799
28799
|
return promise;
|
|
28800
28800
|
}
|
|
28801
28801
|
setScheduler({ args, resolve: resolve11, reject });
|
|
28802
|
-
setTimeout(exec2,
|
|
28802
|
+
setTimeout(exec2, wait2);
|
|
28803
28803
|
return promise;
|
|
28804
28804
|
}
|
|
28805
28805
|
};
|
|
@@ -32465,7 +32465,7 @@ var init_sentry_config = __esm({
|
|
|
32465
32465
|
environment = process.env.SENTRY_ENV === "dev" ? "dev" : "prod";
|
|
32466
32466
|
SENTRY_CONFIG = {
|
|
32467
32467
|
projectName: "okx/openclaw-okx-a2a-extension",
|
|
32468
|
-
release: "0.2.
|
|
32468
|
+
release: "0.2.18",
|
|
32469
32469
|
environment,
|
|
32470
32470
|
runtimeContainer: normalizeRuntimeContainer(process.env.OKX_A2A_RUNTIME_CONTAINER)
|
|
32471
32471
|
};
|
|
@@ -33421,7 +33421,7 @@ async function getCurrentNodeCliVersion() {
|
|
|
33421
33421
|
return await getGlobalNpmPackageVersion(UPDATE_PACKAGES.node) ?? getBundledNodeCliVersion();
|
|
33422
33422
|
}
|
|
33423
33423
|
function getBundledNodeCliVersion() {
|
|
33424
|
-
return true ? "0.2.
|
|
33424
|
+
return true ? "0.2.18" : null;
|
|
33425
33425
|
}
|
|
33426
33426
|
function readConfiguredAiProvider() {
|
|
33427
33427
|
const explicit = process.env.OKX_A2A_AI_PROVIDER || process.env.OKX_AGENT_TASK_AI_CLI;
|
|
@@ -33631,7 +33631,7 @@ async function updateHermes(release, options) {
|
|
|
33631
33631
|
}
|
|
33632
33632
|
}
|
|
33633
33633
|
async function installGatewayPluginForDoctor(target) {
|
|
33634
|
-
const release = isPrereleaseVersion("0.2.
|
|
33634
|
+
const release = isPrereleaseVersion("0.2.18") ? "beta" : "latest";
|
|
33635
33635
|
const insideTargetGateway = detectGatewayInvocation() === target;
|
|
33636
33636
|
const options = {
|
|
33637
33637
|
restart: !insideTargetGateway,
|
|
@@ -49043,7 +49043,6 @@ function createAsyncStreamProxy(stream) {
|
|
|
49043
49043
|
}
|
|
49044
49044
|
});
|
|
49045
49045
|
}
|
|
49046
|
-
var wait = (ms) => new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
49047
49046
|
var DEFAULT_RETRY_DELAY = 6e4;
|
|
49048
49047
|
var DEFAULT_RETRY_ATTEMPTS = 10;
|
|
49049
49048
|
var createStream = async (streamFunction, streamValueMutator, options) => {
|
|
@@ -49052,82 +49051,161 @@ var createStream = async (streamFunction, streamValueMutator, options) => {
|
|
|
49052
49051
|
throw new StreamInvalidRetryAttemptsError();
|
|
49053
49052
|
}
|
|
49054
49053
|
const asyncStream = new AsyncStream();
|
|
49054
|
+
let stopped = false;
|
|
49055
|
+
let current;
|
|
49056
|
+
let recovering = false;
|
|
49057
|
+
let cancelDelay;
|
|
49058
|
+
const isStopped = () => stopped;
|
|
49059
|
+
const isCurrent = (native) => !stopped && current === native;
|
|
49060
|
+
asyncStream.onDone = () => {
|
|
49061
|
+
if (stopped) {
|
|
49062
|
+
return;
|
|
49063
|
+
}
|
|
49064
|
+
stopped = true;
|
|
49065
|
+
cancelDelay?.();
|
|
49066
|
+
const native = current;
|
|
49067
|
+
current = void 0;
|
|
49068
|
+
native?.closer?.end();
|
|
49069
|
+
};
|
|
49070
|
+
const delay = (ms) => new Promise((resolve11) => {
|
|
49071
|
+
const timer = setTimeout(() => {
|
|
49072
|
+
cancelDelay = void 0;
|
|
49073
|
+
resolve11();
|
|
49074
|
+
}, ms);
|
|
49075
|
+
cancelDelay = () => {
|
|
49076
|
+
clearTimeout(timer);
|
|
49077
|
+
cancelDelay = void 0;
|
|
49078
|
+
resolve11();
|
|
49079
|
+
};
|
|
49080
|
+
});
|
|
49081
|
+
const reportError = (error) => {
|
|
49082
|
+
if (!stopped) {
|
|
49083
|
+
onError?.(error);
|
|
49084
|
+
}
|
|
49085
|
+
};
|
|
49086
|
+
const deliver = (value) => {
|
|
49087
|
+
if (stopped || value === void 0) {
|
|
49088
|
+
return;
|
|
49089
|
+
}
|
|
49090
|
+
asyncStream.push(value);
|
|
49091
|
+
onValue?.(value);
|
|
49092
|
+
};
|
|
49055
49093
|
const streamCallback = (error, value) => {
|
|
49094
|
+
if (stopped) {
|
|
49095
|
+
return;
|
|
49096
|
+
}
|
|
49056
49097
|
if (error) {
|
|
49057
49098
|
onError?.(error);
|
|
49058
49099
|
return;
|
|
49059
49100
|
}
|
|
49060
|
-
if (value
|
|
49061
|
-
|
|
49062
|
-
|
|
49063
|
-
|
|
49064
|
-
|
|
49065
|
-
|
|
49066
|
-
|
|
49067
|
-
|
|
49068
|
-
onValue?.(mutatedValue2);
|
|
49069
|
-
}
|
|
49070
|
-
}).catch((error2) => {
|
|
49071
|
-
onError?.(error2);
|
|
49072
|
-
});
|
|
49073
|
-
} else {
|
|
49074
|
-
if (mutatedValue !== void 0) {
|
|
49075
|
-
asyncStream.push(mutatedValue);
|
|
49076
|
-
onValue?.(mutatedValue);
|
|
49077
|
-
}
|
|
49078
|
-
}
|
|
49101
|
+
if (value === void 0) {
|
|
49102
|
+
return;
|
|
49103
|
+
}
|
|
49104
|
+
try {
|
|
49105
|
+
if (streamValueMutator) {
|
|
49106
|
+
const mutatedValue = streamValueMutator(value);
|
|
49107
|
+
if ((0, import_types.isPromise)(mutatedValue)) {
|
|
49108
|
+
void mutatedValue.then(deliver).catch(reportError);
|
|
49079
49109
|
} else {
|
|
49080
|
-
|
|
49081
|
-
onValue?.(value);
|
|
49110
|
+
deliver(mutatedValue);
|
|
49082
49111
|
}
|
|
49083
|
-
}
|
|
49084
|
-
|
|
49112
|
+
} else {
|
|
49113
|
+
deliver(value);
|
|
49085
49114
|
}
|
|
49115
|
+
} catch (error2) {
|
|
49116
|
+
reportError(error2);
|
|
49086
49117
|
}
|
|
49087
49118
|
};
|
|
49088
|
-
const
|
|
49089
|
-
|
|
49090
|
-
|
|
49091
|
-
|
|
49092
|
-
|
|
49119
|
+
const fail = (error) => {
|
|
49120
|
+
void asyncStream.end();
|
|
49121
|
+
onError?.(error);
|
|
49122
|
+
};
|
|
49123
|
+
const open2 = async () => {
|
|
49124
|
+
if (stopped) {
|
|
49125
|
+
return false;
|
|
49126
|
+
}
|
|
49127
|
+
const native = { ready: false, closed: false };
|
|
49128
|
+
current = native;
|
|
49129
|
+
const closer = await streamFunction(streamCallback, () => {
|
|
49130
|
+
onNativeClose(native);
|
|
49131
|
+
});
|
|
49132
|
+
native.closer = closer;
|
|
49133
|
+
if (!isCurrent(native)) {
|
|
49134
|
+
closer.end();
|
|
49135
|
+
return false;
|
|
49136
|
+
}
|
|
49137
|
+
await closer.waitForReady();
|
|
49138
|
+
if (!isCurrent(native)) {
|
|
49139
|
+
closer.end();
|
|
49140
|
+
return false;
|
|
49141
|
+
}
|
|
49142
|
+
if (native.closed || closer.isClosed()) {
|
|
49143
|
+
closer.end();
|
|
49144
|
+
return false;
|
|
49093
49145
|
}
|
|
49094
|
-
|
|
49095
|
-
|
|
49146
|
+
native.ready = true;
|
|
49147
|
+
return true;
|
|
49148
|
+
};
|
|
49149
|
+
const restart = async () => {
|
|
49096
49150
|
try {
|
|
49097
|
-
|
|
49098
|
-
|
|
49099
|
-
|
|
49100
|
-
|
|
49101
|
-
|
|
49102
|
-
|
|
49103
|
-
|
|
49104
|
-
|
|
49105
|
-
|
|
49106
|
-
|
|
49107
|
-
|
|
49108
|
-
|
|
49151
|
+
for (let attempt = 1; attempt <= retryAttempts; attempt++) {
|
|
49152
|
+
await delay(retryDelay);
|
|
49153
|
+
if (isStopped()) {
|
|
49154
|
+
return;
|
|
49155
|
+
}
|
|
49156
|
+
onRetry?.(attempt, retryAttempts);
|
|
49157
|
+
let restarted = false;
|
|
49158
|
+
try {
|
|
49159
|
+
restarted = await open2();
|
|
49160
|
+
} catch (error) {
|
|
49161
|
+
reportError(error);
|
|
49162
|
+
}
|
|
49163
|
+
if (isStopped()) {
|
|
49164
|
+
return;
|
|
49165
|
+
}
|
|
49166
|
+
if (restarted) {
|
|
49167
|
+
try {
|
|
49168
|
+
onRestart?.();
|
|
49169
|
+
} catch (error) {
|
|
49170
|
+
reportError(error);
|
|
49171
|
+
}
|
|
49172
|
+
return;
|
|
49173
|
+
}
|
|
49174
|
+
}
|
|
49175
|
+
fail(new StreamFailedError(retryAttempts));
|
|
49176
|
+
} finally {
|
|
49177
|
+
recovering = false;
|
|
49109
49178
|
}
|
|
49110
49179
|
};
|
|
49111
|
-
const
|
|
49112
|
-
if (
|
|
49113
|
-
|
|
49114
|
-
} else {
|
|
49115
|
-
void asyncStream.end();
|
|
49116
|
-
onError?.(new StreamFailedError(0));
|
|
49180
|
+
const recover = () => {
|
|
49181
|
+
if (stopped || recovering) {
|
|
49182
|
+
return;
|
|
49117
49183
|
}
|
|
49184
|
+
if (!retryOnFail) {
|
|
49185
|
+
fail(new StreamFailedError(0));
|
|
49186
|
+
return;
|
|
49187
|
+
}
|
|
49188
|
+
recovering = true;
|
|
49189
|
+
void restart();
|
|
49118
49190
|
};
|
|
49191
|
+
function onNativeClose(native) {
|
|
49192
|
+
if (!isCurrent(native) || native.closed) {
|
|
49193
|
+
return;
|
|
49194
|
+
}
|
|
49195
|
+
native.closed = true;
|
|
49196
|
+
onFail?.();
|
|
49197
|
+
if (native.ready) {
|
|
49198
|
+
recover();
|
|
49199
|
+
}
|
|
49200
|
+
}
|
|
49201
|
+
let started = false;
|
|
49119
49202
|
try {
|
|
49120
|
-
|
|
49121
|
-
onFail?.();
|
|
49122
|
-
startRetry();
|
|
49123
|
-
});
|
|
49124
|
-
await streamCloser.waitForReady();
|
|
49125
|
-
asyncStream.onDone = () => {
|
|
49126
|
-
streamCloser.end();
|
|
49127
|
-
};
|
|
49203
|
+
started = await open2();
|
|
49128
49204
|
} catch (error) {
|
|
49129
|
-
|
|
49130
|
-
|
|
49205
|
+
reportError(error);
|
|
49206
|
+
}
|
|
49207
|
+
if (!started) {
|
|
49208
|
+
recover();
|
|
49131
49209
|
}
|
|
49132
49210
|
return createAsyncStreamProxy(asyncStream);
|
|
49133
49211
|
};
|
|
@@ -52371,7 +52449,7 @@ function observe(observerId, callbacks, fn) {
|
|
|
52371
52449
|
}
|
|
52372
52450
|
|
|
52373
52451
|
// ../../node_modules/viem/_esm/utils/wait.js
|
|
52374
|
-
async function
|
|
52452
|
+
async function wait(time) {
|
|
52375
52453
|
return new Promise((res) => setTimeout(res, time));
|
|
52376
52454
|
}
|
|
52377
52455
|
|
|
@@ -52384,12 +52462,12 @@ function poll(fn, { emitOnBegin, initialWaitTime, interval }) {
|
|
|
52384
52462
|
if (emitOnBegin)
|
|
52385
52463
|
data = await fn({ unpoll: unwatch });
|
|
52386
52464
|
const initialWait = await initialWaitTime?.(data) ?? interval;
|
|
52387
|
-
await
|
|
52465
|
+
await wait(initialWait);
|
|
52388
52466
|
const poll2 = async () => {
|
|
52389
52467
|
if (!active)
|
|
52390
52468
|
return;
|
|
52391
52469
|
await fn({ unpoll: unwatch });
|
|
52392
|
-
await
|
|
52470
|
+
await wait(interval);
|
|
52393
52471
|
poll2();
|
|
52394
52472
|
};
|
|
52395
52473
|
poll2();
|
|
@@ -52712,7 +52790,7 @@ function withRetry(fn, { delay: delay_ = 100, retryCount = 2, shouldRetry: shoul
|
|
|
52712
52790
|
const retry2 = async ({ error }) => {
|
|
52713
52791
|
const delay = typeof delay_ === "function" ? delay_({ count, error }) : delay_;
|
|
52714
52792
|
if (delay)
|
|
52715
|
-
await
|
|
52793
|
+
await wait(delay);
|
|
52716
52794
|
attemptRetry({ count: count + 1 });
|
|
52717
52795
|
};
|
|
52718
52796
|
try {
|
|
@@ -54875,7 +54953,7 @@ init_createBatchScheduler();
|
|
|
54875
54953
|
function http(url, config = {}) {
|
|
54876
54954
|
const { batch, fetchFn, fetchOptions, key = "http", methods, name = "HTTP JSON-RPC", onFetchRequest, onFetchResponse, retryDelay, raw } = config;
|
|
54877
54955
|
return ({ chain, retryCount: retryCount_, timeout: timeout_ }) => {
|
|
54878
|
-
const { batchSize = 1e3, wait:
|
|
54956
|
+
const { batchSize = 1e3, wait: wait2 = 0 } = typeof batch === "object" ? batch : {};
|
|
54879
54957
|
const retryCount = config.retryCount ?? retryCount_;
|
|
54880
54958
|
const timeout = timeout_ ?? config.timeout ?? 1e4;
|
|
54881
54959
|
const url_ = url || chain?.rpcUrls.default.http[0];
|
|
@@ -54896,7 +54974,7 @@ function http(url, config = {}) {
|
|
|
54896
54974
|
const body = { method, params };
|
|
54897
54975
|
const { schedule } = createBatchScheduler({
|
|
54898
54976
|
id: url_,
|
|
54899
|
-
wait:
|
|
54977
|
+
wait: wait2,
|
|
54900
54978
|
shouldSplitBatch(requests) {
|
|
54901
54979
|
return requests.length > batchSize;
|
|
54902
54980
|
},
|
|
@@ -55113,7 +55191,7 @@ var sepolia = /* @__PURE__ */ defineChain({
|
|
|
55113
55191
|
|
|
55114
55192
|
// ../../node_modules/@xmtp/agent-sdk/dist/index.js
|
|
55115
55193
|
var import_node_crypto7 = require("node:crypto");
|
|
55116
|
-
var version2 = "2.3.
|
|
55194
|
+
var version2 = "2.3.1";
|
|
55117
55195
|
var fromSelf = (message, client) => {
|
|
55118
55196
|
return message.senderInboxId === client.inboxId;
|
|
55119
55197
|
};
|
|
@@ -57162,6 +57240,9 @@ function replayScanBackoffWithJitterMs(consecutiveFailures, randomValue = Math.r
|
|
|
57162
57240
|
const jitteredMs = Math.round(baseMs * (0.9 + boundedRandom * 0.2));
|
|
57163
57241
|
return Math.min(REPLAY_SCAN_MAX_BACKOFF_MS, jitteredMs);
|
|
57164
57242
|
}
|
|
57243
|
+
function isListenHealthy(outcome) {
|
|
57244
|
+
return outcome === "started" || outcome === "retrying";
|
|
57245
|
+
}
|
|
57165
57246
|
function isOfflineReplayForTrigger(trigger) {
|
|
57166
57247
|
return trigger === "startup";
|
|
57167
57248
|
}
|
|
@@ -57171,6 +57252,18 @@ function replaySingleFlightDiscriminator(trigger, clientGeneration) {
|
|
|
57171
57252
|
isOfflineReplayForTrigger(trigger)
|
|
57172
57253
|
);
|
|
57173
57254
|
}
|
|
57255
|
+
var XmtpClientCreateBlockedError = class extends Error {
|
|
57256
|
+
reason;
|
|
57257
|
+
address;
|
|
57258
|
+
agentId;
|
|
57259
|
+
constructor(reason, address, agentId) {
|
|
57260
|
+
super(`xmtp client create blocked (${reason})`);
|
|
57261
|
+
this.name = "XmtpClientCreateBlockedError";
|
|
57262
|
+
this.reason = reason;
|
|
57263
|
+
this.address = address;
|
|
57264
|
+
this.agentId = agentId;
|
|
57265
|
+
}
|
|
57266
|
+
};
|
|
57174
57267
|
var XmtpService = class _XmtpService {
|
|
57175
57268
|
static instance = null;
|
|
57176
57269
|
env = process.env.XMTP_ENV ?? "production";
|
|
@@ -57208,6 +57301,25 @@ var XmtpService = class _XmtpService {
|
|
|
57208
57301
|
streamRecoverySetTimeout = (callback, delayMs) => setTimeout(callback, delayMs);
|
|
57209
57302
|
streamRecoveryClearTimeout = (timer) => clearTimeout(timer);
|
|
57210
57303
|
streamStartSetTimeout = (callback, delayMs) => setTimeout(callback, delayMs);
|
|
57304
|
+
xmtpAgentFactory = createAgentWithInstallationPrune;
|
|
57305
|
+
// Old clients whose close() was not confirmed. Keyed by lower-cased address.
|
|
57306
|
+
// The reference is kept only for controlled cleanup; it is never served.
|
|
57307
|
+
pendingReleaseByAddress = /* @__PURE__ */ new Map();
|
|
57308
|
+
// Addresses whose pending release was confirmed late (after the caller gave
|
|
57309
|
+
// up waiting) and still need a replacement client on the next recycle.
|
|
57310
|
+
releaseConfirmedNeedsCreate = /* @__PURE__ */ new Set();
|
|
57311
|
+
// Lower-cased addresses owned by a create. The slot is held from before the
|
|
57312
|
+
// SDK factory runs until the new client is registered in `clients` (or the
|
|
57313
|
+
// create failed), so no flow can observe "no lock and no client".
|
|
57314
|
+
clientCreateInFlight = /* @__PURE__ */ new Set();
|
|
57315
|
+
// Clients whose close() was confirmed; a repeated release is a no-op.
|
|
57316
|
+
releasedClients = /* @__PURE__ */ new WeakSet();
|
|
57317
|
+
// One listener setup per client, shared by concurrent init/refresh callers.
|
|
57318
|
+
listenTaskByClient = /* @__PURE__ */ new WeakMap();
|
|
57319
|
+
inboundReplayGateOwners = /* @__PURE__ */ new WeakMap();
|
|
57320
|
+
releaseWaitTimeoutMs = 3e4;
|
|
57321
|
+
releaseWaitSetTimeout = (callback, delayMs) => setTimeout(callback, delayMs);
|
|
57322
|
+
releaseWaitClearTimeout = (timer) => clearTimeout(timer);
|
|
57211
57323
|
nextClientGeneration = 1;
|
|
57212
57324
|
clientGenerationByClient = /* @__PURE__ */ new WeakMap();
|
|
57213
57325
|
resolveStartupReplayCompletion;
|
|
@@ -57356,6 +57468,56 @@ var XmtpService = class _XmtpService {
|
|
|
57356
57468
|
return { ok: remaining.length === 0, failures: remaining };
|
|
57357
57469
|
}
|
|
57358
57470
|
async createClientForAgent(agentInfo, options = {}) {
|
|
57471
|
+
const address = agentInfo.communicationAddress;
|
|
57472
|
+
const addressKey = address.toLowerCase();
|
|
57473
|
+
let blockedReason;
|
|
57474
|
+
if (this.pendingReleaseByAddress.has(addressKey)) {
|
|
57475
|
+
blockedReason = "release_pending";
|
|
57476
|
+
} else if (this.clientCreateInFlight.has(addressKey)) {
|
|
57477
|
+
blockedReason = "create_in_flight";
|
|
57478
|
+
} else if (this.getClientByAddress(address)) {
|
|
57479
|
+
blockedReason = "client_active";
|
|
57480
|
+
}
|
|
57481
|
+
if (blockedReason) {
|
|
57482
|
+
throw new XmtpClientCreateBlockedError(
|
|
57483
|
+
blockedReason,
|
|
57484
|
+
address,
|
|
57485
|
+
agentInfo.agentId
|
|
57486
|
+
);
|
|
57487
|
+
}
|
|
57488
|
+
this.clientCreateInFlight.add(addressKey);
|
|
57489
|
+
try {
|
|
57490
|
+
const created = await this.createClientForAgentGuarded(agentInfo, options);
|
|
57491
|
+
await this.registerCreatedClient(created, options.logPrefix ?? "[xmtp-sdk]");
|
|
57492
|
+
return created;
|
|
57493
|
+
} finally {
|
|
57494
|
+
this.clientCreateInFlight.delete(addressKey);
|
|
57495
|
+
}
|
|
57496
|
+
}
|
|
57497
|
+
// Ownership hand-off, still inside the create slot: the new client becomes
|
|
57498
|
+
// visible in `clients` before the slot is released. Never overwrites an
|
|
57499
|
+
// existing registration; a conflicting new object is released, not dropped.
|
|
57500
|
+
async registerCreatedClient(created, phase) {
|
|
57501
|
+
const { address, agent, agentInfo } = created;
|
|
57502
|
+
const addressKey = address.toLowerCase();
|
|
57503
|
+
const existing = this.getClientByAddress(address);
|
|
57504
|
+
if (existing && existing !== agent || this.pendingReleaseByAddress.has(addressKey)) {
|
|
57505
|
+
const reason = existing ? "client_active" : "release_pending";
|
|
57506
|
+
logWithTimestamp(
|
|
57507
|
+
`[xmtp-sdk] create registration conflict (${reason}): ${address} (agentId=${agentInfo.agentId}), releasing the new client`
|
|
57508
|
+
);
|
|
57509
|
+
await this.releaseClient(
|
|
57510
|
+
address,
|
|
57511
|
+
agent,
|
|
57512
|
+
agentInfo.agentId,
|
|
57513
|
+
`${phase}/register-conflict`
|
|
57514
|
+
);
|
|
57515
|
+
throw new XmtpClientCreateBlockedError(reason, address, agentInfo.agentId);
|
|
57516
|
+
}
|
|
57517
|
+
this.stoppedAddresses.delete(addressKey);
|
|
57518
|
+
this.clients.set(address, agent);
|
|
57519
|
+
}
|
|
57520
|
+
async createClientForAgentGuarded(agentInfo, options = {}) {
|
|
57359
57521
|
const address = agentInfo.communicationAddress;
|
|
57360
57522
|
const phase = options.logPrefix ?? "[xmtp-sdk]";
|
|
57361
57523
|
const cooldown = getXmtpCreationCooldown();
|
|
@@ -57384,7 +57546,7 @@ var XmtpService = class _XmtpService {
|
|
|
57384
57546
|
try {
|
|
57385
57547
|
const signer = this.tools.createSigner(agentInfo);
|
|
57386
57548
|
const dbPath = (inboxId2) => `${this.dataDir}/${inboxId2}-${this.env}.db3`;
|
|
57387
|
-
const agent = await
|
|
57549
|
+
const agent = await this.xmtpAgentFactory(signer, {
|
|
57388
57550
|
dbPath,
|
|
57389
57551
|
env: this.env
|
|
57390
57552
|
}, {
|
|
@@ -57393,6 +57555,7 @@ var XmtpService = class _XmtpService {
|
|
|
57393
57555
|
logPrefix: options.logPrefix
|
|
57394
57556
|
});
|
|
57395
57557
|
cooldown.recordCreateSuccess(decision);
|
|
57558
|
+
this.releaseConfirmedNeedsCreate.delete(address.toLowerCase());
|
|
57396
57559
|
if (decision.mode === "probe") {
|
|
57397
57560
|
logger.info(LogEvent.XMTP_RATE_LIMIT_RECOVERED, {
|
|
57398
57561
|
onchainosAgentId: agentInfo.agentId,
|
|
@@ -57430,6 +57593,128 @@ var XmtpService = class _XmtpService {
|
|
|
57430
57593
|
throw err;
|
|
57431
57594
|
}
|
|
57432
57595
|
}
|
|
57596
|
+
logReleaseNotConfirmed(address, agentId, phase, reason, err) {
|
|
57597
|
+
logger.error(
|
|
57598
|
+
LogEvent.XMTP_CLIENT_CLOSE_FAILED,
|
|
57599
|
+
err instanceof Error ? err : new Error(`xmtp client close not confirmed (${reason})`),
|
|
57600
|
+
{ walletAddress: address, onchainosAgentId: agentId, phase, reason }
|
|
57601
|
+
);
|
|
57602
|
+
}
|
|
57603
|
+
// Single release entry (recycle / refresh remove / failed replacement).
|
|
57604
|
+
// Confirmation is ONLY a successful client.close(); a timeout, a missing
|
|
57605
|
+
// close() or a close failure keeps the old reference in
|
|
57606
|
+
// pendingReleaseByAddress and blocks new creates for that address.
|
|
57607
|
+
async releaseClient(address, client, agentId, phase) {
|
|
57608
|
+
const key = address.toLowerCase();
|
|
57609
|
+
if (this.releasedClients.has(client)) {
|
|
57610
|
+
this.unpublishClient(address, client, phase);
|
|
57611
|
+
return true;
|
|
57612
|
+
}
|
|
57613
|
+
const existing = this.pendingReleaseByAddress.get(key);
|
|
57614
|
+
if (existing?.inFlight) {
|
|
57615
|
+
this.unpublishClient(address, client, phase);
|
|
57616
|
+
return false;
|
|
57617
|
+
}
|
|
57618
|
+
const entry = existing ?? { client, agentId, phase };
|
|
57619
|
+
entry.client = client;
|
|
57620
|
+
entry.agentId = agentId;
|
|
57621
|
+
entry.phase = phase;
|
|
57622
|
+
this.pendingReleaseByAddress.set(key, entry);
|
|
57623
|
+
this.unpublishClient(address, client, phase);
|
|
57624
|
+
let timedOut = false;
|
|
57625
|
+
const task = stopAndCloseXmtpClient(client, {
|
|
57626
|
+
address,
|
|
57627
|
+
agentId,
|
|
57628
|
+
phase,
|
|
57629
|
+
onCloseError: (err) => this.logReleaseNotConfirmed(address, agentId, phase, "close_threw", err)
|
|
57630
|
+
}).then((result) => {
|
|
57631
|
+
if (!result.stopped) {
|
|
57632
|
+
logWithTimestamp(
|
|
57633
|
+
`[xmtp-sdk] release: stop failed but close proceeded: ${address} (agentId=${agentId}) phase=${phase}`
|
|
57634
|
+
);
|
|
57635
|
+
}
|
|
57636
|
+
entry.inFlight = void 0;
|
|
57637
|
+
if (result.closed) {
|
|
57638
|
+
this.releasedClients.add(client);
|
|
57639
|
+
}
|
|
57640
|
+
if (result.closed && this.pendingReleaseByAddress.get(key) === entry) {
|
|
57641
|
+
this.pendingReleaseByAddress.delete(key);
|
|
57642
|
+
if (timedOut) {
|
|
57643
|
+
this.releaseConfirmedNeedsCreate.add(key);
|
|
57644
|
+
}
|
|
57645
|
+
}
|
|
57646
|
+
return result;
|
|
57647
|
+
});
|
|
57648
|
+
entry.inFlight = task.then((result) => result.closed);
|
|
57649
|
+
const timeoutHandle = {};
|
|
57650
|
+
const timeoutPromise = new Promise((resolve11) => {
|
|
57651
|
+
timeoutHandle.timer = this.releaseWaitSetTimeout(
|
|
57652
|
+
() => resolve11(null),
|
|
57653
|
+
this.releaseWaitTimeoutMs
|
|
57654
|
+
);
|
|
57655
|
+
});
|
|
57656
|
+
const outcome = await Promise.race([task, timeoutPromise]);
|
|
57657
|
+
if (timeoutHandle.timer !== void 0) {
|
|
57658
|
+
this.releaseWaitClearTimeout(timeoutHandle.timer);
|
|
57659
|
+
}
|
|
57660
|
+
if (outcome === null) {
|
|
57661
|
+
timedOut = true;
|
|
57662
|
+
this.logReleaseNotConfirmed(address, agentId, phase, "close_timeout");
|
|
57663
|
+
return false;
|
|
57664
|
+
}
|
|
57665
|
+
if (outcome.closed) {
|
|
57666
|
+
if (this.pendingReleaseByAddress.get(key) === entry) {
|
|
57667
|
+
this.pendingReleaseByAddress.delete(key);
|
|
57668
|
+
}
|
|
57669
|
+
return true;
|
|
57670
|
+
}
|
|
57671
|
+
if (!outcome.closeFailed) {
|
|
57672
|
+
this.logReleaseNotConfirmed(address, agentId, phase, "close_unavailable");
|
|
57673
|
+
}
|
|
57674
|
+
return false;
|
|
57675
|
+
}
|
|
57676
|
+
// Stops serving `client` to new operations. Every removal is identity
|
|
57677
|
+
// checked, so a late caller can never remove a newer instance (or its replay
|
|
57678
|
+
// gate / recovery / retry state) registered for the same address.
|
|
57679
|
+
unpublishClient(address, client, phase) {
|
|
57680
|
+
const key = address.toLowerCase();
|
|
57681
|
+
let removed = false;
|
|
57682
|
+
for (const [registeredAddress, registered] of this.clients) {
|
|
57683
|
+
if (registered === client && registeredAddress.toLowerCase() === key) {
|
|
57684
|
+
this.clients.delete(registeredAddress);
|
|
57685
|
+
removed = true;
|
|
57686
|
+
}
|
|
57687
|
+
}
|
|
57688
|
+
const gate = this.inboundReplayGates.get(key);
|
|
57689
|
+
if (gate) {
|
|
57690
|
+
const owner = this.inboundReplayGateOwners.get(gate);
|
|
57691
|
+
if (owner === client || owner === void 0 && removed) {
|
|
57692
|
+
this.inboundReplayGates.delete(key);
|
|
57693
|
+
}
|
|
57694
|
+
}
|
|
57695
|
+
this.cancelStreamRecoveryForAddress(address, client);
|
|
57696
|
+
if (removed) {
|
|
57697
|
+
this.replayScanFailuresByAddress.delete(key);
|
|
57698
|
+
this.clearReplayScanRetry(
|
|
57699
|
+
address,
|
|
57700
|
+
phase.startsWith("recycle") ? "client_recycled" : "client_removed"
|
|
57701
|
+
);
|
|
57702
|
+
}
|
|
57703
|
+
if (!this.getClientByAddress(address)) {
|
|
57704
|
+
this.stoppedAddresses.add(key);
|
|
57705
|
+
}
|
|
57706
|
+
}
|
|
57707
|
+
async settlePendingRelease(address) {
|
|
57708
|
+
const entry = this.pendingReleaseByAddress.get(address.toLowerCase());
|
|
57709
|
+
if (!entry) {
|
|
57710
|
+
return true;
|
|
57711
|
+
}
|
|
57712
|
+
if (entry.inFlight) {
|
|
57713
|
+
return false;
|
|
57714
|
+
}
|
|
57715
|
+
const retryPhase = entry.phase.endsWith("/retry") ? entry.phase : `${entry.phase}/retry`;
|
|
57716
|
+
return this.releaseClient(address, entry.client, entry.agentId, retryPhase);
|
|
57717
|
+
}
|
|
57433
57718
|
async recordInstallationHealth(params) {
|
|
57434
57719
|
const { address, agent, agentInfo, phase, attempt } = params;
|
|
57435
57720
|
try {
|
|
@@ -57550,8 +57835,6 @@ var XmtpService = class _XmtpService {
|
|
|
57550
57835
|
const r = results[i];
|
|
57551
57836
|
if (r.status === "fulfilled") {
|
|
57552
57837
|
const { address, agent, agentInfo } = r.value;
|
|
57553
|
-
this.stoppedAddresses.delete(address.toLowerCase());
|
|
57554
|
-
this.clients.set(address, agent);
|
|
57555
57838
|
logWithTimestamp(
|
|
57556
57839
|
`[xmtp-sdk] identity initialized: ${address} (agentId=${agentInfo.agentId})`
|
|
57557
57840
|
);
|
|
@@ -57577,6 +57860,10 @@ var XmtpService = class _XmtpService {
|
|
|
57577
57860
|
phase: "init",
|
|
57578
57861
|
attempt: "1"
|
|
57579
57862
|
});
|
|
57863
|
+
} else if (r.reason instanceof XmtpClientCreateBlockedError) {
|
|
57864
|
+
logWithTimestamp(
|
|
57865
|
+
`[xmtp-sdk] identity init: create blocked (${r.reason.reason}): ${agents[i].communicationAddress} (agentId=${agents[i].agentId})`
|
|
57866
|
+
);
|
|
57580
57867
|
} else {
|
|
57581
57868
|
failedAgents.push(agents[i]);
|
|
57582
57869
|
if (r.reason instanceof XmtpCreationCooldownSkipError) {
|
|
@@ -57613,8 +57900,6 @@ var XmtpService = class _XmtpService {
|
|
|
57613
57900
|
const r = retryResults[i];
|
|
57614
57901
|
if (r.status === "fulfilled") {
|
|
57615
57902
|
const { address, agent, agentInfo } = r.value;
|
|
57616
|
-
this.stoppedAddresses.delete(address.toLowerCase());
|
|
57617
|
-
this.clients.set(address, agent);
|
|
57618
57903
|
logWithTimestamp(
|
|
57619
57904
|
`[xmtp-sdk] retry succeeded: ${address} (agentId=${agentInfo.agentId})`
|
|
57620
57905
|
);
|
|
@@ -57640,6 +57925,11 @@ var XmtpService = class _XmtpService {
|
|
|
57640
57925
|
phase: "init",
|
|
57641
57926
|
attempt: "2"
|
|
57642
57927
|
});
|
|
57928
|
+
} else if (r.reason instanceof XmtpClientCreateBlockedError) {
|
|
57929
|
+
const info = failedAgents[i];
|
|
57930
|
+
logWithTimestamp(
|
|
57931
|
+
`[xmtp-sdk] retry create blocked (${r.reason.reason}): ${info.communicationAddress} (agentId=${info.agentId})`
|
|
57932
|
+
);
|
|
57643
57933
|
} else if (r.reason instanceof XmtpCreationCooldownSkipError) {
|
|
57644
57934
|
const info = failedAgents[i];
|
|
57645
57935
|
logWithTimestamp(
|
|
@@ -57722,36 +58012,38 @@ var XmtpService = class _XmtpService {
|
|
|
57722
58012
|
throw err;
|
|
57723
58013
|
}
|
|
57724
58014
|
}
|
|
58015
|
+
for (const pendingKey of [...this.pendingReleaseByAddress.keys()]) {
|
|
58016
|
+
const settled = await this.settlePendingRelease(pendingKey);
|
|
58017
|
+
logWithTimestamp(
|
|
58018
|
+
`[xmtp-sdk] refresh: pending release ${pendingKey} ${settled ? "confirmed" : "still pending"}`
|
|
58019
|
+
);
|
|
58020
|
+
}
|
|
57725
58021
|
const oldAddresses = new Set(
|
|
57726
|
-
this.allAgents.map((a) => a.communicationAddress)
|
|
58022
|
+
this.allAgents.map((a) => a.communicationAddress.toLowerCase())
|
|
58023
|
+
);
|
|
58024
|
+
const newAddresses = new Set(
|
|
58025
|
+
newAgents.map((a) => a.communicationAddress.toLowerCase())
|
|
57727
58026
|
);
|
|
57728
|
-
const newAddresses = new Set(newAgents.map((a) => a.communicationAddress));
|
|
57729
58027
|
const added = newAgents.filter(
|
|
57730
|
-
(a) => !oldAddresses.has(a.communicationAddress) || !this.
|
|
58028
|
+
(a) => !oldAddresses.has(a.communicationAddress.toLowerCase()) || !this.getClientByAddress(a.communicationAddress)
|
|
57731
58029
|
);
|
|
57732
58030
|
const removed = this.allAgents.filter(
|
|
57733
|
-
(a) => !newAddresses.has(a.communicationAddress)
|
|
58031
|
+
(a) => !newAddresses.has(a.communicationAddress.toLowerCase())
|
|
57734
58032
|
);
|
|
57735
58033
|
this.allAgents = newAgents;
|
|
57736
58034
|
for (const agentInfo of removed) {
|
|
57737
58035
|
const address = agentInfo.communicationAddress;
|
|
57738
|
-
const client = this.
|
|
58036
|
+
const client = this.getClientByAddress(address);
|
|
57739
58037
|
if (client) {
|
|
57740
58038
|
try {
|
|
57741
|
-
this.
|
|
57742
|
-
this.stoppedAddresses.add(address.toLowerCase());
|
|
57743
|
-
await stopAndCloseXmtpClient(client, {
|
|
58039
|
+
const released = await this.releaseClient(
|
|
57744
58040
|
address,
|
|
57745
|
-
|
|
57746
|
-
|
|
57747
|
-
|
|
57748
|
-
|
|
57749
|
-
err instanceof Error ? err : new Error(String(err)),
|
|
57750
|
-
{ walletAddress: address, onchainosAgentId: agentInfo.agentId, phase: "refresh/remove" }
|
|
57751
|
-
)
|
|
57752
|
-
});
|
|
58041
|
+
client,
|
|
58042
|
+
agentInfo.agentId,
|
|
58043
|
+
"refresh/remove"
|
|
58044
|
+
);
|
|
57753
58045
|
logWithTimestamp(
|
|
57754
|
-
`[xmtp-sdk] refresh: stopped client: ${address} (agentId=${agentInfo.agentId})`
|
|
58046
|
+
`[xmtp-sdk] refresh: stopped client: ${address} (agentId=${agentInfo.agentId}) released=${released}`
|
|
57755
58047
|
);
|
|
57756
58048
|
} catch (err) {
|
|
57757
58049
|
logWithTimestamp(`[xmtp-sdk] refresh: failed to stop client: ${address}`, err);
|
|
@@ -57761,10 +58053,6 @@ var XmtpService = class _XmtpService {
|
|
|
57761
58053
|
phase: "stop-client"
|
|
57762
58054
|
});
|
|
57763
58055
|
}
|
|
57764
|
-
this.clients.delete(address);
|
|
57765
|
-
this.inboundReplayGates.delete(address.toLowerCase());
|
|
57766
|
-
this.replayScanFailuresByAddress.delete(address.toLowerCase());
|
|
57767
|
-
this.clearReplayScanRetry(address, "client_removed");
|
|
57768
58056
|
logger.info(LogEvent.AGENT_CLIENT_REMOVED, {
|
|
57769
58057
|
...agentExtras({
|
|
57770
58058
|
walletAddress: address,
|
|
@@ -57806,8 +58094,6 @@ var XmtpService = class _XmtpService {
|
|
|
57806
58094
|
const r = addResults[i];
|
|
57807
58095
|
if (r.status === "fulfilled") {
|
|
57808
58096
|
const { address, agentInfo } = r.value;
|
|
57809
|
-
this.stoppedAddresses.delete(address.toLowerCase());
|
|
57810
|
-
this.clients.set(address, r.value.agent);
|
|
57811
58097
|
logWithTimestamp(
|
|
57812
58098
|
`[xmtp-sdk] refresh: identity initialized: ${address} (agentId=${agentInfo.agentId})`
|
|
57813
58099
|
);
|
|
@@ -57834,6 +58120,10 @@ var XmtpService = class _XmtpService {
|
|
|
57834
58120
|
phase: "refresh",
|
|
57835
58121
|
attempt: "1"
|
|
57836
58122
|
});
|
|
58123
|
+
} else if (r.reason instanceof XmtpClientCreateBlockedError) {
|
|
58124
|
+
logWithTimestamp(
|
|
58125
|
+
`[xmtp-sdk] refresh: create blocked (${r.reason.reason}): ${added[i].communicationAddress} (agentId=${added[i].agentId})`
|
|
58126
|
+
);
|
|
57837
58127
|
} else {
|
|
57838
58128
|
failedAgents.push(added[i]);
|
|
57839
58129
|
if (r.reason instanceof XmtpCreationCooldownSkipError) {
|
|
@@ -57873,8 +58163,6 @@ var XmtpService = class _XmtpService {
|
|
|
57873
58163
|
const r = retryResults[i];
|
|
57874
58164
|
if (r.status === "fulfilled") {
|
|
57875
58165
|
const { address, agentInfo } = r.value;
|
|
57876
|
-
this.stoppedAddresses.delete(address.toLowerCase());
|
|
57877
|
-
this.clients.set(address, r.value.agent);
|
|
57878
58166
|
logWithTimestamp(
|
|
57879
58167
|
`[xmtp-sdk] refresh: retry succeeded: ${address} (agentId=${agentInfo.agentId})`
|
|
57880
58168
|
);
|
|
@@ -57901,6 +58189,11 @@ var XmtpService = class _XmtpService {
|
|
|
57901
58189
|
phase: "refresh",
|
|
57902
58190
|
attempt: "2"
|
|
57903
58191
|
});
|
|
58192
|
+
} else if (r.reason instanceof XmtpClientCreateBlockedError) {
|
|
58193
|
+
const info = failedAgents[i];
|
|
58194
|
+
logWithTimestamp(
|
|
58195
|
+
`[xmtp-sdk] refresh: retry create blocked (${r.reason.reason}): ${info.communicationAddress} (agentId=${info.agentId})`
|
|
58196
|
+
);
|
|
57904
58197
|
} else if (r.reason instanceof XmtpCreationCooldownSkipError) {
|
|
57905
58198
|
const info = failedAgents[i];
|
|
57906
58199
|
logWithTimestamp(
|
|
@@ -57926,7 +58219,8 @@ var XmtpService = class _XmtpService {
|
|
|
57926
58219
|
}
|
|
57927
58220
|
}
|
|
57928
58221
|
await this.startListeningForAddresses(
|
|
57929
|
-
added.map((a) => a.communicationAddress)
|
|
58222
|
+
added.map((a) => a.communicationAddress),
|
|
58223
|
+
"refresh/listen-failed"
|
|
57930
58224
|
);
|
|
57931
58225
|
for (const agentInfo of added) {
|
|
57932
58226
|
const address = agentInfo.communicationAddress;
|
|
@@ -57991,30 +58285,42 @@ var XmtpService = class _XmtpService {
|
|
|
57991
58285
|
}
|
|
57992
58286
|
for (const agentInfo of this.allAgents) {
|
|
57993
58287
|
const address = agentInfo.communicationAddress;
|
|
57994
|
-
const
|
|
57995
|
-
|
|
58288
|
+
const addressKey = address.toLowerCase();
|
|
58289
|
+
const oldClient = this.getClientByAddress(address);
|
|
58290
|
+
const hasPendingRelease = this.pendingReleaseByAddress.has(addressKey) || this.releaseConfirmedNeedsCreate.has(addressKey);
|
|
58291
|
+
if (!oldClient && !hasPendingRelease) {
|
|
57996
58292
|
continue;
|
|
57997
58293
|
}
|
|
57998
|
-
|
|
57999
|
-
|
|
58000
|
-
|
|
58001
|
-
|
|
58002
|
-
|
|
58003
|
-
address
|
|
58004
|
-
|
|
58005
|
-
|
|
58006
|
-
|
|
58007
|
-
|
|
58008
|
-
|
|
58009
|
-
|
|
58010
|
-
|
|
58011
|
-
|
|
58012
|
-
|
|
58013
|
-
|
|
58014
|
-
|
|
58015
|
-
|
|
58294
|
+
if (!oldClient) {
|
|
58295
|
+
let settled = false;
|
|
58296
|
+
try {
|
|
58297
|
+
settled = await this.settlePendingRelease(address);
|
|
58298
|
+
} catch (err) {
|
|
58299
|
+
logWithTimestamp(`[xmtp-sdk] recycle: pending release retry failed: ${address}`, err);
|
|
58300
|
+
}
|
|
58301
|
+
if (!settled) {
|
|
58302
|
+
failed++;
|
|
58303
|
+
continue;
|
|
58304
|
+
}
|
|
58305
|
+
} else {
|
|
58306
|
+
let released = false;
|
|
58307
|
+
try {
|
|
58308
|
+
released = await this.releaseClient(
|
|
58309
|
+
address,
|
|
58310
|
+
oldClient,
|
|
58311
|
+
agentInfo.agentId,
|
|
58312
|
+
"recycle"
|
|
58313
|
+
);
|
|
58314
|
+
} catch (err) {
|
|
58315
|
+
logWithTimestamp(`[xmtp-sdk] recycle: failed to stop client: ${address}`, err);
|
|
58316
|
+
logger.error(LogEvent.AGENT_REFRESH_FAILED, err instanceof Error ? err : new Error(String(err)), {
|
|
58317
|
+
walletAddress: address,
|
|
58318
|
+
onchainosAgentId: agentInfo.agentId,
|
|
58319
|
+
phase: "recycle/stop-client"
|
|
58320
|
+
});
|
|
58321
|
+
}
|
|
58016
58322
|
logWithTimestamp(
|
|
58017
|
-
`[xmtp-sdk] recycle: stopped client: ${address} (agentId=${agentInfo.agentId})`
|
|
58323
|
+
`[xmtp-sdk] recycle: stopped client: ${address} (agentId=${agentInfo.agentId}) released=${released}`
|
|
58018
58324
|
);
|
|
58019
58325
|
logger.info(LogEvent.AGENT_CLIENT_REMOVED, {
|
|
58020
58326
|
...agentExtras({
|
|
@@ -58024,23 +58330,18 @@ var XmtpService = class _XmtpService {
|
|
|
58024
58330
|
}),
|
|
58025
58331
|
phase: "recycle"
|
|
58026
58332
|
});
|
|
58027
|
-
|
|
58028
|
-
|
|
58029
|
-
|
|
58030
|
-
|
|
58031
|
-
logger.error(LogEvent.AGENT_REFRESH_FAILED, err instanceof Error ? err : new Error(String(err)), {
|
|
58032
|
-
walletAddress: address,
|
|
58033
|
-
onchainosAgentId: agentInfo.agentId,
|
|
58034
|
-
phase: "recycle/stop-client"
|
|
58035
|
-
});
|
|
58036
|
-
continue;
|
|
58333
|
+
if (!released) {
|
|
58334
|
+
failed++;
|
|
58335
|
+
continue;
|
|
58336
|
+
}
|
|
58037
58337
|
}
|
|
58338
|
+
let newAgent;
|
|
58339
|
+
let newAgentReleased = false;
|
|
58038
58340
|
try {
|
|
58039
58341
|
const { agent } = await this.createClientForAgent(agentInfo, {
|
|
58040
58342
|
logPrefix: "[xmtp-sdk:recycle]"
|
|
58041
58343
|
});
|
|
58042
|
-
|
|
58043
|
-
this.clients.set(address, agent);
|
|
58344
|
+
newAgent = agent;
|
|
58044
58345
|
logWithTimestamp(
|
|
58045
58346
|
`[xmtp-sdk] recycle: identity initialized: ${address} (agentId=${agentInfo.agentId})`
|
|
58046
58347
|
);
|
|
@@ -58064,7 +58365,13 @@ var XmtpService = class _XmtpService {
|
|
|
58064
58365
|
agentInfo,
|
|
58065
58366
|
phase: "recycle"
|
|
58066
58367
|
});
|
|
58067
|
-
await this.startListeningForAddresses([address]);
|
|
58368
|
+
const listen = (await this.startListeningForAddresses([address], "recycle/listen-failed")).get(address);
|
|
58369
|
+
if (listen?.client !== agent || !isListenHealthy(listen.outcome)) {
|
|
58370
|
+
newAgentReleased = listen?.client === agent && listen.outcome === "failed";
|
|
58371
|
+
throw new Error(
|
|
58372
|
+
`xmtp listener not started (${listen?.client === agent ? listen.outcome : "client_replaced"})`
|
|
58373
|
+
);
|
|
58374
|
+
}
|
|
58068
58375
|
const replayGate = this.inboundReplayGates.get(addressKey);
|
|
58069
58376
|
let replaySummary;
|
|
58070
58377
|
try {
|
|
@@ -58083,8 +58390,21 @@ var XmtpService = class _XmtpService {
|
|
|
58083
58390
|
recycled++;
|
|
58084
58391
|
} catch (err) {
|
|
58085
58392
|
failed++;
|
|
58086
|
-
|
|
58087
|
-
|
|
58393
|
+
if (newAgent && !newAgentReleased) {
|
|
58394
|
+
try {
|
|
58395
|
+
await this.releaseClient(
|
|
58396
|
+
address,
|
|
58397
|
+
newAgent,
|
|
58398
|
+
agentInfo.agentId,
|
|
58399
|
+
"recycle/create-failed"
|
|
58400
|
+
);
|
|
58401
|
+
} catch (releaseErr) {
|
|
58402
|
+
logWithTimestamp(
|
|
58403
|
+
`[xmtp-sdk] recycle: failed to release new client: ${address}`,
|
|
58404
|
+
releaseErr
|
|
58405
|
+
);
|
|
58406
|
+
}
|
|
58407
|
+
}
|
|
58088
58408
|
logWithTimestamp(`[xmtp-sdk] recycle: failed to recreate client: ${address}`, err);
|
|
58089
58409
|
logger.error(
|
|
58090
58410
|
LogEvent.XMTP_CONNECTION_FAILED,
|
|
@@ -58488,7 +58808,7 @@ var XmtpService = class _XmtpService {
|
|
|
58488
58808
|
}
|
|
58489
58809
|
}
|
|
58490
58810
|
async startListening() {
|
|
58491
|
-
await this.startListeningForAddresses([...this.clients.keys()]);
|
|
58811
|
+
await this.startListeningForAddresses([...this.clients.keys()], "listen-failed");
|
|
58492
58812
|
}
|
|
58493
58813
|
async drainInboundReplayGate(address, expectedGate) {
|
|
58494
58814
|
if (!expectedGate) {
|
|
@@ -58553,11 +58873,22 @@ var XmtpService = class _XmtpService {
|
|
|
58553
58873
|
);
|
|
58554
58874
|
return gate;
|
|
58555
58875
|
}
|
|
58556
|
-
|
|
58876
|
+
// With `client`, only that client's recovery is cancelled, so a late caller
|
|
58877
|
+
// cannot cancel the recovery of a newer instance on the same address.
|
|
58878
|
+
cancelStreamRecoveryForAddress(address, client) {
|
|
58557
58879
|
const addressKey = address.toLowerCase();
|
|
58558
|
-
const
|
|
58880
|
+
const entry = this.streamRecoveryCleanupByAddress.get(addressKey);
|
|
58881
|
+
if (!entry || client && entry.client !== client) {
|
|
58882
|
+
return;
|
|
58883
|
+
}
|
|
58559
58884
|
this.streamRecoveryCleanupByAddress.delete(addressKey);
|
|
58560
|
-
cleanup
|
|
58885
|
+
entry.cleanup();
|
|
58886
|
+
}
|
|
58887
|
+
// True while `client` is the registered client of `address` (case-insensitive)
|
|
58888
|
+
// and the address is neither stopped nor being released.
|
|
58889
|
+
isCurrentListenOwner(address, client) {
|
|
58890
|
+
const key = address.toLowerCase();
|
|
58891
|
+
return this.getClientByAddress(address) === client && !this.stoppedAddresses.has(key) && !this.pendingReleaseByAddress.has(key);
|
|
58561
58892
|
}
|
|
58562
58893
|
getClientGeneration(client) {
|
|
58563
58894
|
const existing = this.clientGenerationByClient.get(client);
|
|
@@ -58709,10 +59040,17 @@ var XmtpService = class _XmtpService {
|
|
|
58709
59040
|
this.notifyAgentsWakeupAfterReplay();
|
|
58710
59041
|
return summary;
|
|
58711
59042
|
}
|
|
58712
|
-
|
|
59043
|
+
// Starts (at most once per client) the listener of every registered address
|
|
59044
|
+
// and reports each outcome. A "failed" client, i.e. one with neither a live
|
|
59045
|
+
// listener nor an owned retry task, is released with `releasePhase` before
|
|
59046
|
+
// this returns, so it is never served as a healthy instance.
|
|
59047
|
+
async startListeningForAddresses(addresses, releasePhase = "listen-failed") {
|
|
58713
59048
|
const valid = addresses.filter((addr) => this.clients.has(addr));
|
|
58714
|
-
|
|
58715
|
-
|
|
59049
|
+
const targets = valid.map((address) => ({
|
|
59050
|
+
address,
|
|
59051
|
+
client: this.clients.get(address)
|
|
59052
|
+
}));
|
|
59053
|
+
const listenForClient = async (address, agent) => {
|
|
58716
59054
|
const clientGeneration = this.getClientGeneration(agent);
|
|
58717
59055
|
const addressKey = address.toLowerCase();
|
|
58718
59056
|
const tag = `[xmtp-sdk:${address}]`;
|
|
@@ -58723,6 +59061,11 @@ var XmtpService = class _XmtpService {
|
|
|
58723
59061
|
onchainosAgentId: onchainosAgent?.agentId,
|
|
58724
59062
|
role: onchainosAgent?.role
|
|
58725
59063
|
};
|
|
59064
|
+
const ownsAddress = () => this.isCurrentListenOwner(address, agent);
|
|
59065
|
+
if (!ownsAddress()) {
|
|
59066
|
+
logWithTimestamp(`${tag} listener setup skipped: client no longer current`);
|
|
59067
|
+
return "skipped";
|
|
59068
|
+
}
|
|
58726
59069
|
try {
|
|
58727
59070
|
await agent.client.conversations.syncAll([
|
|
58728
59071
|
import_node_bindings2.ConsentState.Allowed,
|
|
@@ -58730,13 +59073,21 @@ var XmtpService = class _XmtpService {
|
|
|
58730
59073
|
]);
|
|
58731
59074
|
logWithTimestamp(`${tag} conversations synced (non-Denied)`);
|
|
58732
59075
|
} catch (err) {
|
|
58733
|
-
|
|
59076
|
+
if (!ownsAddress()) {
|
|
59077
|
+
logWithTimestamp(`${tag} stale conversation sync failed after replacement, ignored:`, err);
|
|
59078
|
+
return "skipped";
|
|
59079
|
+
}
|
|
59080
|
+
logWithTimestamp(`${tag} conversation sync failed, listener not started:`, err);
|
|
58734
59081
|
logger.error(
|
|
58735
59082
|
LogEvent.CONVERSATIONS_STREAM_FAILED,
|
|
58736
59083
|
err instanceof Error ? err : void 0,
|
|
58737
59084
|
agentExtras(identity)
|
|
58738
59085
|
);
|
|
58739
|
-
return;
|
|
59086
|
+
return "failed";
|
|
59087
|
+
}
|
|
59088
|
+
if (!ownsAddress()) {
|
|
59089
|
+
logWithTimestamp(`${tag} listener setup skipped after sync: client no longer current`);
|
|
59090
|
+
return "skipped";
|
|
58740
59091
|
}
|
|
58741
59092
|
agent.use(loggingMiddleware(identity));
|
|
58742
59093
|
agent.use(selfFilterMiddleware());
|
|
@@ -58765,6 +59116,7 @@ var XmtpService = class _XmtpService {
|
|
|
58765
59116
|
});
|
|
58766
59117
|
const gate = new InboundReplayGate(inbound);
|
|
58767
59118
|
this.inboundReplayGates.set(address.toLowerCase(), gate);
|
|
59119
|
+
this.inboundReplayGateOwners.set(gate, agent);
|
|
58768
59120
|
agent.use(gate.middleware);
|
|
58769
59121
|
} else {
|
|
58770
59122
|
logWithTimestamp(
|
|
@@ -58782,16 +59134,25 @@ var XmtpService = class _XmtpService {
|
|
|
58782
59134
|
const MAX_RETRIES = 5;
|
|
58783
59135
|
const BASE_DELAY_MS = 1e3;
|
|
58784
59136
|
const startWithRetry = async (attempt = 0) => {
|
|
58785
|
-
if (
|
|
59137
|
+
if (!ownsAddress()) {
|
|
58786
59138
|
logWithTimestamp(`${tag} start skipped: client stopped or removed`);
|
|
58787
|
-
return;
|
|
59139
|
+
return "skipped";
|
|
58788
59140
|
}
|
|
58789
59141
|
try {
|
|
58790
59142
|
const liveStreamOptions = {
|
|
58791
59143
|
consentStates: [import_node_bindings2.ConsentState.Allowed, import_node_bindings2.ConsentState.Unknown]
|
|
58792
59144
|
};
|
|
58793
59145
|
await agent.start(liveStreamOptions);
|
|
59146
|
+
if (!ownsAddress()) {
|
|
59147
|
+
logWithTimestamp(`${tag} stale agent.start resolved after replacement, ignored`);
|
|
59148
|
+
return "skipped";
|
|
59149
|
+
}
|
|
59150
|
+
return "started";
|
|
58794
59151
|
} catch (err) {
|
|
59152
|
+
if (!ownsAddress()) {
|
|
59153
|
+
logWithTimestamp(`${tag} stale agent.start failed after replacement, ignored:`, err);
|
|
59154
|
+
return "skipped";
|
|
59155
|
+
}
|
|
58795
59156
|
logWithTimestamp(`${tag} agent.start error (attempt=${attempt}):`, err);
|
|
58796
59157
|
logger.error(
|
|
58797
59158
|
LogEvent.AGENT_START_FAILED,
|
|
@@ -58801,17 +59162,27 @@ var XmtpService = class _XmtpService {
|
|
|
58801
59162
|
attempt: String(attempt)
|
|
58802
59163
|
}
|
|
58803
59164
|
);
|
|
58804
|
-
scheduleRetry(attempt);
|
|
59165
|
+
return scheduleRetry(attempt);
|
|
58805
59166
|
}
|
|
58806
59167
|
};
|
|
58807
59168
|
const scheduleRetry = (attempt) => {
|
|
58808
|
-
if (
|
|
59169
|
+
if (!ownsAddress()) {
|
|
58809
59170
|
logWithTimestamp(`${tag} reconnect skipped: client stopped or removed`);
|
|
58810
|
-
return;
|
|
59171
|
+
return "skipped";
|
|
58811
59172
|
}
|
|
58812
59173
|
if (attempt >= MAX_RETRIES) {
|
|
58813
|
-
logWithTimestamp(
|
|
58814
|
-
|
|
59174
|
+
logWithTimestamp(
|
|
59175
|
+
`${tag} reached max retries (${MAX_RETRIES}), giving up reconnect; releasing client`
|
|
59176
|
+
);
|
|
59177
|
+
void this.releaseClient(
|
|
59178
|
+
address,
|
|
59179
|
+
agent,
|
|
59180
|
+
identity.onchainosAgentId ?? "",
|
|
59181
|
+
"listen/retry-exhausted"
|
|
59182
|
+
).catch((err) => {
|
|
59183
|
+
logWithTimestamp(`${tag} release after retry exhaustion failed:`, err);
|
|
59184
|
+
});
|
|
59185
|
+
return "failed";
|
|
58815
59186
|
}
|
|
58816
59187
|
const delay = BASE_DELAY_MS * 2 ** attempt;
|
|
58817
59188
|
logWithTimestamp(`${tag} reconnecting in ${delay}ms (attempt=${attempt + 1})`);
|
|
@@ -58819,6 +59190,7 @@ var XmtpService = class _XmtpService {
|
|
|
58819
59190
|
() => void startWithRetry(attempt + 1),
|
|
58820
59191
|
delay
|
|
58821
59192
|
);
|
|
59193
|
+
return "retrying";
|
|
58822
59194
|
};
|
|
58823
59195
|
const streamRecovery = new StreamRecoveryTelemetry();
|
|
58824
59196
|
let recoveryTimeout;
|
|
@@ -58838,10 +59210,10 @@ var XmtpService = class _XmtpService {
|
|
|
58838
59210
|
recoveryStabilityTimeout = void 0;
|
|
58839
59211
|
}
|
|
58840
59212
|
};
|
|
58841
|
-
this.streamRecoveryCleanupByAddress.set(
|
|
58842
|
-
|
|
58843
|
-
cleanupStreamRecovery
|
|
58844
|
-
);
|
|
59213
|
+
this.streamRecoveryCleanupByAddress.set(addressKey, {
|
|
59214
|
+
client: agent,
|
|
59215
|
+
cleanup: cleanupStreamRecovery
|
|
59216
|
+
});
|
|
58845
59217
|
agent.on("unhandledError", (err) => {
|
|
58846
59218
|
if (recoveryDisposed || this.clients.get(address) !== agent || this.stoppedAddresses.has(addressKey)) {
|
|
58847
59219
|
return;
|
|
@@ -59003,9 +59375,54 @@ var XmtpService = class _XmtpService {
|
|
|
59003
59375
|
`${tag} agent message event msg=${msg?.id ?? "(unknown)"} kind=${msg?.kind ?? "(unknown)"} conv=${conversation?.id ?? msg?.conversationId ?? "(unknown)"} sender=${msg?.senderInboxId ?? "(unknown)"} isText=${typeof ctx.isText === "function" ? String(ctx.isText()) : "unknown"} preview="${previewDebugContent(msg?.content)}"`
|
|
59004
59376
|
);
|
|
59005
59377
|
});
|
|
59006
|
-
await startWithRetry();
|
|
59007
|
-
logWithTimestamp(`${tag} message listener
|
|
59378
|
+
const outcome = await startWithRetry();
|
|
59379
|
+
logWithTimestamp(`${tag} message listener ${outcome}`);
|
|
59380
|
+
return outcome;
|
|
59381
|
+
};
|
|
59382
|
+
const settled = await parallelMap(targets, async ({ address, client }) => {
|
|
59383
|
+
let task = this.listenTaskByClient.get(client);
|
|
59384
|
+
if (!task) {
|
|
59385
|
+
task = listenForClient(address, client);
|
|
59386
|
+
this.listenTaskByClient.set(client, task);
|
|
59387
|
+
}
|
|
59388
|
+
let outcome;
|
|
59389
|
+
try {
|
|
59390
|
+
outcome = await task;
|
|
59391
|
+
} catch (err) {
|
|
59392
|
+
logWithTimestamp(`[xmtp-sdk:${address}] listener setup failed:`, err);
|
|
59393
|
+
logger.error(
|
|
59394
|
+
LogEvent.AGENT_START_FAILED,
|
|
59395
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
59396
|
+
{
|
|
59397
|
+
...agentExtras({
|
|
59398
|
+
walletAddress: address,
|
|
59399
|
+
inboxId: client.client?.inboxId,
|
|
59400
|
+
onchainosAgentId: this.getAgentByAddress(address)?.agentId
|
|
59401
|
+
}),
|
|
59402
|
+
phase: "listener-setup"
|
|
59403
|
+
}
|
|
59404
|
+
);
|
|
59405
|
+
outcome = "failed";
|
|
59406
|
+
}
|
|
59407
|
+
if (outcome === "failed") {
|
|
59408
|
+
await this.releaseClient(
|
|
59409
|
+
address,
|
|
59410
|
+
client,
|
|
59411
|
+
this.getAgentByAddress(address)?.agentId ?? "",
|
|
59412
|
+
releasePhase
|
|
59413
|
+
);
|
|
59414
|
+
}
|
|
59415
|
+
return outcome;
|
|
59416
|
+
});
|
|
59417
|
+
const results = /* @__PURE__ */ new Map();
|
|
59418
|
+
targets.forEach(({ address, client }, i) => {
|
|
59419
|
+
const r = settled[i];
|
|
59420
|
+
results.set(address, {
|
|
59421
|
+
client,
|
|
59422
|
+
outcome: r.status === "fulfilled" ? r.value : "failed"
|
|
59423
|
+
});
|
|
59008
59424
|
});
|
|
59425
|
+
return results;
|
|
59009
59426
|
}
|
|
59010
59427
|
async replayOfflineMessagesForAddress(address, expectedClient, trigger = "periodic_repair", recoveryIdentity) {
|
|
59011
59428
|
const addressReplayStartedAt = Date.now();
|
|
@@ -61716,7 +62133,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
|
|
|
61716
62133
|
client: {
|
|
61717
62134
|
id: "gateway-client",
|
|
61718
62135
|
displayName: "okx-a2a-node",
|
|
61719
|
-
version: "0.2.
|
|
62136
|
+
version: "0.2.18",
|
|
61720
62137
|
platform: "node",
|
|
61721
62138
|
mode: "backend",
|
|
61722
62139
|
instanceId
|
|
@@ -61727,7 +62144,7 @@ function buildConnectParams(config, instanceId, protocolVersion) {
|
|
|
61727
62144
|
commands: [],
|
|
61728
62145
|
permissions: {},
|
|
61729
62146
|
locale: Intl.DateTimeFormat().resolvedOptions().locale || "en-US",
|
|
61730
|
-
userAgent: `okx-a2a-node/${"0.2.
|
|
62147
|
+
userAgent: `okx-a2a-node/${"0.2.18"}`,
|
|
61731
62148
|
auth: {
|
|
61732
62149
|
...config.token ? { token: config.token } : {},
|
|
61733
62150
|
...config.password ? { password: config.password } : {}
|
|
@@ -68067,12 +68484,12 @@ async function runListenerWithLock(options, paths) {
|
|
|
68067
68484
|
});
|
|
68068
68485
|
}
|
|
68069
68486
|
});
|
|
68070
|
-
service.setPluginVersion("0.2.
|
|
68487
|
+
service.setPluginVersion("0.2.18");
|
|
68071
68488
|
await service.init();
|
|
68072
68489
|
const pluginVersionStatus = service.pluginVersionStatus;
|
|
68073
68490
|
if (pluginVersionStatus.unavailable) {
|
|
68074
68491
|
throw new Error(
|
|
68075
|
-
`@okxweb3/a2a-node v${"0.2.
|
|
68492
|
+
`@okxweb3/a2a-node v${"0.2.18"} is below the required minimum v${pluginVersionStatus.minVersion}`
|
|
68076
68493
|
);
|
|
68077
68494
|
}
|
|
68078
68495
|
const systemConfig = service.getSystemConfig();
|
|
@@ -68100,7 +68517,7 @@ async function runListenerWithLock(options, paths) {
|
|
|
68100
68517
|
onchainosAgentId: "*",
|
|
68101
68518
|
reason: "system-config missing sentryDsn",
|
|
68102
68519
|
pluginId: "@okxweb3/a2a-node",
|
|
68103
|
-
pluginVersion: "0.2.
|
|
68520
|
+
pluginVersion: "0.2.18"
|
|
68104
68521
|
});
|
|
68105
68522
|
}
|
|
68106
68523
|
logWithTimestamp(
|
|
@@ -70873,7 +71290,7 @@ async function exportDiagnosticLogs(options) {
|
|
|
70873
71290
|
node: process.version,
|
|
70874
71291
|
platform: process.platform,
|
|
70875
71292
|
arch: process.arch,
|
|
70876
|
-
packageVersion: true ? "0.2.
|
|
71293
|
+
packageVersion: true ? "0.2.18" : "unknown",
|
|
70877
71294
|
sensitiveContentIncluded: options.includeSensitiveContent,
|
|
70878
71295
|
listenerAndLlmContentIncluded: true,
|
|
70879
71296
|
credentialsAlwaysRedacted: true,
|
|
@@ -72785,7 +73202,7 @@ async function runDoctor(options = {}) {
|
|
|
72785
73202
|
platform: options.platform ?? process.platform,
|
|
72786
73203
|
env: options.env ?? process.env,
|
|
72787
73204
|
target: options.target ?? resolveDoctorTarget(options.env ?? process.env),
|
|
72788
|
-
cliVersion: options.cliVersion ?? (true ? "0.2.
|
|
73205
|
+
cliVersion: options.cliVersion ?? (true ? "0.2.18" : "0.0.0"),
|
|
72789
73206
|
fixMode: options.fix === true,
|
|
72790
73207
|
nonInteractive: options.nonInteractive === true,
|
|
72791
73208
|
packageChanged: false,
|