@perkos/perkos-a2a 0.12.19 → 0.12.22

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.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Gateway health reporter.
3
3
  *
4
- * The PerkOS mini-app's `POST /api/agents/[agentId]/gateways/[type]/status`
4
+ * The PerkOS API's `POST /agents/:agentId/gateways/:type/status`
5
5
  * route flips a gateway's status from "pending" (set when the wallet
6
6
  * configures it in the wizard) to "active" or "error". Without
7
7
  * something calling it, every gateway sits at "pending" forever in
@@ -15,15 +15,9 @@
15
15
  * bridge — the admin panel staying at "pending" is preferable to a
16
16
  * dead bridge.
17
17
  *
18
- * Why presence-based reporting (not real Hermes platform polling):
19
- * Hermes upstream exposes connected-platform state only as a
20
- * Python-internal getter (gateway/config.py: get_connected_platforms).
21
- * There's no HTTP route we can hit from the sidecar without first
22
- * building one. Reporting "active" for every configured gateway
23
- * is the simplest signal that's better than the "pending forever"
24
- * floor. Once Hermes adds the route (or we ship our own plugin
25
- * that exposes it), this module can be extended to read real
26
- * state without changing its contract with the mini-app.
18
+ * Telegram is probed against Bot API getMe before status is reported. Other
19
+ * gateways remain pending until they have an equally real provider probe;
20
+ * environment presence alone is never treated as health.
27
21
  *
28
22
  * Inputs (env, all optional):
29
23
  * PERKOS_AGENT_ID — per-wallet agent doc id (required to
@@ -38,7 +32,7 @@
38
32
  * (same secret the bridge already uses
39
33
  * to authenticate to chat.perkos.xyz).
40
34
  * PERKOS_GATEWAY_STATUS_URL — base URL, defaults to
41
- * https://app.perkos.xyz/api/agents.
35
+ * https://api.perkos.xyz/agents.
42
36
  * PERKOS_GATEWAY_REPORT_DELAY_MS — how long to wait after bridge
43
37
  * start before reporting. Default 30s.
44
38
  *
@@ -52,7 +46,7 @@
52
46
  * PerkOS#TBD).
53
47
  */
54
48
  export const KNOWN_GATEWAYS = ["telegram", "farcaster", "slack"];
55
- const DEFAULT_BASE_URL = "https://app.perkos.xyz/api/agents";
49
+ const DEFAULT_BASE_URL = "https://api.perkos.xyz/agents";
56
50
  const DEFAULT_DELAY_MS = 30_000;
57
51
  const POST_TIMEOUT_MS = 10_000;
58
52
  function enabledFromEnv(env, gateway) {
@@ -96,23 +90,64 @@ export function startGatewayHealthReporter(opts = {}) {
96
90
  const parsed = Number(raw);
97
91
  return Number.isFinite(parsed) && parsed >= 0 ? parsed : DEFAULT_DELAY_MS;
98
92
  })();
99
- log.info(`[gateway-health] will report ${enabled.join(", ")} as active in ${delayMs}ms`);
93
+ log.info(`[gateway-health] will probe ${enabled.join(", ")} in ${delayMs}ms`);
100
94
  return new Promise((resolve) => {
101
95
  setTimeout(async () => {
102
96
  const results = [];
103
97
  for (const gateway of enabled) {
98
+ if (gateway !== "telegram") {
99
+ const error = `${gateway} has no provider-backed health probe yet`;
100
+ log.info(`[gateway-health] ${error}; leaving status pending`);
101
+ results.push({ gateway, ok: false, status: null, error });
102
+ continue;
103
+ }
104
+ const probe = await probeTelegram(fetcher, env.TELEGRAM_BOT_TOKEN);
104
105
  results.push(await postOne(fetcher, log, {
105
106
  baseUrl,
106
107
  agentId,
107
108
  agentName,
108
109
  relayKey,
109
110
  gateway,
111
+ gatewayStatus: probe.ok ? "active" : "error",
112
+ message: probe.message,
110
113
  }));
111
114
  }
112
115
  resolve(results);
113
116
  }, delayMs);
114
117
  });
115
118
  }
