@perkos/perkos-a2a 0.8.35 → 0.9.1
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 +99 -21
- package/dist/agent.d.ts +14 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +363 -0
- package/dist/agent.js.map +1 -0
- package/dist/agentic-actions.js +472 -0
- package/dist/agentic-actions.js.map +1 -0
- package/dist/chat-client.d.ts +77 -0
- package/dist/chat-client.d.ts.map +1 -0
- package/dist/chat-client.js +364 -0
- package/dist/chat-client.js.map +1 -0
- package/dist/chat-store.d.ts +87 -0
- package/dist/chat-store.d.ts.map +1 -0
- package/dist/chat-store.js +233 -0
- package/dist/chat-store.js.map +1 -0
- package/dist/chat-types.d.ts +166 -0
- package/dist/chat-types.d.ts.map +1 -0
- package/dist/chat-types.js +13 -0
- package/dist/chat-types.js.map +1 -0
- package/dist/hermes-cli.d.ts +30 -0
- package/dist/hermes-cli.d.ts.map +1 -0
- package/dist/hermes-cli.js +120 -0
- package/dist/hermes-cli.js.map +1 -0
- package/dist/hermes-plugin.d.ts +91 -0
- package/dist/hermes-plugin.d.ts.map +1 -0
- package/dist/hermes-plugin.js +196 -0
- package/dist/hermes-plugin.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1022 -26
- package/dist/index.js.map +4 -4
- package/dist/pairing.js +66 -0
- package/dist/pairing.js.map +1 -0
- package/dist/relay-client.js +222 -0
- package/dist/relay-client.js.map +1 -0
- package/dist/relay.js +274 -0
- package/dist/relay.js.map +1 -0
- package/dist/runtime-reply.js +137 -0
- package/dist/runtime-reply.js.map +1 -0
- package/dist/server.js +611 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +36 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -1
- package/dist/types.js.map +1 -1
- package/docs/chat-client.md +190 -0
- package/docs/demo-setup.md +273 -0
- package/openclaw.plugin.json +38 -1
- package/package.json +25 -21
- package/scripts/hermes/install.mjs +211 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append-only JSONL store for PerkOS chat conversations.
|
|
3
|
+
*
|
|
4
|
+
* Files live at:
|
|
5
|
+
* <storeRoot>/<convId>/messages.jsonl
|
|
6
|
+
* <storeRoot>/<convId>/metadata.json
|
|
7
|
+
*
|
|
8
|
+
* Privacy invariant: this is the canonical record of conversation content.
|
|
9
|
+
* The PerkOS cloud (Firestore) holds only metadata (title, participants,
|
|
10
|
+
* lastMessageAt). Bodies live exclusively here, on the agent's filesystem.
|
|
11
|
+
*/
|
|
12
|
+
import { createHash } from "node:crypto";
|
|
13
|
+
import { createReadStream } from "node:fs";
|
|
14
|
+
import { appendFile, mkdir, open, readFile, writeFile, } from "node:fs/promises";
|
|
15
|
+
import { homedir } from "node:os";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
/** Sanitize a convId so it can safely become a directory name. */
|
|
18
|
+
function safeConvId(convId) {
|
|
19
|
+
if (!/^[A-Za-z0-9_-]{1,128}$/.test(convId)) {
|
|
20
|
+
throw new Error(`invalid convId: ${convId}`);
|
|
21
|
+
}
|
|
22
|
+
return convId;
|
|
23
|
+
}
|
|
24
|
+
export class ChatStore {
|
|
25
|
+
root;
|
|
26
|
+
constructor(options = {}) {
|
|
27
|
+
this.root = options.storeRoot ?? join(homedir(), ".perkos", "conversations");
|
|
28
|
+
}
|
|
29
|
+
/** Directory for a single conversation. */
|
|
30
|
+
dirFor(convId) {
|
|
31
|
+
return join(this.root, safeConvId(convId));
|
|
32
|
+
}
|
|
33
|
+
/** Path to the JSONL log for a conv. */
|
|
34
|
+
jsonlPath(convId) {
|
|
35
|
+
return join(this.dirFor(convId), "messages.jsonl");
|
|
36
|
+
}
|
|
37
|
+
/** Path to the metadata file for a conv. */
|
|
38
|
+
metaPath(convId) {
|
|
39
|
+
return join(this.dirFor(convId), "metadata.json");
|
|
40
|
+
}
|
|
41
|
+
/** Ensure the conv directory exists. Idempotent. */
|
|
42
|
+
async ensureDir(convId) {
|
|
43
|
+
await mkdir(this.dirFor(convId), { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Write metadata for a conversation. Called on `channel_join` so the agent
|
|
47
|
+
* has a local record of which participants belong to a conv.
|
|
48
|
+
*/
|
|
49
|
+
async writeMetadata(meta) {
|
|
50
|
+
await this.ensureDir(meta.convId);
|
|
51
|
+
await writeFile(this.metaPath(meta.convId), JSON.stringify(meta, null, 2));
|
|
52
|
+
}
|
|
53
|
+
async readMetadata(convId) {
|
|
54
|
+
try {
|
|
55
|
+
const raw = await readFile(this.metaPath(convId), "utf8");
|
|
56
|
+
return JSON.parse(raw);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
if (isNotFound(err))
|
|
60
|
+
return null;
|
|
61
|
+
throw err;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Append a message to the conversation log. The line written is exactly
|
|
66
|
+
* `JSON.stringify(msg) + "\n"`. The store does not validate ordering; if
|
|
67
|
+
* messages arrive out of timestamp order, that is recorded as-is.
|
|
68
|
+
*/
|
|
69
|
+
async append(convId, msg) {
|
|
70
|
+
await this.ensureDir(convId);
|
|
71
|
+
await appendFile(this.jsonlPath(convId), JSON.stringify(msg) + "\n");
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Read a history page, reverse-chronological. Returns messages with
|
|
75
|
+
* timestamp strictly less than `before` (if provided), up to `limit`.
|
|
76
|
+
*
|
|
77
|
+
* The output order is chronological ascending — i.e. callers can `concat`
|
|
78
|
+
* pages from oldest to newest without sorting.
|
|
79
|
+
*/
|
|
80
|
+
async readPage(convId, opts) {
|
|
81
|
+
const limit = Math.max(1, Math.min(500, opts.limit));
|
|
82
|
+
const before = opts.before ?? null;
|
|
83
|
+
let lines;
|
|
84
|
+
try {
|
|
85
|
+
const raw = await readFile(this.jsonlPath(convId), "utf8");
|
|
86
|
+
lines = raw.split("\n").filter((l) => l.length > 0);
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
if (isNotFound(err))
|
|
90
|
+
return { messages: [], hasMore: false };
|
|
91
|
+
throw err;
|
|
92
|
+
}
|
|
93
|
+
// Walk lines from newest (end) to oldest (start), collecting up to limit.
|
|
94
|
+
const collected = [];
|
|
95
|
+
let hasMore = false;
|
|
96
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
97
|
+
let msg;
|
|
98
|
+
try {
|
|
99
|
+
msg = JSON.parse(lines[i]);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (before && msg.timestamp >= before)
|
|
105
|
+
continue;
|
|
106
|
+
if (collected.length >= limit) {
|
|
107
|
+
hasMore = true;
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
collected.push(msg);
|
|
111
|
+
}
|
|
112
|
+
return { messages: collected.reverse(), hasMore };
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Produce a tamper-evident summary of the conversation log for receipt
|
|
116
|
+
* issuance. Streams `messages.jsonl` through sha256 (followed by a
|
|
117
|
+
* separator + metadata.json content if present), so memory usage stays
|
|
118
|
+
* constant regardless of conv size.
|
|
119
|
+
*
|
|
120
|
+
* The hash is deterministic: same jsonl bytes → same hex string. A
|
|
121
|
+
* downstream verifier with the jsonl can recompute and confirm.
|
|
122
|
+
*
|
|
123
|
+
* Returns counts + first/last timestamps for the receipt manifest.
|
|
124
|
+
*/
|
|
125
|
+
async computeReceipt(convId) {
|
|
126
|
+
const path = this.jsonlPath(convId);
|
|
127
|
+
// Probe existence first — createReadStream() defers ENOENT to the
|
|
128
|
+
// 'error' event, which would otherwise reject our Promise.
|
|
129
|
+
try {
|
|
130
|
+
const fd = await open(path, "r");
|
|
131
|
+
await fd.close();
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
if (isNotFound(err))
|
|
135
|
+
return null;
|
|
136
|
+
throw err;
|
|
137
|
+
}
|
|
138
|
+
const stream = createReadStream(path, { encoding: "utf8", highWaterMark: 64 * 1024 });
|
|
139
|
+
const hash = createHash("sha256");
|
|
140
|
+
let messageCount = 0;
|
|
141
|
+
let firstMessageAt = null;
|
|
142
|
+
let lastMessageAt = null;
|
|
143
|
+
let leftover = "";
|
|
144
|
+
return new Promise((resolve, reject) => {
|
|
145
|
+
stream.on("data", (chunk) => {
|
|
146
|
+
const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
147
|
+
hash.update(text);
|
|
148
|
+
const combined = leftover + text;
|
|
149
|
+
const lines = combined.split("\n");
|
|
150
|
+
leftover = lines.pop() ?? "";
|
|
151
|
+
for (const line of lines) {
|
|
152
|
+
if (!line)
|
|
153
|
+
continue;
|
|
154
|
+
messageCount++;
|
|
155
|
+
try {
|
|
156
|
+
const parsed = JSON.parse(line);
|
|
157
|
+
const ts = parsed.timestamp;
|
|
158
|
+
if (typeof ts === "string") {
|
|
159
|
+
if (firstMessageAt === null || ts < firstMessageAt)
|
|
160
|
+
firstMessageAt = ts;
|
|
161
|
+
if (lastMessageAt === null || ts > lastMessageAt)
|
|
162
|
+
lastMessageAt = ts;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
/* malformed line — still counted toward hash */
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
stream.on("end", async () => {
|
|
171
|
+
if (leftover.length > 0) {
|
|
172
|
+
messageCount++;
|
|
173
|
+
try {
|
|
174
|
+
const parsed = JSON.parse(leftover);
|
|
175
|
+
const ts = parsed.timestamp;
|
|
176
|
+
if (typeof ts === "string") {
|
|
177
|
+
if (firstMessageAt === null || ts < firstMessageAt)
|
|
178
|
+
firstMessageAt = ts;
|
|
179
|
+
if (lastMessageAt === null || ts > lastMessageAt)
|
|
180
|
+
lastMessageAt = ts;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch { /* ignore */ }
|
|
184
|
+
}
|
|
185
|
+
// Fold metadata.json into the hash if present, so the receipt
|
|
186
|
+
// also commits to participant + historyHost. Use a 0x1E (record
|
|
187
|
+
// separator) byte as an unambiguous boundary.
|
|
188
|
+
try {
|
|
189
|
+
const metaRaw = await readFile(this.metaPath(convId), "utf8");
|
|
190
|
+
hash.update("\x1e");
|
|
191
|
+
hash.update(metaRaw);
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
/* metadata missing → still produce a receipt over the jsonl alone */
|
|
195
|
+
}
|
|
196
|
+
resolve({
|
|
197
|
+
transcriptHash: hash.digest("hex"),
|
|
198
|
+
hashAlgo: "sha256",
|
|
199
|
+
messageCount,
|
|
200
|
+
firstMessageAt,
|
|
201
|
+
lastMessageAt,
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
stream.on("error", (err) => reject(err));
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Return the number of messages in the log. Useful for tests and stats.
|
|
209
|
+
* Avoid using this on the hot path — it reads the full file.
|
|
210
|
+
*/
|
|
211
|
+
async count(convId) {
|
|
212
|
+
let fd;
|
|
213
|
+
try {
|
|
214
|
+
fd = await open(this.jsonlPath(convId), "r");
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
if (isNotFound(err))
|
|
218
|
+
return 0;
|
|
219
|
+
throw err;
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
const raw = await fd.readFile({ encoding: "utf8" });
|
|
223
|
+
return raw.split("\n").filter((l) => l.length > 0).length;
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
await fd.close();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function isNotFound(err) {
|
|
231
|
+
return !!err && typeof err === "object" && err.code === "ENOENT";
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=chat-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-store.js","sourceRoot":"","sources":["../src/chat-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PerkOS-Chat protocol types.
|
|
3
|
+
*
|
|
4
|
+
* Wire format spoken to `wss://chat.perkos.xyz/chat`. The chat server routes
|
|
5
|
+
* frames between users (browser, authenticated via Firebase ID token) and
|
|
6
|
+
* agents (this client, authenticated via the same relay API key issued
|
|
7
|
+
* during PerkOS-Transport pairing).
|
|
8
|
+
*
|
|
9
|
+
* Companion server: github.com/PerkOS-xyz/PerkOS-Chat
|
|
10
|
+
* Full spec: see that repo's docs/protocol.md
|
|
11
|
+
*/
|
|
12
|
+
/** Identity strings exchanged on the chat wire. */
|
|
13
|
+
export type ChatIdentity = `user:${string}` | `agent:${string}`;
|
|
14
|
+
/** A single persisted message in a conversation's jsonl. */
|
|
15
|
+
export interface ChatMessage {
|
|
16
|
+
id: string;
|
|
17
|
+
from: ChatIdentity;
|
|
18
|
+
/** Message body. May be markdown. */
|
|
19
|
+
text: string;
|
|
20
|
+
/** ISO 8601 timestamp. */
|
|
21
|
+
timestamp: string;
|
|
22
|
+
/** Optional id of the message this one replies to. */
|
|
23
|
+
replyTo?: string | null;
|
|
24
|
+
}
|
|
25
|
+
/** Sent by this client immediately after the WS opens. */
|
|
26
|
+
export interface AuthFrame {
|
|
27
|
+
type: "auth";
|
|
28
|
+
role: "agent";
|
|
29
|
+
agentName: string;
|
|
30
|
+
apiKey: string;
|
|
31
|
+
}
|
|
32
|
+
export interface AuthOkFrame {
|
|
33
|
+
type: "auth_ok";
|
|
34
|
+
session: {
|
|
35
|
+
agentName: string;
|
|
36
|
+
scopes: string[];
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export interface AuthErrorFrame {
|
|
40
|
+
type: "auth_error";
|
|
41
|
+
code: string;
|
|
42
|
+
message: string;
|
|
43
|
+
}
|
|
44
|
+
/** Server → agent: a new user (or another agent) sent a message in this conv. */
|
|
45
|
+
export interface ChatDeliverFrame {
|
|
46
|
+
type: "chat_deliver";
|
|
47
|
+
id: string;
|
|
48
|
+
convId: string;
|
|
49
|
+
from: ChatIdentity;
|
|
50
|
+
text: string;
|
|
51
|
+
timestamp: string;
|
|
52
|
+
}
|
|
53
|
+
/** Server → agent: another agent posted in a multi-participant channel. */
|
|
54
|
+
export interface ChatMessageInboundFrame {
|
|
55
|
+
type: "chat_message";
|
|
56
|
+
id: string;
|
|
57
|
+
convId: string;
|
|
58
|
+
from: ChatIdentity;
|
|
59
|
+
text: string;
|
|
60
|
+
replyTo?: string | null;
|
|
61
|
+
timestamp: string;
|
|
62
|
+
}
|
|
63
|
+
/** Agent → server: reply to a conv. The server broadcasts as `chat_message`. */
|
|
64
|
+
export interface ChatReplyFrame {
|
|
65
|
+
type: "chat_reply";
|
|
66
|
+
id?: string;
|
|
67
|
+
convId: string;
|
|
68
|
+
/** Required: tells the server which wallet's conv tree to look up. */
|
|
69
|
+
walletAddress: string;
|
|
70
|
+
text: string;
|
|
71
|
+
replyTo?: string | null;
|
|
72
|
+
}
|
|
73
|
+
/** Server → agent: please serve a history page. */
|
|
74
|
+
export interface HistoryRequestFrame {
|
|
75
|
+
type: "history_request";
|
|
76
|
+
id: string;
|
|
77
|
+
convId: string;
|
|
78
|
+
forWallet: string;
|
|
79
|
+
/** ISO timestamp — return messages strictly older than this. */
|
|
80
|
+
before?: string | null;
|
|
81
|
+
limit: number;
|
|
82
|
+
}
|
|
83
|
+
/** Agent → server: history chunk response. */
|
|
84
|
+
export interface HistoryChunkFrame {
|
|
85
|
+
type: "history_chunk";
|
|
86
|
+
id: string;
|
|
87
|
+
convId: string;
|
|
88
|
+
forWallet: string;
|
|
89
|
+
messages: ChatMessage[];
|
|
90
|
+
hasMore: boolean;
|
|
91
|
+
}
|
|
92
|
+
/** Server → agent: heads-up that this agent is now a participant in a conv. */
|
|
93
|
+
export interface ChannelJoinFrame {
|
|
94
|
+
type: "channel_join";
|
|
95
|
+
convId: string;
|
|
96
|
+
participants: ChatIdentity[];
|
|
97
|
+
historyHost: ChatIdentity;
|
|
98
|
+
}
|
|
99
|
+
export interface TypingFrame {
|
|
100
|
+
type: "typing";
|
|
101
|
+
convId: string;
|
|
102
|
+
/** When echoed by the server, this is populated. */
|
|
103
|
+
from?: ChatIdentity;
|
|
104
|
+
state: "start" | "stop";
|
|
105
|
+
}
|
|
106
|
+
export interface AckFrame {
|
|
107
|
+
type: "ack";
|
|
108
|
+
id: string;
|
|
109
|
+
convId: string;
|
|
110
|
+
delivered: number;
|
|
111
|
+
timestamp: string;
|
|
112
|
+
}
|
|
113
|
+
/** Server → agent: please compute a tamper-evident hash of this conv. */
|
|
114
|
+
export interface ReceiptRequestFrame {
|
|
115
|
+
type: "receipt_request";
|
|
116
|
+
id: string;
|
|
117
|
+
convId: string;
|
|
118
|
+
/** Wallet that the receipt is being issued for. */
|
|
119
|
+
forWallet: string;
|
|
120
|
+
}
|
|
121
|
+
/** Agent → server: hash + metadata. Server routes back to the wallet. */
|
|
122
|
+
export interface ReceiptResponseFrame {
|
|
123
|
+
type: "receipt_response";
|
|
124
|
+
id: string;
|
|
125
|
+
convId: string;
|
|
126
|
+
forWallet: string;
|
|
127
|
+
/** sha256 hex of the canonical jsonl + metadata.json. */
|
|
128
|
+
transcriptHash: string;
|
|
129
|
+
hashAlgo: "sha256";
|
|
130
|
+
messageCount: number;
|
|
131
|
+
firstMessageAt: string | null;
|
|
132
|
+
lastMessageAt: string | null;
|
|
133
|
+
/** ISO timestamp the agent produced the hash. */
|
|
134
|
+
generatedAt: string;
|
|
135
|
+
}
|
|
136
|
+
export interface ChatErrorFrame {
|
|
137
|
+
type: "error";
|
|
138
|
+
code: string;
|
|
139
|
+
message: string;
|
|
140
|
+
}
|
|
141
|
+
export interface PingFrame {
|
|
142
|
+
type: "ping";
|
|
143
|
+
}
|
|
144
|
+
export interface PongFrame {
|
|
145
|
+
type: "pong";
|
|
146
|
+
ts: string;
|
|
147
|
+
}
|
|
148
|
+
export type ChatFrame = AuthFrame | AuthOkFrame | AuthErrorFrame | ChatDeliverFrame | ChatMessageInboundFrame | ChatReplyFrame | HistoryRequestFrame | HistoryChunkFrame | ChannelJoinFrame | TypingFrame | AckFrame | ChatErrorFrame | ReceiptRequestFrame | ReceiptResponseFrame | PingFrame | PongFrame;
|
|
149
|
+
export interface ChatConfig {
|
|
150
|
+
/** Whether the chat client should connect at startup. Default: false. */
|
|
151
|
+
enabled: boolean;
|
|
152
|
+
/** WebSocket URL. Default: wss://chat.perkos.xyz/chat. */
|
|
153
|
+
url: string;
|
|
154
|
+
/** Relay API key for this agent (same key used for PerkOS-Transport pairing). */
|
|
155
|
+
apiKey: string;
|
|
156
|
+
/** Root directory for the JSONL stores. Default: ~/.perkos/conversations. */
|
|
157
|
+
storeRoot?: string;
|
|
158
|
+
/** Maximum messages returned per history page. Default: 50. */
|
|
159
|
+
defaultHistoryLimit?: number;
|
|
160
|
+
/** Reconnect floor/ceiling in ms. Defaults: 1000 / 60000. */
|
|
161
|
+
minReconnectMs?: number;
|
|
162
|
+
maxReconnectMs?: number;
|
|
163
|
+
/** Heartbeat interval ms. Default: 25000. */
|
|
164
|
+
heartbeatIntervalMs?: number;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=chat-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-types.d.ts","sourceRoot":"","sources":["../src/chat-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PerkOS-Chat protocol types.
|
|
3
|
+
*
|
|
4
|
+
* Wire format spoken to `wss://chat.perkos.xyz/chat`. The chat server routes
|
|
5
|
+
* frames between users (browser, authenticated via Firebase ID token) and
|
|
6
|
+
* agents (this client, authenticated via the same relay API key issued
|
|
7
|
+
* during PerkOS-Transport pairing).
|
|
8
|
+
*
|
|
9
|
+
* Companion server: github.com/PerkOS-xyz/PerkOS-Chat
|
|
10
|
+
* Full spec: see that repo's docs/protocol.md
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=chat-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-types.js","sourceRoot":"","sources":["../src/chat-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* perkos-a2a-hermes — opinionated CLI wrapper for Hermes deployments.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the OpenClaw "install one plugin, run it" ergonomics for
|
|
6
|
+
* Hermes users: presets the runtime to `hermes-api`, picks up the
|
|
7
|
+
* Hermes API URL/token/endpoint from the common env var names, and
|
|
8
|
+
* boots the same A2A bridge as `perkos-a2a-agent` — without requiring
|
|
9
|
+
* the operator to remember the runtime-specific flags.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* perkos-a2a-hermes \
|
|
13
|
+
* --agent-name Apollo \
|
|
14
|
+
* --relay-url wss://transport.perkos.xyz/a2a \
|
|
15
|
+
* --relay-key "$A2A_RELAY_API_KEY"
|
|
16
|
+
*
|
|
17
|
+
* Env vars consulted (precedence: flags > env):
|
|
18
|
+
* A2A_AGENT_NAME agent name
|
|
19
|
+
* A2A_PORT local A2A port (default 5060)
|
|
20
|
+
* A2A_BIND_HOST bind host (default 0.0.0.0)
|
|
21
|
+
* A2A_PUBLIC_URL advertised base URL
|
|
22
|
+
* A2A_RELAY_URL transport WS URL
|
|
23
|
+
* A2A_RELAY_API_KEY transport relay API key
|
|
24
|
+
* HERMES_API_URL Hermes API base URL (default http://127.0.0.1:8642)
|
|
25
|
+
* HERMES_API_ENDPOINT Hermes API endpoint (default /v1/responses)
|
|
26
|
+
* HERMES_API_KEY Hermes API bearer token
|
|
27
|
+
* A2A_HERMES_SESSION Hermes session key (default a2a)
|
|
28
|
+
*/
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=hermes-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes-cli.d.ts","sourceRoot":"","sources":["../src/hermes-cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* perkos-a2a-hermes — opinionated CLI wrapper for Hermes deployments.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the OpenClaw "install one plugin, run it" ergonomics for
|
|
6
|
+
* Hermes users: presets the runtime to `hermes-api`, picks up the
|
|
7
|
+
* Hermes API URL/token/endpoint from the common env var names, and
|
|
8
|
+
* boots the same A2A bridge as `perkos-a2a-agent` — without requiring
|
|
9
|
+
* the operator to remember the runtime-specific flags.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* perkos-a2a-hermes \
|
|
13
|
+
* --agent-name Apollo \
|
|
14
|
+
* --relay-url wss://transport.perkos.xyz/a2a \
|
|
15
|
+
* --relay-key "$A2A_RELAY_API_KEY"
|
|
16
|
+
*
|
|
17
|
+
* Env vars consulted (precedence: flags > env):
|
|
18
|
+
* A2A_AGENT_NAME agent name
|
|
19
|
+
* A2A_PORT local A2A port (default 5060)
|
|
20
|
+
* A2A_BIND_HOST bind host (default 0.0.0.0)
|
|
21
|
+
* A2A_PUBLIC_URL advertised base URL
|
|
22
|
+
* A2A_RELAY_URL transport WS URL
|
|
23
|
+
* A2A_RELAY_API_KEY transport relay API key
|
|
24
|
+
* HERMES_API_URL Hermes API base URL (default http://127.0.0.1:8642)
|
|
25
|
+
* HERMES_API_ENDPOINT Hermes API endpoint (default /v1/responses)
|
|
26
|
+
* HERMES_API_KEY Hermes API bearer token
|
|
27
|
+
* A2A_HERMES_SESSION Hermes session key (default a2a)
|
|
28
|
+
*/
|
|
29
|
+
import { createHermesPlugin } from "./hermes-plugin.js";
|
|
30
|
+
function argValue(flag) {
|
|
31
|
+
const idx = process.argv.indexOf(flag);
|
|
32
|
+
if (idx === -1)
|
|
33
|
+
return undefined;
|
|
34
|
+
return process.argv[idx + 1];
|
|
35
|
+
}
|
|
36
|
+
function hasFlag(flag) {
|
|
37
|
+
return process.argv.includes(flag);
|
|
38
|
+
}
|
|
39
|
+
function printHelp() {
|
|
40
|
+
console.log(`perkos-a2a-hermes — A2A bridge with Hermes API delivery preset.
|
|
41
|
+
|
|
42
|
+
Required:
|
|
43
|
+
--agent-name <name> Or A2A_AGENT_NAME
|
|
44
|
+
|
|
45
|
+
Common flags:
|
|
46
|
+
--port <n> A2A HTTP port (default 5060)
|
|
47
|
+
--bind-host <host> 0.0.0.0 (default) or 127.0.0.1
|
|
48
|
+
--public-url <url> Advertised base URL
|
|
49
|
+
--relay-url <wss> Transport relay URL (A2A_RELAY_URL)
|
|
50
|
+
--relay-key <key> Transport relay API key (A2A_RELAY_API_KEY)
|
|
51
|
+
--hermes-url <url> Hermes API base URL (HERMES_API_URL)
|
|
52
|
+
--hermes-endpoint <path> Hermes API endpoint (HERMES_API_ENDPOINT)
|
|
53
|
+
--hermes-token <token> Hermes API bearer token (HERMES_API_KEY)
|
|
54
|
+
--hermes-session <key> Hermes session key (default a2a)
|
|
55
|
+
--info Print resolved config + exit (no server boot)
|
|
56
|
+
-h, --help
|
|
57
|
+
|
|
58
|
+
This is the Hermes-flavoured sibling of \`perkos-a2a-agent\`. For full
|
|
59
|
+
config control, use \`perkos-a2a-agent --config a2a.config.json\`.
|
|
60
|
+
`);
|
|
61
|
+
}
|
|
62
|
+
function resolveConfig() {
|
|
63
|
+
const agentName = argValue("--agent-name") || process.env.A2A_AGENT_NAME;
|
|
64
|
+
if (!agentName) {
|
|
65
|
+
console.error("perkos-a2a-hermes: --agent-name (or A2A_AGENT_NAME) is required\n");
|
|
66
|
+
printHelp();
|
|
67
|
+
process.exit(2);
|
|
68
|
+
}
|
|
69
|
+
const port = Number(argValue("--port") || process.env.A2A_PORT || 5060);
|
|
70
|
+
if (!Number.isFinite(port) || port <= 0) {
|
|
71
|
+
console.error(`perkos-a2a-hermes: invalid port ${argValue("--port")}`);
|
|
72
|
+
process.exit(2);
|
|
73
|
+
}
|
|
74
|
+
const relayUrl = argValue("--relay-url") || process.env.A2A_RELAY_URL;
|
|
75
|
+
const relayKey = argValue("--relay-key") || process.env.A2A_RELAY_API_KEY;
|
|
76
|
+
const relay = relayUrl && relayKey
|
|
77
|
+
? { url: relayUrl, apiKey: relayKey, enabled: true }
|
|
78
|
+
: undefined;
|
|
79
|
+
return {
|
|
80
|
+
agentName,
|
|
81
|
+
port,
|
|
82
|
+
bindHost: argValue("--bind-host") || process.env.A2A_BIND_HOST,
|
|
83
|
+
publicUrl: argValue("--public-url") || process.env.A2A_PUBLIC_URL,
|
|
84
|
+
relay,
|
|
85
|
+
hermes: {
|
|
86
|
+
url: argValue("--hermes-url") || process.env.HERMES_API_URL,
|
|
87
|
+
endpoint: argValue("--hermes-endpoint") || process.env.HERMES_API_ENDPOINT,
|
|
88
|
+
sessionKey: argValue("--hermes-session") || process.env.A2A_HERMES_SESSION || "a2a",
|
|
89
|
+
token: argValue("--hermes-token") || process.env.HERMES_API_KEY,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
async function main() {
|
|
94
|
+
if (hasFlag("-h") || hasFlag("--help")) {
|
|
95
|
+
printHelp();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const config = resolveConfig();
|
|
99
|
+
const plugin = createHermesPlugin(config);
|
|
100
|
+
if (hasFlag("--info")) {
|
|
101
|
+
const info = plugin.info();
|
|
102
|
+
console.log(JSON.stringify({ ...info, relayConfigured: Boolean(config.relay) }, null, 2));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
await plugin.start();
|
|
106
|
+
process.on("SIGINT", async () => {
|
|
107
|
+
await plugin.stop();
|
|
108
|
+
process.exit(0);
|
|
109
|
+
});
|
|
110
|
+
process.on("SIGTERM", async () => {
|
|
111
|
+
await plugin.stop();
|
|
112
|
+
process.exit(0);
|
|
113
|
+
});
|
|
114
|
+
console.log(`[perkos-a2a/hermes] running as ${config.agentName} on port ${config.port ?? 5060}`);
|
|
115
|
+
}
|
|
116
|
+
main().catch((err) => {
|
|
117
|
+
console.error("[perkos-a2a/hermes] fatal:", err);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
});
|
|
120
|
+
//# sourceMappingURL=hermes-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes-cli.js","sourceRoot":"","sources":["../src/hermes-cli.ts"],"names":[],"mappings":"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"}
|