@perkos/perkos-a2a 0.12.64 → 0.12.65

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.
@@ -0,0 +1,9 @@
1
+ import type { A2APluginConfig } from "./types.js";
2
+ export type PlatformControlPlane = {
3
+ apiBaseUrl: string;
4
+ agentId: string;
5
+ relayApiKey: string;
6
+ };
7
+ /** Resolve the same platform identity whether installers persisted it in config or service env. */
8
+ export declare function resolvePlatformControlPlane(config: A2APluginConfig, env?: Record<string, string | undefined>): PlatformControlPlane | null;
9
+ //# sourceMappingURL=platform-control-plane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-control-plane.d.ts","sourceRoot":"","sources":["../src/platform-control-plane.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,oBAAoB,GAAG;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,mGAAmG;AACnG,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,eAAe,EACvB,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,oBAAoB,GAAG,IAAI,CAgB7B"}
@@ -0,0 +1,25 @@
1
+ /** Resolve the same platform identity whether installers persisted it in config or service env. */
2
+ export function resolvePlatformControlPlane(config, env = process.env) {
3
+ const heartbeat = config.platform?.heartbeatUrl?.trim() || env.PERKOS_HEARTBEAT_URL?.trim();
4
+ const relayApiKey = config.relay?.apiKey?.trim()
5
+ || config.chat?.apiKey?.trim()
6
+ || env.A2A_RELAY_API_KEY?.trim()
7
+ || env.A2A_CHAT_API_KEY?.trim();
8
+ if (!heartbeat || !relayApiKey)
9
+ return null;
10
+ let url;
11
+ try {
12
+ url = new URL(heartbeat);
13
+ }
14
+ catch {
15
+ return null;
16
+ }
17
+ const match = url.pathname.match(/^(.*)\/agents\/([^/]+)\/heartbeat\/?$/u);
18
+ const agentId = config.platform?.agentId?.trim()
19
+ || (match ? decodeURIComponent(match[2]) : "")
20
+ || env.PERKOS_AGENT_ID?.trim();
21
+ if (!match || !agentId)
22
+ return null;
23
+ return { apiBaseUrl: `${url.origin}${match[1]}`, agentId, relayApiKey };
24
+ }
25
+ //# sourceMappingURL=platform-control-plane.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-control-plane.js","sourceRoot":"","sources":["../src/platform-control-plane.ts"],"names":[],"mappings":"AAQA,mGAAmG;AACnG,MAAM,UAAU,2BAA2B,CACzC,MAAuB,EACvB,MAA0C,OAAO,CAAC,GAAG;IAErD,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,oBAAoB,EAAE,IAAI,EAAE,CAAC;IAC5F,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE;WAC3C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;WAC3B,GAAG,CAAC,iBAAiB,EAAE,IAAI,EAAE;WAC7B,GAAG,CAAC,gBAAgB,EAAE,IAAI,EAAE,CAAC;IAClC,IAAI,CAAC,SAAS,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAE5C,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QAAC,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;IACxD,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC3E,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE;WAC3C,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;WAC5C,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC;IACjC,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO,EAAE,UAAU,EAAE,GAAG,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=platform-control-plane.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-control-plane.test.d.ts","sourceRoot":"","sources":["../src/platform-control-plane.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,32 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { resolvePlatformControlPlane } from "./platform-control-plane.js";
3
+ const baseConfig = {
4
+ agentName: "Athena",
5
+ port: 5050,
6
+ skills: [],
7
+ peers: {},
8
+ runtime: { kind: "hermes-api" },
9
+ };
10
+ describe("resolvePlatformControlPlane", () => {
11
+ it("uses plugin config when the complete identity is persisted there", () => {
12
+ expect(resolvePlatformControlPlane({
13
+ ...baseConfig,
14
+ relay: { enabled: true, url: "wss://dev.transport.perkos.xyz/a2a", apiKey: "rk_config" },
15
+ platform: { agentId: "athena", heartbeatUrl: "https://dev.api.perkos.xyz/agents/athena/heartbeat" },
16
+ }, {})).toEqual({ apiBaseUrl: "https://dev.api.perkos.xyz", agentId: "athena", relayApiKey: "rk_config" });
17
+ });
18
+ it("uses service env when update-hermes keeps runtime identity outside plugin JSON", () => {
19
+ expect(resolvePlatformControlPlane(baseConfig, {
20
+ PERKOS_HEARTBEAT_URL: "https://dev.api.perkos.xyz/agents/athena/heartbeat",
21
+ A2A_RELAY_API_KEY: "rk_env",
22
+ })).toEqual({ apiBaseUrl: "https://dev.api.perkos.xyz", agentId: "athena", relayApiKey: "rk_env" });
23
+ });
24
+ it("fails closed without a complete validated heartbeat identity", () => {
25
+ expect(resolvePlatformControlPlane(baseConfig, { A2A_RELAY_API_KEY: "rk_env" })).toBeNull();
26
+ expect(resolvePlatformControlPlane(baseConfig, {
27
+ PERKOS_HEARTBEAT_URL: "not-a-url",
28
+ A2A_RELAY_API_KEY: "rk_env",
29
+ })).toBeNull();
30
+ });
31
+ });
32
+ //# sourceMappingURL=platform-control-plane.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-control-plane.test.js","sourceRoot":"","sources":["../src/platform-control-plane.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAG1E,MAAM,UAAU,GAAoB;IAClC,SAAS,EAAE,QAAQ;IACnB,IAAI,EAAE,IAAI;IACV,MAAM,EAAE,EAAE;IACV,KAAK,EAAE,EAAE;IACT,OAAO,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;CAChC,CAAC;AAEF,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE;IAC3C,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,CAAC,2BAA2B,CAAC;YACjC,GAAG,UAAU;YACb,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,oCAAoC,EAAE,MAAM,EAAE,WAAW,EAAE;YACxF,QAAQ,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,oDAAoD,EAAE;SACpG,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,4BAA4B,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC;IAC7G,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gFAAgF,EAAE,GAAG,EAAE;QACxF,MAAM,CAAC,2BAA2B,CAAC,UAAU,EAAE;YAC7C,oBAAoB,EAAE,oDAAoD;YAC1E,iBAAiB,EAAE,QAAQ;SAC5B,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,4BAA4B,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,CAAC,2BAA2B,CAAC,UAAU,EAAE,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC5F,MAAM,CAAC,2BAA2B,CAAC,UAAU,EAAE;YAC7C,oBAAoB,EAAE,WAAW;YACjC,iBAAiB,EAAE,QAAQ;SAC5B,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"voice-capability.d.ts","sourceRoot":"","sources":["../src/voice-capability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,YAAY,CAAC;AAE/D,eAAO,MAAM,yBAAyB,EAAG,oBAA6B,CAAC;AACvE,eAAO,MAAM,0BAA0B,EAAG,qBAA8B,CAAC;AAEzE,KAAK,WAAW,GAAG;IACjB,oBAAoB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACpG,2BAA2B,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxG,CAAC;AAEF,KAAK,iBAAiB,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;AAsCpD;;;;GAIG;AACH,wBAAsB,6BAA6B,CACjD,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,eAAe,EACvB,SAAS,GAAE,iBAAiC,GAC3C,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBxB"}
1
+ {"version":3,"file":"voice-capability.d.ts","sourceRoot":"","sources":["../src/voice-capability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,YAAY,CAAC;AAG/D,eAAO,MAAM,yBAAyB,EAAG,oBAA6B,CAAC;AACvE,eAAO,MAAM,0BAA0B,EAAG,qBAA8B,CAAC;AAEzE,KAAK,WAAW,GAAG;IACjB,oBAAoB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACpG,2BAA2B,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxG,CAAC;AAEF,KAAK,iBAAiB,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;AA0BpD;;;;GAIG;AACH,wBAAsB,6BAA6B,CACjD,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,eAAe,EACvB,SAAS,GAAE,iBAAiC,GAC3C,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBxB"}
@@ -1,3 +1,4 @@
1
+ import { resolvePlatformControlPlane } from "./platform-control-plane.js";
1
2
  export const PERKOS_VOICE_PROBE_MARKER = "PERKOS_VOICE_PROBE";
2
3
  export const PERKOS_VOICE_ENROLL_MARKER = "PERKOS_VOICE_ENROLL";
3
4
  function runtime(runtimeKind) {
@@ -9,28 +10,10 @@ function runtime(runtimeKind) {
9
10
  return "zeroclaw";
10
11
  return null;
11
12
  }
12
- function controlPlane(config) {
13
- const heartbeat = config.platform?.heartbeatUrl;
14
- const relayApiKey = config.relay?.apiKey || config.chat?.apiKey;
15
- if (!heartbeat || !relayApiKey)
16
- return null;
17
- let url;
18
- try {
19
- url = new URL(heartbeat);
20
- }
21
- catch {
22
- return null;
23
- }
24
- const match = url.pathname.match(/^(.*)\/agents\/([^/]+)\/heartbeat\/?$/u);
25
- const agentId = config.platform?.agentId || (match ? decodeURIComponent(match[2]) : "");
26
- if (!match || !agentId)
27
- return null;
28
- return { apiBaseUrl: `${url.origin}${match[1]}`, agentId, relayApiKey };
29
- }
30
13
  async function reportPluginMissing(message, config) {
31
14
  if (message !== PERKOS_VOICE_PROBE_MARKER)
32
15
  return "PERKOS_VOICE_FAILED:voice_plugin_missing";
33
- const target = controlPlane(config);
16
+ const target = resolvePlatformControlPlane(config);
34
17
  if (!target)
35
18
  return "PERKOS_VOICE_FAILED:a2a_identity_unavailable";
36
19
  const response = await fetch(`${target.apiBaseUrl}/agents/${encodeURIComponent(target.agentId)}/voice-credential/capability-report`, {
@@ -53,7 +36,7 @@ export async function tryHandleInstalledVoiceMarker(message, config, loadVoice =
53
36
  const marker = message.trim();
54
37
  if (marker !== PERKOS_VOICE_PROBE_MARKER && marker !== PERKOS_VOICE_ENROLL_MARKER)
55
38
  return null;
56
- const target = controlPlane(config);
39
+ const target = resolvePlatformControlPlane(config);
57
40
  if (!target)
58
41
  return "PERKOS_VOICE_FAILED:a2a_identity_unavailable";
59
42
  const runtimeKind = runtime(config.runtime?.kind);
@@ -1 +1 @@
1
- {"version":3,"file":"voice-capability.js","sourceRoot":"","sources":["../src/voice-capability.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"voice-capability.js","sourceRoot":"","sources":["../src/voice-capability.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAE1E,MAAM,CAAC,MAAM,yBAAyB,GAAG,oBAA6B,CAAC;AACvE,MAAM,CAAC,MAAM,0BAA0B,GAAG,qBAA8B,CAAC;AASzE,SAAS,OAAO,CAAC,WAAoC;IACnD,IAAI,WAAW,KAAK,QAAQ,IAAI,WAAW,KAAK,YAAY;QAAE,OAAO,QAAQ,CAAC;IAC9E,IAAI,WAAW,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAClD,IAAI,WAAW,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAClD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,OAAe,EAAE,MAAuB;IACzE,IAAI,OAAO,KAAK,yBAAyB;QAAE,OAAO,0CAA0C,CAAC;IAC7F,MAAM,MAAM,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACnD,IAAI,CAAC,MAAM;QAAE,OAAO,8CAA8C,CAAC;IACnE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,UAAU,WAAW,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,qCAAqC,EAAE;QACnI,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,MAAM,CAAC,WAAW,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC9F,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,sBAAsB,EAAE,CAAC;KACnF,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACrB,OAAO,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,+CAA+C,CAAC,CAAC,CAAC,+CAA+C,CAAC;AAC1H,CAAC;AAED,KAAK,UAAU,aAAa;IAC1B,MAAM,SAAS,GAAG,0BAA0B,CAAC;IAC7C,OAAO,MAAM,CAAC,SAAS,CAAyB,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,OAAe,EACf,MAAuB,EACvB,YAA+B,aAAa;IAE5C,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,MAAM,KAAK,yBAAyB,IAAI,MAAM,KAAK,0BAA0B;QAAE,OAAO,IAAI,CAAC;IAC/F,MAAM,MAAM,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACnD,IAAI,CAAC,MAAM;QAAE,OAAO,8CAA8C,CAAC;IACnE,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,WAAW;QAAE,OAAO,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7D,IAAI,KAAkB,CAAC;IACvB,IAAI,CAAC;QAAC,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,CAAC;IACxF,IAAI,OAAO,KAAK,CAAC,oBAAoB,KAAK,UAAU,IAAI,OAAO,KAAK,CAAC,2BAA2B,KAAK,UAAU,EAAE,CAAC;QAChH,OAAO,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,KAAK,CAAC,oBAAoB,CAAC,MAAM,EAAE;QACxC,GAAG,MAAM;QACT,OAAO,EAAE,WAAW;QACpB,SAAS,EAAE,KAAK,CAAC,2BAA2B;KAC7C,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,15 @@
1
+ # Identidad del control plane desde config o entorno
2
+
3
+ ## Hallazgo
4
+
5
+ El bridge Hermes instalado por `update-hermes` puede conservar `PERKOS_HEARTBEAT_URL` y `A2A_RELAY_API_KEY` en el entorno del servicio. Heartbeat ya lee ambos orígenes, pero los handlers de mantenimiento y Voice sólo consultaban el JSON del plugin. Así, una instancia podía anunciar una capability Chat-bound válida y responder `a2a_identity_unavailable` al recibir el marcador.
6
+
7
+ ## Decisión
8
+
9
+ Un resolvedor compartido aplica una precedencia única: configuración explícita del plugin y luego variables del servicio. Valida una URL de heartbeat con la ruta exacta `/agents/<id>/heartbeat`, deriva el API base y nunca registra ni devuelve la credencial fuera del proceso. Mantenimiento y Voice consumen el mismo resolvedor para impedir nuevas divergencias.
10
+
11
+ ## Seguridad y verificación
12
+
13
+ La ausencia de URL o credencial continúa fallando cerrado. La capability sigue ligada a la conexión Chat y a `bridgeInstanceId`; este cambio sólo hace accesible al handler la misma identidad que ya usa heartbeat. Las pruebas cubren identidad completa en config, fallback completo por entorno y rechazo de identidad incompleta o URL inválida.
14
+
15
+ > Relacionado: [[PerkOS-Projects/README]] · [[PerkOS-A2A]] · [[PerkOS-API]] · [[PerkOS]] · [[PerkOS-Voice]]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "perkos-a2a",
3
3
  "name": "PerkOS A2A",
4
- "version": "0.12.64",
4
+ "version": "0.12.65",
5
5
  "description": "Agent-to-Agent (A2A) protocol communication for OpenClaw agents",
6
6
  "author": "PerkOS",
7
7
  "configSchema": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@perkos/perkos-a2a",
3
- "version": "0.12.64",
3
+ "version": "0.12.65",
4
4
  "description": "A2A Protocol communication plugin for OpenClaw — Agent-to-Agent protocol implementation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",