@perkos/perkos-a2a 0.8.12 → 0.8.14
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/README.md +167 -1
- package/bin/agent.ts +173 -0
- package/bin/relay.ts +20 -2
- package/dist/agent.d.ts +14 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +250 -0
- package/dist/agent.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +373 -168
- package/dist/index.js.map +4 -4
- package/dist/relay-client.js +1 -1
- package/dist/relay-client.js.map +1 -1
- package/dist/relay.d.ts +3 -1
- package/dist/relay.d.ts.map +1 -1
- package/dist/relay.js +14 -1
- package/dist/relay.js.map +1 -1
- package/dist/runtime-reply.d.ts +13 -0
- package/dist/runtime-reply.d.ts.map +1 -0
- package/dist/runtime-reply.js +114 -0
- package/dist/runtime-reply.js.map +1 -0
- package/dist/server.d.ts +4 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +74 -52
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +31 -6
- package/dist/types.d.ts.map +1 -1
- package/openclaw.plugin.json +121 -18
- package/package.json +13 -9
package/dist/index.js
CHANGED
|
@@ -5368,9 +5368,9 @@ var require_read = __commonJS({
|
|
|
5368
5368
|
}
|
|
5369
5369
|
});
|
|
5370
5370
|
|
|
5371
|
-
// node_modules/
|
|
5371
|
+
// node_modules/media-typer/index.js
|
|
5372
5372
|
var require_media_typer = __commonJS({
|
|
5373
|
-
"node_modules/
|
|
5373
|
+
"node_modules/media-typer/index.js"(exports) {
|
|
5374
5374
|
var paramRegExp = /; *([!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) *= *("(?:[ !\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u0020-\u007e])*"|[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+) */g;
|
|
5375
5375
|
var textRegExp = /^[\u0020-\u007e\u0080-\u00ff]+$/;
|
|
5376
5376
|
var tokenRegExp = /^[!#$%&'\*\+\-\.0-9A-Z\^_`a-z\|~]+$/;
|
|
@@ -14035,7 +14035,7 @@ var require_mime_types = __commonJS({
|
|
|
14035
14035
|
exports.charset = charset;
|
|
14036
14036
|
exports.charsets = { lookup: charset };
|
|
14037
14037
|
exports.contentType = contentType;
|
|
14038
|
-
exports.extension =
|
|
14038
|
+
exports.extension = extension2;
|
|
14039
14039
|
exports.extensions = /* @__PURE__ */ Object.create(null);
|
|
14040
14040
|
exports.lookup = lookup;
|
|
14041
14041
|
exports.types = /* @__PURE__ */ Object.create(null);
|
|
@@ -14068,7 +14068,7 @@ var require_mime_types = __commonJS({
|
|
|
14068
14068
|
}
|
|
14069
14069
|
return mime;
|
|
14070
14070
|
}
|
|
14071
|
-
function
|
|
14071
|
+
function extension2(type) {
|
|
14072
14072
|
if (!type || typeof type !== "string") {
|
|
14073
14073
|
return false;
|
|
14074
14074
|
}
|
|
@@ -14083,11 +14083,11 @@ var require_mime_types = __commonJS({
|
|
|
14083
14083
|
if (!path || typeof path !== "string") {
|
|
14084
14084
|
return false;
|
|
14085
14085
|
}
|
|
14086
|
-
var
|
|
14087
|
-
if (!
|
|
14086
|
+
var extension3 = extname("x." + path).toLowerCase().substr(1);
|
|
14087
|
+
if (!extension3) {
|
|
14088
14088
|
return false;
|
|
14089
14089
|
}
|
|
14090
|
-
return exports.types[
|
|
14090
|
+
return exports.types[extension3] || false;
|
|
14091
14091
|
}
|
|
14092
14092
|
function populateMaps(extensions, types) {
|
|
14093
14093
|
var preference = ["nginx", "apache", void 0, "iana"];
|
|
@@ -14099,15 +14099,15 @@ var require_mime_types = __commonJS({
|
|
|
14099
14099
|
}
|
|
14100
14100
|
extensions[type] = exts;
|
|
14101
14101
|
for (var i = 0; i < exts.length; i++) {
|
|
14102
|
-
var
|
|
14103
|
-
if (types[
|
|
14104
|
-
var from = preference.indexOf(db[types[
|
|
14102
|
+
var extension3 = exts[i];
|
|
14103
|
+
if (types[extension3]) {
|
|
14104
|
+
var from = preference.indexOf(db[types[extension3]].source);
|
|
14105
14105
|
var to = preference.indexOf(mime.source);
|
|
14106
|
-
if (types[
|
|
14106
|
+
if (types[extension3] !== "application/octet-stream" && (from > to || from === to && types[extension3].substr(0, 12) === "application/")) {
|
|
14107
14107
|
continue;
|
|
14108
14108
|
}
|
|
14109
14109
|
}
|
|
14110
|
-
types[
|
|
14110
|
+
types[extension3] = type;
|
|
14111
14111
|
}
|
|
14112
14112
|
});
|
|
14113
14113
|
}
|
|
@@ -14305,10 +14305,7 @@ var require_json = __commonJS({
|
|
|
14305
14305
|
var index = str.indexOf(char);
|
|
14306
14306
|
var partial = "";
|
|
14307
14307
|
if (index !== -1) {
|
|
14308
|
-
partial = str.substring(0, index) + JSON_SYNTAX_CHAR;
|
|
14309
|
-
for (var i = index + 1; i < str.length; i++) {
|
|
14310
|
-
partial += JSON_SYNTAX_CHAR;
|
|
14311
|
-
}
|
|
14308
|
+
partial = str.substring(0, index) + new Array(str.length - index + 1).join(JSON_SYNTAX_CHAR);
|
|
14312
14309
|
}
|
|
14313
14310
|
try {
|
|
14314
14311
|
JSON.parse(partial);
|
|
@@ -15083,9 +15080,8 @@ var require_side_channel_list = __commonJS({
|
|
|
15083
15080
|
}
|
|
15084
15081
|
},
|
|
15085
15082
|
"delete": function(key) {
|
|
15086
|
-
var root = $o && $o.next;
|
|
15087
15083
|
var deletedNode = listDelete($o, key);
|
|
15088
|
-
if (deletedNode &&
|
|
15084
|
+
if (deletedNode && $o && !$o.next) {
|
|
15089
15085
|
$o = void 0;
|
|
15090
15086
|
}
|
|
15091
15087
|
return !!deletedNode;
|
|
@@ -16196,6 +16192,8 @@ var require_utils = __commonJS({
|
|
|
16196
16192
|
var newIndex = getMaxIndex(target) + 1;
|
|
16197
16193
|
target[newIndex] = source;
|
|
16198
16194
|
setMaxIndex(target, newIndex);
|
|
16195
|
+
} else if (options && options.strictMerge) {
|
|
16196
|
+
return [target, source];
|
|
16199
16197
|
} else if (options && (options.plainObjects || options.allowPrototypes) || !has.call(Object.prototype, source)) {
|
|
16200
16198
|
target[source] = true;
|
|
16201
16199
|
}
|
|
@@ -16699,6 +16697,7 @@ var require_parse = __commonJS({
|
|
|
16699
16697
|
parseArrays: true,
|
|
16700
16698
|
plainObjects: false,
|
|
16701
16699
|
strictDepth: false,
|
|
16700
|
+
strictMerge: true,
|
|
16702
16701
|
strictNullHandling: false,
|
|
16703
16702
|
throwOnLimitExceeded: false
|
|
16704
16703
|
};
|
|
@@ -16725,9 +16724,9 @@ var require_parse = __commonJS({
|
|
|
16725
16724
|
var limit = options.parameterLimit === Infinity ? void 0 : options.parameterLimit;
|
|
16726
16725
|
var parts = cleanStr.split(
|
|
16727
16726
|
options.delimiter,
|
|
16728
|
-
options.throwOnLimitExceeded ? limit + 1 : limit
|
|
16727
|
+
options.throwOnLimitExceeded && typeof limit !== "undefined" ? limit + 1 : limit
|
|
16729
16728
|
);
|
|
16730
|
-
if (options.throwOnLimitExceeded && parts.length > limit) {
|
|
16729
|
+
if (options.throwOnLimitExceeded && typeof limit !== "undefined" && parts.length > limit) {
|
|
16731
16730
|
throw new RangeError("Parameter limit exceeded. Only " + limit + " parameter" + (limit === 1 ? "" : "s") + " allowed.");
|
|
16732
16731
|
}
|
|
16733
16732
|
var skipIndex = -1;
|
|
@@ -16787,7 +16786,7 @@ var require_parse = __commonJS({
|
|
|
16787
16786
|
}
|
|
16788
16787
|
if (key !== null) {
|
|
16789
16788
|
var existing = has.call(obj, key);
|
|
16790
|
-
if (existing && options.duplicates === "combine") {
|
|
16789
|
+
if (existing && (options.duplicates === "combine" || part.indexOf("[]=") > -1)) {
|
|
16791
16790
|
obj[key] = utils.combine(
|
|
16792
16791
|
obj[key],
|
|
16793
16792
|
val,
|
|
@@ -16944,6 +16943,7 @@ var require_parse = __commonJS({
|
|
|
16944
16943
|
parseArrays: opts.parseArrays !== false,
|
|
16945
16944
|
plainObjects: typeof opts.plainObjects === "boolean" ? opts.plainObjects : defaults.plainObjects,
|
|
16946
16945
|
strictDepth: typeof opts.strictDepth === "boolean" ? !!opts.strictDepth : defaults.strictDepth,
|
|
16946
|
+
strictMerge: typeof opts.strictMerge === "boolean" ? !!opts.strictMerge : defaults.strictMerge,
|
|
16947
16947
|
strictNullHandling: typeof opts.strictNullHandling === "boolean" ? opts.strictNullHandling : defaults.strictNullHandling,
|
|
16948
16948
|
throwOnLimitExceeded: typeof opts.throwOnLimitExceeded === "boolean" ? opts.throwOnLimitExceeded : false
|
|
16949
16949
|
};
|
|
@@ -17102,14 +17102,14 @@ var require_urlencoded = __commonJS({
|
|
|
17102
17102
|
}
|
|
17103
17103
|
function parameterCount(body, limit) {
|
|
17104
17104
|
var count = 0;
|
|
17105
|
-
var index =
|
|
17106
|
-
|
|
17105
|
+
var index = -1;
|
|
17106
|
+
do {
|
|
17107
17107
|
count++;
|
|
17108
|
-
|
|
17109
|
-
if (count === limit) {
|
|
17108
|
+
if (count > limit) {
|
|
17110
17109
|
return void 0;
|
|
17111
17110
|
}
|
|
17112
|
-
|
|
17111
|
+
index = body.indexOf("&", index + 1);
|
|
17112
|
+
} while (index !== -1);
|
|
17113
17113
|
return count;
|
|
17114
17114
|
}
|
|
17115
17115
|
function parser(name) {
|
|
@@ -17431,7 +17431,7 @@ var require_finalhandler = __commonJS({
|
|
|
17431
17431
|
module.exports = finalhandler;
|
|
17432
17432
|
function finalhandler(req, res, options) {
|
|
17433
17433
|
var opts = options || {};
|
|
17434
|
-
var
|
|
17434
|
+
var env2 = opts.env || process.env.NODE_ENV || "development";
|
|
17435
17435
|
var onerror = opts.onerror;
|
|
17436
17436
|
return function(err) {
|
|
17437
17437
|
var headers;
|
|
@@ -17448,7 +17448,7 @@ var require_finalhandler = __commonJS({
|
|
|
17448
17448
|
} else {
|
|
17449
17449
|
headers = getErrorHeaders(err);
|
|
17450
17450
|
}
|
|
17451
|
-
msg = getErrorMessage(err, status,
|
|
17451
|
+
msg = getErrorMessage(err, status, env2);
|
|
17452
17452
|
} else {
|
|
17453
17453
|
status = 404;
|
|
17454
17454
|
msg = "Cannot " + req.method + " " + encodeUrl(getResourceName(req));
|
|
@@ -17479,9 +17479,9 @@ var require_finalhandler = __commonJS({
|
|
|
17479
17479
|
}
|
|
17480
17480
|
return headers;
|
|
17481
17481
|
}
|
|
17482
|
-
function getErrorMessage(err, status,
|
|
17482
|
+
function getErrorMessage(err, status, env2) {
|
|
17483
17483
|
var msg;
|
|
17484
|
-
if (
|
|
17484
|
+
if (env2 !== "production") {
|
|
17485
17485
|
msg = err.stack;
|
|
17486
17486
|
if (!msg && typeof err.toString === "function") {
|
|
17487
17487
|
msg = err.toString();
|
|
@@ -17653,6 +17653,7 @@ var require_path_to_regexp = __commonJS({
|
|
|
17653
17653
|
}
|
|
17654
17654
|
pos = offset + match.length;
|
|
17655
17655
|
if (match === "*") {
|
|
17656
|
+
backtrack = "";
|
|
17656
17657
|
extraOffset += 3;
|
|
17657
17658
|
return "(.*)";
|
|
17658
17659
|
}
|
|
@@ -17673,6 +17674,7 @@ var require_path_to_regexp = __commonJS({
|
|
|
17673
17674
|
offset: offset + extraOffset
|
|
17674
17675
|
});
|
|
17675
17676
|
var result = "(?:" + format + slash + capture + (star ? "((?:[/" + format + "].+?)?)" : "") + ")" + optional;
|
|
17677
|
+
backtrack = "";
|
|
17676
17678
|
extraOffset += result.length - match.length;
|
|
17677
17679
|
return result;
|
|
17678
17680
|
}
|
|
@@ -19662,9 +19664,9 @@ var require_forwarded = __commonJS({
|
|
|
19662
19664
|
}
|
|
19663
19665
|
});
|
|
19664
19666
|
|
|
19665
|
-
// node_modules/
|
|
19667
|
+
// node_modules/ipaddr.js/lib/ipaddr.js
|
|
19666
19668
|
var require_ipaddr = __commonJS({
|
|
19667
|
-
"node_modules/
|
|
19669
|
+
"node_modules/ipaddr.js/lib/ipaddr.js"(exports, module) {
|
|
19668
19670
|
(function() {
|
|
19669
19671
|
var expandIPv6, ipaddr, ipv4Part, ipv4Regexes, ipv6Part, ipv6Regexes, matchCIDR, root, zoneIndex;
|
|
19670
19672
|
ipaddr = {};
|
|
@@ -20571,7 +20573,8 @@ var require_utils2 = __commonJS({
|
|
|
20571
20573
|
}
|
|
20572
20574
|
function parseExtendedQueryString(str) {
|
|
20573
20575
|
return qs.parse(str, {
|
|
20574
|
-
allowPrototypes: true
|
|
20576
|
+
allowPrototypes: true,
|
|
20577
|
+
arrayLimit: 1e3
|
|
20575
20578
|
});
|
|
20576
20579
|
}
|
|
20577
20580
|
function newObject() {
|
|
@@ -20611,10 +20614,10 @@ var require_application = __commonJS({
|
|
|
20611
20614
|
this.defaultConfiguration();
|
|
20612
20615
|
};
|
|
20613
20616
|
app.defaultConfiguration = function defaultConfiguration() {
|
|
20614
|
-
var
|
|
20617
|
+
var env2 = process.env.NODE_ENV || "development";
|
|
20615
20618
|
this.enable("x-powered-by");
|
|
20616
20619
|
this.set("etag", "weak");
|
|
20617
|
-
this.set("env",
|
|
20620
|
+
this.set("env", env2);
|
|
20618
20621
|
this.set("query parser", "extended");
|
|
20619
20622
|
this.set("subdomain offset", 2);
|
|
20620
20623
|
this.set("trust proxy", false);
|
|
@@ -20622,7 +20625,7 @@ var require_application = __commonJS({
|
|
|
20622
20625
|
configurable: true,
|
|
20623
20626
|
value: true
|
|
20624
20627
|
});
|
|
20625
|
-
debug("booting in %s mode",
|
|
20628
|
+
debug("booting in %s mode", env2);
|
|
20626
20629
|
this.on("mount", function onmount(parent) {
|
|
20627
20630
|
if (this.settings[trustProxyDefaultSymbol] === true && typeof parent.settings["trust proxy fn"] === "function") {
|
|
20628
20631
|
delete this.settings["trust proxy"];
|
|
@@ -20639,7 +20642,7 @@ var require_application = __commonJS({
|
|
|
20639
20642
|
this.set("view", View);
|
|
20640
20643
|
this.set("views", resolve("views"));
|
|
20641
20644
|
this.set("jsonp callback name", "callback");
|
|
20642
|
-
if (
|
|
20645
|
+
if (env2 === "production") {
|
|
20643
20646
|
this.enable("view cache");
|
|
20644
20647
|
}
|
|
20645
20648
|
Object.defineProperty(this, "router", {
|
|
@@ -20717,8 +20720,8 @@ var require_application = __commonJS({
|
|
|
20717
20720
|
if (typeof fn !== "function") {
|
|
20718
20721
|
throw new Error("callback function required");
|
|
20719
20722
|
}
|
|
20720
|
-
var
|
|
20721
|
-
this.engines[
|
|
20723
|
+
var extension2 = ext[0] !== "." ? "." + ext : ext;
|
|
20724
|
+
this.engines[extension2] = fn;
|
|
20722
20725
|
return this;
|
|
20723
20726
|
};
|
|
20724
20727
|
app.param = function param(name, fn) {
|
|
@@ -22746,7 +22749,7 @@ var require_permessage_deflate = __commonJS({
|
|
|
22746
22749
|
var kBuffers = /* @__PURE__ */ Symbol("buffers");
|
|
22747
22750
|
var kError = /* @__PURE__ */ Symbol("error");
|
|
22748
22751
|
var zlibLimiter;
|
|
22749
|
-
var
|
|
22752
|
+
var PerMessageDeflate2 = class {
|
|
22750
22753
|
/**
|
|
22751
22754
|
* Creates a PerMessageDeflate instance.
|
|
22752
22755
|
*
|
|
@@ -22757,6 +22760,9 @@ var require_permessage_deflate = __commonJS({
|
|
|
22757
22760
|
* acknowledge disabling of client context takeover
|
|
22758
22761
|
* @param {Number} [options.concurrencyLimit=10] The number of concurrent
|
|
22759
22762
|
* calls to zlib
|
|
22763
|
+
* @param {Boolean} [options.isServer=false] Create the instance in either
|
|
22764
|
+
* server or client mode
|
|
22765
|
+
* @param {Number} [options.maxPayload=0] The maximum allowed message length
|
|
22760
22766
|
* @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the
|
|
22761
22767
|
* use of a custom server window size
|
|
22762
22768
|
* @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
|
|
@@ -22767,15 +22773,12 @@ var require_permessage_deflate = __commonJS({
|
|
|
22767
22773
|
* deflate
|
|
22768
22774
|
* @param {Object} [options.zlibInflateOptions] Options to pass to zlib on
|
|
22769
22775
|
* inflate
|
|
22770
|
-
* @param {Boolean} [isServer=false] Create the instance in either server or
|
|
22771
|
-
* client mode
|
|
22772
|
-
* @param {Number} [maxPayload=0] The maximum allowed message length
|
|
22773
22776
|
*/
|
|
22774
|
-
constructor(options
|
|
22775
|
-
this._maxPayload = maxPayload | 0;
|
|
22777
|
+
constructor(options) {
|
|
22776
22778
|
this._options = options || {};
|
|
22777
22779
|
this._threshold = this._options.threshold !== void 0 ? this._options.threshold : 1024;
|
|
22778
|
-
this.
|
|
22780
|
+
this._maxPayload = this._options.maxPayload | 0;
|
|
22781
|
+
this._isServer = !!this._options.isServer;
|
|
22779
22782
|
this._deflate = null;
|
|
22780
22783
|
this._inflate = null;
|
|
22781
22784
|
this.params = null;
|
|
@@ -23084,7 +23087,7 @@ var require_permessage_deflate = __commonJS({
|
|
|
23084
23087
|
});
|
|
23085
23088
|
}
|
|
23086
23089
|
};
|
|
23087
|
-
module.exports =
|
|
23090
|
+
module.exports = PerMessageDeflate2;
|
|
23088
23091
|
function deflateOnData(chunk) {
|
|
23089
23092
|
this[kBuffers].push(chunk);
|
|
23090
23093
|
this[kTotalLength] += chunk.length;
|
|
@@ -23319,7 +23322,7 @@ var require_receiver = __commonJS({
|
|
|
23319
23322
|
"node_modules/ws/lib/receiver.js"(exports, module) {
|
|
23320
23323
|
"use strict";
|
|
23321
23324
|
var { Writable } = __require("stream");
|
|
23322
|
-
var
|
|
23325
|
+
var PerMessageDeflate2 = require_permessage_deflate();
|
|
23323
23326
|
var {
|
|
23324
23327
|
BINARY_TYPES,
|
|
23325
23328
|
EMPTY_BUFFER,
|
|
@@ -23486,7 +23489,7 @@ var require_receiver = __commonJS({
|
|
|
23486
23489
|
return;
|
|
23487
23490
|
}
|
|
23488
23491
|
const compressed = (buf[0] & 64) === 64;
|
|
23489
|
-
if (compressed && !this._extensions[
|
|
23492
|
+
if (compressed && !this._extensions[PerMessageDeflate2.extensionName]) {
|
|
23490
23493
|
const error = this.createError(
|
|
23491
23494
|
RangeError,
|
|
23492
23495
|
"RSV1 must be clear",
|
|
@@ -23730,7 +23733,7 @@ var require_receiver = __commonJS({
|
|
|
23730
23733
|
* @private
|
|
23731
23734
|
*/
|
|
23732
23735
|
decompress(data, cb) {
|
|
23733
|
-
const perMessageDeflate = this._extensions[
|
|
23736
|
+
const perMessageDeflate = this._extensions[PerMessageDeflate2.extensionName];
|
|
23734
23737
|
perMessageDeflate.decompress(data, this._fin, (err, buf) => {
|
|
23735
23738
|
if (err) return cb(err);
|
|
23736
23739
|
if (buf.length) {
|
|
@@ -23912,7 +23915,10 @@ var require_sender = __commonJS({
|
|
|
23912
23915
|
"use strict";
|
|
23913
23916
|
var { Duplex } = __require("stream");
|
|
23914
23917
|
var { randomFillSync } = __require("crypto");
|
|
23915
|
-
var
|
|
23918
|
+
var {
|
|
23919
|
+
types: { isUint8Array }
|
|
23920
|
+
} = __require("util");
|
|
23921
|
+
var PerMessageDeflate2 = require_permessage_deflate();
|
|
23916
23922
|
var { EMPTY_BUFFER, kWebSocket, NOOP } = require_constants();
|
|
23917
23923
|
var { isBlob, isValidStatusCode } = require_validation();
|
|
23918
23924
|
var { mask: applyMask, toBuffer } = require_buffer_util();
|
|
@@ -24065,8 +24071,10 @@ var require_sender = __commonJS({
|
|
|
24065
24071
|
buf.writeUInt16BE(code, 0);
|
|
24066
24072
|
if (typeof data === "string") {
|
|
24067
24073
|
buf.write(data, 2);
|
|
24068
|
-
} else {
|
|
24074
|
+
} else if (isUint8Array(data)) {
|
|
24069
24075
|
buf.set(data, 2);
|
|
24076
|
+
} else {
|
|
24077
|
+
throw new TypeError("Second argument must be a string or a Uint8Array");
|
|
24070
24078
|
}
|
|
24071
24079
|
}
|
|
24072
24080
|
const options = {
|
|
@@ -24196,7 +24204,7 @@ var require_sender = __commonJS({
|
|
|
24196
24204
|
* @public
|
|
24197
24205
|
*/
|
|
24198
24206
|
send(data, options, cb) {
|
|
24199
|
-
const perMessageDeflate = this._extensions[
|
|
24207
|
+
const perMessageDeflate = this._extensions[PerMessageDeflate2.extensionName];
|
|
24200
24208
|
let opcode = options.binary ? 2 : 1;
|
|
24201
24209
|
let rsv1 = options.compress;
|
|
24202
24210
|
let byteLength;
|
|
@@ -24320,7 +24328,7 @@ var require_sender = __commonJS({
|
|
|
24320
24328
|
this.sendFrame(_Sender.frame(data, options), cb);
|
|
24321
24329
|
return;
|
|
24322
24330
|
}
|
|
24323
|
-
const perMessageDeflate = this._extensions[
|
|
24331
|
+
const perMessageDeflate = this._extensions[PerMessageDeflate2.extensionName];
|
|
24324
24332
|
this._bufferedBytes += options[kByteLength];
|
|
24325
24333
|
this._state = DEFLATING;
|
|
24326
24334
|
perMessageDeflate.compress(data, options.fin, (_, buf) => {
|
|
@@ -24758,11 +24766,11 @@ var require_extension = __commonJS({
|
|
|
24758
24766
|
return offers;
|
|
24759
24767
|
}
|
|
24760
24768
|
function format(extensions) {
|
|
24761
|
-
return Object.keys(extensions).map((
|
|
24762
|
-
let configurations = extensions[
|
|
24769
|
+
return Object.keys(extensions).map((extension2) => {
|
|
24770
|
+
let configurations = extensions[extension2];
|
|
24763
24771
|
if (!Array.isArray(configurations)) configurations = [configurations];
|
|
24764
24772
|
return configurations.map((params) => {
|
|
24765
|
-
return [
|
|
24773
|
+
return [extension2].concat(
|
|
24766
24774
|
Object.keys(params).map((k) => {
|
|
24767
24775
|
let values = params[k];
|
|
24768
24776
|
if (!Array.isArray(values)) values = [values];
|
|
@@ -24788,7 +24796,7 @@ var require_websocket = __commonJS({
|
|
|
24788
24796
|
var { randomBytes, createHash } = __require("crypto");
|
|
24789
24797
|
var { Duplex, Readable } = __require("stream");
|
|
24790
24798
|
var { URL } = __require("url");
|
|
24791
|
-
var
|
|
24799
|
+
var PerMessageDeflate2 = require_permessage_deflate();
|
|
24792
24800
|
var Receiver2 = require_receiver();
|
|
24793
24801
|
var Sender2 = require_sender();
|
|
24794
24802
|
var { isBlob } = require_validation();
|
|
@@ -24996,8 +25004,8 @@ var require_websocket = __commonJS({
|
|
|
24996
25004
|
this.emit("close", this._closeCode, this._closeMessage);
|
|
24997
25005
|
return;
|
|
24998
25006
|
}
|
|
24999
|
-
if (this._extensions[
|
|
25000
|
-
this._extensions[
|
|
25007
|
+
if (this._extensions[PerMessageDeflate2.extensionName]) {
|
|
25008
|
+
this._extensions[PerMessageDeflate2.extensionName].cleanup();
|
|
25001
25009
|
}
|
|
25002
25010
|
this._receiver.removeAllListeners();
|
|
25003
25011
|
this._readyState = _WebSocket.CLOSED;
|
|
@@ -25159,7 +25167,7 @@ var require_websocket = __commonJS({
|
|
|
25159
25167
|
fin: true,
|
|
25160
25168
|
...options
|
|
25161
25169
|
};
|
|
25162
|
-
if (!this._extensions[
|
|
25170
|
+
if (!this._extensions[PerMessageDeflate2.extensionName]) {
|
|
25163
25171
|
opts.compress = false;
|
|
25164
25172
|
}
|
|
25165
25173
|
this._sender.send(data || EMPTY_BUFFER, opts, cb);
|
|
@@ -25285,7 +25293,7 @@ var require_websocket = __commonJS({
|
|
|
25285
25293
|
} else {
|
|
25286
25294
|
try {
|
|
25287
25295
|
parsedUrl = new URL(address);
|
|
25288
|
-
} catch
|
|
25296
|
+
} catch {
|
|
25289
25297
|
throw new SyntaxError(`Invalid URL: ${address}`);
|
|
25290
25298
|
}
|
|
25291
25299
|
}
|
|
@@ -25333,13 +25341,13 @@ var require_websocket = __commonJS({
|
|
|
25333
25341
|
opts.path = parsedUrl.pathname + parsedUrl.search;
|
|
25334
25342
|
opts.timeout = opts.handshakeTimeout;
|
|
25335
25343
|
if (opts.perMessageDeflate) {
|
|
25336
|
-
perMessageDeflate = new
|
|
25337
|
-
opts.perMessageDeflate
|
|
25338
|
-
false,
|
|
25339
|
-
opts.maxPayload
|
|
25340
|
-
);
|
|
25344
|
+
perMessageDeflate = new PerMessageDeflate2({
|
|
25345
|
+
...opts.perMessageDeflate,
|
|
25346
|
+
isServer: false,
|
|
25347
|
+
maxPayload: opts.maxPayload
|
|
25348
|
+
});
|
|
25341
25349
|
opts.headers["Sec-WebSocket-Extensions"] = format({
|
|
25342
|
-
[
|
|
25350
|
+
[PerMessageDeflate2.extensionName]: perMessageDeflate.offer()
|
|
25343
25351
|
});
|
|
25344
25352
|
}
|
|
25345
25353
|
if (protocols.length) {
|
|
@@ -25482,19 +25490,19 @@ var require_websocket = __commonJS({
|
|
|
25482
25490
|
return;
|
|
25483
25491
|
}
|
|
25484
25492
|
const extensionNames = Object.keys(extensions);
|
|
25485
|
-
if (extensionNames.length !== 1 || extensionNames[0] !==
|
|
25493
|
+
if (extensionNames.length !== 1 || extensionNames[0] !== PerMessageDeflate2.extensionName) {
|
|
25486
25494
|
const message = "Server indicated an extension that was not requested";
|
|
25487
25495
|
abortHandshake(websocket, socket, message);
|
|
25488
25496
|
return;
|
|
25489
25497
|
}
|
|
25490
25498
|
try {
|
|
25491
|
-
perMessageDeflate.accept(extensions[
|
|
25499
|
+
perMessageDeflate.accept(extensions[PerMessageDeflate2.extensionName]);
|
|
25492
25500
|
} catch (err) {
|
|
25493
25501
|
const message = "Invalid Sec-WebSocket-Extensions header";
|
|
25494
25502
|
abortHandshake(websocket, socket, message);
|
|
25495
25503
|
return;
|
|
25496
25504
|
}
|
|
25497
|
-
websocket._extensions[
|
|
25505
|
+
websocket._extensions[PerMessageDeflate2.extensionName] = perMessageDeflate;
|
|
25498
25506
|
}
|
|
25499
25507
|
websocket.setSocket(socket, head, {
|
|
25500
25508
|
allowSynchronousEvents: opts.allowSynchronousEvents,
|
|
@@ -25813,9 +25821,9 @@ var require_websocket_server = __commonJS({
|
|
|
25813
25821
|
var http = __require("http");
|
|
25814
25822
|
var { Duplex } = __require("stream");
|
|
25815
25823
|
var { createHash } = __require("crypto");
|
|
25816
|
-
var
|
|
25817
|
-
var
|
|
25818
|
-
var
|
|
25824
|
+
var extension2 = require_extension();
|
|
25825
|
+
var PerMessageDeflate2 = require_permessage_deflate();
|
|
25826
|
+
var subprotocol2 = require_subprotocol();
|
|
25819
25827
|
var WebSocket2 = require_websocket();
|
|
25820
25828
|
var { CLOSE_TIMEOUT, GUID, kWebSocket } = require_constants();
|
|
25821
25829
|
var keyRegex = /^[+/0-9A-Za-z]{22}==$/;
|
|
@@ -26038,7 +26046,7 @@ var require_websocket_server = __commonJS({
|
|
|
26038
26046
|
let protocols = /* @__PURE__ */ new Set();
|
|
26039
26047
|
if (secWebSocketProtocol !== void 0) {
|
|
26040
26048
|
try {
|
|
26041
|
-
protocols =
|
|
26049
|
+
protocols = subprotocol2.parse(secWebSocketProtocol);
|
|
26042
26050
|
} catch (err) {
|
|
26043
26051
|
const message = "Invalid Sec-WebSocket-Protocol header";
|
|
26044
26052
|
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
|
|
@@ -26048,16 +26056,16 @@ var require_websocket_server = __commonJS({
|
|
|
26048
26056
|
const secWebSocketExtensions = req.headers["sec-websocket-extensions"];
|
|
26049
26057
|
const extensions = {};
|
|
26050
26058
|
if (this.options.perMessageDeflate && secWebSocketExtensions !== void 0) {
|
|
26051
|
-
const perMessageDeflate = new
|
|
26052
|
-
this.options.perMessageDeflate,
|
|
26053
|
-
true,
|
|
26054
|
-
this.options.maxPayload
|
|
26055
|
-
);
|
|
26059
|
+
const perMessageDeflate = new PerMessageDeflate2({
|
|
26060
|
+
...this.options.perMessageDeflate,
|
|
26061
|
+
isServer: true,
|
|
26062
|
+
maxPayload: this.options.maxPayload
|
|
26063
|
+
});
|
|
26056
26064
|
try {
|
|
26057
|
-
const offers =
|
|
26058
|
-
if (offers[
|
|
26059
|
-
perMessageDeflate.accept(offers[
|
|
26060
|
-
extensions[
|
|
26065
|
+
const offers = extension2.parse(secWebSocketExtensions);
|
|
26066
|
+
if (offers[PerMessageDeflate2.extensionName]) {
|
|
26067
|
+
perMessageDeflate.accept(offers[PerMessageDeflate2.extensionName]);
|
|
26068
|
+
extensions[PerMessageDeflate2.extensionName] = perMessageDeflate;
|
|
26061
26069
|
}
|
|
26062
26070
|
} catch (err) {
|
|
26063
26071
|
const message = "Invalid or unacceptable Sec-WebSocket-Extensions header";
|
|
@@ -26128,10 +26136,10 @@ var require_websocket_server = __commonJS({
|
|
|
26128
26136
|
ws._protocol = protocol;
|
|
26129
26137
|
}
|
|
26130
26138
|
}
|
|
26131
|
-
if (extensions[
|
|
26132
|
-
const params = extensions[
|
|
26133
|
-
const value =
|
|
26134
|
-
[
|
|
26139
|
+
if (extensions[PerMessageDeflate2.extensionName]) {
|
|
26140
|
+
const params = extensions[PerMessageDeflate2.extensionName].params;
|
|
26141
|
+
const value = extension2.format({
|
|
26142
|
+
[PerMessageDeflate2.extensionName]: [params]
|
|
26135
26143
|
});
|
|
26136
26144
|
headers.push(`Sec-WebSocket-Extensions: ${value}`);
|
|
26137
26145
|
ws._extensions = extensions;
|
|
@@ -26200,13 +26208,16 @@ var require_websocket_server = __commonJS({
|
|
|
26200
26208
|
|
|
26201
26209
|
// src/server.ts
|
|
26202
26210
|
var import_express = __toESM(require_express2(), 1);
|
|
26203
|
-
import { randomUUID as
|
|
26211
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
26204
26212
|
import { homedir, networkInterfaces } from "os";
|
|
26205
26213
|
|
|
26206
26214
|
// node_modules/ws/wrapper.mjs
|
|
26207
26215
|
var import_stream = __toESM(require_stream(), 1);
|
|
26216
|
+
var import_extension = __toESM(require_extension(), 1);
|
|
26217
|
+
var import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
|
|
26208
26218
|
var import_receiver = __toESM(require_receiver(), 1);
|
|
26209
26219
|
var import_sender = __toESM(require_sender(), 1);
|
|
26220
|
+
var import_subprotocol = __toESM(require_subprotocol(), 1);
|
|
26210
26221
|
var import_websocket = __toESM(require_websocket(), 1);
|
|
26211
26222
|
var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
26212
26223
|
var wrapper_default = import_websocket.default;
|
|
@@ -26255,7 +26266,7 @@ var RelayClient = class {
|
|
|
26255
26266
|
from: this.options.agentName,
|
|
26256
26267
|
payload,
|
|
26257
26268
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
26258
|
-
}, "task_response",
|
|
26269
|
+
}, "task_response", Number(process.env.A2A_RELAY_RESPONSE_WAIT_MS || 6e4));
|
|
26259
26270
|
}
|
|
26260
26271
|
/** Discover agents connected to the relay */
|
|
26261
26272
|
async discover() {
|
|
@@ -26424,6 +26435,7 @@ import { randomUUID as randomUUID2 } from "crypto";
|
|
|
26424
26435
|
var DEFAULT_CONFIG = {
|
|
26425
26436
|
port: 6060,
|
|
26426
26437
|
apiKeys: [],
|
|
26438
|
+
registeredAgents: {},
|
|
26427
26439
|
maxQueuePerAgent: 200,
|
|
26428
26440
|
rateLimitPerMinute: 60,
|
|
26429
26441
|
heartbeatIntervalMs: 3e4,
|
|
@@ -26531,7 +26543,14 @@ var RelayHub = class {
|
|
|
26531
26543
|
this.sendError(ws, "missing_name", "agentName is required for registration");
|
|
26532
26544
|
return null;
|
|
26533
26545
|
}
|
|
26534
|
-
|
|
26546
|
+
const approvedKey = this.config.registeredAgents[name];
|
|
26547
|
+
if (Object.keys(this.config.registeredAgents).length > 0) {
|
|
26548
|
+
if (!approvedKey || approvedKey !== apiKey) {
|
|
26549
|
+
this.sendError(ws, "not_approved", "Agent is not approved for this relay or API key does not match");
|
|
26550
|
+
ws.close(4001, "Agent not approved");
|
|
26551
|
+
return null;
|
|
26552
|
+
}
|
|
26553
|
+
} else if (this.config.apiKeys.length > 0 && !this.config.apiKeys.includes(apiKey)) {
|
|
26535
26554
|
this.sendError(ws, "auth_failed", "Invalid API key");
|
|
26536
26555
|
ws.close(4001, "Authentication failed");
|
|
26537
26556
|
return null;
|
|
@@ -26569,6 +26588,10 @@ var RelayHub = class {
|
|
|
26569
26588
|
}
|
|
26570
26589
|
msg.from = fromAgent;
|
|
26571
26590
|
msg.timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
26591
|
+
if (Object.keys(this.config.registeredAgents).length > 0 && !(target in this.config.registeredAgents)) {
|
|
26592
|
+
this.sendError(this.agents.get(fromAgent).ws, "target_not_approved", `Target agent ${target} is not approved on this relay`);
|
|
26593
|
+
return;
|
|
26594
|
+
}
|
|
26572
26595
|
const targetAgent = this.agents.get(target);
|
|
26573
26596
|
if (targetAgent && targetAgent.ws.readyState === import_websocket.default.OPEN) {
|
|
26574
26597
|
targetAgent.ws.send(JSON.stringify(msg));
|
|
@@ -26664,11 +26687,114 @@ var RelayHub = class {
|
|
|
26664
26687
|
}
|
|
26665
26688
|
};
|
|
26666
26689
|
|
|
26690
|
+
// src/runtime-reply.ts
|
|
26691
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
26692
|
+
function env(name) {
|
|
26693
|
+
const value = process.env[name];
|
|
26694
|
+
return value && value.trim() ? value.trim() : void 0;
|
|
26695
|
+
}
|
|
26696
|
+
function stripTaskMarker(text, marker) {
|
|
26697
|
+
const trimmed = text.trim();
|
|
26698
|
+
if (!trimmed.includes(marker)) return trimmed;
|
|
26699
|
+
return trimmed.slice(trimmed.indexOf(marker) + marker.length).trim();
|
|
26700
|
+
}
|
|
26701
|
+
function agentIdFor(config) {
|
|
26702
|
+
return env("A2A_AGENT_ID") || env("HERMES_AGENT_ID") || config.agentName || "perkos-a2a-agent";
|
|
26703
|
+
}
|
|
26704
|
+
function llmSystemPrompt(config) {
|
|
26705
|
+
const agentName = config.agentName || config.runtime?.kind || "PerkOS A2A agent";
|
|
26706
|
+
return [
|
|
26707
|
+
`You are ${agentName}, a PerkOS A2A agent.`,
|
|
26708
|
+
"Reply concisely and directly.",
|
|
26709
|
+
"If asked to confirm receipt, confirm that you received the task via PerkOS A2A and are using PerkOS LLM.",
|
|
26710
|
+
"Do not mention implementation details unless asked."
|
|
26711
|
+
].join(" ");
|
|
26712
|
+
}
|
|
26713
|
+
async function generateRuntimeReply(config, text, marker) {
|
|
26714
|
+
const runtimeKind = config.runtime?.kind || "openclaw";
|
|
26715
|
+
const apiKey = env("PERKOS_LLM_API_KEY") || env("OPENAI_API_KEY") || env("OLLAMA_API_KEY");
|
|
26716
|
+
if (!apiKey) {
|
|
26717
|
+
throw new Error("No PerkOS LLM API key available in environment");
|
|
26718
|
+
}
|
|
26719
|
+
const headers = {
|
|
26720
|
+
"content-type": "application/json",
|
|
26721
|
+
authorization: `Bearer ${apiKey}`,
|
|
26722
|
+
"x-agent-id": agentIdFor(config)
|
|
26723
|
+
};
|
|
26724
|
+
const system = llmSystemPrompt(config);
|
|
26725
|
+
const user = [
|
|
26726
|
+
text,
|
|
26727
|
+
"",
|
|
26728
|
+
"Return only the useful final answer.",
|
|
26729
|
+
`Do not include ${marker}; the A2A bridge will attach the marker/task result.`
|
|
26730
|
+
].join("\n");
|
|
26731
|
+
if (runtimeKind === "hermes") {
|
|
26732
|
+
const base2 = (env("OPENAI_BASE_URL") || "https://api.llm.perkos.xyz/v1").replace(/\/+$/, "");
|
|
26733
|
+
const model2 = env("HERMES_INFERENCE_MODEL") || env("OPENAI_MODEL") || "kimi-k2.6:cloud";
|
|
26734
|
+
const response2 = await fetch(`${base2}/chat/completions`, {
|
|
26735
|
+
method: "POST",
|
|
26736
|
+
headers,
|
|
26737
|
+
body: JSON.stringify({
|
|
26738
|
+
model: model2,
|
|
26739
|
+
messages: [
|
|
26740
|
+
{ role: "system", content: system },
|
|
26741
|
+
{ role: "user", content: user }
|
|
26742
|
+
],
|
|
26743
|
+
temperature: 0.2
|
|
26744
|
+
})
|
|
26745
|
+
});
|
|
26746
|
+
if (!response2.ok) {
|
|
26747
|
+
const body = await response2.text().catch(() => "");
|
|
26748
|
+
throw new Error(`PerkOS LLM OpenAI-compatible call failed (${response2.status}): ${body || response2.statusText}`);
|
|
26749
|
+
}
|
|
26750
|
+
const data2 = await response2.json();
|
|
26751
|
+
return stripTaskMarker(data2.choices?.[0]?.message?.content || "Task completed.", marker);
|
|
26752
|
+
}
|
|
26753
|
+
const base = (env("OLLAMA_BASE_URL") || "https://api.llm.perkos.xyz").replace(/\/+$/, "");
|
|
26754
|
+
const model = env("OLLAMA_MODEL") || "kimi-k2.6:cloud";
|
|
26755
|
+
const response = await fetch(`${base}/api/chat`, {
|
|
26756
|
+
method: "POST",
|
|
26757
|
+
headers,
|
|
26758
|
+
body: JSON.stringify({
|
|
26759
|
+
model,
|
|
26760
|
+
stream: false,
|
|
26761
|
+
messages: [
|
|
26762
|
+
{ role: "system", content: system },
|
|
26763
|
+
{ role: "user", content: user }
|
|
26764
|
+
]
|
|
26765
|
+
})
|
|
26766
|
+
});
|
|
26767
|
+
if (!response.ok) {
|
|
26768
|
+
const body = await response.text().catch(() => "");
|
|
26769
|
+
throw new Error(`PerkOS LLM Ollama-compatible call failed (${response.status}): ${body || response.statusText}`);
|
|
26770
|
+
}
|
|
26771
|
+
const data = await response.json();
|
|
26772
|
+
return stripTaskMarker(data.message?.content || data.response || "Task completed.", marker);
|
|
26773
|
+
}
|
|
26774
|
+
function completeTaskWithReply(task, finalText) {
|
|
26775
|
+
task.artifacts.push({
|
|
26776
|
+
kind: "artifact",
|
|
26777
|
+
artifactId: randomUUID3(),
|
|
26778
|
+
parts: [{ kind: "text", text: finalText }]
|
|
26779
|
+
});
|
|
26780
|
+
task.status = {
|
|
26781
|
+
state: "completed",
|
|
26782
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26783
|
+
message: {
|
|
26784
|
+
role: "agent",
|
|
26785
|
+
parts: [{ kind: "text", text: finalText }]
|
|
26786
|
+
}
|
|
26787
|
+
};
|
|
26788
|
+
}
|
|
26789
|
+
function isTerminalTaskState(state) {
|
|
26790
|
+
return state === "completed" || state === "failed" || state === "canceled";
|
|
26791
|
+
}
|
|
26792
|
+
|
|
26667
26793
|
// src/server.ts
|
|
26668
26794
|
function appendArtifact(task, text) {
|
|
26669
26795
|
task.artifacts.push({
|
|
26670
26796
|
kind: "artifact",
|
|
26671
|
-
artifactId:
|
|
26797
|
+
artifactId: randomUUID4(),
|
|
26672
26798
|
parts: [{ kind: "text", text }]
|
|
26673
26799
|
});
|
|
26674
26800
|
}
|
|
@@ -26718,7 +26844,7 @@ var A2AServer = class {
|
|
|
26718
26844
|
description: `PerkOS agent: ${config.agentName}`,
|
|
26719
26845
|
protocolVersion: "0.3.0",
|
|
26720
26846
|
version: "1.0.0",
|
|
26721
|
-
url: `http://localhost:${config.port}/a2a/jsonrpc`,
|
|
26847
|
+
url: `${(config.publicUrl || `http://localhost:${config.port}`).replace(/\/+$/, "")}/a2a/jsonrpc`,
|
|
26722
26848
|
skills: config.skills || [],
|
|
26723
26849
|
capabilities: { pushNotifications: false },
|
|
26724
26850
|
defaultInputModes: ["text"],
|
|
@@ -26822,9 +26948,8 @@ var A2AServer = class {
|
|
|
26822
26948
|
}
|
|
26823
26949
|
async handleSendMessage(params, rpcId) {
|
|
26824
26950
|
const message = params.message;
|
|
26825
|
-
const taskId =
|
|
26826
|
-
const contextId = message?.contextId ||
|
|
26827
|
-
const meta = message?.metadata || {};
|
|
26951
|
+
const taskId = randomUUID4();
|
|
26952
|
+
const contextId = message?.contextId || randomUUID4();
|
|
26828
26953
|
const task = {
|
|
26829
26954
|
kind: "task",
|
|
26830
26955
|
id: taskId,
|
|
@@ -26833,10 +26958,7 @@ var A2AServer = class {
|
|
|
26833
26958
|
messages: [message],
|
|
26834
26959
|
artifacts: [],
|
|
26835
26960
|
metadata: {
|
|
26836
|
-
fromAgent:
|
|
26837
|
-
replyToTaskId: meta.replyToTaskId,
|
|
26838
|
-
conversationId: meta.conversationId || contextId,
|
|
26839
|
-
kind: meta.kind || "request"
|
|
26961
|
+
fromAgent: message?.metadata?.fromAgent || "unknown"
|
|
26840
26962
|
},
|
|
26841
26963
|
sessionKeyHint: "agent:main"
|
|
26842
26964
|
};
|
|
@@ -26852,33 +26974,11 @@ var A2AServer = class {
|
|
|
26852
26974
|
this.tasks.set(task.id, structuredClone(task));
|
|
26853
26975
|
const textParts = task.messages.flatMap((m) => m.parts || []).filter((p) => p.kind === "text").map((p) => p.text).join("\n");
|
|
26854
26976
|
try {
|
|
26855
|
-
if (task.metadata?.kind === "response" && task.metadata?.replyToTaskId) {
|
|
26856
|
-
const original = this.tasks.get(String(task.metadata.replyToTaskId));
|
|
26857
|
-
if (original) {
|
|
26858
|
-
appendArtifact(original, textParts || "(empty response)");
|
|
26859
|
-
original.status = {
|
|
26860
|
-
state: "completed",
|
|
26861
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26862
|
-
message: {
|
|
26863
|
-
role: "agent",
|
|
26864
|
-
parts: [{ kind: "text", text: textParts || "(empty response)" }]
|
|
26865
|
-
}
|
|
26866
|
-
};
|
|
26867
|
-
this.tasks.set(original.id, structuredClone(original));
|
|
26868
|
-
appendArtifact(task, `Response linked to original task ${original.id}`);
|
|
26869
|
-
task.status = { state: "completed", timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
26870
|
-
this.tasks.set(task.id, structuredClone(task));
|
|
26871
|
-
this.logger.info(`[perkos-a2a] Response task ${task.id} linked to original task ${original.id}`);
|
|
26872
|
-
return;
|
|
26873
|
-
}
|
|
26874
|
-
}
|
|
26875
26977
|
if (this.messageInjector) {
|
|
26876
26978
|
this.messageInjector(textParts, {
|
|
26877
26979
|
source: "a2a",
|
|
26878
26980
|
fromAgent: task.metadata?.fromAgent,
|
|
26879
|
-
taskId: task.id
|
|
26880
|
-
conversationId: task.metadata?.conversationId,
|
|
26881
|
-
kind: task.metadata?.kind
|
|
26981
|
+
taskId: task.id
|
|
26882
26982
|
});
|
|
26883
26983
|
appendArtifact(task, "Task accepted and dispatched for execution");
|
|
26884
26984
|
this.tasks.set(task.id, structuredClone(task));
|
|
@@ -26954,11 +27054,11 @@ var A2AServer = class {
|
|
|
26954
27054
|
return this.success(rpcId, task);
|
|
26955
27055
|
}
|
|
26956
27056
|
/** Send a task to a peer agent via A2A protocol (direct HTTP or relay) */
|
|
26957
|
-
async sendTask(targetAgent, messageText
|
|
27057
|
+
async sendTask(targetAgent, messageText) {
|
|
26958
27058
|
const targetUrl = this.config.peers[targetAgent];
|
|
26959
27059
|
if (targetUrl) {
|
|
26960
27060
|
try {
|
|
26961
|
-
return await this.sendTaskDirect(targetAgent, targetUrl, messageText
|
|
27061
|
+
return await this.sendTaskDirect(targetAgent, targetUrl, messageText);
|
|
26962
27062
|
} catch (err) {
|
|
26963
27063
|
if (!this.relayClient?.isConnected()) {
|
|
26964
27064
|
throw err;
|
|
@@ -26969,13 +27069,13 @@ var A2AServer = class {
|
|
|
26969
27069
|
}
|
|
26970
27070
|
}
|
|
26971
27071
|
if (this.relayClient?.isConnected()) {
|
|
26972
|
-
return this.sendTaskViaRelay(targetAgent, messageText
|
|
27072
|
+
return this.sendTaskViaRelay(targetAgent, messageText);
|
|
26973
27073
|
}
|
|
26974
27074
|
throw new Error(
|
|
26975
27075
|
`Cannot reach ${targetAgent}: no direct URL configured and relay not connected. Known peers: ${Object.keys(this.config.peers).join(", ")}`
|
|
26976
27076
|
);
|
|
26977
27077
|
}
|
|
26978
|
-
async sendTaskDirect(targetAgent, targetUrl, messageText
|
|
27078
|
+
async sendTaskDirect(targetAgent, targetUrl, messageText) {
|
|
26979
27079
|
const headers = { "Content-Type": "application/json" };
|
|
26980
27080
|
const peerAuth = this.config.peerAuth?.[targetAgent];
|
|
26981
27081
|
if (peerAuth) {
|
|
@@ -26984,19 +27084,14 @@ var A2AServer = class {
|
|
|
26984
27084
|
const payload = {
|
|
26985
27085
|
jsonrpc: "2.0",
|
|
26986
27086
|
method: "message/send",
|
|
26987
|
-
id:
|
|
27087
|
+
id: randomUUID4(),
|
|
26988
27088
|
params: {
|
|
26989
27089
|
message: {
|
|
26990
27090
|
kind: "message",
|
|
26991
|
-
messageId:
|
|
27091
|
+
messageId: randomUUID4(),
|
|
26992
27092
|
role: "user",
|
|
26993
27093
|
parts: [{ kind: "text", text: messageText }],
|
|
26994
|
-
metadata: {
|
|
26995
|
-
fromAgent: this.config.agentName,
|
|
26996
|
-
conversationId: metadata?.conversationId,
|
|
26997
|
-
replyToTaskId: metadata?.replyToTaskId,
|
|
26998
|
-
kind: metadata?.kind || "request"
|
|
26999
|
-
}
|
|
27094
|
+
metadata: { fromAgent: this.config.agentName }
|
|
27000
27095
|
}
|
|
27001
27096
|
}
|
|
27002
27097
|
};
|
|
@@ -27005,10 +27100,51 @@ var A2AServer = class {
|
|
|
27005
27100
|
headers,
|
|
27006
27101
|
body: JSON.stringify(payload)
|
|
27007
27102
|
});
|
|
27008
|
-
|
|
27103
|
+
const initial = await response.json();
|
|
27104
|
+
const task = initial.result;
|
|
27105
|
+
if (task?.id && !isTerminalTaskState(task.status?.state)) {
|
|
27106
|
+
const terminal = await this.waitForRemoteTaskTerminal(targetUrl, headers, task.id).catch((err) => {
|
|
27107
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
27108
|
+
this.logger.info(`[perkos-a2a] Waiting for ${targetAgent} task ${task.id} terminal state failed: ${msg}`);
|
|
27109
|
+
return null;
|
|
27110
|
+
});
|
|
27111
|
+
if (terminal) return terminal;
|
|
27112
|
+
}
|
|
27113
|
+
return initial;
|
|
27114
|
+
}
|
|
27115
|
+
async waitForRemoteTaskTerminal(targetUrl, headers, taskId, timeoutMs = Number(process.env.A2A_SEND_WAIT_MS || 45e3), pollMs = Number(process.env.A2A_SEND_POLL_MS || 1e3)) {
|
|
27116
|
+
const deadline = Date.now() + timeoutMs;
|
|
27117
|
+
while (Date.now() < deadline) {
|
|
27118
|
+
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
27119
|
+
const response = await fetch(`${targetUrl}/a2a/jsonrpc`, {
|
|
27120
|
+
method: "POST",
|
|
27121
|
+
headers,
|
|
27122
|
+
body: JSON.stringify({
|
|
27123
|
+
jsonrpc: "2.0",
|
|
27124
|
+
method: "tasks/get",
|
|
27125
|
+
id: randomUUID4(),
|
|
27126
|
+
params: { id: taskId }
|
|
27127
|
+
})
|
|
27128
|
+
});
|
|
27129
|
+
const json = await response.json();
|
|
27130
|
+
const task = json.result;
|
|
27131
|
+
if (task && isTerminalTaskState(task.status?.state)) return json;
|
|
27132
|
+
}
|
|
27133
|
+
return null;
|
|
27134
|
+
}
|
|
27135
|
+
async waitForLocalTaskTerminal(taskId, timeoutMs = Number(process.env.A2A_RELAY_WAIT_MS || 45e3), pollMs = Number(process.env.A2A_RELAY_POLL_MS || 1e3)) {
|
|
27136
|
+
const deadline = Date.now() + timeoutMs;
|
|
27137
|
+
while (Date.now() < deadline) {
|
|
27138
|
+
const task = this.tasks.get(taskId);
|
|
27139
|
+
if (task && isTerminalTaskState(task.status?.state)) {
|
|
27140
|
+
return this.success(randomUUID4(), structuredClone(task));
|
|
27141
|
+
}
|
|
27142
|
+
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
27143
|
+
}
|
|
27144
|
+
return null;
|
|
27009
27145
|
}
|
|
27010
|
-
async sendTaskViaRelay(targetAgent, messageText
|
|
27011
|
-
const rpcId =
|
|
27146
|
+
async sendTaskViaRelay(targetAgent, messageText) {
|
|
27147
|
+
const rpcId = randomUUID4();
|
|
27012
27148
|
const result = await this.relayClient.sendTask(targetAgent, {
|
|
27013
27149
|
jsonrpc: "2.0",
|
|
27014
27150
|
method: "message/send",
|
|
@@ -27016,15 +27152,10 @@ var A2AServer = class {
|
|
|
27016
27152
|
params: {
|
|
27017
27153
|
message: {
|
|
27018
27154
|
kind: "message",
|
|
27019
|
-
messageId:
|
|
27155
|
+
messageId: randomUUID4(),
|
|
27020
27156
|
role: "user",
|
|
27021
27157
|
parts: [{ kind: "text", text: messageText }],
|
|
27022
|
-
metadata: {
|
|
27023
|
-
fromAgent: this.config.agentName,
|
|
27024
|
-
conversationId: metadata?.conversationId,
|
|
27025
|
-
replyToTaskId: metadata?.replyToTaskId,
|
|
27026
|
-
kind: metadata?.kind || "request"
|
|
27027
|
-
}
|
|
27158
|
+
metadata: { fromAgent: this.config.agentName }
|
|
27028
27159
|
}
|
|
27029
27160
|
}
|
|
27030
27161
|
});
|
|
@@ -27074,7 +27205,19 @@ var A2AServer = class {
|
|
|
27074
27205
|
const payload = msg.payload;
|
|
27075
27206
|
const params = payload.params || payload;
|
|
27076
27207
|
const rpcId = payload.id || msg.id;
|
|
27077
|
-
this.handleSendMessage(params, rpcId).then((response) => {
|
|
27208
|
+
this.handleSendMessage(params, rpcId).then(async (response) => {
|
|
27209
|
+
const task = response.result;
|
|
27210
|
+
if (task?.id && !isTerminalTaskState(task.status?.state)) {
|
|
27211
|
+
const terminal = await this.waitForLocalTaskTerminal(task.id).catch((err) => {
|
|
27212
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
27213
|
+
this.logger.info(`[perkos-a2a] Waiting for relay task ${task.id} terminal state failed: ${errMsg}`);
|
|
27214
|
+
return null;
|
|
27215
|
+
});
|
|
27216
|
+
if (terminal) {
|
|
27217
|
+
this.relayClient?.sendTaskResponse(msg, terminal);
|
|
27218
|
+
return;
|
|
27219
|
+
}
|
|
27220
|
+
}
|
|
27078
27221
|
this.relayClient?.sendTaskResponse(msg, response);
|
|
27079
27222
|
}).catch((err) => {
|
|
27080
27223
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -27099,8 +27242,9 @@ var A2AServer = class {
|
|
|
27099
27242
|
const relayConfig = this.config.relay;
|
|
27100
27243
|
this.relayHub = new RelayHub(
|
|
27101
27244
|
{
|
|
27102
|
-
port: this.config.port,
|
|
27103
|
-
apiKeys: this.config.auth?.apiKeys || [],
|
|
27245
|
+
port: this.config.relay?.hubPort || this.config.port,
|
|
27246
|
+
apiKeys: this.config.relay?.hubApiKeys || this.config.auth?.apiKeys || [],
|
|
27247
|
+
registeredAgents: this.config.relay?.registeredAgents || {},
|
|
27104
27248
|
maxQueuePerAgent: 200,
|
|
27105
27249
|
rateLimitPerMinute: 60,
|
|
27106
27250
|
heartbeatIntervalMs: 3e4,
|
|
@@ -27162,11 +27306,12 @@ var A2AServer = class {
|
|
|
27162
27306
|
tryListen(port, attempt = 1) {
|
|
27163
27307
|
const maxAttempts = 3;
|
|
27164
27308
|
try {
|
|
27165
|
-
const
|
|
27309
|
+
const bindHost = this.config.bindHost || "0.0.0.0";
|
|
27310
|
+
const srv = this.app.listen(port, bindHost, () => {
|
|
27166
27311
|
this.logger.info(
|
|
27167
|
-
`[perkos-a2a] ${this.config.agentName} server on
|
|
27312
|
+
`[perkos-a2a] ${this.config.agentName} server on ${bindHost}:${port}`
|
|
27168
27313
|
);
|
|
27169
|
-
this.agentCard.url = `http://localhost:${port}/a2a/jsonrpc`;
|
|
27314
|
+
this.agentCard.url = `${(this.config.publicUrl || `http://localhost:${port}`).replace(/\/+$/, "")}/a2a/jsonrpc`;
|
|
27170
27315
|
});
|
|
27171
27316
|
srv.on("error", (err) => {
|
|
27172
27317
|
if (err.code === "EADDRINUSE" && attempt < maxAttempts) {
|
|
@@ -27193,7 +27338,7 @@ var A2AServer = class {
|
|
|
27193
27338
|
};
|
|
27194
27339
|
|
|
27195
27340
|
// src/index.ts
|
|
27196
|
-
import { randomUUID as
|
|
27341
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
27197
27342
|
function wakeGatewayAgent(requestHeartbeatNow, reason, logger, sessionKey = "agent:main") {
|
|
27198
27343
|
if (typeof requestHeartbeatNow === "function") {
|
|
27199
27344
|
try {
|
|
@@ -27207,6 +27352,34 @@ function wakeGatewayAgent(requestHeartbeatNow, reason, logger, sessionKey = "age
|
|
|
27207
27352
|
logger.info("[perkos-a2a] runtime.system.requestHeartbeatNow unavailable \u2014 task will process on next agent turn");
|
|
27208
27353
|
}
|
|
27209
27354
|
}
|
|
27355
|
+
function openclawWakeSessionKey(config) {
|
|
27356
|
+
return config.runtime?.sessionKey || "agent:main";
|
|
27357
|
+
}
|
|
27358
|
+
function openclawEventSessionKey(config) {
|
|
27359
|
+
const key = config.runtime?.sessionKey;
|
|
27360
|
+
if (!key) return "agent:main:main";
|
|
27361
|
+
return key.endsWith(":main") ? key : `${key}:main`;
|
|
27362
|
+
}
|
|
27363
|
+
async function deliverToHermes(config, message, logger) {
|
|
27364
|
+
const runtime = config.runtime || {};
|
|
27365
|
+
const baseUrl = (runtime.hermesUrl || process.env.HERMES_WORKSPACE_URL || "http://127.0.0.1:3000").replace(/\/+$/, "");
|
|
27366
|
+
const endpoint = runtime.hermesEndpoint || "/api/session-send";
|
|
27367
|
+
const sessionKey = runtime.sessionKey || "main";
|
|
27368
|
+
const token = runtime.hermesToken || process.env.HERMES_WORKSPACE_TOKEN || process.env.HERMES_SESSION_TOKEN;
|
|
27369
|
+
const url = `${baseUrl}${endpoint.startsWith("/") ? endpoint : `/${endpoint}`}`;
|
|
27370
|
+
const headers = { "content-type": "application/json" };
|
|
27371
|
+
if (token) headers.cookie = `claude-auth=${token}`;
|
|
27372
|
+
const response = await fetch(url, {
|
|
27373
|
+
method: "POST",
|
|
27374
|
+
headers,
|
|
27375
|
+
body: JSON.stringify({ sessionKey, message })
|
|
27376
|
+
});
|
|
27377
|
+
if (!response.ok) {
|
|
27378
|
+
const body = await response.text().catch(() => "");
|
|
27379
|
+
throw new Error(`Hermes delivery failed (${response.status}): ${body || response.statusText}`);
|
|
27380
|
+
}
|
|
27381
|
+
logger.info(`[perkos-a2a] Delivered inbound A2A task to Hermes session ${sessionKey} via ${url}`);
|
|
27382
|
+
}
|
|
27210
27383
|
function register(api) {
|
|
27211
27384
|
const pluginConfig = api.config?.plugins?.entries?.["perkos-a2a"]?.config || {
|
|
27212
27385
|
agentName: "agent",
|
|
@@ -27230,6 +27403,7 @@ function register(api) {
|
|
|
27230
27403
|
logger.info("[perkos-a2a] runtime.system.requestHeartbeatNow unavailable \u2014 wake will rely on next agent turn");
|
|
27231
27404
|
}
|
|
27232
27405
|
server.setTaskResultHandler(async (task, text) => {
|
|
27406
|
+
const runtimeKind = pluginConfig.runtime?.kind || "openclaw";
|
|
27233
27407
|
const from = task.metadata?.fromAgent || "unknown";
|
|
27234
27408
|
const marker = `[A2A_RESULT:${task.id}]`;
|
|
27235
27409
|
const eventText = [
|
|
@@ -27249,22 +27423,43 @@ function register(api) {
|
|
|
27249
27423
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
27250
27424
|
message: {
|
|
27251
27425
|
role: "agent",
|
|
27252
|
-
parts: [{ kind: "text", text:
|
|
27426
|
+
parts: [{ kind: "text", text: `Task dispatched to ${runtimeKind} runtime.` }]
|
|
27253
27427
|
}
|
|
27254
27428
|
};
|
|
27429
|
+
if (runtimeKind === "hermes") {
|
|
27430
|
+
await deliverToHermes(pluginConfig, eventText, logger);
|
|
27431
|
+
task.artifacts.push({
|
|
27432
|
+
kind: "artifact",
|
|
27433
|
+
artifactId: randomUUID5(),
|
|
27434
|
+
parts: [{ kind: "text", text: `debug: delivered task ${task.id} to Hermes Workspace` }]
|
|
27435
|
+
});
|
|
27436
|
+
const finalText2 = await generateRuntimeReply(pluginConfig, text, marker);
|
|
27437
|
+
completeTaskWithReply(task, finalText2);
|
|
27438
|
+
return;
|
|
27439
|
+
}
|
|
27440
|
+
if (runtimeKind === "none") {
|
|
27441
|
+
task.artifacts.push({
|
|
27442
|
+
kind: "artifact",
|
|
27443
|
+
artifactId: randomUUID5(),
|
|
27444
|
+
parts: [{ kind: "text", text: `debug: runtime delivery disabled for ${marker}` }]
|
|
27445
|
+
});
|
|
27446
|
+
return;
|
|
27447
|
+
}
|
|
27255
27448
|
task.artifacts.push({
|
|
27256
27449
|
kind: "artifact",
|
|
27257
|
-
artifactId:
|
|
27450
|
+
artifactId: randomUUID5(),
|
|
27258
27451
|
parts: [{ kind: "text", text: `debug: enqueued system event for ${marker}` }]
|
|
27259
27452
|
});
|
|
27260
27453
|
if (enqueueSystemEvent) {
|
|
27261
|
-
enqueueSystemEvent(eventText, { sessionKey:
|
|
27454
|
+
enqueueSystemEvent(eventText, { sessionKey: openclawEventSessionKey(pluginConfig) });
|
|
27262
27455
|
}
|
|
27456
|
+
const finalText = await generateRuntimeReply(pluginConfig, text, marker);
|
|
27457
|
+
completeTaskWithReply(task, finalText);
|
|
27263
27458
|
wakeGatewayAgent(
|
|
27264
27459
|
requestHeartbeatNow,
|
|
27265
27460
|
`[A2A] Process queued task ${task.id}`,
|
|
27266
27461
|
logger,
|
|
27267
|
-
|
|
27462
|
+
openclawWakeSessionKey(pluginConfig)
|
|
27268
27463
|
);
|
|
27269
27464
|
});
|
|
27270
27465
|
server.setTaskFailureHandler(async (task, errorText) => {
|
|
@@ -27283,7 +27478,8 @@ function register(api) {
|
|
|
27283
27478
|
const time = (/* @__PURE__ */ new Date()).toISOString();
|
|
27284
27479
|
pendingTasks.push({ from, text, taskId, time });
|
|
27285
27480
|
logger.info(`[perkos-a2a] Task queued from ${from} (${taskId}), ${pendingTasks.length} pending`);
|
|
27286
|
-
|
|
27481
|
+
const runtimeKind = pluginConfig.runtime?.kind || "openclaw";
|
|
27482
|
+
if (runtimeKind === "openclaw" && enqueueSystemEvent) {
|
|
27287
27483
|
const eventText = [
|
|
27288
27484
|
`[A2A OBSERVABILITY EVENT]`,
|
|
27289
27485
|
`From: ${from} | Task ID: ${taskId} | Time: ${time}`,
|
|
@@ -27291,19 +27487,21 @@ function register(api) {
|
|
|
27291
27487
|
text
|
|
27292
27488
|
].join("\n");
|
|
27293
27489
|
try {
|
|
27294
|
-
enqueueSystemEvent(eventText, { sessionKey:
|
|
27490
|
+
enqueueSystemEvent(eventText, { sessionKey: openclawEventSessionKey(pluginConfig) });
|
|
27295
27491
|
logger.info(`[perkos-a2a] Observability system event enqueued for task ${taskId}`);
|
|
27296
27492
|
} catch (err) {
|
|
27297
27493
|
const msg = err instanceof Error ? err.message : String(err);
|
|
27298
27494
|
logger.error(`[perkos-a2a] Failed to enqueue observability system event: ${msg}`);
|
|
27299
27495
|
}
|
|
27300
27496
|
}
|
|
27301
|
-
|
|
27302
|
-
|
|
27303
|
-
|
|
27304
|
-
|
|
27305
|
-
|
|
27306
|
-
|
|
27497
|
+
if (runtimeKind === "openclaw") {
|
|
27498
|
+
wakeGatewayAgent(
|
|
27499
|
+
requestHeartbeatNow,
|
|
27500
|
+
`[A2A] Incoming task from ${from} (${taskId}).`,
|
|
27501
|
+
logger,
|
|
27502
|
+
openclawWakeSessionKey(pluginConfig)
|
|
27503
|
+
);
|
|
27504
|
+
}
|
|
27307
27505
|
});
|
|
27308
27506
|
api.registerHook("before_agent_start", async () => {
|
|
27309
27507
|
if (pendingTasks.length === 0) return {};
|
|
@@ -27320,7 +27518,7 @@ function register(api) {
|
|
|
27320
27518
|
}
|
|
27321
27519
|
logger.info(`[perkos-a2a] Injecting ${tasks.length} observability note(s) into agent context via before_agent_start`);
|
|
27322
27520
|
return { prependContext: lines.join("\n") };
|
|
27323
|
-
});
|
|
27521
|
+
}, { name: "perkos-a2a-before-agent-start", description: "Inject pending A2A observability notes before agent starts." });
|
|
27324
27522
|
api.runtime?.events?.onSessionTranscriptUpdate?.((update) => {
|
|
27325
27523
|
const message = update?.message;
|
|
27326
27524
|
const text = Array.isArray(message?.parts) ? message.parts.filter((p) => p?.kind === "text" && typeof p?.text === "string").map((p) => p.text).join("\n") : typeof message?.text === "string" ? message.text : "";
|
|
@@ -27328,11 +27526,12 @@ function register(api) {
|
|
|
27328
27526
|
for (const task of server.getTasks()) {
|
|
27329
27527
|
const marker = `[A2A_RESULT:${task.id}]`;
|
|
27330
27528
|
if (!text.includes(marker)) continue;
|
|
27529
|
+
if (task.status.state === "completed") continue;
|
|
27331
27530
|
const finalText = text.slice(text.indexOf(marker) + marker.length).trim();
|
|
27332
27531
|
if (!finalText) continue;
|
|
27333
27532
|
task.artifacts.push({
|
|
27334
27533
|
kind: "artifact",
|
|
27335
|
-
artifactId:
|
|
27534
|
+
artifactId: randomUUID5(),
|
|
27336
27535
|
parts: [{ kind: "text", text: finalText }]
|
|
27337
27536
|
});
|
|
27338
27537
|
task.status = {
|
|
@@ -27594,9 +27793,15 @@ Relay: ${pluginConfig.relay?.enabled ? "enabled" : "disabled"}`);
|
|
|
27594
27793
|
console.log(`Auth: ${pluginConfig.auth?.requireApiKey ? "enabled" : "disabled"}`);
|
|
27595
27794
|
console.log(`System event injection: ${!!enqueueSystemEvent}`);
|
|
27596
27795
|
console.log("\n--- Recommendations ---\n");
|
|
27796
|
+
console.log("Same-host / same-IP rule:");
|
|
27797
|
+
console.log(" IP address is transport only, not agent identity.");
|
|
27798
|
+
console.log(" If multiple agents share this host/LAN/public IP, assign unique agentName + port.");
|
|
27799
|
+
console.log(` Local loopback URL for this agent: http://127.0.0.1:${pluginConfig.port}/a2a/jsonrpc`);
|
|
27800
|
+
console.log(" Configure same-host peers as http://127.0.0.1:<peer-port>, not by shared public IP.");
|
|
27801
|
+
console.log("");
|
|
27597
27802
|
if (!net.isBehindNat) {
|
|
27598
|
-
console.log("You have a public IP.
|
|
27599
|
-
console.log(`
|
|
27803
|
+
console.log("You have a public IP. Use it only for remote peers that cannot reach a local/tunnel URL.");
|
|
27804
|
+
console.log(` Public A2A URL candidate: http://${net.publicIp}:${pluginConfig.port}/a2a/jsonrpc`);
|
|
27600
27805
|
} else if (pluginConfig.relay?.enabled) {
|
|
27601
27806
|
console.log("You are behind NAT but relay is configured. Bidirectional communication via relay.");
|
|
27602
27807
|
} else if (net.hasTailscale && net.tailscaleIp) {
|