@nopeek/agent-bridge 0.7.17 → 0.7.18
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/backends.js +2 -3
- package/dist/tool-progress.d.ts +4 -2
- package/dist/tool-progress.js +27 -24
- package/package.json +1 -1
package/dist/backends.js
CHANGED
|
@@ -25,8 +25,7 @@ const SOUL_TEMPLATE = `You are {{NAME}} (handle @{{HANDLE}}), a personal AI agen
|
|
|
25
25
|
NoPeek end-to-end-encrypted messenger. A human messages you in a chat; you help;
|
|
26
26
|
you reply. Everything you output is sent verbatim as a chat message.
|
|
27
27
|
|
|
28
|
-
Voice: friendly, sharp, concise. This is a chat, not a report
|
|
29
|
-
or brief lists, no markdown headers. Answer the question directly.
|
|
28
|
+
Voice: friendly, sharp, concise. This is a chat, not a report. Telegram markdown is ok (**bold**, lists, inline code, fenced copy blocks). Answer the question directly.
|
|
30
29
|
|
|
31
30
|
You have your own memory of past conversations in this chat (each chat is a
|
|
32
31
|
separate ongoing thread). Remember what the humans tell you.
|
|
@@ -293,7 +292,7 @@ you reply. Your replies are chat messages — every word you print is sent verba
|
|
|
293
292
|
|
|
294
293
|
## Voice
|
|
295
294
|
- Friendly, sharp, practical. Concise by default — this is a chat, not a report.
|
|
296
|
-
- Plain language.
|
|
295
|
+
- Plain language. Telegram markdown is ok: **bold** labels, lists, inline code, and fenced copy blocks. No # headers.
|
|
297
296
|
|
|
298
297
|
## Memory
|
|
299
298
|
- This profile is yours alone: your soul (this file) and your memories
|
package/dist/tool-progress.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export type ToolProgressEvent = {
|
|
|
7
7
|
/** One Telegram-style line. Running events only; completed is silent. */
|
|
8
8
|
export declare function formatToolLine(ev: ToolProgressEvent): string | null;
|
|
9
9
|
/** Hint so Hermes ends a tool-using turn with a recap, like Telegram. */
|
|
10
|
-
export declare const RECAP_HINT = "When this turn used tools, your LAST message must be
|
|
10
|
+
export declare const RECAP_HINT = "When this turn used tools, your LAST message must be ONE phone briefing (not split). Use **bold** labels and blank lines like Telegram: **What was wrong**, **What I did**, **Current state**. Put copyable commands in ``` fences. Never end on a tool list, a diff, or \"tasks completed\". Skip the briefing only for simple chat with no tools. No em dashes.";
|
|
11
11
|
/** Posted when tools ran but the model never wrote a human recap. */
|
|
12
12
|
export declare const MISSING_BRIEFING = "Done. I finished that work. Ask if you want the recap: what was wrong, what I did, and where things stand.";
|
|
13
13
|
export interface StreamHandle {
|
|
@@ -78,10 +78,12 @@ export declare class TurnPublisher {
|
|
|
78
78
|
/** After `bubbleGapMs` of silence, seal the current bubble. Next text is new. */
|
|
79
79
|
private armGap;
|
|
80
80
|
private enqueue;
|
|
81
|
-
/**
|
|
81
|
+
/** After tools start, hold prose until finish() so the briefing is one bubble. */
|
|
82
82
|
private appendCommentary;
|
|
83
83
|
/** Finalize the current commentary so later tools land below it. */
|
|
84
84
|
private commitText;
|
|
85
|
+
/** Final recap stays one Telegram-style bubble. Dumps still dropped. */
|
|
86
|
+
private sendBriefing;
|
|
85
87
|
private sendBubbles;
|
|
86
88
|
private addProgressLine;
|
|
87
89
|
private closeProgress;
|
package/dist/tool-progress.js
CHANGED
|
@@ -49,7 +49,7 @@ function tidyLabel(raw) {
|
|
|
49
49
|
return s.length > 80 ? `${s.slice(0, 77)}...` : s;
|
|
50
50
|
}
|
|
51
51
|
/** Hint so Hermes ends a tool-using turn with a recap, like Telegram. */
|
|
52
|
-
export const RECAP_HINT = "When this turn used tools, your LAST message must be
|
|
52
|
+
export const RECAP_HINT = "When this turn used tools, your LAST message must be ONE phone briefing (not split). Use **bold** labels and blank lines like Telegram: **What was wrong**, **What I did**, **Current state**. Put copyable commands in ``` fences. Never end on a tool list, a diff, or \"tasks completed\". Skip the briefing only for simple chat with no tools. No em dashes.";
|
|
53
53
|
/** Posted when tools ran but the model never wrote a human recap. */
|
|
54
54
|
export const MISSING_BRIEFING = "Done. I finished that work. Ask if you want the recap: what was wrong, what I did, and where things stand.";
|
|
55
55
|
/** Text in `full` that has not already been posted as commentary. */
|
|
@@ -100,6 +100,8 @@ export function isDumpLine(line) {
|
|
|
100
100
|
// Unified-diff / review lines: "+ const x =" not "+1 country".
|
|
101
101
|
if (/^[+-]\s{2,}\S/.test(l))
|
|
102
102
|
return true;
|
|
103
|
+
if (/^[+-][A-Za-z_]/.test(l))
|
|
104
|
+
return true;
|
|
103
105
|
if (/^[+-]\s*(import |from |export |const |let |function |class |def |if cmd\b|return )/.test(l))
|
|
104
106
|
return true;
|
|
105
107
|
if (/^[+-]\s*["'`{]/.test(l))
|
|
@@ -148,8 +150,6 @@ export function stripDumps(text) {
|
|
|
148
150
|
return text;
|
|
149
151
|
if (!text.includes("\n"))
|
|
150
152
|
return isDumpLine(text) ? "" : text;
|
|
151
|
-
if (isToolDump(text))
|
|
152
|
-
return "";
|
|
153
153
|
return text
|
|
154
154
|
.split("\n")
|
|
155
155
|
.filter((l) => !isDumpLine(l))
|
|
@@ -275,13 +275,16 @@ export class TurnPublisher {
|
|
|
275
275
|
if (this.seen.has(line) && this.progressLines.includes(line))
|
|
276
276
|
return;
|
|
277
277
|
this.seen.add(line);
|
|
278
|
+
const firstTool = !this.toolsUsed;
|
|
278
279
|
this.toolsUsed = true;
|
|
279
280
|
this.cancelStart();
|
|
280
281
|
this.cancelGap();
|
|
281
282
|
this.enqueue(async () => {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
283
|
+
if (firstTool) {
|
|
284
|
+
const pending = this.held;
|
|
285
|
+
this.held = "";
|
|
286
|
+
await this.commitText(pending);
|
|
287
|
+
}
|
|
285
288
|
await this.addProgressLine(line);
|
|
286
289
|
});
|
|
287
290
|
}
|
|
@@ -290,16 +293,20 @@ export class TurnPublisher {
|
|
|
290
293
|
this.cancelGap();
|
|
291
294
|
await this.write;
|
|
292
295
|
await this.closeProgress();
|
|
293
|
-
|
|
296
|
+
const pending = this.held;
|
|
294
297
|
this.held = "";
|
|
298
|
+
if (!this.toolsUsed) {
|
|
299
|
+
await this.commitText(pending);
|
|
300
|
+
}
|
|
295
301
|
const rest = unpublishedTail(reply.trim(), this.published);
|
|
296
|
-
|
|
302
|
+
const briefing = rest || (this.toolsUsed ? pending.trim() : "");
|
|
303
|
+
if (briefing) {
|
|
297
304
|
this.opts.stopTyping();
|
|
298
|
-
await this.
|
|
305
|
+
await this.sendBriefing(briefing);
|
|
299
306
|
}
|
|
300
307
|
if (this.toolsUsed && reply.trim() && !isHumanBriefing(this.published)) {
|
|
301
308
|
this.opts.stopTyping();
|
|
302
|
-
await this.
|
|
309
|
+
await this.sendBriefing(MISSING_BRIEFING);
|
|
303
310
|
}
|
|
304
311
|
if (!this.published.trim())
|
|
305
312
|
return "empty";
|
|
@@ -354,26 +361,13 @@ export class TurnPublisher {
|
|
|
354
361
|
console.error(`[turn] ${err.message}`);
|
|
355
362
|
});
|
|
356
363
|
}
|
|
357
|
-
/**
|
|
364
|
+
/** After tools start, hold prose until finish() so the briefing is one bubble. */
|
|
358
365
|
async appendCommentary(chunk) {
|
|
359
366
|
if (!chunk)
|
|
360
367
|
return;
|
|
361
368
|
if (this.toolsUsed) {
|
|
362
369
|
await this.closeProgress();
|
|
363
370
|
this.held += chunk;
|
|
364
|
-
const cut = this.held.lastIndexOf("\n\n");
|
|
365
|
-
if (cut >= 0) {
|
|
366
|
-
const ready = this.held.slice(0, cut);
|
|
367
|
-
this.held = this.held.slice(cut + 2);
|
|
368
|
-
this.opts.stopTyping();
|
|
369
|
-
await this.sendBubbles(ready);
|
|
370
|
-
}
|
|
371
|
-
else if (this.held.length >= this.maxBubbleChars) {
|
|
372
|
-
const ready = this.held;
|
|
373
|
-
this.held = "";
|
|
374
|
-
this.opts.stopTyping();
|
|
375
|
-
await this.sendBubbles(ready);
|
|
376
|
-
}
|
|
377
371
|
return;
|
|
378
372
|
}
|
|
379
373
|
this.opts.stopTyping();
|
|
@@ -442,6 +436,15 @@ export class TurnPublisher {
|
|
|
442
436
|
this.opts.stopTyping();
|
|
443
437
|
await this.sendBubbles(pending);
|
|
444
438
|
}
|
|
439
|
+
/** Final recap stays one Telegram-style bubble. Dumps still dropped. */
|
|
440
|
+
async sendBriefing(text) {
|
|
441
|
+
const cleaned = stripDumps(text.replace(/\r\n/g, "\n")).trim();
|
|
442
|
+
if (!cleaned || isToolDump(cleaned))
|
|
443
|
+
return false;
|
|
444
|
+
await this.sink.send(cleaned);
|
|
445
|
+
this.published += this.published ? `\n\n${cleaned}` : cleaned;
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
445
448
|
async sendBubbles(text) {
|
|
446
449
|
const parts = splitBubbles(text, this.maxBubbleChars);
|
|
447
450
|
if (!parts.length)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nopeek/agent-bridge",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.18",
|
|
4
4
|
"description": "Run your own agents as E2EE NoPeek bots. Pairs with one-time codes (multiple accounts per computer), runs every bot each account owns, and pipes messages to any command or webhook.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|