blun-king-cli 9.1.405 → 9.1.407
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/LIESMICH.txt
CHANGED
|
@@ -404,6 +404,28 @@ Bei identischem Inhalt bleiben Dateidentität und Änderungszeit erhalten; die
|
|
|
404
404
|
Prüfung und Härtung der privaten Dateirechte läuft trotzdem weiter. Echte
|
|
405
405
|
Änderungen verwenden unverändert den crash-sicheren atomaren Schreibweg.
|
|
406
406
|
|
|
407
|
+
Verlässliche Beziehungskontinuität
|
|
408
|
+
----------------------------------
|
|
409
|
+
|
|
410
|
+
Ab BLUN King 9.1.406 wird ein erneut zugestelltes privates Telegram-Ereignis
|
|
411
|
+
mit demselben Zeitstempel und Text nur einmal gespeichert. Eine tatsächlich
|
|
412
|
+
später wiederholte Aussage bleibt dagegen Teil des Verlaufs.
|
|
413
|
+
|
|
414
|
+
Natürliche ausdrückliche Hinweise wie „Dieter ist dein Boss, bitte merken“
|
|
415
|
+
werden auch dann erkannt, wenn die Bitte um Erinnerung am Ende steht. Sie
|
|
416
|
+
gelangen als Referenzdaten in einen begrenzten, nur ergänzbaren
|
|
417
|
+
Beziehungskontext. Sie erteilen oder ändern niemals Berechtigungen;
|
|
418
|
+
Gruppeninhalte, Geheimnisse und Zugriffsaussagen bleiben ausgeschlossen.
|
|
419
|
+
|
|
420
|
+
Stabiler Telegram-Reply-Weg
|
|
421
|
+
--------------------------
|
|
422
|
+
|
|
423
|
+
Ab BLUN King 9.1.407 kann der Duplikatschutz des Telegram-Reply-Werkzeugs das
|
|
424
|
+
aktuelle Eingangsprotokoll wieder direkt lesen. Normale Antworten scheitern
|
|
425
|
+
dadurch nicht mehr an einem fehlenden Laufzeitimport; der getrennte
|
|
426
|
+
Bridge-Fallback bleibt nur die Absicherung und nicht der unbeabsichtigte
|
|
427
|
+
Hauptweg.
|
|
428
|
+
|
|
407
429
|
Der eigentliche Anhang und die vollständige Nutzernachricht bleiben für den Zug
|
|
408
430
|
unverändert verfügbar. Die Begrenzung betrifft ausschließlich die kleine
|
|
409
431
|
lexikalische Vorauswahl von höchstens zwei Werkzeugschemas; ToolSearch und alle
|
package/README.md
CHANGED
|
@@ -412,6 +412,26 @@ Bei identischem Inhalt bleiben Dateidentität und Änderungszeit erhalten; die
|
|
|
412
412
|
Prüfung und Härtung der privaten Dateirechte läuft trotzdem weiter. Echte
|
|
413
413
|
Änderungen verwenden unverändert den crash-sicheren atomaren Schreibweg.
|
|
414
414
|
|
|
415
|
+
## Verlässliche Beziehungskontinuität
|
|
416
|
+
|
|
417
|
+
Ab BLUN King 9.1.406 wird ein erneut zugestelltes privates Telegram-Ereignis
|
|
418
|
+
mit demselben Zeitstempel und Text nur einmal gespeichert. Eine tatsächlich
|
|
419
|
+
später wiederholte Aussage bleibt dagegen Teil des Verlaufs.
|
|
420
|
+
|
|
421
|
+
Natürliche ausdrückliche Hinweise wie „Dieter ist dein Boss, bitte merken“
|
|
422
|
+
werden auch dann erkannt, wenn die Bitte um Erinnerung am Ende steht. Sie
|
|
423
|
+
gelangen als Referenzdaten in einen begrenzten, nur ergänzbaren
|
|
424
|
+
Beziehungskontext. Sie erteilen oder ändern niemals Berechtigungen;
|
|
425
|
+
Gruppeninhalte, Geheimnisse und Zugriffsaussagen bleiben ausgeschlossen.
|
|
426
|
+
|
|
427
|
+
## Stabiler Telegram-Reply-Weg
|
|
428
|
+
|
|
429
|
+
Ab BLUN King 9.1.407 kann der Duplikatschutz des Telegram-Reply-Werkzeugs das
|
|
430
|
+
aktuelle Eingangsprotokoll wieder direkt lesen. Normale Antworten scheitern
|
|
431
|
+
dadurch nicht mehr an einem fehlenden Laufzeitimport; der getrennte
|
|
432
|
+
Bridge-Fallback bleibt nur die Absicherung und nicht der unbeabsichtigte
|
|
433
|
+
Hauptweg.
|
|
434
|
+
|
|
415
435
|
Der eigentliche Anhang und die vollständige Nutzernachricht bleiben für den Zug
|
|
416
436
|
unverändert verfügbar. Die Begrenzung betrifft ausschließlich die kleine
|
|
417
437
|
lexikalische Vorauswahl von höchstens zwei Werkzeugschemas; ToolSearch und alle
|
|
@@ -86,6 +86,22 @@ function attentionForReturn({ root, agentId, actorId, previousAt, currentAt }) {
|
|
|
86
86
|
return writeJsonAtomic(root, target, attention) ? attention : undefined;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
function normalizedJournalEntries(value) {
|
|
90
|
+
if (!Array.isArray(value)) return [];
|
|
91
|
+
const entries = [];
|
|
92
|
+
const seen = new Set();
|
|
93
|
+
for (const entry of value) {
|
|
94
|
+
const occurredAt = trustedTimestamp(entry?.occurred_at);
|
|
95
|
+
const text = redactSecrets(entry?.text);
|
|
96
|
+
if (!occurredAt || !text) continue;
|
|
97
|
+
const key = `${occurredAt}\0${text}`;
|
|
98
|
+
if (seen.has(key)) continue;
|
|
99
|
+
seen.add(key);
|
|
100
|
+
entries.push({ occurred_at: occurredAt, text });
|
|
101
|
+
}
|
|
102
|
+
return entries.slice(-MAX_ENTRIES);
|
|
103
|
+
}
|
|
104
|
+
|
|
89
105
|
function prepareRelationshipTurn(input = {}) {
|
|
90
106
|
const root = path.resolve(String(input.root ?? ''));
|
|
91
107
|
const agentId = safeId(input.agentId);
|
|
@@ -98,14 +114,14 @@ function prepareRelationshipTurn(input = {}) {
|
|
|
98
114
|
const text = redactSecrets(input.text);
|
|
99
115
|
const target = path.resolve(root, 'agents', agentId, 'journal', 'recent', `${actorId}.json`);
|
|
100
116
|
const existing = readJson(root, target);
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
117
|
+
const rawEntries = Array.isArray(existing?.entries) ? existing.entries.slice(-MAX_ENTRIES) : [];
|
|
118
|
+
const entries = normalizedJournalEntries(rawEntries);
|
|
119
|
+
const currentKey = text ? `${occurredAt}\0${text}` : '';
|
|
120
|
+
const historical = currentKey
|
|
121
|
+
? entries.filter((entry) => `${entry.occurred_at}\0${entry.text}` !== currentKey)
|
|
122
|
+
: entries;
|
|
123
|
+
const previous = historical.at(-1);
|
|
124
|
+
const recent = historical.slice(-MAX_RECENT_CONTEXT);
|
|
109
125
|
const attention = attentionForReturn({
|
|
110
126
|
root,
|
|
111
127
|
agentId,
|
|
@@ -115,8 +131,11 @@ function prepareRelationshipTurn(input = {}) {
|
|
|
115
131
|
});
|
|
116
132
|
|
|
117
133
|
if (text) {
|
|
118
|
-
const
|
|
119
|
-
|
|
134
|
+
const alreadyStored = entries.some((entry) => `${entry.occurred_at}\0${entry.text}` === currentKey);
|
|
135
|
+
const next = alreadyStored ? entries : [...entries, { occurred_at: occurredAt, text }].slice(-MAX_ENTRIES);
|
|
136
|
+
if (JSON.stringify(next) !== JSON.stringify(rawEntries)) {
|
|
137
|
+
writeJsonAtomic(root, target, { version: 1, actor_id: actorId, entries: next });
|
|
138
|
+
}
|
|
120
139
|
}
|
|
121
140
|
return { recent, attention };
|
|
122
141
|
}
|
|
@@ -30,6 +30,7 @@ const CANDIDATE_PATTERNS = [
|
|
|
30
30
|
kind: 'explicit_relationship_note',
|
|
31
31
|
patterns: [
|
|
32
32
|
/^(?:bitte\s+)?merk(?:e)?\s+dir\s*(?::|,|\s+dass\s+)?\s*(.+)$/iu,
|
|
33
|
+
/^(.+?)(?:\s*[,;:\u2014-]\s*|\s+)bitte\s+merken[.!?]*$/iu,
|
|
33
34
|
/^(?:please\s+)?remember(?:\s+that)?\s*(?::|,)?\s*(.+)$/iu,
|
|
34
35
|
],
|
|
35
36
|
},
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as _enum, B as object, F as discriminatedUnion, G as union, H as preprocess, I as intersection, J as datetime, K as unknown, L as literal, M as array, N as boolean, P as custom, R as looseObject, S as outboxLog, U as record, V as optional, W as string, X as __commonJSMin, Y as safeParse$1, Z as __toESM, c as MAX_CHUNK_LIMIT, f as readAccess, g as botToken, i as chunk, j as _null, k as require_out, l as assertAllowedChat, m as appendJsonl, n as isGroupNoiseReply, r as PHOTO_EXTS, t as isGroupChat, u as assertSendable, v as envFile, x as loadEnvFile, y as inboxDir, z as number } from "./noise.mjs";
|
|
1
|
+
import { A as _enum, B as object, F as discriminatedUnion, G as union, H as preprocess, I as intersection, J as datetime, K as unknown, L as literal, M as array, N as boolean, P as custom, R as looseObject, S as outboxLog, U as record, V as optional, W as string, X as __commonJSMin, Y as safeParse$1, Z as __toESM, b as inboxLog, c as MAX_CHUNK_LIMIT, f as readAccess, g as botToken, i as chunk, j as _null, k as require_out, l as assertAllowedChat, m as appendJsonl, n as isGroupNoiseReply, r as PHOTO_EXTS, t as isGroupChat, u as assertSendable, v as envFile, x as loadEnvFile, y as inboxDir, z as number } from "./noise.mjs";
|
|
2
2
|
import process$1 from "node:process";
|
|
3
3
|
import { mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { extname, join } from "node:path";
|