@nopeek/agent-bridge 0.5.5 → 0.5.6
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/bot.d.ts +5 -0
- package/dist/bot.js +28 -1
- package/dist/bridge.d.ts +1 -1
- package/dist/bridge.js +1 -1
- package/package.json +1 -1
package/dist/bot.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ export declare class BotRunner {
|
|
|
24
24
|
private allowed;
|
|
25
25
|
private accessLoaded;
|
|
26
26
|
private declined;
|
|
27
|
+
private chains;
|
|
28
|
+
private cantPost;
|
|
27
29
|
private log;
|
|
28
30
|
private logErr;
|
|
29
31
|
constructor(info: BotInfo, cfg: BridgeConfig);
|
|
@@ -50,4 +52,7 @@ export declare class BotRunner {
|
|
|
50
52
|
/** Bounded dedupe so a redelivered frame is never answered twice. */
|
|
51
53
|
private remember;
|
|
52
54
|
private handleMessage;
|
|
55
|
+
/** A FORBIDDEN post (broadcast channel, bot not an operator) fails for every
|
|
56
|
+
* future message too — mute the channel so the brain stops running there. */
|
|
57
|
+
private notePostFailure;
|
|
53
58
|
}
|
package/dist/bot.js
CHANGED
|
@@ -28,6 +28,13 @@ export class BotRunner {
|
|
|
28
28
|
allowed = new Set();
|
|
29
29
|
accessLoaded = false;
|
|
30
30
|
declined = new Set(); // (senderId) already told "not authorized" once
|
|
31
|
+
// Per-channel serialization: two messages in one channel must be answered in
|
|
32
|
+
// order, one at a time — concurrent brain runs against the same agent session
|
|
33
|
+
// (e.g. one Hermes session per channel) deadlock or reply out of order.
|
|
34
|
+
chains = new Map();
|
|
35
|
+
// Channels the bot can't post to (e.g. broadcast, non-operator): after the
|
|
36
|
+
// first FORBIDDEN, skip the brain entirely — replies there can never land.
|
|
37
|
+
cantPost = new Set();
|
|
31
38
|
log;
|
|
32
39
|
logErr;
|
|
33
40
|
constructor(info, cfg) {
|
|
@@ -153,8 +160,15 @@ export class BotRunner {
|
|
|
153
160
|
this.log(`received channel key for ${p.channelId} (welcome ceremony completed)`);
|
|
154
161
|
}));
|
|
155
162
|
np.on("message", ((m) => {
|
|
156
|
-
|
|
163
|
+
const prev = this.chains.get(m.channelId) ?? Promise.resolve();
|
|
164
|
+
const next = prev.then(() => this.handleMessage(m).catch((err) => {
|
|
165
|
+
this.notePostFailure(m.channelId, err);
|
|
157
166
|
this.logErr(`handler error for ${m.messageId}: ${err.message}`);
|
|
167
|
+
}));
|
|
168
|
+
this.chains.set(m.channelId, next);
|
|
169
|
+
void next.finally(() => {
|
|
170
|
+
if (this.chains.get(m.channelId) === next)
|
|
171
|
+
this.chains.delete(m.channelId);
|
|
158
172
|
});
|
|
159
173
|
}));
|
|
160
174
|
await this.refreshAccess(); // load the allow list before we answer anyone
|
|
@@ -216,6 +230,8 @@ export class BotRunner {
|
|
|
216
230
|
this.remember(m.messageId);
|
|
217
231
|
if (m.senderUserId === this.info.userId)
|
|
218
232
|
return; // never answer ourselves
|
|
233
|
+
if (this.cantPost.has(m.channelId))
|
|
234
|
+
return; // replies can't land here — don't burn a brain run
|
|
219
235
|
if (m.decryptionFailed) {
|
|
220
236
|
// Likely a missed welcome (message arrived before our key). Sync the key
|
|
221
237
|
// so the NEXT message decrypts; this frame's plaintext is unrecoverable.
|
|
@@ -278,6 +294,7 @@ export class BotRunner {
|
|
|
278
294
|
}
|
|
279
295
|
streamRef.p = ch.stream();
|
|
280
296
|
streamRef.p.catch((err) => {
|
|
297
|
+
this.notePostFailure(m.channelId, err);
|
|
281
298
|
this.logErr(`stream open failed (falling back to a single send): ${err.message}`);
|
|
282
299
|
});
|
|
283
300
|
}
|
|
@@ -323,4 +340,14 @@ export class BotRunner {
|
|
|
323
340
|
this.handled++;
|
|
324
341
|
this.log(`${m.channelId} -> replied (${reply.trim().length} chars, handled=${this.handled})`);
|
|
325
342
|
}
|
|
343
|
+
/** A FORBIDDEN post (broadcast channel, bot not an operator) fails for every
|
|
344
|
+
* future message too — mute the channel so the brain stops running there. */
|
|
345
|
+
notePostFailure(channelId, err) {
|
|
346
|
+
if (!/only operators can post|FORBIDDEN/i.test(err.message))
|
|
347
|
+
return;
|
|
348
|
+
if (this.cantPost.has(channelId))
|
|
349
|
+
return;
|
|
350
|
+
this.cantPost.add(channelId);
|
|
351
|
+
this.log(`muting ${channelId} — bot cannot post here (${err.message.slice(0, 80)})`);
|
|
352
|
+
}
|
|
326
353
|
}
|
package/dist/bridge.d.ts
CHANGED
package/dist/bridge.js
CHANGED
|
@@ -14,7 +14,7 @@ import { resolveBrain } from "./brain.js";
|
|
|
14
14
|
import { provisionSoul, provisionHermesProfile } from "./backends.js";
|
|
15
15
|
import { reportCapabilities } from "./capabilities.js";
|
|
16
16
|
import { isBrainBackend } from "./config.js";
|
|
17
|
-
export const VERSION = "0.5.
|
|
17
|
+
export const VERSION = "0.5.6";
|
|
18
18
|
/** How often to re-probe + report brain availability to the server. */
|
|
19
19
|
const CAPABILITIES_INTERVAL_MS = 5 * 60_000;
|
|
20
20
|
export class PairError extends Error {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nopeek/agent-bridge",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
4
4
|
"description": "Run your own agents as E2EE NoPeek bots. Pairs with a one-time code, runs every bot you own, and pipes messages to any command or webhook.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|