salt-agent-sdk 0.1.0
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 +282 -0
- package/dist/actions.d.ts +72 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +706 -0
- package/dist/actions.js.map +1 -0
- package/dist/client.d.ts +141 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +188 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +40 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +61 -0
- package/dist/config.js.map +1 -0
- package/dist/crypto.d.ts +46 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +124 -0
- package/dist/crypto.js.map +1 -0
- package/dist/delegations.d.ts +58 -0
- package/dist/delegations.d.ts.map +1 -0
- package/dist/delegations.js +140 -0
- package/dist/delegations.js.map +1 -0
- package/dist/identities.d.ts +25 -0
- package/dist/identities.d.ts.map +1 -0
- package/dist/identities.js +107 -0
- package/dist/identities.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/webhook.d.ts +127 -0
- package/dist/webhook.d.ts.map +1 -0
- package/dist/webhook.js +470 -0
- package/dist/webhook.js.map +1 -0
- package/package.json +29 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"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"}
|
package/dist/webhook.js
ADDED
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// The webhook server: receives salt-api's callbacks, decides WHETHER and to
|
|
3
|
+
// WHOM a reply is owed (dedup, GACM silence, mediator observe-gating,
|
|
4
|
+
// agent-to-agent loop capping, delegation-reply short-circuiting, identity
|
|
5
|
+
// resolution by trial-decryption), and hands off a clean, already-decrypted
|
|
6
|
+
// context to the consumer's callback for the one decision that's actually
|
|
7
|
+
// theirs: WHAT to say. Everything about the Salt protocol mechanics stays
|
|
8
|
+
// here; nothing about any particular model/agent-loop does.
|
|
9
|
+
//
|
|
10
|
+
// Extracted from salt-claude-agent/src/index.js, which mixed both concerns
|
|
11
|
+
// together. Prompt-string construction (hand-off mode notes, mediator
|
|
12
|
+
// coaching prefixes, card-interaction/invoice-paid instructions) is
|
|
13
|
+
// deliberately NOT here -- that's reference-implementation territory built
|
|
14
|
+
// on top of this module, since it's specific to how one particular model
|
|
15
|
+
// wants a situation framed.
|
|
16
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
19
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
20
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
21
|
+
}
|
|
22
|
+
Object.defineProperty(o, k2, desc);
|
|
23
|
+
}) : (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
o[k2] = m[k];
|
|
26
|
+
}));
|
|
27
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
28
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
29
|
+
}) : function(o, v) {
|
|
30
|
+
o["default"] = v;
|
|
31
|
+
});
|
|
32
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
33
|
+
var ownKeys = function(o) {
|
|
34
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
35
|
+
var ar = [];
|
|
36
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
37
|
+
return ar;
|
|
38
|
+
};
|
|
39
|
+
return ownKeys(o);
|
|
40
|
+
};
|
|
41
|
+
return function (mod) {
|
|
42
|
+
if (mod && mod.__esModule) return mod;
|
|
43
|
+
var result = {};
|
|
44
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
45
|
+
__setModuleDefault(result, mod);
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
})();
|
|
49
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
50
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
51
|
+
};
|
|
52
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
+
exports.HANDOFF_BRIEFING_MARKER = void 0;
|
|
54
|
+
exports.createWebhookServer = createWebhookServer;
|
|
55
|
+
const express_1 = __importDefault(require("express"));
|
|
56
|
+
const pgp = __importStar(require("./crypto"));
|
|
57
|
+
const delegations = __importStar(require("./delegations"));
|
|
58
|
+
const PGP_MESSAGE_RE = /^-----BEGIN PGP MESSAGE/;
|
|
59
|
+
/** The exact marker a hand-off briefing must start with, so the incoming
|
|
60
|
+
* agent's polling loop (below) can detect it arrived. Consumers building
|
|
61
|
+
* the outgoing briefing prompt must instruct their model to emit this
|
|
62
|
+
* exact line first. */
|
|
63
|
+
exports.HANDOFF_BRIEFING_MARKER = "[[SALT-HANDOFF-BRIEFING]]";
|
|
64
|
+
const consoleLogger = {
|
|
65
|
+
info: (msg) => console.log(msg),
|
|
66
|
+
error: (msg) => console.error(msg),
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Creates the Express app for a Salt agent's webhook endpoint. Mount it
|
|
70
|
+
* yourself (e.g. `createWebhookServer(opts).listen(port)`, or grab `.app`
|
|
71
|
+
* to compose it into a bigger server).
|
|
72
|
+
*/
|
|
73
|
+
function createWebhookServer(options) {
|
|
74
|
+
const { client, identities, pgpPassphrase, webhookSharedSecret, mediatorAgentId } = options;
|
|
75
|
+
const logger = options.logger ?? consoleLogger;
|
|
76
|
+
const app = (0, express_1.default)();
|
|
77
|
+
app.use(express_1.default.json());
|
|
78
|
+
// Salt fires one webhook per chat member with a callback URL
|
|
79
|
+
// (Message#send_webhook in salt-api). When two or more identities THIS
|
|
80
|
+
// process hosts share a chat -- which delegation makes possible -- that's
|
|
81
|
+
// multiple deliveries of the SAME message to this SAME endpoint. Only one
|
|
82
|
+
// delivery can ever actually decrypt (the recipient's key), so without
|
|
83
|
+
// this guard that single message gets fully reprocessed once per
|
|
84
|
+
// redundant delivery, including racing past the delegations registry.
|
|
85
|
+
const MAX_SEEN_MESSAGE_IDS = 2000;
|
|
86
|
+
const seenMessageIds = new Set();
|
|
87
|
+
function alreadyProcessed(messageId) {
|
|
88
|
+
if (messageId == null)
|
|
89
|
+
return false;
|
|
90
|
+
if (seenMessageIds.has(messageId))
|
|
91
|
+
return true;
|
|
92
|
+
seenMessageIds.add(messageId);
|
|
93
|
+
if (seenMessageIds.size > MAX_SEEN_MESSAGE_IDS) {
|
|
94
|
+
const oldest = seenMessageIds.values().next().value;
|
|
95
|
+
if (oldest !== undefined)
|
|
96
|
+
seenMessageIds.delete(oldest);
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
// A second, independent safety net beyond delegations.ts's depth limit --
|
|
101
|
+
// that only bounds explicit delegate-call recursion, not two hosted
|
|
102
|
+
// agents just organically replying to each other's plain messages once a
|
|
103
|
+
// conversation starts. Cap it hard: once a chat between two identities
|
|
104
|
+
// THIS process hosts crosses this many auto-replies, the receiving
|
|
105
|
+
// identity just stops answering the other one there, until a human sends
|
|
106
|
+
// something new (which resets the count).
|
|
107
|
+
const MAX_AGENT_TO_AGENT_REPLIES_PER_CHAT = 2;
|
|
108
|
+
const agentToAgentReplyCounts = new Map();
|
|
109
|
+
app.get("/health", (_req, res) => {
|
|
110
|
+
res.json({
|
|
111
|
+
status: "ok",
|
|
112
|
+
identities: identities.all().map((i) => ({ salt_app_id: i.saltAppId, username: i.username })),
|
|
113
|
+
...(options.healthExtra ? options.healthExtra() : {}),
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
// Every identity this process hosts shares this one endpoint, so the
|
|
117
|
+
// first step is figuring out *which* identity a given message is
|
|
118
|
+
// addressed to. Salt encrypts the message to every chat member's public
|
|
119
|
+
// key as a single multi-recipient PGP blob -- it only decrypts with a
|
|
120
|
+
// private key that was actually a member of that chat, so trying each
|
|
121
|
+
// known identity in turn and keeping whichever one succeeds is both
|
|
122
|
+
// correct and cheap for the small number of identities a process hosts.
|
|
123
|
+
async function resolveIdentity(ciphertext) {
|
|
124
|
+
for (const candidate of identities.all()) {
|
|
125
|
+
try {
|
|
126
|
+
const plaintext = await pgp.decrypt(ciphertext, candidate.privateKey, pgpPassphrase);
|
|
127
|
+
return { identity: candidate, plaintext };
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Not addressed to this identity -- try the next one.
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
// Fetches + decrypts a chat's recent messages with `identity`'s own key.
|
|
136
|
+
// Correct for any genuine member (including a silent observer): every
|
|
137
|
+
// message posted since joining was multi-recipient-encrypted to include
|
|
138
|
+
// that key. Messages from before joining simply fail to decrypt and are
|
|
139
|
+
// skipped -- the same degrade-gracefully convention Salt's own clients use.
|
|
140
|
+
async function buildSharedChatContext(identity, sharedChatId) {
|
|
141
|
+
let messages;
|
|
142
|
+
try {
|
|
143
|
+
messages = await client.getChatMessages(identity.apiKey, sharedChatId);
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
logger.error(`[shared-context] fetching chat ${sharedChatId} failed: ${err.message}`);
|
|
147
|
+
return "(couldn't load the conversation)";
|
|
148
|
+
}
|
|
149
|
+
const lines = [];
|
|
150
|
+
for (const raw of messages) {
|
|
151
|
+
const m = raw;
|
|
152
|
+
if (m.event_type || typeof m.message !== "string" || !PGP_MESSAGE_RE.test(m.message))
|
|
153
|
+
continue;
|
|
154
|
+
try {
|
|
155
|
+
const text = await pgp.decrypt(m.message, identity.privateKey, pgpPassphrase);
|
|
156
|
+
lines.push(`${m.user?.display_name || "someone"}: ${text}`);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// Predates this identity joining the chat -- skip silently.
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return lines.length ? lines.join("\n") : "(no messages yet)";
|
|
163
|
+
}
|
|
164
|
+
// Decrypts an attachment's PGP metadata blob (key/iv/filename/content_type),
|
|
165
|
+
// downloads the ciphertext, and AES-GCM-decrypts it. Only images are
|
|
166
|
+
// returned with actual bytes -- the SDK doesn't know how any given model
|
|
167
|
+
// wants other file types represented, so those get a text note instead.
|
|
168
|
+
async function decryptAttachmentIfPresent(identity, message) {
|
|
169
|
+
if (!message.resource?.encrypted_key)
|
|
170
|
+
return undefined;
|
|
171
|
+
try {
|
|
172
|
+
const metaJson = await pgp.decrypt(message.resource.encrypted_key, identity.privateKey, pgpPassphrase);
|
|
173
|
+
const meta = JSON.parse(metaJson);
|
|
174
|
+
if (!meta.content_type?.startsWith("image/")) {
|
|
175
|
+
return {
|
|
176
|
+
filename: meta.filename,
|
|
177
|
+
contentType: meta.content_type || "unknown",
|
|
178
|
+
size: meta.size,
|
|
179
|
+
unsupportedNote: `attached file: ${meta.filename}, ${meta.content_type || "unknown type"}, ${meta.size} bytes -- not viewable, only images are.`,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
const ciphertextBytes = await client.getAttachment(identity.apiKey, message.message_id);
|
|
183
|
+
const plaintext = pgp.decryptAttachment(ciphertextBytes, meta.key, meta.iv);
|
|
184
|
+
return { filename: meta.filename, contentType: meta.content_type, size: meta.size, data: plaintext };
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
logger.error(`[attachment] failed to decrypt: ${err.message}`);
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Pings the typing indicator for the duration of `fn` -- callers wrap the
|
|
192
|
+
// WHOLE "decide what to say, then say it" arc with this (not just the
|
|
193
|
+
// final post), since that first part (asking a model) is almost always
|
|
194
|
+
// the slow one and is exactly when a human benefits from seeing
|
|
195
|
+
// "X is typing...". Rides the existing ephemeral typing channel
|
|
196
|
+
// (content-free, receivers self-expire after ~4s) on the same 2.5s
|
|
197
|
+
// cadence the human composer uses.
|
|
198
|
+
async function withTypingHeartbeat(identity, chatId, fn) {
|
|
199
|
+
void client.signalTyping(identity.apiKey, chatId);
|
|
200
|
+
const timer = setInterval(() => void client.signalTyping(identity.apiKey, chatId), 2500);
|
|
201
|
+
try {
|
|
202
|
+
return await fn();
|
|
203
|
+
}
|
|
204
|
+
finally {
|
|
205
|
+
clearInterval(timer);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Builds the reply() closure shared by every context type:
|
|
209
|
+
// encrypt-for-every-recipient + post + drain this reply's delegation
|
|
210
|
+
// trail onto it + fire-and-forget metrics. Does NOT itself manage the
|
|
211
|
+
// typing indicator -- see withTypingHeartbeat, which wraps the whole
|
|
212
|
+
// callback (including whatever happens before reply() is even called).
|
|
213
|
+
function makeReply(identity, chatId) {
|
|
214
|
+
return async (text) => {
|
|
215
|
+
const startedAt = Date.now();
|
|
216
|
+
let recipientKeys;
|
|
217
|
+
try {
|
|
218
|
+
const members = await client.getChatMembers(identity.apiKey, chatId);
|
|
219
|
+
recipientKeys = members
|
|
220
|
+
.filter((u) => parseInt(String(u.id), 10) !== identity.saltAppId && u.public_key)
|
|
221
|
+
.map((u) => u.public_key);
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
logger.error(`[chat ${chatId}] fetching members failed: ${err.message}`);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (recipientKeys.length === 0) {
|
|
228
|
+
logger.error(`[chat ${chatId}] no recipient public keys; not sending.`);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
let encryptedMessage, senderMessage;
|
|
232
|
+
try {
|
|
233
|
+
encryptedMessage = await pgp.encryptFor(text, recipientKeys);
|
|
234
|
+
senderMessage = await pgp.encryptFor(text, [identity.publicKey]);
|
|
235
|
+
}
|
|
236
|
+
catch (err) {
|
|
237
|
+
logger.error(`[chat ${chatId}] encryption failed: ${err.message}`);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const trail = delegations.drainTrail(identity.saltAppId, chatId);
|
|
241
|
+
try {
|
|
242
|
+
await client.postMessage(identity.apiKey, chatId, encryptedMessage, senderMessage, trail);
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
logger.error(`[chat ${chatId}] posting reply failed: ${err.message}`);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
client.trackEvent(identity.apiKey, "agent_reply_sent", {
|
|
249
|
+
chat_id: chatId,
|
|
250
|
+
latency_ms: Date.now() - startedAt,
|
|
251
|
+
delegation_count: (trail || []).length,
|
|
252
|
+
});
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
async function handleMessage(body) {
|
|
256
|
+
const message = body.message;
|
|
257
|
+
const chatId = message.chat_id;
|
|
258
|
+
const chatMeta = body.chat;
|
|
259
|
+
if (alreadyProcessed(message.message_id))
|
|
260
|
+
return;
|
|
261
|
+
if (message.event_type)
|
|
262
|
+
return; // system events aren't prompts
|
|
263
|
+
const ciphertext = message.message;
|
|
264
|
+
if (typeof ciphertext !== "string" || !PGP_MESSAGE_RE.test(ciphertext))
|
|
265
|
+
return;
|
|
266
|
+
const resolved = await resolveIdentity(ciphertext);
|
|
267
|
+
if (!resolved) {
|
|
268
|
+
logger.error(`[chat ${chatId}] no known identity could decrypt this message; ignoring.`);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
let { identity, plaintext: caption } = resolved;
|
|
272
|
+
// GACM routing fix: salt-api sends one webhook delivery PER agent
|
|
273
|
+
// member, but they all land on this shared server and message-id dedup
|
|
274
|
+
// collapses them into a single pass -- whose decrypt-resolved identity
|
|
275
|
+
// is arbitrary (any member key opens a multi-recipient blob). When the
|
|
276
|
+
// chat declares an active agent that's hosted here, hand this pass to
|
|
277
|
+
// THAT identity; the plaintext is identical under any key, only "who
|
|
278
|
+
// replies" changes.
|
|
279
|
+
if (chatMeta?.active_agent_id) {
|
|
280
|
+
const active = identities.get(parseInt(String(chatMeta.active_agent_id), 10));
|
|
281
|
+
if (active)
|
|
282
|
+
identity = active;
|
|
283
|
+
}
|
|
284
|
+
const senderRaw = message.user;
|
|
285
|
+
const senderId = senderRaw ? parseInt(String(senderRaw.id), 10) : NaN;
|
|
286
|
+
// Reply to a pending delegation call? Hand it to that waiting promise
|
|
287
|
+
// instead of starting a fresh reply cycle -- see delegations.ts.
|
|
288
|
+
if (delegations.resolveIfPending(chatId, senderId, caption))
|
|
289
|
+
return;
|
|
290
|
+
// Never reply to our own messages (the reply we post is itself
|
|
291
|
+
// delivered back to us as a webhook) -- this is what prevents an
|
|
292
|
+
// infinite loop.
|
|
293
|
+
if (senderId === identity.saltAppId)
|
|
294
|
+
return;
|
|
295
|
+
// Mediated Chat: this identity is the configured Mediator, and this
|
|
296
|
+
// message is in the SHARED chat it silently observes -- present for
|
|
297
|
+
// context, but it only actually speaks in each human's own private
|
|
298
|
+
// coaching chat (coaching_for_chat_id pointing back at this one).
|
|
299
|
+
const isMediator = !!mediatorAgentId && identity.saltAppId === mediatorAgentId;
|
|
300
|
+
if (isMediator && chatMeta?.mediator_agent_id && !chatMeta.coaching_for_chat_id)
|
|
301
|
+
return;
|
|
302
|
+
// Global Agent Chat Mode: when the chat declares an active agent and
|
|
303
|
+
// it isn't this identity, stay silent. Lets retired/handed-off-from
|
|
304
|
+
// agents remain in the room without ever double-replying.
|
|
305
|
+
if (chatMeta?.active_agent_id && String(chatMeta.active_agent_id) !== String(identity.saltAppId))
|
|
306
|
+
return;
|
|
307
|
+
// A human sender always resets the count -- only agent-to-agent
|
|
308
|
+
// volleys are capped, never a real conversation with a person.
|
|
309
|
+
const senderIsAgent = !!identities.get(senderId) || senderRaw?.account_type === "Agent";
|
|
310
|
+
if (senderIsAgent) {
|
|
311
|
+
const count = (agentToAgentReplyCounts.get(chatId) || 0) + 1;
|
|
312
|
+
agentToAgentReplyCounts.set(chatId, count);
|
|
313
|
+
if (count > MAX_AGENT_TO_AGENT_REPLIES_PER_CHAT) {
|
|
314
|
+
logger.error(`[chat ${chatId}] agent-to-agent reply cap reached; not auto-replying to ${senderId} again.`);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
agentToAgentReplyCounts.delete(chatId);
|
|
320
|
+
}
|
|
321
|
+
const { depth, text: strippedCaption } = delegations.parseIncoming(caption);
|
|
322
|
+
let mediatorSharedContext;
|
|
323
|
+
let attachment;
|
|
324
|
+
if (isMediator && chatMeta?.coaching_for_chat_id) {
|
|
325
|
+
mediatorSharedContext = await buildSharedChatContext(identity, chatMeta.coaching_for_chat_id);
|
|
326
|
+
}
|
|
327
|
+
else if (message.resource_type === "Attachment") {
|
|
328
|
+
attachment = await decryptAttachmentIfPresent(identity, message);
|
|
329
|
+
}
|
|
330
|
+
if (!options.onMessage)
|
|
331
|
+
return;
|
|
332
|
+
const ctx = {
|
|
333
|
+
identity,
|
|
334
|
+
chatId,
|
|
335
|
+
senderId,
|
|
336
|
+
sender: senderRaw,
|
|
337
|
+
text: strippedCaption,
|
|
338
|
+
delegationDepth: depth,
|
|
339
|
+
chatMeta,
|
|
340
|
+
mediatorSharedContext,
|
|
341
|
+
attachment,
|
|
342
|
+
reply: makeReply(identity, chatId),
|
|
343
|
+
};
|
|
344
|
+
try {
|
|
345
|
+
await withTypingHeartbeat(identity, chatId, () => Promise.resolve(options.onMessage(ctx)));
|
|
346
|
+
}
|
|
347
|
+
catch (err) {
|
|
348
|
+
logger.error(`[chat ${chatId}] onMessage failed: ${err.message}`);
|
|
349
|
+
// Discard any trail entries a partial run recorded -- there's no
|
|
350
|
+
// reply for them to ride on, and they must not leak onto the next one.
|
|
351
|
+
delegations.drainTrail(identity.saltAppId, chatId);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
async function handleCardInteraction(body) {
|
|
355
|
+
const identity = identities.get(parseInt(String(body.owner_id), 10));
|
|
356
|
+
if (!identity || !options.onCardInteraction)
|
|
357
|
+
return;
|
|
358
|
+
try {
|
|
359
|
+
await options.onCardInteraction({
|
|
360
|
+
identity,
|
|
361
|
+
chatId: body.chat_id,
|
|
362
|
+
cardId: body.card_id,
|
|
363
|
+
actionId: body.action_id,
|
|
364
|
+
user: body.user,
|
|
365
|
+
blocks: body.state?.blocks,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
catch (err) {
|
|
369
|
+
logger.error(`[chat ${body.chat_id}] onCardInteraction failed: ${err.message}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
async function handleInvoicePaid(body) {
|
|
373
|
+
const identity = identities.get(parseInt(String(body.seller_id), 10));
|
|
374
|
+
if (!identity || !body.chat_id || !options.onInvoicePaid)
|
|
375
|
+
return;
|
|
376
|
+
const chatId = body.chat_id;
|
|
377
|
+
const ctx = {
|
|
378
|
+
identity,
|
|
379
|
+
chatId,
|
|
380
|
+
buyer: body.buyer,
|
|
381
|
+
lineItems: body.line_items || [],
|
|
382
|
+
amount: body.amount,
|
|
383
|
+
isTopUp: !!body.billing_account_id,
|
|
384
|
+
transferRequestId: body.transfer_request_id,
|
|
385
|
+
reply: makeReply(identity, chatId),
|
|
386
|
+
};
|
|
387
|
+
try {
|
|
388
|
+
await withTypingHeartbeat(identity, chatId, () => Promise.resolve(options.onInvoicePaid(ctx)));
|
|
389
|
+
}
|
|
390
|
+
catch (err) {
|
|
391
|
+
logger.error(`[chat ${chatId}] onInvoicePaid failed: ${err.message}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
async function handleHandoffConfirmed(body) {
|
|
395
|
+
const identity = identities.get(parseInt(String(body.from_agent_id), 10));
|
|
396
|
+
if (!identity || !options.onHandoffConfirmed)
|
|
397
|
+
return;
|
|
398
|
+
const chatId = body.chat_id;
|
|
399
|
+
const ctx = { identity, chatId, reason: body.reason, reply: makeReply(identity, chatId) };
|
|
400
|
+
try {
|
|
401
|
+
await withTypingHeartbeat(identity, chatId, () => Promise.resolve(options.onHandoffConfirmed(ctx)));
|
|
402
|
+
}
|
|
403
|
+
catch (err) {
|
|
404
|
+
logger.error(`[chat ${chatId}] onHandoffConfirmed failed: ${err.message}`);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
async function handleHandoffReceived(body) {
|
|
408
|
+
const identity = identities.get(parseInt(String(body.to_agent_id), 10));
|
|
409
|
+
if (!identity || !options.onHandoffReceived)
|
|
410
|
+
return;
|
|
411
|
+
const chatId = body.chat_id;
|
|
412
|
+
// handoff_confirmed and handoff_received fire at the same moment, but
|
|
413
|
+
// the outgoing agent still has to COMPOSE its briefing -- introduce too
|
|
414
|
+
// fast and there's nothing to ground it in yet. Poll until the
|
|
415
|
+
// HANDOFF_BRIEFING_MARKER shows up (or ~20s passes, e.g. the outgoing
|
|
416
|
+
// agent isn't hosted anywhere reachable / errored).
|
|
417
|
+
let context = "";
|
|
418
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
419
|
+
context = await buildSharedChatContext(identity, chatId);
|
|
420
|
+
if (context.includes(exports.HANDOFF_BRIEFING_MARKER))
|
|
421
|
+
break;
|
|
422
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
423
|
+
}
|
|
424
|
+
const ctx = { identity, chatId, reason: body.reason, context, reply: makeReply(identity, chatId) };
|
|
425
|
+
try {
|
|
426
|
+
await withTypingHeartbeat(identity, chatId, () => Promise.resolve(options.onHandoffReceived(ctx)));
|
|
427
|
+
}
|
|
428
|
+
catch (err) {
|
|
429
|
+
logger.error(`[chat ${chatId}] onHandoffReceived failed: ${err.message}`);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async function dispatch(body) {
|
|
433
|
+
if (body?.type === "card_interaction")
|
|
434
|
+
return handleCardInteraction(body);
|
|
435
|
+
if (body?.type === "invoice_paid")
|
|
436
|
+
return handleInvoicePaid(body);
|
|
437
|
+
if (body?.type === "handoff_confirmed")
|
|
438
|
+
return handleHandoffConfirmed(body);
|
|
439
|
+
if (body?.type === "handoff_received")
|
|
440
|
+
return handleHandoffReceived(body);
|
|
441
|
+
if (body?.message)
|
|
442
|
+
return handleMessage(body);
|
|
443
|
+
}
|
|
444
|
+
// salt-api's WebhookJob POSTs here with { chat, message } (or a typed
|
|
445
|
+
// event body for card/invoice/handoff). Ack immediately (200) and process
|
|
446
|
+
// in the background so a slow agent-loop call can't make Salt's webhook
|
|
447
|
+
// delivery time out.
|
|
448
|
+
//
|
|
449
|
+
// WEBHOOK_SHARED_SECRET: when this server is publicly reachable, anyone
|
|
450
|
+
// can POST here. Encrypted-message webhooks fail safe (forged ciphertext
|
|
451
|
+
// never decrypts), but card_interaction/invoice_paid payloads are
|
|
452
|
+
// PLAINTEXT and would be acted on -- so when the secret is configured
|
|
453
|
+
// (production), every POST must carry the matching header salt-api's
|
|
454
|
+
// jobs send. Unset (local dev), the check is skipped entirely.
|
|
455
|
+
app.post("/", (req, res) => {
|
|
456
|
+
if (webhookSharedSecret && req.get("X-Salt-Webhook-Secret") !== webhookSharedSecret) {
|
|
457
|
+
res.status(401).json({ error: "invalid webhook secret" });
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
res.status(200).json({ status: "accepted" });
|
|
461
|
+
dispatch(req.body).catch((err) => logger.error(`[webhook] unhandled error: ${err.message}`));
|
|
462
|
+
});
|
|
463
|
+
return {
|
|
464
|
+
app,
|
|
465
|
+
listen(port) {
|
|
466
|
+
app.listen(port, () => logger.info(`salt-agent-sdk webhook server listening on :${port}`));
|
|
467
|
+
},
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "salt-agent-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Plumbing for building Salt (saltfor.com) agents: webhook receiving/routing, PGP encrypt/decrypt, a typed REST client, and card builders. Bring your own agent logic -- this handles everything Salt-protocol-specific.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=18"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc -p tsconfig.json",
|
|
16
|
+
"dev": "tsc -p tsconfig.json --watch",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"ethers": "^6.13.0",
|
|
21
|
+
"express": "^4.19.0",
|
|
22
|
+
"openpgp": "^5.11.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/express": "^4.17.21",
|
|
26
|
+
"@types/node": "^20.14.0",
|
|
27
|
+
"typescript": "^5.5.0"
|
|
28
|
+
}
|
|
29
|
+
}
|