119
+ async function probeTelegram(fetcher, rawToken) {
120
+ const token = rawToken?.trim();
121
+ if (!token)
122
+ return { ok: false, message: "Telegram bot token is missing." };
123
+ const controller = new AbortController();
124
+ const timer = setTimeout(() => controller.abort(), POST_TIMEOUT_MS);
125
+ try {
126
+ const response = await fetcher(`https://api.telegram.org/bot${encodeURIComponent(token)}/getMe`, { signal: controller.signal });
127
+ const body = (await response.json().catch(() => null));
128
+ if (!response.ok || body?.ok !== true) {
129
+ return {
130
+ ok: false,
131
+ message: body?.description || `Telegram getMe failed (${response.status}).`,
132
+ };
133
+ }
134
+ const identity = body.result?.username
135
+ ? `@${body.result.username}`
136
+ : body.result?.id
137
+ ? String(body.result.id)
138
+ : "bot";
139
+ return { ok: true, message: `Telegram authenticated as ${identity}.` };
140
+ }
141
+ catch (err) {
142
+ return {
143
+ ok: false,
144
+ message: `Telegram probe failed: ${err instanceof Error ? err.message : String(err)}`,
145
+ };
146
+ }
147
+ finally {
148
+ clearTimeout(timer);
149
+ }
150
+ }
116
151
  async function postOne(fetcher, log, args) {
117
152
  const url = `${args.baseUrl}/${encodeURIComponent(args.agentId)}/gateways/${args.gateway}/status`;
118
153
  const controller = new AbortController();
@@ -126,10 +161,13 @@ async function postOne(fetcher, log, args) {
126
161
  "x-agent-name": args.agentName,
127
162
  "content-type": "application/json",
128
163
  },
129
- body: JSON.stringify({ status: "active" }),
164
+ body: JSON.stringify({
165
+ status: args.gatewayStatus,
166
+ message: args.message,
167
+ }),
130
168
  });
131
169
  if (response.ok) {
132
- log.info(`[gateway-health] reported ${args.gateway} → active (${response.status})`);
170
+ log.info(`[gateway-health] reported ${args.gateway} → ${args.gatewayStatus} (${response.status})`);
133
171
  return { gateway: args.gateway, ok: true, status: response.status };
134
172
  }
135
173
  const text = await response.text().catch(() => "");
