blun-king-cli 9.1.497 → 9.1.498
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/CHANGELOG.md +10 -0
- package/LIESMICH.txt +18 -1
- package/README.md +18 -1
- package/bin/usage-cache-efficiency-policy.cjs +26 -0
- package/blun.mjs +27 -4
- package/package.json +1 -1
- package/telegram-plugin/dist/bridge.mjs +0 -20
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 9.1.498 - 2026-08-30
|
|
4
|
+
|
|
5
|
+
- Shows prompt-cache hit rate plus cache-read and cache-write tokens per model in `/usage`.
|
|
6
|
+
- Adds `/tokens` as a short alias for the existing detailed context doctor without introducing another model call.
|
|
7
|
+
- Adds `/offload` as an alias for the existing archive-backed context compaction command.
|
|
8
|
+
- Preserves every distinct authorized Telegram bot message instead of dropping same-sender messages that arrive within a fixed 15-second window.
|
|
9
|
+
- Preserves the exact TodoList through full compaction and adds a one-shot recovery reminder to read the archived history path before broad searches when an exact path, command, hash, or requirement is uncertain.
|
|
10
|
+
- Keeps completed TodoList evidence append-only: later uncertainty becomes a separate in-progress step instead of silently reverting or removing completed work.
|
|
11
|
+
- Defers recurring session-loop wakeups while the maintained TodoList still contains active or pending work, coalescing missed intervals until the assignment is genuinely idle without delaying unrelated scheduled reminders.
|
|
12
|
+
|
|
3
13
|
## 9.1.497 - 2026-08-30
|
|
4
14
|
|
|
5
15
|
- Prioritizes Telegram bot messages from shared groups behind direct and explicitly addressed traffic but ahead of ordinary queued context, without forcing a reply.
|
package/LIESMICH.txt
CHANGED
|
@@ -9,7 +9,7 @@ Installation
|
|
|
9
9
|
------------
|
|
10
10
|
Die geprüfte Version exakt global installieren:
|
|
11
11
|
|
|
12
|
-
npm install -g blun-king-cli@9.1.
|
|
12
|
+
npm install -g blun-king-cli@9.1.498
|
|
13
13
|
|
|
14
14
|
Start
|
|
15
15
|
-----
|
|
@@ -65,6 +65,23 @@ geschriebenen Entwurf zu löschen. Das gilt auch bei
|
|
|
65
65
|
Autovervollständigung, Geistervorschlägen, Bash-Eingabe und einer offenen
|
|
66
66
|
Mehrzeileneingabe.
|
|
67
67
|
|
|
68
|
+
Version 9.1.498 zeigt in /usage die gemessene Prompt-Cache-Trefferquote sowie
|
|
69
|
+
gelesene und geschriebene Cache-Token je Modell. /tokens ist ein kurzer Alias
|
|
70
|
+
fuer die bereits vorhandene detaillierte Kontextdiagnose; /offload ruft die
|
|
71
|
+
vorhandene archivierende Kontextverdichtung auf. Unterschiedliche autorisierte
|
|
72
|
+
Botnachrichten werden nicht mehr durch ein starres 15-Sekunden-Fenster verworfen.
|
|
73
|
+
Nach einer vollständigen Verdichtung bleibt die exakte Todo-Liste erhalten. Ein
|
|
74
|
+
einmaliger Wiederherstellungshinweis verlangt bei unsicheren Pfaden, Befehlen,
|
|
75
|
+
Hashes oder Anforderungen zuerst das Lesen des archivierten Verlaufs, bevor eine
|
|
76
|
+
breite Dateisuche oder ein Neubeginn zulässig ist.
|
|
77
|
+
Erledigte Todo-Schritte bleiben als Nachweis erhalten. Neue widersprüchliche
|
|
78
|
+
Erkenntnisse werden als eigener laufender Schritt mit Begründung ergänzt, statt
|
|
79
|
+
einen bereits belegten Abschluss still zurückzustufen oder zu entfernen.
|
|
80
|
+
Wiederkehrende Session-Loops warten, solange die gepflegte Todo-Liste noch
|
|
81
|
+
laufende oder ausstehende Arbeit enthält. Verpasste Intervalle werden bis zum
|
|
82
|
+
echten Leerlauf zusammengefasst; andere geplante Erinnerungen bleiben davon
|
|
83
|
+
unberührt.
|
|
84
|
+
|
|
68
85
|
Version 9.1.497 priorisiert Telegram-Botnachrichten aus gemeinsamen Gruppen
|
|
69
86
|
hinter privaten und ausdrücklich adressierten Nachrichten, aber vor normalem
|
|
70
87
|
Kontext. Die Priorisierung erzwingt keine Antwort. Eine angenommene
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Voraussetzung ist Node.js 24.15 oder neuer. Die geprüfte Version wird exakt
|
|
|
9
9
|
installiert:
|
|
10
10
|
|
|
11
11
|
```powershell
|
|
12
|
-
npm install -g blun-king-cli@9.1.
|
|
12
|
+
npm install -g blun-king-cli@9.1.498
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Reproduzierbares Staging und Packen
|
|
@@ -81,6 +81,23 @@ konkurrierenden Start zurückgewiesen und bleiben an der Spitze der
|
|
|
81
81
|
FIFO-Warteschlange. Für diesen normalen Wartestatus erscheint kein
|
|
82
82
|
`turn.agent_busy`-Fehler.
|
|
83
83
|
|
|
84
|
+
Version 9.1.498 zeigt in `/usage` die gemessene Prompt-Cache-Trefferquote sowie
|
|
85
|
+
gelesene und geschriebene Cache-Token je Modell. `/tokens` ist ein kurzer Alias
|
|
86
|
+
fuer die bereits vorhandene detaillierte Kontextdiagnose; `/offload` ruft die
|
|
87
|
+
vorhandene archivierende Kontextverdichtung auf. Unterschiedliche autorisierte
|
|
88
|
+
Botnachrichten werden nicht mehr durch ein starres 15-Sekunden-Fenster verworfen.
|
|
89
|
+
Nach einer vollständigen Verdichtung bleibt die exakte Todo-Liste erhalten. Ein
|
|
90
|
+
einmaliger Wiederherstellungshinweis verlangt bei unsicheren Pfaden, Befehlen,
|
|
91
|
+
Hashes oder Anforderungen zuerst das Lesen des archivierten Verlaufs, bevor eine
|
|
92
|
+
breite Dateisuche oder ein Neubeginn zulässig ist.
|
|
93
|
+
Erledigte Todo-Schritte bleiben als Nachweis erhalten. Neue widersprüchliche
|
|
94
|
+
Erkenntnisse werden als eigener laufender Schritt mit Begründung ergänzt, statt
|
|
95
|
+
einen bereits belegten Abschluss still zurückzustufen oder zu entfernen.
|
|
96
|
+
Wiederkehrende Session-Loops warten außerdem, solange die gepflegte Todo-Liste
|
|
97
|
+
noch laufende oder ausstehende Arbeit enthält. Verpasste Intervalle werden bis
|
|
98
|
+
zum echten Leerlauf zusammengefasst; andere geplante Erinnerungen bleiben davon
|
|
99
|
+
unberührt.
|
|
100
|
+
|
|
84
101
|
Version 9.1.497 priorisiert Telegram-Botnachrichten aus gemeinsamen Gruppen
|
|
85
102
|
hinter privaten und ausdrücklich adressierten Nachrichten, aber vor normalem
|
|
86
103
|
Kontext. Die Priorisierung erzwingt keine Antwort. Eine angenommene
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function wholeNonNegative(value) {
|
|
4
|
+
if (!Number.isFinite(value) || value <= 0) return 0;
|
|
5
|
+
return Math.floor(value);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function buildCacheEfficiency(usage = {}) {
|
|
9
|
+
const uncachedTokens = wholeNonNegative(usage.inputOther);
|
|
10
|
+
const readTokens = wholeNonNegative(usage.inputCacheRead);
|
|
11
|
+
const writeTokens = wholeNonNegative(usage.inputCacheCreation);
|
|
12
|
+
const inputTokens = uncachedTokens + readTokens + writeTokens;
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
hasActivity: readTokens > 0 || writeTokens > 0,
|
|
16
|
+
hitRate: inputTokens > 0 ? Math.min(1, readTokens / inputTokens) : 0,
|
|
17
|
+
inputTokens,
|
|
18
|
+
readTokens,
|
|
19
|
+
writeTokens,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = {
|
|
24
|
+
buildCacheEfficiency,
|
|
25
|
+
wholeNonNegative,
|
|
26
|
+
};
|
package/blun.mjs
CHANGED
|
@@ -75375,6 +75375,7 @@ var init_full = __esmMin((() => {
|
|
|
75375
75375
|
"permission_mode",
|
|
75376
75376
|
"plan_mode",
|
|
75377
75377
|
"plugin_session_start",
|
|
75378
|
+
"compaction_recovery",
|
|
75378
75379
|
"todo_list_reminder",
|
|
75379
75380
|
"tool-awareness"
|
|
75380
75381
|
]);
|
|
@@ -77053,6 +77054,7 @@ function createCronScheduler(opts) {
|
|
|
77053
77054
|
const now = clocks.wallNow();
|
|
77054
77055
|
try {
|
|
77055
77056
|
for (const task of tasks) try {
|
|
77057
|
+
if (!isIdle(task)) continue;
|
|
77056
77058
|
if (inFlight.has(task.id)) continue;
|
|
77057
77059
|
if (task.paused === true) continue;
|
|
77058
77060
|
const parsed = getParsed(task.cron);
|
|
@@ -77180,6 +77182,10 @@ var init_telemetry_events = __esmMin((() => {
|
|
|
77180
77182
|
}));
|
|
77181
77183
|
//#endregion
|
|
77182
77184
|
//#region ../../packages/agent-core/src/agent/cron/manager.ts
|
|
77185
|
+
function hasUnfinishedTodoWork(agent) {
|
|
77186
|
+
const todos = agent.tools.storeData()["todo"];
|
|
77187
|
+
return Array.isArray(todos) && todos.some((todo) => todo?.status === "in_progress" || todo?.status === "pending");
|
|
77188
|
+
}
|
|
77183
77189
|
var STALE_THRESHOLD_MS, CronManager;
|
|
77184
77190
|
var init_manager$3 = __esmMin((() => {
|
|
77185
77191
|
init_clock();
|
|
@@ -77239,7 +77245,7 @@ var init_manager$3 = __esmMin((() => {
|
|
|
77239
77245
|
this.scheduler = createCronScheduler({
|
|
77240
77246
|
clocks: this.clocks,
|
|
77241
77247
|
source: () => this.store.list(),
|
|
77242
|
-
isIdle: () => !agent.turn.hasActiveTurn,
|
|
77248
|
+
isIdle: (task) => !agent.turn.hasActiveTurn && (task?.owner !== "session-loop" || !hasUnfinishedTodoWork(agent)),
|
|
77243
77249
|
isKilled: () => process.env["BLUN_DISABLE_CRON"] === "1",
|
|
77244
77250
|
onFire: (task, ctx) => {
|
|
77245
77251
|
this.handleFire(task, ctx);
|
|
@@ -233121,7 +233127,7 @@ var init_mission_contract_bridge = __esmMin((() => {
|
|
|
233121
233127
|
}));
|
|
233122
233128
|
//#endregion
|
|
233123
233129
|
//#region ../../packages/agent-core/src/agent/injection/manager.ts
|
|
233124
|
-
var ACTIVE_BACKGROUND_TASK_GUIDANCE, InjectionManager;
|
|
233130
|
+
var ACTIVE_BACKGROUND_TASK_GUIDANCE, POST_COMPACTION_RECOVERY_GUIDANCE, InjectionManager;
|
|
233125
233131
|
var init_manager$2 = __esmMin((() => {
|
|
233126
233132
|
init_task_list();
|
|
233127
233133
|
init_action_style();
|
|
@@ -233136,6 +233142,7 @@ var init_manager$2 = __esmMin((() => {
|
|
|
233136
233142
|
init_validated_learning_signal();
|
|
233137
233143
|
init_tool_awareness();
|
|
233138
233144
|
ACTIVE_BACKGROUND_TASK_GUIDANCE = "The conversation was compacted, so the earlier messages that started these background tasks are gone — but the tasks are still running from before. Do not start duplicates. Use TaskOutput to fetch a task’s result, TaskList to list them, TaskUpdate to send additional instructions to a running agent task, and TaskStop to cancel one.";
|
|
233145
|
+
POST_COMPACTION_RECOVERY_GUIDANCE = "The conversation was compacted. Continue from the persisted TodoList and summary. If an exact file path, command, hash, requirement, or other working detail is missing or uncertain, use Read on the summary's history_path before broad filesystem searches, guessing, or starting work over.";
|
|
233139
233146
|
InjectionManager = class {
|
|
233140
233147
|
agent;
|
|
233141
233148
|
injectors;
|
|
@@ -233193,9 +233200,16 @@ var init_manager$2 = __esmMin((() => {
|
|
|
233193
233200
|
}
|
|
233194
233201
|
async injectAfterCompaction() {
|
|
233195
233202
|
await this.injectGoal();
|
|
233203
|
+
this.injectCompactionRecoveryGuidance();
|
|
233196
233204
|
this.injectActiveBackgroundTasks();
|
|
233197
233205
|
await this.inject();
|
|
233198
233206
|
}
|
|
233207
|
+
injectCompactionRecoveryGuidance() {
|
|
233208
|
+
this.agent.context.appendSystemReminder(POST_COMPACTION_RECOVERY_GUIDANCE, {
|
|
233209
|
+
kind: "injection",
|
|
233210
|
+
variant: "compaction_recovery"
|
|
233211
|
+
});
|
|
233212
|
+
}
|
|
233199
233213
|
/**
|
|
233200
233214
|
* Post-compaction only: re-surface still-running background tasks. Folding the
|
|
233201
233215
|
* live context to [recent user prompts, summary] drops the messages that
|
|
@@ -403833,7 +403847,7 @@ const BUILTIN_SLASH_COMMAND_DEFINITIONS = [
|
|
|
403833
403847
|
},
|
|
403834
403848
|
{
|
|
403835
403849
|
name: "compact",
|
|
403836
|
-
aliases: [],
|
|
403850
|
+
aliases: ["offload"],
|
|
403837
403851
|
descriptionKey: "command.compact.description",
|
|
403838
403852
|
priority: 80,
|
|
403839
403853
|
argumentHint: "<instruction>"
|
|
@@ -403976,7 +403990,7 @@ const BUILTIN_SLASH_COMMAND_DEFINITIONS = [
|
|
|
403976
403990
|
},
|
|
403977
403991
|
{
|
|
403978
403992
|
name: "context-doctor",
|
|
403979
|
-
aliases: [],
|
|
403993
|
+
aliases: ["tokens"],
|
|
403980
403994
|
descriptionKey: "contextDoctor.description",
|
|
403981
403995
|
priority: 66,
|
|
403982
403996
|
availability: "always"
|
|
@@ -417895,9 +417909,11 @@ function buildSessionUsageSection(usage, error, value, muted, errorStyle) {
|
|
|
417895
417909
|
for (const [model, row] of entries) {
|
|
417896
417910
|
const input = usageInputTotal$2(row);
|
|
417897
417911
|
const output = usageNumber(row.output);
|
|
417912
|
+
const cache = buildCacheEfficiency(row);
|
|
417898
417913
|
totalInput += input;
|
|
417899
417914
|
totalOutput += output;
|
|
417900
417915
|
lines.push(` ${muted(sanitizeTerminalText(model))} ${uiText("usage.input")} ${value(formatExactTokenCount(input, locale))} ${uiText("usage.output")} ${value(formatExactTokenCount(output, locale))} ${uiText("usage.total")} ${value(formatExactTokenCount(input + output, locale))}`);
|
|
417916
|
+
if (cache.hasActivity) lines.push(` ${muted("CACHE")} ${value(`${Math.round(cache.hitRate * 100)}%`)} | R ${value(formatExactTokenCount(cache.readTokens, locale))} | W ${value(formatExactTokenCount(cache.writeTokens, locale))}`);
|
|
417901
417917
|
}
|
|
417902
417918
|
if (entries.length > 1) lines.push(` ${muted(uiText("usage.total"))} ${uiText("usage.input")} ${value(formatExactTokenCount(totalInput, locale))} ${uiText("usage.output")} ${value(formatExactTokenCount(totalOutput, locale))} ${uiText("usage.total")} ${value(formatExactTokenCount(totalInput + totalOutput, locale))}`);
|
|
417903
417919
|
return lines;
|
|
@@ -417964,6 +417980,7 @@ var { buildApprovalRejectionStop } = createRequire(import.meta.url)("./bin/appro
|
|
|
417964
417980
|
var { reconcileContextBudget } = createRequire(import.meta.url)("./bin/context-budget-ledger.cjs");
|
|
417965
417981
|
var { buildContextInsight } = createRequire(import.meta.url)("./bin/context-insight-policy.cjs");
|
|
417966
417982
|
var { buildContextDoctor } = createRequire(import.meta.url)("./bin/context-doctor-policy.cjs");
|
|
417983
|
+
var { buildCacheEfficiency } = createRequire(import.meta.url)("./bin/usage-cache-efficiency-policy.cjs");
|
|
417967
417984
|
var { buildValidatedLearningInsight } = createRequire(import.meta.url)("./bin/validated-learning-insight-policy.cjs");
|
|
417968
417985
|
var { readValidatedLearningCandidates } = createRequire(import.meta.url)("./bin/validated-learning-signal.cjs");
|
|
417969
417986
|
function buildUsageReportLines(options) {
|
|
@@ -423231,6 +423248,12 @@ function enforceGoalTodoPolicy(agent, context) {
|
|
|
423231
423248
|
if (context.toolCall.name === "TodoList") {
|
|
423232
423249
|
const nextTodos = context.args?.todos;
|
|
423233
423250
|
if (!Array.isArray(nextTodos)) return;
|
|
423251
|
+
const normalizeTitle = (value) => String(value ?? "").trim().toLowerCase().replace(/\s+/gu, " ");
|
|
423252
|
+
const missingCompleted = todos.filter((todo, index) => todo?.status === "done" && !nextTodos.some((nextTodo) => nextTodo?.status === "done" && normalizeTitle(nextTodo.title) === normalizeTitle(todo.title)) && nextTodos[index]?.status !== "done");
|
|
423253
|
+
if (missingCompleted.length > 0) return {
|
|
423254
|
+
block: true,
|
|
423255
|
+
reason: `Completed TodoList evidence is append-only. Keep each completed item present and done. If later evidence reopens work, retain the completed item and add a separate in_progress item with the reason. Missing completed item: ${String(missingCompleted[0]?.title ?? "").trim()}`
|
|
423256
|
+
};
|
|
423234
423257
|
if (nextTodos.length === 0) {
|
|
423235
423258
|
if (activeGoal !== null) return {
|
|
423236
423259
|
block: true,
|
package/package.json
CHANGED
|
@@ -130,25 +130,6 @@ function matchesAny(text, patterns) {
|
|
|
130
130
|
} catch {}
|
|
131
131
|
return false;
|
|
132
132
|
}
|
|
133
|
-
/**
|
|
134
|
-
* Bot-to-bot loop guard (Telegram's own safety requirement for Bot API 10.0
|
|
135
|
-
* bot-to-bot mode): once King can receive other bots' messages, an unthrottled
|
|
136
|
-
* exchange could ping-pong forever. We throttle deliveries FROM a given bot in
|
|
137
|
-
* a given group to at most one per BOT_COOLDOWN_MS, so two bots can never fast-
|
|
138
|
-
* loop. In-memory per bridge process — resets on restart, which is fine.
|
|
139
|
-
*/
|
|
140
|
-
const BOT_COOLDOWN_MS = 15e3;
|
|
141
|
-
const lastBotDelivery = /* @__PURE__ */ new Map();
|
|
142
|
-
/** Exposed for tests; drops stale entries so the map can't grow unbounded. */
|
|
143
|
-
function botLoopGuardAllows(senderId, now = Date.now(), cooldownMs = BOT_COOLDOWN_MS) {
|
|
144
|
-
const last = lastBotDelivery.get(senderId);
|
|
145
|
-
if (last !== void 0 && now - last < cooldownMs) return false;
|
|
146
|
-
lastBotDelivery.set(senderId, now);
|
|
147
|
-
if (lastBotDelivery.size > 200) {
|
|
148
|
-
for (const [key, ts] of lastBotDelivery) if (now - ts > cooldownMs) lastBotDelivery.delete(key);
|
|
149
|
-
}
|
|
150
|
-
return true;
|
|
151
|
-
}
|
|
152
133
|
function gate(ctx, botUsername) {
|
|
153
134
|
const access = readAccess();
|
|
154
135
|
if (pruneExpired(access)) saveAccess(access);
|
|
@@ -227,7 +208,6 @@ function gate(ctx, botUsername) {
|
|
|
227
208
|
if (groupAllowFrom.length > 0 && !groupAllowFrom.includes(senderId)) return { action: "drop" };
|
|
228
209
|
const mentionBypass = from.isBot !== true && (policy.alwaysAllowFrom ?? []).includes(senderId);
|
|
229
210
|
const addressed = !matchesAny(ctx.text, access.ignorePatterns) && (mentionBypass || isMentioned(ctx, botUsername, access.mentionPatterns));
|
|
230
|
-
if (!addressed && from.isBot === true && !botLoopGuardAllows(senderId)) return { action: "drop" };
|
|
231
211
|
return {
|
|
232
212
|
action: "deliver",
|
|
233
213
|
access,
|