@perkos/perkos-a2a 0.12.59 → 0.12.61

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,19 @@
1
+ import type { A2APluginConfig } from "./types.js";
2
+ export declare const PERKOS_VOICE_PROBE_MARKER: "PERKOS_VOICE_PROBE";
3
+ export declare const PERKOS_VOICE_ENROLL_MARKER: "PERKOS_VOICE_ENROLL";
4
+ type VoiceModule = {
5
+ handleA2AVoiceMarker: (message: string, options: Record<string, unknown>) => Promise<string | null>;
6
+ configureA2AVoiceEnrollment: (enrollment: unknown) => Promise<{
7
+ ready: boolean;
8
+ actionCode?: string;
9
+ }>;
10
+ };
11
+ type VoiceModuleLoader = () => Promise<VoiceModule>;
12
+ /**
13
+ * Optional bridge: exact Voice markers are consumed before the model sees
14
+ * them. A2A supplies identity/transport only; the separately installed Voice
15
+ * package owns support detection, credential storage and runtime activation.
16
+ */
17
+ export declare function tryHandleInstalledVoiceMarker(message: string, config: A2APluginConfig, loadVoice?: VoiceModuleLoader): Promise<string | null>;
18
+ export {};
19
+ //# sourceMappingURL=voice-capability.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,78 @@
1
+ export const PERKOS_VOICE_PROBE_MARKER = "PERKOS_VOICE_PROBE";
2
+ export const PERKOS_VOICE_ENROLL_MARKER = "PERKOS_VOICE_ENROLL";
3
+ function runtime(runtimeKind) {
4
+ if (runtimeKind === "hermes" || runtimeKind === "hermes-api")
5
+ return "hermes";
6
+ if (runtimeKind === "openclaw")
7
+ return "openclaw";
8
+ if (runtimeKind === "zeroclaw")
9
+ return "zeroclaw";
10
+ return null;
11
+ }
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
+ async function reportPluginMissing(message, config) {
31
+ if (message !== PERKOS_VOICE_PROBE_MARKER)
32
+ return "PERKOS_VOICE_FAILED:voice_plugin_missing";
33
+ const target = controlPlane(config);
34
+ if (!target)
35
+ return "PERKOS_VOICE_FAILED:a2a_identity_unavailable";
36
+ const response = await fetch(`${target.apiBaseUrl}/agents/${encodeURIComponent(target.agentId)}/voice-credential/capability-report`, {
37
+ method: "POST",
38
+ headers: { authorization: `Bearer ${target.relayApiKey}`, "content-type": "application/json" },
39
+ body: JSON.stringify({ state: "unsupported", reasonCode: "voice_plugin_missing" }),
40
+ }).catch(() => null);
41
+ return response?.ok ? "PERKOS_VOICE_UNSUPPORTED:voice_plugin_missing" : "PERKOS_VOICE_FAILED:control_plane_unavailable";
42
+ }
43
+ async function defaultLoader() {
44
+ const specifier = "@perkos/perkos-voice/a2a";
45
+ return import(specifier);
46
+ }
47
+ /**
48
+ * Optional bridge: exact Voice markers are consumed before the model sees
49
+ * them. A2A supplies identity/transport only; the separately installed Voice
50
+ * package owns support detection, credential storage and runtime activation.
51
+ */
52
+ export async function tryHandleInstalledVoiceMarker(message, config, loadVoice = defaultLoader) {
53
+ const marker = message.trim();
54
+ if (marker !== PERKOS_VOICE_PROBE_MARKER && marker !== PERKOS_VOICE_ENROLL_MARKER)
55
+ return null;
56
+ const target = controlPlane(config);
57
+ if (!target)
58
+ return "PERKOS_VOICE_FAILED:a2a_identity_unavailable";
59
+ const runtimeKind = runtime(config.runtime?.kind);
60
+ if (!runtimeKind)
61
+ return reportPluginMissing(marker, config);
62
+ let voice;
63
+ try {
64
+ voice = await loadVoice();
65
+ }
66
+ catch {
67
+ return reportPluginMissing(marker, config);
68
+ }
69
+ if (typeof voice.handleA2AVoiceMarker !== "function" || typeof voice.configureA2AVoiceEnrollment !== "function") {
70
+ return reportPluginMissing(marker, config);
71
+ }
72
+ return voice.handleA2AVoiceMarker(marker, {
73
+ ...target,
74
+ runtime: runtimeKind,
75
+ configure: voice.configureA2AVoiceEnrollment,
76
+ });
77
+ }
78
+ //# sourceMappingURL=voice-capability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-capability.js","sourceRoot":"","sources":["../src/voice-capability.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=voice-capability.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-capability.test.d.ts","sourceRoot":"","sources":["../src/voice-capability.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,32 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { tryHandleInstalledVoiceMarker } from "./voice-capability.js";
3
+ const config = {
4
+ agentName: "Athena", port: 5060, skills: [], peers: {},
5
+ runtime: { kind: "hermes-api" },
6
+ relay: { url: "wss://transport.perkos.xyz/a2a", apiKey: "rk_private", enabled: true },
7
+ platform: { agentId: "athena-id", heartbeatUrl: "https://dev.api.perkos.xyz/agents/athena-id/heartbeat" },
8
+ };
9
+ describe("optional Voice capability bridge", () => {
10
+ it("delegates exact Voice markers with the existing scoped identity", async () => {
11
+ let options;
12
+ const result = await tryHandleInstalledVoiceMarker("PERKOS_VOICE_ENROLL", config, async () => ({
13
+ handleA2AVoiceMarker: async (_message, value) => { options = value; return "PERKOS_VOICE_READY"; },
14
+ configureA2AVoiceEnrollment: async () => ({ ready: true }),
15
+ }));
16
+ expect(result).toBe("PERKOS_VOICE_READY");
17
+ expect(options?.apiBaseUrl).toBe("https://dev.api.perkos.xyz");
18
+ expect(options?.agentId).toBe("athena-id");
19
+ expect(options?.relayApiKey).toBe("rk_private");
20
+ expect(options?.runtime).toBe("hermes");
21
+ });
22
+ it("ignores natural language and keeps Voice parallel", async () => {
23
+ let loaded = false;
24
+ const result = await tryHandleInstalledVoiceMarker("please enable calls", config, async () => {
25
+ loaded = true;
26
+ throw new Error("not used");
27
+ });
28
+ expect(result).toBeNull();
29
+ expect(loaded).toBe(false);
30
+ });
31
+ });
32
+ //# sourceMappingURL=voice-capability.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-capability.test.js","sourceRoot":"","sources":["../src/voice-capability.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAC;AAGtE,MAAM,MAAM,GAAoB;IAC9B,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE;IACtD,OAAO,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;IAC/B,KAAK,EAAE,EAAE,GAAG,EAAE,gCAAgC,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE;IACrF,QAAQ,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,uDAAuD,EAAE;CAC1G,CAAC;AAEF,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAClD,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,IAAI,OAA4C,CAAC;QACjD,MAAM,MAAM,GAAG,MAAM,6BAA6B,CAAC,qBAAqB,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;YAC7F,oBAAoB,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,GAAG,OAAO,GAAG,KAAK,CAAC,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC;YAClG,2BAA2B,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;SAC3D,CAAC,CAAC,CAAC;QACJ,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAC1C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC/D,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC3C,MAAM,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAChD,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,MAAM,MAAM,GAAG,MAAM,6BAA6B,CAAC,qBAAqB,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE;YAC3F,MAAM,GAAG,IAAI,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC1B,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ # Optional Voice package resolution
2
+
3
+ ## Decision
4
+
5
+ PerkOS Voice remains a capability parallel to A2A, but A2A declares
6
+ `@perkos/perkos-voice` as an `optionalDependency`. This places the package next
7
+ to A2A in npm-managed private runtime installations, where the existing dynamic
8
+ `import("@perkos/perkos-voice/a2a")` can resolve it normally. Unsupported
9
+ runtimes still report their runtime/model limitation and never enable calls.
10
+
11
+ The alternatives were an optional peer dependency, which would require every
12
+ runtime installer to perform a second correctly scoped install, or resolving a
13
+ global package path, which is host-specific and bypasses normal Node package
14
+ resolution. The optional dependency is preferred because npm may omit or fail
15
+ it without making A2A installation fail, while a successful installation is
16
+ discoverable without secrets, custom paths, or model involvement.
17
+
18
+ ## Verification
19
+
20
+ Release validation must prove manifest and lockfile agreement, the existing
21
+ missing-package fallback, successful dynamic delegation, the full A2A suite,
22
+ and a clean external install that imports both package subpaths. The package
23
+ remains absent from A2A responses and no Voice credential crosses the A2A
24
+ boundary.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "perkos-a2a",
3
3
  "name": "PerkOS A2A",
4
- "version": "0.12.59",
4
+ "version": "0.12.61",
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.59",
3
+ "version": "0.12.61",
4
4
  "description": "A2A Protocol communication plugin for OpenClaw — Agent-to-Agent protocol implementation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -78,6 +78,9 @@
78
78
  "express": "^4.22.2",
79
79
  "ws": "^8.20.1"
80
80
  },
81
+ "optionalDependencies": {
82
+ "@perkos/perkos-voice": "^0.1.0"
83
+ },
81
84
  "overrides": {
82
85
  "qs": "^6.15.2"
83
86
  },