@@ -1 +1 @@
1
- {"version":3,"file":"gateway-health.js","sourceRoot":"","sources":["../src/gateway-health.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gateway-health.js","sourceRoot":"","sources":["../src/gateway-health.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@
8
8
  * v0.8.0: Uses enqueueSystemEvent + WebSocket wake for immediate task processing.
9
9
  */
10
10
  import type { A2APluginConfig } from "./types.js";
11
+ import type { ChatMessage } from "./chat-types.js";
11
12
  export { A2AServer, detectNetworking } from "./server.js";
12
13
  export { RelayHub } from "./relay.js";
13
14
  export { RelayClient } from "./relay-client.js";
@@ -16,5 +17,7 @@ export { ChatStore } from "./chat-store.js";
16
17
  export * from "./types.js";
17
18
  /** Keep every chat thread in its own OpenClaw runtime session. */
18
19
  export declare function openclawChatSessionKey(config: A2APluginConfig, convId: string): string;
20
+ /** Build a bounded, agent-local transcript so every runtime turn has continuity. */
21
+ export declare function formatRecentChatContext(messages: ChatMessage[], currentMessageId: string): string;
19
22
  export default function register(api: any): void;
20
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAMlD,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,cAAc,YAAY,CAAC;AAiC3B,kEAAkE;AAClE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAItF;AAkDD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,GAAG,QA4vBxC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAGV,WAAW,EAEZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,cAAc,YAAY,CAAC;AAiC3B,kEAAkE;AAClE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAItF;AAYD,oFAAoF;AACpF,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,WAAW,EAAE,EACvB,gBAAgB,EAAE,MAAM,GACvB,MAAM,CAWR;AA2CD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,GAAG,QAwwBxC"}
package/dist/index.js CHANGED
@@ -22632,6 +22632,218 @@ var require_constants = __commonJS({
22632
22632
  }
22633
22633
  });
22634
22634
 
22635
+ // ../../../../node_modules/node-gyp-build/node-gyp-build.js
22636
+ var require_node_gyp_build = __commonJS({
22637
+ "../../../../node_modules/node-gyp-build/node-gyp-build.js"(exports, module) {
22638
+ var fs = __require("fs");
22639
+ var path = __require("path");
22640
+ var os = __require("os");
22641
+ var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
22642
+ var vars = process.config && process.config.variables || {};
22643
+ var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
22644
+ var abi = process.versions.modules;
22645
+ var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
22646
+ var arch = process.env.npm_config_arch || os.arch();
22647
+ var platform = process.env.npm_config_platform || os.platform();
22648
+ var libc = process.env.LIBC || (isAlpine(platform) ? "musl" : "glibc");
22649
+ var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || "";
22650
+ var uv = (process.versions.uv || "").split(".")[0];
22651
+ module.exports = load;
22652
+ function load(dir) {
22653
+ return runtimeRequire(load.resolve(dir));
22654
+ }
22655
+ load.resolve = load.path = function(dir) {
22656
+ dir = path.resolve(dir || ".");
22657
+ try {
22658
+ var name = runtimeRequire(path.join(dir, "package.json")).name.toUpperCase().replace(/-/g, "_");
22659
+ if (process.env[name + "_PREBUILD"]) dir = process.env[name + "_PREBUILD"];
22660
+ } catch (err) {
22661
+ }
22662
+ if (!prebuildsOnly) {
22663
+ var release = getFirst(path.join(dir, "build/Release"), matchBuild);
22664
+ if (release) return release;
22665
+ var debug = getFirst(path.join(dir, "build/Debug"), matchBuild);
22666
+ if (debug) return debug;
22667
+ }
22668
+ var prebuild = resolve(dir);
22669
+ if (prebuild) return prebuild;
22670
+ var nearby = resolve(path.dirname(process.execPath));
22671
+ if (nearby) return nearby;
22672
+ var target = [
22673
+ "platform=" + platform,
22674
+ "arch=" + arch,
22675
+ "runtime=" + runtime,
22676
+ "abi=" + abi,
22677
+ "uv=" + uv,
22678
+ armv ? "armv=" + armv : "",
22679
+ "libc=" + libc,
22680
+ "node=" + process.versions.node,
22681
+ process.versions.electron ? "electron=" + process.versions.electron : "",
22682
+ typeof __webpack_require__ === "function" ? "webpack=true" : ""
22683
+ // eslint-disable-line
22684
+ ].filter(Boolean).join(" ");
22685
+ throw new Error("No native build was found for " + target + "\n loaded from: " + dir + "\n");
22686
+ function resolve(dir2) {
22687
+ var tuples = readdirSync(path.join(dir2, "prebuilds")).map(parseTuple);
22688
+ var tuple = tuples.filter(matchTuple(platform, arch)).sort(compareTuples)[0];
22689
+ if (!tuple) return;
22690
+ var prebuilds = path.join(dir2, "prebuilds", tuple.name);
22691
+ var parsed = readdirSync(prebuilds).map(parseTags);
22692
+ var candidates = parsed.filter(matchTags(runtime, abi));
22693
+ var winner = candidates.sort(compareTags(runtime))[0];
22694
+ if (winner) return path.join(prebuilds, winner.file);
22695
+ }
22696
+ };
22697
+ function readdirSync(dir) {
22698
+ try {
22699
+ return fs.readdirSync(dir);
22700
+ } catch (err) {
22701
+ return [];
22702
+ }
22703
+ }
22704
+ function getFirst(dir, filter) {
22705
+ var files = readdirSync(dir).filter(filter);
22706
+ return files[0] && path.join(dir, files[0]);
22707
+ }
22708
+ function matchBuild(name) {
22709
+ return /\.node$/.test(name);
22710
+ }
22711
+ function parseTuple(name) {
22712
+ var arr = name.split("-");
22713
+ if (arr.length !== 2) return;
22714
+ var platform2 = arr[0];
22715
+ var architectures = arr[1].split("+");
22716
+ if (!platform2) return;
22717
+ if (!architectures.length) return;
22718
+ if (!architectures.every(Boolean)) return;
22719
+ return { name, platform: platform2, architectures };
22720
+ }
22721
+ function matchTuple(platform2, arch2) {
22722
+ return function(tuple) {
22723
+ if (tuple == null) return false;
22724
+ if (tuple.platform !== platform2) return false;
22725
+ return tuple.architectures.includes(arch2);
22726
+ };
22727
+ }
22728
+ function compareTuples(a, b) {
22729
+ return a.architectures.length - b.architectures.length;
22730
+ }
22731
+ function parseTags(file) {
22732
+ var arr = file.split(".");
22733
+ var extension2 = arr.pop();
22734
+ var tags = { file, specificity: 0 };
22735
+ if (extension2 !== "node") return;
22736
+ for (var i = 0; i < arr.length; i++) {
22737
+ var tag = arr[i];
22738
+ if (tag === "node" || tag === "electron" || tag === "node-webkit") {
22739
+ tags.runtime = tag;
22740
+ } else if (tag === "napi") {
22741
+ tags.napi = true;
22742
+ } else if (tag.slice(0, 3) === "abi") {
22743
+ tags.abi = tag.slice(3);
22744
+ } else if (tag.slice(0, 2) === "uv") {
22745
+ tags.uv = tag.slice(2);
22746
+ } else if (tag.slice(0, 4) === "armv") {
22747
+ tags.armv = tag.slice(4);
22748
+ } else if (tag === "glibc" || tag === "musl") {
22749
+ tags.libc = tag;
22750
+ } else {
22751
+ continue;
22752
+ }
22753
+ tags.specificity++;
22754
+ }
22755
+ return tags;
22756
+ }
22757
+ function matchTags(runtime2, abi2) {
22758
+ return function(tags) {
22759
+ if (tags == null) return false;
22760
+ if (tags.runtime && tags.runtime !== runtime2 && !runtimeAgnostic(tags)) return false;
22761
+ if (tags.abi && tags.abi !== abi2 && !tags.napi) return false;
22762
+ if (tags.uv && tags.uv !== uv) return false;
22763
+ if (tags.armv && tags.armv !== armv) return false;
22764
+ if (tags.libc && tags.libc !== libc) return false;
22765
+ return true;
22766
+ };
22767
+ }
22768
+ function runtimeAgnostic(tags) {
22769
+ return tags.runtime === "node" && tags.napi;
22770
+ }
22771
+ function compareTags(runtime2) {
22772
+ return function(a, b) {
22773
+ if (a.runtime !== b.runtime) {
22774
+ return a.runtime === runtime2 ? -1 : 1;
22775
+ } else if (a.abi !== b.abi) {
22776
+ return a.abi ? -1 : 1;
22777
+ } else if (a.specificity !== b.specificity) {
22778
+ return a.specificity > b.specificity ? -1 : 1;
22779
+ } else {
22780
+ return 0;
22781
+ }
22782
+ };
22783
+ }
22784
+ function isNwjs() {
22785
+ return !!(process.versions && process.versions.nw);
22786
+ }
22787
+ function isElectron() {
22788
+ if (process.versions && process.versions.electron) return true;
22789
+ if (process.env.ELECTRON_RUN_AS_NODE) return true;
22790
+ return typeof window !== "undefined" && window.process && window.process.type === "renderer";
22791
+ }
22792
+ function isAlpine(platform2) {
22793
+ return platform2 === "linux" && fs.existsSync("/etc/alpine-release");
22794
+ }
22795
+ load.parseTags = parseTags;
22796
+ load.matchTags = matchTags;
22797
+ load.compareTags = compareTags;
22798
+ load.parseTuple = parseTuple;
22799
+ load.matchTuple = matchTuple;
22800
+ load.compareTuples = compareTuples;
22801
+ }
22802
+ });
22803
+
22804
+ // ../../../../node_modules/node-gyp-build/index.js
22805
+ var require_node_gyp_build2 = __commonJS({
22806
+ "../../../../node_modules/node-gyp-build/index.js"(exports, module) {
22807
+ var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
22808
+ if (typeof runtimeRequire.addon === "function") {
22809
+ module.exports = runtimeRequire.addon.bind(runtimeRequire);
22810
+ } else {
22811
+ module.exports = require_node_gyp_build();
22812
+ }
22813
+ }
22814
+ });
22815
+
22816
+ // ../../../../node_modules/bufferutil/fallback.js
22817
+ var require_fallback = __commonJS({
22818
+ "../../../../node_modules/bufferutil/fallback.js"(exports, module) {
22819
+ "use strict";
22820
+ var mask = (source, mask2, output, offset, length) => {
22821
+ for (var i = 0; i < length; i++) {
22822
+ output[offset + i] = source[i] ^ mask2[i & 3];
22823
+ }
22824
+ };
22825
+ var unmask = (buffer, mask2) => {
22826
+ const length = buffer.length;
22827
+ for (var i = 0; i < length; i++) {
22828
+ buffer[i] ^= mask2[i & 3];
22829
+ }
22830
+ };
22831
+ module.exports = { mask, unmask };
22832
+ }
22833
+ });
22834
+
22835
+ // ../../../../node_modules/bufferutil/index.js
22836
+ var require_bufferutil = __commonJS({
22837
+ "../../../../node_modules/bufferutil/index.js"(exports, module) {
22838
+ "use strict";
22839
+ try {
22840
+ module.exports = require_node_gyp_build2()(__dirname);
22841
+ } catch (e) {
22842
+ module.exports = require_fallback();
22843
+ }
22844
+ }
22845
+ });
22846
+
22635
22847
  // node_modules/ws/lib/buffer-util.js
22636
22848
  var require_buffer_util = __commonJS({
22637
22849
  "node_modules/ws/lib/buffer-util.js"(exports, module) {
@@ -22692,7 +22904,7 @@ var require_buffer_util = __commonJS({
22692
22904
  };
22693
22905
  if (!process.env.WS_NO_BUFFER_UTIL) {
22694
22906
  try {
22695
- const bufferUtil = __require("bufferutil");
22907
+ const bufferUtil = require_bufferutil();
22696
22908
  module.exports.mask = function(source, mask, output, offset, length) {
22697
22909
  if (length < 48) _mask(source, mask, output, offset, length);
22698
22910
  else bufferUtil.mask(source, mask, output, offset, length);
@@ -23140,6 +23352,55 @@ var require_permessage_deflate = __commonJS({
23140
23352
  }
23141
23353
  });
23142
23354
 
23355
+ // ../../../../node_modules/utf-8-validate/fallback.js
23356
+ var require_fallback2 = __commonJS({
23357
+ "../../../../node_modules/utf-8-validate/fallback.js"(exports, module) {
23358
+ "use strict";
23359
+ function isValidUTF8(buf) {
23360
+ const len = buf.length;
23361
+ let i = 0;
23362
+ while (i < len) {
23363
+ if ((buf[i] & 128) === 0) {
23364
+ i++;
23365
+ } else if ((buf[i] & 224) === 192) {
23366
+ if (i + 1 === len || (buf[i + 1] & 192) !== 128 || (buf[i] & 254) === 192) {
23367
+ return false;
23368
+ }
23369
+ i += 2;
23370
+ } else if ((buf[i] & 240) === 224) {
23371
+ if (i + 2 >= len || (buf[i + 1] & 192) !== 128 || (buf[i + 2] & 192) !== 128 || buf[i] === 224 && (buf[i + 1] & 224) === 128 || // overlong
23372
+ buf[i] === 237 && (buf[i + 1] & 224) === 160) {
23373
+ return false;
23374
+ }
23375
+ i += 3;
23376
+ } else if ((buf[i] & 248) === 240) {
23377
+ if (i + 3 >= len || (buf[i + 1] & 192) !== 128 || (buf[i + 2] & 192) !== 128 || (buf[i + 3] & 192) !== 128 || buf[i] === 240 && (buf[i + 1] & 240) === 128 || // overlong
23378
+ buf[i] === 244 && buf[i + 1] > 143 || buf[i] > 244) {
23379
+ return false;
23380
+ }
23381
+ i += 4;
23382
+ } else {
23383
+ return false;
23384
+ }
23385
+ }
23386
+ return true;
23387
+ }
23388
+ module.exports = isValidUTF8;
23389
+ }
23390
+ });
23391
+
23392
+ // ../../../../node_modules/utf-8-validate/index.js
23393
+ var require_utf_8_validate = __commonJS({
23394
+ "../../../../node_modules/utf-8-validate/index.js"(exports, module) {
23395
+ "use strict";
23396
+ try {
23397
+ module.exports = require_node_gyp_build2()(__dirname);
23398
+ } catch (e) {
23399
+ module.exports = require_fallback2();
23400
+ }
23401
+ }
23402
+ });
23403
+
23143
23404
  // node_modules/ws/lib/validation.js
23144
23405
  var require_validation = __commonJS({
23145
23406
  "node_modules/ws/lib/validation.js"(exports, module) {
@@ -23331,7 +23592,7 @@ var require_validation = __commonJS({
23331
23592
  };
23332
23593
  } else if (!process.env.WS_NO_UTF_8_VALIDATE) {
23333
23594
  try {
23334
- const isValidUTF8 = __require("utf-8-validate");
23595
+ const isValidUTF8 = require_utf_8_validate();
23335
23596
  module.exports.isValidUTF8 = function(buf) {
23336
23597
  return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);
23337
23598
  };
@@ -26252,6 +26513,8 @@ import { randomUUID } from "crypto";
26252
26513
  var MIN_RECONNECT_MS = 1e3;
26253
26514
  var MAX_RECONNECT_MS = 6e4;
26254
26515
  var HEARTBEAT_INTERVAL_MS = 25e3;
26516
+ var ORPHAN_TTL_MS = 10 * 6e4;
26517
+ var ORPHAN_MAX = 256;
26255
26518
  var RelayClient = class {
26256
26519
  ws = null;
26257
26520
  options;
@@ -26262,6 +26525,8 @@ var RelayClient = class {
26262
26525
  connected = false;
26263
26526
  stopped = false;
26264
26527
  pendingCallbacks = /* @__PURE__ */ new Map();
26528
+ /** Responses that arrived with nobody waiting, claimable by a retry. */
26529
+ orphanResponses = /* @__PURE__ */ new Map();
26265
26530
  constructor(options) {
26266
26531
  this.options = options;
26267
26532
  this.logger = options.logger || { info: console.log, error: console.error };
@@ -26282,12 +26547,25 @@ var RelayClient = class {
26282
26547
  }
26283
26548
  this.connected = false;
26284
26549
  }
26285
- /** Send a task to another agent via the relay */
26286
- async sendTask(targetAgent, payload) {
26550
+ /**
26551
+ * Send a task to another agent via the relay.
26552
+ *
26553
+ * Pass `taskId` to retry a task that already went out: the relay dedups on
26554
+ * the id and will not run the work twice, and if the first attempt's response
26555
+ * arrived after we gave up it is claimed from the orphan buffer instead of
26556
+ * waiting again. Omit it for genuinely new work.
26557
+ */
26558
+ async sendTask(targetAgent, payload, taskId) {
26559
+ const id = taskId ?? randomUUID();
26560
+ const alreadyAnswered = this.claimOrphan(id);
26561
+ if (alreadyAnswered) {
26562
+ this.logger.info(`[perkos-a2a] Reusing buffered response for task ${id}`);
26563
+ return alreadyAnswered;
26564
+ }
26287
26565
  return this.sendAndWait({
26288
26566
  type: "task",
26289
26567
  to: targetAgent,
26290
- id: randomUUID(),
26568
+ id,
26291
26569
  from: this.options.agentName,
26292
26570
  payload,
26293
26571
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
@@ -26372,10 +26650,10 @@ var RelayClient = class {
26372
26650
  this.send(msg);
26373
26651
  }
26374
26652
  handleMessage(msg) {
26375
- const callback = this.pendingCallbacks.get(msg.id);
26376
- if (callback) {
26653
+ const pending = this.pendingCallbacks.get(msg.id);
26654
+ if (pending && (msg.type === pending.expectedType || msg.type === "error")) {
26377
26655
  this.pendingCallbacks.delete(msg.id);
26378
- callback(msg);
26656
+ pending.settle(msg);
26379
26657
  return;
26380
26658
  }
26381
26659
  switch (msg.type) {
@@ -26385,8 +26663,15 @@ var RelayClient = class {
26385
26663
  case "task":
26386
26664
  this.options.onTask(msg);
26387
26665
  break;
26666
+ case "task_ack":
26667
+ if (msg.payload?.deduplicated) {
26668
+ this.logger.info(`[perkos-a2a] Relay deduplicated task ${msg.id}; awaiting the original response`);
26669
+ }
26670
+ break;
26388
26671
  case "task_response":
26389
- this.logger.info(`[perkos-a2a] Received unmatched task response: ${msg.id}`);
26672
+ this.bufferOrphan(msg);
26673
+ this.logger.info(`[perkos-a2a] Buffered unmatched task response: ${msg.id}`);
26674
+ this.options.onOrphanTaskResponse?.(msg);
26390
26675
  break;
26391
26676
  case "discover_response":
26392
26677
  if (this.options.onDiscoverResponse) {
@@ -26407,18 +26692,39 @@ var RelayClient = class {
26407
26692
  this.ws.send(JSON.stringify(msg));
26408
26693
  }
26409
26694
  }
26695
+ /** Take a buffered response for `id`, if one arrived while nobody waited. */
26696
+ claimOrphan(id) {
26697
+ const entry = this.orphanResponses.get(id);
26698
+ if (!entry) return null;
26699
+ this.orphanResponses.delete(id);
26700
+ if (entry.expiresAt <= Date.now()) return null;
26701
+ return entry.msg;
26702
+ }
26703
+ bufferOrphan(msg) {
26704
+ const now = Date.now();
26705
+ for (const [id, entry] of this.orphanResponses) {
26706
+ if (entry.expiresAt <= now) this.orphanResponses.delete(id);
26707
+ }
26708
+ this.orphanResponses.set(msg.id, { msg, expiresAt: now + ORPHAN_TTL_MS });
26709
+ while (this.orphanResponses.size > ORPHAN_MAX) {
26710
+ this.orphanResponses.delete(this.orphanResponses.keys().next().value);
26711
+ }
26712
+ }
26410
26713
  async sendAndWait(msg, expectedType, timeoutMs) {
26411
26714
  return new Promise((resolve, reject) => {
26412
26715
  const timer = setTimeout(() => {
26413
26716
  this.pendingCallbacks.delete(msg.id);
26414
26717
  reject(new Error(`Relay request timed out after ${timeoutMs}ms`));
26415
26718
  }, timeoutMs);
26416
- this.pendingCallbacks.set(msg.id, (response) => {
26417
- clearTimeout(timer);
26418
- if (response.type === "error") {
26419
- reject(new Error(`Relay error: ${response.payload.message}`));
26420
- } else {
26421
- resolve(response);
26719
+ this.pendingCallbacks.set(msg.id, {
26720
+ expectedType,
26721
+ settle: (response) => {
26722
+ clearTimeout(timer);
26723
+ if (response.type === "error") {
26724
+ reject(new Error(`Relay error: ${response.payload.message}`));
26725
+ } else {
26726
+ resolve(response);
26727
+ }
26422
26728
  }
26423
26729
  });
26424
26730
  this.send(msg);
@@ -27034,6 +27340,7 @@ var A2AServer = class {
27034
27340
  messages: [message],
27035
27341
  artifacts: [],
27036
27342
  metadata: {
27343
+ ...message?.metadata,
27037
27344
  fromAgent: message?.metadata?.fromAgent || "unknown"
27038
27345
  },
27039
27346
  sessionKeyHint: "agent:main"
@@ -27281,9 +27588,9 @@ var A2AServer = class {
27281
27588
  const payload = msg.payload;
27282
27589
  const params = payload.params || payload;
27283
27590
  const rpcId = payload.id || msg.id;
27284
- const acceptQueued = params?.message?.metadata?.acceptQueued === true;
27285
27591
  this.handleSendMessage(params, rpcId).then(async (response) => {
27286
27592
  const task = response.result;
27593
+ const acceptQueued = task?.messages?.[0]?.metadata?.acceptQueued === true;
27287
27594
  if (task?.id && !isTerminalTaskState(task.status?.state)) {
27288
27595
  if (acceptQueued) {
27289
27596
  this.relayClient?.sendTaskResponse(
@@ -27301,7 +27608,12 @@ var A2AServer = class {
27301
27608
  return;
27302
27609
  }
27303
27610
  }
27304
- this.relayClient?.sendTaskResponse(msg, response);
27611
+ if (!acceptQueued) {
27612
+ this.relayClient?.sendTaskResponse(
27613
+ msg,
27614
+ response
27615
+ );
27616
+ }
27305
27617
  }).catch((err) => {
27306
27618
  const errMsg2 = err instanceof Error ? err.message : String(err);
27307
27619
  this.logger.error(`[perkos-a2a] Failed to process relay task: ${errMsg2}`);
@@ -28449,6 +28761,14 @@ function parseWalletFromIdentity(identity) {
28449
28761
  const addr = identity.slice("user:".length);
28450
28762
  return addr.startsWith("0x") ? addr.toLowerCase() : null;
28451
28763
  }
28764
+ var CHAT_CONTEXT_MESSAGE_LIMIT = 12;
28765
+ var CHAT_CONTEXT_CHAR_LIMIT = 6e3;
28766
+ function formatRecentChatContext(messages, currentMessageId) {
28767
+ const prior = messages.filter((message) => message.id !== currentMessageId).slice(-CHAT_CONTEXT_MESSAGE_LIMIT).map((message) => `${message.from}: ${message.text.trim()}`).filter((line) => line.length > 0);
28768
+ if (prior.length === 0) return "(No earlier messages in this conversation.)";
28769
+ const transcript = prior.join("\n");
28770
+ return transcript.length <= CHAT_CONTEXT_CHAR_LIMIT ? transcript : `\u2026${transcript.slice(-CHAT_CONTEXT_CHAR_LIMIT)}`;
28771
+ }
28452
28772
  async function deliverToHermes(config, message, logger) {
28453
28773
  const runtime = config.runtime || {};
28454
28774
  const baseUrl = (runtime.hermesUrl || "http://127.0.0.1:8642").replace(/\/+$/, "");
@@ -28681,6 +29001,13 @@ function register(api) {
28681
29001
  onChatDeliver: async (frame) => {
28682
29002
  const walletAddress = parseWalletFromIdentity(frame.from);
28683
29003
  const marker = `[PERKOS_CHAT:${frame.convId}]`;
29004
+ const recentPage = await chatClient?.getStore().readPage(frame.convId, {
29005
+ limit: CHAT_CONTEXT_MESSAGE_LIMIT + 1
29006
+ });
29007
+ const recentContext = formatRecentChatContext(
29008
+ recentPage?.messages ?? [],
29009
+ frame.id
29010
+ );
28684
29011
  const eventText = [
28685
29012
  marker,
28686
29013
  `From: ${frame.from}`,
@@ -28694,6 +29021,11 @@ function register(api) {
28694
29021
  walletAddress ? ` walletAddress: "${walletAddress}"` : ` walletAddress: <derived from From>`,
28695
29022
  ` text: <your reply>`,
28696
29023
  "",
29024
+ "Recent conversation context (oldest to newest):",
29025
+ recentContext,
29026
+ "",
29027
+ "Use the recent context. Do not ask again for information the user already provided.",
29028
+ "",
28697
29029
  "Message body:",
28698
29030
  frame.text
28699
29031
  ].filter(Boolean).join("\n");
@@ -29124,6 +29456,7 @@ export {
29124
29456
  RelayHub,
29125
29457
  register as default,
29126
29458
  detectNetworking,
29459
+ formatRecentChatContext,
29127
29460
  isWebhookEvent,
29128
29461
  openclawChatSessionKey
29129
29462
  };