@perkos/perkos-a2a 0.9.0 → 0.9.2
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/dist/agentic-actions.js +472 -0
- package/dist/agentic-actions.js.map +1 -0
- package/dist/bridge-agent.d.ts +14 -0
- package/dist/bridge-agent.d.ts.map +1 -0
- package/dist/bridge-agent.js +319 -0
- package/dist/bridge-agent.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/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/package.json +7 -34
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PerkOS-Chat client.
|
|
3
|
+
*
|
|
4
|
+
* Connects an agent to `wss://chat.perkos.xyz/chat`. Handles auth, automatic
|
|
5
|
+
* reconnect with exponential backoff, heartbeat, persistent JSONL storage of
|
|
6
|
+
* incoming and outgoing messages, and history pagination.
|
|
7
|
+
*
|
|
8
|
+
* This is a sibling of `RelayClient` (which speaks the A2A task protocol).
|
|
9
|
+
* Same runtime conventions, different wire format — chat uses framed JSON
|
|
10
|
+
* with role-aware auth instead of A2A JSON-RPC.
|
|
11
|
+
*
|
|
12
|
+
* Companion server: github.com/PerkOS-xyz/PerkOS-Chat
|
|
13
|
+
*/
|
|
14
|
+
import { randomUUID } from "node:crypto";
|
|
15
|
+
import WebSocket from "ws";
|
|
16
|
+
import { ChatStore } from "./chat-store.js";
|
|
17
|
+
const DEFAULT_URL = "wss://chat.perkos.xyz/chat";
|
|
18
|
+
const DEFAULT_HISTORY_LIMIT = 50;
|
|
19
|
+
const DEFAULT_MIN_RECONNECT = 1_000;
|
|
20
|
+
const DEFAULT_MAX_RECONNECT = 60_000;
|
|
21
|
+
const DEFAULT_HEARTBEAT_MS = 25_000;
|
|
22
|
+
const AUTH_TIMEOUT_MS = 10_000;
|
|
23
|
+
export class ChatClient {
|
|
24
|
+
ws = null;
|
|
25
|
+
config;
|
|
26
|
+
agentName;
|
|
27
|
+
handlers;
|
|
28
|
+
logger;
|
|
29
|
+
store;
|
|
30
|
+
reconnectMs;
|
|
31
|
+
reconnectTimer = null;
|
|
32
|
+
heartbeatTimer = null;
|
|
33
|
+
connected = false;
|
|
34
|
+
authed = false;
|
|
35
|
+
stopped = false;
|
|
36
|
+
constructor(opts) {
|
|
37
|
+
this.agentName = opts.agentName;
|
|
38
|
+
const cfg = opts.config;
|
|
39
|
+
this.config = {
|
|
40
|
+
enabled: cfg.enabled,
|
|
41
|
+
url: cfg.url || DEFAULT_URL,
|
|
42
|
+
apiKey: cfg.apiKey,
|
|
43
|
+
storeRoot: cfg.storeRoot,
|
|
44
|
+
defaultHistoryLimit: cfg.defaultHistoryLimit ?? DEFAULT_HISTORY_LIMIT,
|
|
45
|
+
minReconnectMs: cfg.minReconnectMs ?? DEFAULT_MIN_RECONNECT,
|
|
46
|
+
maxReconnectMs: cfg.maxReconnectMs ?? DEFAULT_MAX_RECONNECT,
|
|
47
|
+
heartbeatIntervalMs: cfg.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_MS,
|
|
48
|
+
};
|
|
49
|
+
this.handlers = opts.handlers ?? {};
|
|
50
|
+
this.logger = this.handlers.logger ?? { info: console.log, error: console.error };
|
|
51
|
+
this.store = new ChatStore({ storeRoot: this.config.storeRoot });
|
|
52
|
+
this.reconnectMs = this.config.minReconnectMs;
|
|
53
|
+
}
|
|
54
|
+
/** Storage handle — exposed so consumers can read history without going through the wire. */
|
|
55
|
+
getStore() {
|
|
56
|
+
return this.store;
|
|
57
|
+
}
|
|
58
|
+
isConnected() {
|
|
59
|
+
return this.connected && this.authed;
|
|
60
|
+
}
|
|
61
|
+
start() {
|
|
62
|
+
if (!this.config.enabled) {
|
|
63
|
+
this.logger.info("[perkos-chat] disabled in config; not connecting");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (!this.config.apiKey) {
|
|
67
|
+
this.logger.error("[perkos-chat] missing apiKey; cannot connect");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
this.stopped = false;
|
|
71
|
+
this.connect();
|
|
72
|
+
}
|
|
73
|
+
stop() {
|
|
74
|
+
this.stopped = true;
|
|
75
|
+
this.clearTimers();
|
|
76
|
+
if (this.ws) {
|
|
77
|
+
try {
|
|
78
|
+
this.ws.close(1000, "client shutting down");
|
|
79
|
+
}
|
|
80
|
+
catch { /* ignore */ }
|
|
81
|
+
this.ws = null;
|
|
82
|
+
}
|
|
83
|
+
this.connected = false;
|
|
84
|
+
this.authed = false;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Send a reply from this agent into a conversation. Appends to the local
|
|
88
|
+
* store optimistically, then sends to the server. If the WS is offline,
|
|
89
|
+
* the local store is still updated and the message is dropped from the
|
|
90
|
+
* wire — callers should re-send after reconnect if guaranteed delivery is
|
|
91
|
+
* required (the simple agent loop should just regenerate from history).
|
|
92
|
+
*/
|
|
93
|
+
async sendReply(opts) {
|
|
94
|
+
const id = randomUUID();
|
|
95
|
+
const msg = {
|
|
96
|
+
id,
|
|
97
|
+
from: `agent:${this.agentName}`,
|
|
98
|
+
text: opts.text,
|
|
99
|
+
timestamp: new Date().toISOString(),
|
|
100
|
+
replyTo: opts.replyTo ?? null,
|
|
101
|
+
};
|
|
102
|
+
await this.store.append(opts.convId, msg);
|
|
103
|
+
const frame = {
|
|
104
|
+
type: "chat_reply",
|
|
105
|
+
id,
|
|
106
|
+
convId: opts.convId,
|
|
107
|
+
walletAddress: opts.walletAddress,
|
|
108
|
+
text: opts.text,
|
|
109
|
+
replyTo: opts.replyTo ?? null,
|
|
110
|
+
};
|
|
111
|
+
const delivered = this.sendFrame(frame);
|
|
112
|
+
return { id, delivered };
|
|
113
|
+
}
|
|
114
|
+
// -------------------------------------------------------------------------
|
|
115
|
+
// WebSocket lifecycle
|
|
116
|
+
// -------------------------------------------------------------------------
|
|
117
|
+
connect() {
|
|
118
|
+
if (this.stopped)
|
|
119
|
+
return;
|
|
120
|
+
const url = this.config.url;
|
|
121
|
+
this.logger.info(`[perkos-chat] connecting to ${url}`);
|
|
122
|
+
try {
|
|
123
|
+
this.ws = new WebSocket(url);
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
this.logger.error(`[perkos-chat] failed to construct WS: ${errMsg(err)}`);
|
|
127
|
+
this.scheduleReconnect();
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
let authTimer = setTimeout(() => {
|
|
131
|
+
if (!this.authed) {
|
|
132
|
+
this.logger.error("[perkos-chat] auth timeout");
|
|
133
|
+
try {
|
|
134
|
+
this.ws?.close(4002, "auth timeout");
|
|
135
|
+
}
|
|
136
|
+
catch { /* ignore */ }
|
|
137
|
+
}
|
|
138
|
+
}, AUTH_TIMEOUT_MS);
|
|
139
|
+
this.ws.on("open", () => {
|
|
140
|
+
this.connected = true;
|
|
141
|
+
this.reconnectMs = this.config.minReconnectMs;
|
|
142
|
+
this.sendFrame({
|
|
143
|
+
type: "auth",
|
|
144
|
+
role: "agent",
|
|
145
|
+
agentName: this.agentName,
|
|
146
|
+
apiKey: this.config.apiKey,
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
this.ws.on("message", (data) => {
|
|
150
|
+
let frame;
|
|
151
|
+
try {
|
|
152
|
+
frame = JSON.parse(data.toString("utf8"));
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
this.logger.error("[perkos-chat] failed to parse frame");
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (authTimer) {
|
|
159
|
+
clearTimeout(authTimer);
|
|
160
|
+
authTimer = null;
|
|
161
|
+
}
|
|
162
|
+
void this.handleFrame(frame);
|
|
163
|
+
});
|
|
164
|
+
this.ws.on("close", (code, reason) => {
|
|
165
|
+
this.connected = false;
|
|
166
|
+
this.authed = false;
|
|
167
|
+
this.clearTimers();
|
|
168
|
+
if (authTimer) {
|
|
169
|
+
clearTimeout(authTimer);
|
|
170
|
+
authTimer = null;
|
|
171
|
+
}
|
|
172
|
+
if (!this.stopped) {
|
|
173
|
+
this.logger.info(`[perkos-chat] disconnected (${code}: ${reason?.toString() || "no reason"}); reconnecting`);
|
|
174
|
+
this.scheduleReconnect();
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
this.ws.on("error", (err) => {
|
|
178
|
+
this.logger.error(`[perkos-chat] WS error: ${errMsg(err)}`);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
async handleFrame(frame) {
|
|
182
|
+
switch (frame.type) {
|
|
183
|
+
case "auth_ok":
|
|
184
|
+
this.authed = true;
|
|
185
|
+
this.logger.info(`[perkos-chat] authed as agent:${this.agentName}`);
|
|
186
|
+
this.startHeartbeat();
|
|
187
|
+
return;
|
|
188
|
+
case "auth_error":
|
|
189
|
+
this.logger.error(`[perkos-chat] auth_error ${frame.code}: ${frame.message}`);
|
|
190
|
+
try {
|
|
191
|
+
this.ws?.close(4401, frame.code);
|
|
192
|
+
}
|
|
193
|
+
catch { /* ignore */ }
|
|
194
|
+
return;
|
|
195
|
+
case "chat_deliver":
|
|
196
|
+
case "chat_message": {
|
|
197
|
+
await this.persistInbound(frame);
|
|
198
|
+
if (this.handlers.onChatDeliver) {
|
|
199
|
+
try {
|
|
200
|
+
await this.handlers.onChatDeliver(frame);
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
this.logger.error(`[perkos-chat] onChatDeliver threw: ${errMsg(err)}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
case "history_request":
|
|
209
|
+
await this.respondToHistoryRequest(frame);
|
|
210
|
+
return;
|
|
211
|
+
case "receipt_request":
|
|
212
|
+
await this.respondToReceiptRequest(frame);
|
|
213
|
+
return;
|
|
214
|
+
case "channel_join":
|
|
215
|
+
await this.handleChannelJoin(frame);
|
|
216
|
+
return;
|
|
217
|
+
case "ack":
|
|
218
|
+
case "pong":
|
|
219
|
+
case "typing":
|
|
220
|
+
return;
|
|
221
|
+
case "error":
|
|
222
|
+
this.logger.error(`[perkos-chat] server error ${frame.code}: ${frame.message}`);
|
|
223
|
+
return;
|
|
224
|
+
default:
|
|
225
|
+
// Unknown — log for visibility but don't blow up
|
|
226
|
+
this.logger.info(`[perkos-chat] unknown frame type: ${frame.type}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async persistInbound(frame) {
|
|
230
|
+
const msg = {
|
|
231
|
+
id: frame.id,
|
|
232
|
+
from: frame.from,
|
|
233
|
+
text: frame.text,
|
|
234
|
+
timestamp: frame.timestamp,
|
|
235
|
+
replyTo: "replyTo" in frame ? frame.replyTo ?? null : null,
|
|
236
|
+
};
|
|
237
|
+
try {
|
|
238
|
+
await this.store.append(frame.convId, msg);
|
|
239
|
+
}
|
|
240
|
+
catch (err) {
|
|
241
|
+
this.logger.error(`[perkos-chat] failed to append to store: ${errMsg(err)}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
async handleChannelJoin(frame) {
|
|
245
|
+
const now = new Date().toISOString();
|
|
246
|
+
const existing = await this.store.readMetadata(frame.convId);
|
|
247
|
+
const meta = {
|
|
248
|
+
convId: frame.convId,
|
|
249
|
+
participants: frame.participants,
|
|
250
|
+
historyHost: frame.historyHost,
|
|
251
|
+
createdAt: existing?.createdAt ?? now,
|
|
252
|
+
updatedAt: now,
|
|
253
|
+
};
|
|
254
|
+
try {
|
|
255
|
+
await this.store.writeMetadata(meta);
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
this.logger.error(`[perkos-chat] failed to write metadata for ${frame.convId}: ${errMsg(err)}`);
|
|
259
|
+
}
|
|
260
|
+
if (this.handlers.onChannelJoin) {
|
|
261
|
+
try {
|
|
262
|
+
await this.handlers.onChannelJoin(frame);
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
this.logger.error(`[perkos-chat] onChannelJoin threw: ${errMsg(err)}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
async respondToReceiptRequest(frame) {
|
|
270
|
+
let summary;
|
|
271
|
+
try {
|
|
272
|
+
summary = await this.store.computeReceipt(frame.convId);
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
this.logger.error(`[perkos-chat] receipt computation failed: ${errMsg(err)}`);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (!summary) {
|
|
279
|
+
// No jsonl for this conv → nothing to hash. Reply with an empty hash
|
|
280
|
+
// so the user sees a definitive "no content" rather than a timeout.
|
|
281
|
+
this.sendFrame({
|
|
282
|
+
type: "receipt_response",
|
|
283
|
+
id: frame.id,
|
|
284
|
+
convId: frame.convId,
|
|
285
|
+
forWallet: frame.forWallet,
|
|
286
|
+
transcriptHash: "",
|
|
287
|
+
hashAlgo: "sha256",
|
|
288
|
+
messageCount: 0,
|
|
289
|
+
firstMessageAt: null,
|
|
290
|
+
lastMessageAt: null,
|
|
291
|
+
generatedAt: new Date().toISOString(),
|
|
292
|
+
});
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
this.sendFrame({
|
|
296
|
+
type: "receipt_response",
|
|
297
|
+
id: frame.id,
|
|
298
|
+
convId: frame.convId,
|
|
299
|
+
forWallet: frame.forWallet,
|
|
300
|
+
transcriptHash: summary.transcriptHash,
|
|
301
|
+
hashAlgo: summary.hashAlgo,
|
|
302
|
+
messageCount: summary.messageCount,
|
|
303
|
+
firstMessageAt: summary.firstMessageAt,
|
|
304
|
+
lastMessageAt: summary.lastMessageAt,
|
|
305
|
+
generatedAt: new Date().toISOString(),
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
async respondToHistoryRequest(frame) {
|
|
309
|
+
const limit = frame.limit ?? this.config.defaultHistoryLimit;
|
|
310
|
+
let page;
|
|
311
|
+
try {
|
|
312
|
+
page = await this.store.readPage(frame.convId, { before: frame.before ?? null, limit });
|
|
313
|
+
}
|
|
314
|
+
catch (err) {
|
|
315
|
+
this.logger.error(`[perkos-chat] history read failed: ${errMsg(err)}`);
|
|
316
|
+
page = { messages: [], hasMore: false };
|
|
317
|
+
}
|
|
318
|
+
this.sendFrame({
|
|
319
|
+
type: "history_chunk",
|
|
320
|
+
id: frame.id,
|
|
321
|
+
convId: frame.convId,
|
|
322
|
+
forWallet: frame.forWallet,
|
|
323
|
+
messages: page.messages,
|
|
324
|
+
hasMore: page.hasMore,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
sendFrame(frame) {
|
|
328
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
329
|
+
this.ws.send(JSON.stringify(frame));
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
startHeartbeat() {
|
|
335
|
+
if (this.heartbeatTimer)
|
|
336
|
+
clearInterval(this.heartbeatTimer);
|
|
337
|
+
this.heartbeatTimer = setInterval(() => {
|
|
338
|
+
if (!this.sendFrame({ type: "ping" })) {
|
|
339
|
+
// Socket gone; close() will trigger reconnect.
|
|
340
|
+
}
|
|
341
|
+
}, this.config.heartbeatIntervalMs);
|
|
342
|
+
}
|
|
343
|
+
scheduleReconnect() {
|
|
344
|
+
if (this.stopped)
|
|
345
|
+
return;
|
|
346
|
+
const delay = this.reconnectMs;
|
|
347
|
+
this.reconnectTimer = setTimeout(() => this.connect(), delay);
|
|
348
|
+
this.reconnectMs = Math.min(delay * 2, this.config.maxReconnectMs);
|
|
349
|
+
}
|
|
350
|
+
clearTimers() {
|
|
351
|
+
if (this.heartbeatTimer) {
|
|
352
|
+
clearInterval(this.heartbeatTimer);
|
|
353
|
+
this.heartbeatTimer = null;
|
|
354
|
+
}
|
|
355
|
+
if (this.reconnectTimer) {
|
|
356
|
+
clearTimeout(this.reconnectTimer);
|
|
357
|
+
this.reconnectTimer = null;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
function errMsg(err) {
|
|
362
|
+
return err instanceof Error ? err.message : String(err);
|
|
363
|
+
}
|
|
364
|
+
//# sourceMappingURL=chat-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-client.js","sourceRoot":"","sources":["../src/chat-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
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 type { ChatIdentity, ChatMessage } from "./chat-types.js";
|
|
13
|
+
export interface ConversationMetadata {
|
|
14
|
+
convId: string;
|
|
15
|
+
participants: ChatIdentity[];
|
|
16
|
+
historyHost: ChatIdentity;
|
|
17
|
+
/** ISO timestamp recorded the first time we see this conv. */
|
|
18
|
+
createdAt: string;
|
|
19
|
+
/** ISO timestamp of the most recent append. */
|
|
20
|
+
updatedAt: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ChatStoreOptions {
|
|
23
|
+
/** Defaults to ~/.perkos/conversations */
|
|
24
|
+
storeRoot?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare class ChatStore {
|
|
27
|
+
readonly root: string;
|
|
28
|
+
constructor(options?: ChatStoreOptions);
|
|
29
|
+
/** Directory for a single conversation. */
|
|
30
|
+
dirFor(convId: string): string;
|
|
31
|
+
/** Path to the JSONL log for a conv. */
|
|
32
|
+
jsonlPath(convId: string): string;
|
|
33
|
+
/** Path to the metadata file for a conv. */
|
|
34
|
+
metaPath(convId: string): string;
|
|
35
|
+
/** Ensure the conv directory exists. Idempotent. */
|
|
36
|
+
ensureDir(convId: string): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Write metadata for a conversation. Called on `channel_join` so the agent
|
|
39
|
+
* has a local record of which participants belong to a conv.
|
|
40
|
+
*/
|
|
41
|
+
writeMetadata(meta: ConversationMetadata): Promise<void>;
|
|
42
|
+
readMetadata(convId: string): Promise<ConversationMetadata | null>;
|
|
43
|
+
/**
|
|
44
|
+
* Append a message to the conversation log. The line written is exactly
|
|
45
|
+
* `JSON.stringify(msg) + "\n"`. The store does not validate ordering; if
|
|
46
|
+
* messages arrive out of timestamp order, that is recorded as-is.
|
|
47
|
+
*/
|
|
48
|
+
append(convId: string, msg: ChatMessage): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Read a history page, reverse-chronological. Returns messages with
|
|
51
|
+
* timestamp strictly less than `before` (if provided), up to `limit`.
|
|
52
|
+
*
|
|
53
|
+
* The output order is chronological ascending — i.e. callers can `concat`
|
|
54
|
+
* pages from oldest to newest without sorting.
|
|
55
|
+
*/
|
|
56
|
+
readPage(convId: string, opts: {
|
|
57
|
+
before?: string | null;
|
|
58
|
+
limit: number;
|
|
59
|
+
}): Promise<{
|
|
60
|
+
messages: ChatMessage[];
|
|
61
|
+
hasMore: boolean;
|
|
62
|
+
}>;
|
|
63
|
+
/**
|
|
64
|
+
* Produce a tamper-evident summary of the conversation log for receipt
|
|
65
|
+
* issuance. Streams `messages.jsonl` through sha256 (followed by a
|
|
66
|
+
* separator + metadata.json content if present), so memory usage stays
|
|
67
|
+
* constant regardless of conv size.
|
|
68
|
+
*
|
|
69
|
+
* The hash is deterministic: same jsonl bytes → same hex string. A
|
|
70
|
+
* downstream verifier with the jsonl can recompute and confirm.
|
|
71
|
+
*
|
|
72
|
+
* Returns counts + first/last timestamps for the receipt manifest.
|
|
73
|
+
*/
|
|
74
|
+
computeReceipt(convId: string): Promise<{
|
|
75
|
+
transcriptHash: string;
|
|
76
|
+
hashAlgo: "sha256";
|
|
77
|
+
messageCount: number;
|
|
78
|
+
firstMessageAt: string | null;
|
|
79
|
+
lastMessageAt: string | null;
|
|
80
|
+
} | null>;
|
|
81
|
+
/**
|
|
82
|
+
* Return the number of messages in the log. Useful for tests and stats.
|
|
83
|
+
* Avoid using this on the hot path — it reads the full file.
|
|
84
|
+
*/
|
|
85
|
+
count(convId: string): Promise<number>;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=chat-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-store.d.ts","sourceRoot":"","sources":["../src/chat-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAcH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEjE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,WAAW,EAAE,YAAY,CAAC;IAC1B,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAUD,qBAAa,SAAS;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,OAAO,GAAE,gBAAqB;IAI1C,2CAA2C;IAC3C,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAI9B,wCAAwC;IACxC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAIjC,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAIhC,oDAAoD;IAC9C,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C;;;OAGG;IACG,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxD,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAUxE;;;;OAIG;IACG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7D;;;;;;OAMG;IACG,QAAQ,CACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAC9C,OAAO,CAAC;QAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAkCzD;;;;;;;;;;OAUG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAC5C,cAAc,EAAE,MAAM,CAAC;QACvB,QAAQ,EAAE,QAAQ,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;KAC9B,GAAG,IAAI,CAAC;IA0ET;;;OAGG;IACG,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAe7C"}
|