blun-king-cli 9.1.117 → 9.1.119

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
@@ -113,6 +113,10 @@ Version 9.1.106 erlaubt Agentenprofilen, Werkzeuge namentlich auszuschließen. K
113
113
 
114
114
  Version 9.1.109 hält nur noch die neun Werkzeuge dauerhaft in der Modellanfrage, auf die mehr als 98 Prozent von Fredriks 3.183 gemessenen Werkzeugaufrufen entfielen. Alle übrigen Werkzeuge bleiben über `ToolSearch` auffindbar und nach dem ersten Laden für den Rest der Sitzung verfügbar. Dadurch sinkt die Schemalast bei jedem normalen Modellschritt, ohne ein Werkzeug zu entfernen oder den Schnellweg für Telegram-Antworten und ausstehende Medienergebnisse zu verändern.
115
115
 
116
+ Ab BLUN King 9.1.118 bleibt der Sitzungszeitstempel im Systemprompt während einer laufenden Sitzung unverändert. Das erneute Einlesen von Verzeichnisübersicht, AGENTS.md-Dateien, Zusatzverzeichnissen und Skillinformationen kann den Prompt weiterhin ändern, wenn sich die jeweiligen Quellen tatsächlich verändert haben. Bleiben diese Quellen gleich, entwertet die Aktualisierung nach einer Verdichtung den Präfix-Cache des Anbieters nicht mehr allein durch einen neuen Zeitstempel. In Fredriks gemessener Sitzung unterschieden sich die beiden letzten Systemprompts mit jeweils 68.631 Zeichen nur in der Zeitangabe, und zwar erst nach einem gemeinsamen Präfix von 27.111 Zeichen. Der geänderte Zeitstempel verhinderte damit die Wiederverwendung der übrigen 41.512 unveränderten Zeichen aus dem Präfix-Cache.
117
+
118
+ Ab BLUN King 9.1.119 enthält der bei jedem Modellschritt erneut gesendete Prompt nur noch eine kleine Auswahl häufig benötigter Skills. Alle übrigen registrierten Skills bleiben verfügbar und lassen sich über das Skill-Werkzeug anhand ihres Namens oder Zwecks suchen; der ausgewählte Skill wird anschließend bei Bedarf geladen. Dadurch sinkt die wiederholt übertragene Promptlast, ohne Skills zu löschen oder die vollständige Ansicht unter `/skills` einzuschränken.
119
+
116
120
  Verliert ein delegierter Einzelagent oder ein Mitglied eines Agentenschwarms die Provider-Verbindung, erhält es eine leere Provider-Antwort, bricht sein Stream wegen Leerlaufs ab oder meldet der Server HTTP 408/500/502/503/504, setzt BLUN King denselben Agenten anhand seines dauerhaften Verlaufs fort. Bei Einzelagenten sowie bei Schwarm-Unterbrechungen außerhalb von HTTP 429 wartet die erste Fortsetzung zwei Sekunden und die zweite fünf Sekunden; danach bleibt der ursprüngliche Fehler sichtbar. HTTP 429 behält im Schwarm seine getrennte, längere Überlastungsregel. Authentifizierungs-, Zahlungs- oder Kontingent-, Richtlinien-, Kontext-, Werkzeug- und Codefehler sowie manuelle Abbrüche lösen keine automatische Fortsetzung aus. Jeder Fortsetzungsversuch verwendet die bestehende Agenten-ID, damit bereits abgeschlossene Arbeit nicht wiederholt wird.
117
121
 
118
122
  Rein lesende Sitzungsdiagnose
package/README.md CHANGED
@@ -119,6 +119,10 @@ Version 9.1.106 erlaubt Agentenprofilen, Werkzeuge namentlich auszuschließen. K
119
119
 
120
120
  Version 9.1.109 hält nur noch die neun Werkzeuge dauerhaft in der Modellanfrage, auf die mehr als 98 Prozent von Fredriks 3.183 gemessenen Werkzeugaufrufen entfielen. Alle übrigen Werkzeuge bleiben über `ToolSearch` auffindbar und nach dem ersten Laden für den Rest der Sitzung verfügbar. Dadurch sinkt die Schemalast bei jedem normalen Modellschritt, ohne ein Werkzeug zu entfernen oder den Schnellweg für Telegram-Antworten und ausstehende Medienergebnisse zu verändern.
121
121
 
122
+ Ab BLUN King 9.1.118 bleibt der Sitzungszeitstempel im Systemprompt während einer laufenden Sitzung unverändert. Das erneute Einlesen von Verzeichnisübersicht, AGENTS.md-Dateien, Zusatzverzeichnissen und Skillinformationen kann den Prompt weiterhin ändern, wenn sich die jeweiligen Quellen tatsächlich verändert haben. Bleiben diese Quellen gleich, entwertet die Aktualisierung nach einer Verdichtung den Präfix-Cache des Anbieters nicht mehr allein durch einen neuen Zeitstempel. In Fredriks gemessener Sitzung unterschieden sich die beiden letzten Systemprompts mit jeweils 68.631 Zeichen nur in der Zeitangabe, und zwar erst nach einem gemeinsamen Präfix von 27.111 Zeichen. Der geänderte Zeitstempel verhinderte damit die Wiederverwendung der übrigen 41.512 unveränderten Zeichen aus dem Präfix-Cache.
123
+
124
+ Ab BLUN King 9.1.119 enthält der bei jedem Modellschritt erneut gesendete Prompt nur noch eine kleine Auswahl häufig benötigter Skills. Alle übrigen registrierten Skills bleiben verfügbar und lassen sich über das Skill-Werkzeug anhand ihres Namens oder Zwecks suchen; der ausgewählte Skill wird anschließend bei Bedarf geladen. Dadurch sinkt die wiederholt übertragene Promptlast, ohne Skills zu löschen oder die vollständige Ansicht unter `/skills` einzuschränken.
125
+
122
126
  Ab BLUN King 9.1.99 werden auch direkt aufeinanderfolgende reine Textergebnisse als Stapel betrachtet. Enthalten sie zusammen mehr als 12.000 Zeichen, obwohl kein einzelnes Ergebnis diese Grenze überschreitet, speichert King so viele der größten geeigneten Ergebnisse wie nötig in privaten Dateien. In der Modellprojektion verbleiben lesbare Verweise. Der unveränderte Sitzungsrohverlauf bleibt vollständig erhalten. Gemischte Medienergebnisse, einzelne Ergebnisse unter 3.000 Zeichen und Stapel bis einschließlich 12.000 Zeichen bleiben unverändert. Beispiel: Bei zwei Suchergebnissen mit 7.000 und 6.000 Zeichen wird das größere Ergebnis privat gespeichert; Anfang, Ende, ausgelassene Zeichenzahl und `output_path` bleiben für den Agenten sichtbar.
123
127
 
124
128
  Ab BLUN King 9.1.100 beendet eine begrenzte Grep-Inhaltssuche ripgrep, sobald der Versatz, die angeforderten Zeilen und eine zusätzliche Vorschauzeile vollständig vorliegen. Die Vorschauzeile belegt, ob eine weitere Seite existiert, ohne vorher bis zu 10 MB einzulesen. Unbegrenzte Suchen, Trefferzählungen und nach Änderungszeit sortierte Dateilisten laufen weiterhin vollständig durch.
@@ -9,6 +9,8 @@ const FIRST_USE_SKILLS = new Set([
9
9
  'blun-app-design-system',
10
10
  ]);
11
11
 
12
+ const DEFAULT_SEARCH_LIMIT = 12;
13
+
12
14
  function compactDescription(value) {
13
15
  const normalized = String(value || '').replace(/\s+/g, ' ').trim();
14
16
  if (normalized.length <= SKILL_DESCRIPTION_MAX_CHARS) return normalized;
@@ -26,8 +28,64 @@ function renderCompactSkillListing(skills) {
26
28
  return (Array.isArray(skills) ? skills : []).map(renderCompactSkillEntry).join('\n');
27
29
  }
28
30
 
31
+ function isResidentSkill(skill) {
32
+ return FIRST_USE_SKILLS.has(String(skill?.name || '').trim().toLowerCase());
33
+ }
34
+
35
+ function renderResidentSkillListing(skills) {
36
+ return (Array.isArray(skills) ? skills : [])
37
+ .filter(isResidentSkill)
38
+ .map(renderCompactSkillEntry)
39
+ .join('\n');
40
+ }
41
+
42
+ function normalizeSearchText(value) {
43
+ return String(value || '')
44
+ .normalize('NFKD')
45
+ .replace(/[\u0300-\u036f]/g, '')
46
+ .toLowerCase()
47
+ .replace(/[^a-z0-9]+/g, ' ')
48
+ .trim();
49
+ }
50
+
51
+ function searchSkills(skills, query, limit = DEFAULT_SEARCH_LIMIT) {
52
+ const normalizedQuery = normalizeSearchText(query);
53
+ const queryTokens = normalizedQuery.split(/\s+/).filter(Boolean);
54
+ if (queryTokens.length === 0 || !Number.isFinite(limit) || limit <= 0) return [];
55
+
56
+ return (Array.isArray(skills) ? skills : [])
57
+ .filter((skill) => skill?.metadata?.disableModelInvocation !== true)
58
+ .map((skill) => {
59
+ const name = normalizeSearchText(skill?.name);
60
+ const description = normalizeSearchText(skill?.description);
61
+ const searchable = `${name} ${description}`.trim();
62
+ if (!queryTokens.every((token) => searchable.includes(token))) return null;
63
+ const score = name === normalizedQuery ? 0 : name.startsWith(normalizedQuery) ? 1 : name.includes(normalizedQuery) ? 2 : 3;
64
+ return { skill, name, score };
65
+ })
66
+ .filter(Boolean)
67
+ .sort((left, right) => left.score - right.score || left.name.localeCompare(right.name))
68
+ .slice(0, Math.floor(limit))
69
+ .map((entry) => entry.skill);
70
+ }
71
+
72
+ function renderSkillSearchResult(query, skills) {
73
+ const lines = [`No exact skill named "${String(query || '').trim()}" was found. Matching skills:`];
74
+ for (const skill of skills) {
75
+ const description = compactDescription(skill?.description);
76
+ lines.push(description ? `- ${skill.name}: ${description}` : `- ${skill.name}`);
77
+ }
78
+ lines.push('Call the Skill tool again with one exact skill name from this list.');
79
+ return lines.join('\n');
80
+ }
81
+
29
82
  module.exports = {
83
+ DEFAULT_SEARCH_LIMIT,
30
84
  SKILL_DESCRIPTION_MAX_CHARS,
85
+ isResidentSkill,
31
86
  renderCompactSkillEntry,
32
87
  renderCompactSkillListing,
88
+ renderResidentSkillListing,
89
+ renderSkillSearchResult,
90
+ searchSkills,
33
91
  };
package/blun.mjs CHANGED
@@ -235656,13 +235656,13 @@ function truncate$2(value, max) {
235656
235656
  }
235657
235657
  return `${result}…`;
235658
235658
  }
235659
- var LISTING_DESC_MAX, renderCompactSkillEntry, SessionSkillRegistry, SOURCE_GROUPS, graphemeSegmenter$2;
235659
+ var LISTING_DESC_MAX, isResidentSkill, renderCompactSkillEntry, renderSkillSearchResult, searchSkills, SessionSkillRegistry, SOURCE_GROUPS, graphemeSegmenter$2;
235660
235660
  var init_registry = __esmMin((() => {
235661
235661
  init_parser$1();
235662
235662
  init_scanner();
235663
235663
  init_types$15();
235664
235664
  init_xml_escape();
235665
- ({ renderCompactSkillEntry } = createRequire(import.meta.url)("./bin/skill-listing-performance-policy.cjs"));
235665
+ ({ isResidentSkill, renderCompactSkillEntry, renderSkillSearchResult, searchSkills } = createRequire(import.meta.url)("./bin/skill-listing-performance-policy.cjs"));
235666
235666
  LISTING_DESC_MAX = 250;
235667
235667
  SessionSkillRegistry = class {
235668
235668
  byName = /* @__PURE__ */ new Map();
@@ -235741,10 +235741,13 @@ var init_registry = __esmMin((() => {
235741
235741
  return rendered.length === 0 ? "No skills" : rendered;
235742
235742
  }
235743
235743
  getModelSkillListing() {
235744
- const lines = ["DISREGARD any earlier skill listings. Current available skills:"];
235745
- const listing = renderGroupedSkills(this.listInvocableSkills().filter((skill) => skill.metadata.isSubSkill !== true), formatModelSkill);
235744
+ const lines = [
235745
+ "DISREGARD any earlier skill listings. Frequently used skills are listed below.",
235746
+ "Other registered skills remain available: call the Skill tool with search words to discover their exact names."
235747
+ ];
235748
+ const listing = renderGroupedSkills(this.listInvocableSkills().filter((skill) => skill.metadata.isSubSkill !== true && isResidentSkill(skill)), formatModelSkill);
235746
235749
  if (listing.length > 0) lines.push(listing);
235747
- return lines.length === 1 ? "" : lines.join("\n");
235750
+ return lines.join("\n");
235748
235751
  }
235749
235752
  };
235750
235753
  SOURCE_GROUPS = [
@@ -252921,7 +252924,7 @@ var init_skill_tool = __esmMin((() => {
252921
252924
  }
252922
252925
  };
252923
252926
  SkillToolInputSchema = object({
252924
- skill: string().describe("The exact name of the skill to invoke, spelled as it appears in the current skill listing (e.g. \"commit\", \"pdf\")."),
252927
+ skill: string().describe("An exact skill name to invoke, or search words to discover matching registered skills when the exact name is unknown."),
252925
252928
  args: string().optional().describe("Optional argument string for the skill, written like a command line (e.g. `-m \"fix bug\"`, `123`, a file path). It is split on whitespace (quotes group a token) and expanded into the skill's placeholders ($NAME, $1, $ARGUMENTS); if the skill body has no placeholders, the whole string is still appended as a trailing `ARGUMENTS:` line. Omit it only when there is nothing to pass.")
252926
252929
  });
252927
252930
  SkillTool = class SkillTool {
@@ -252959,7 +252962,11 @@ var init_skill_tool = __esmMin((() => {
252959
252962
  const skills = this.agent.skills;
252960
252963
  if (skills === null) return errorResult(`Skill "${args.skill}" not found in the current skill listing.`);
252961
252964
  const skill = skills.registry.getSkill(args.skill);
252962
- if (skill === void 0) return errorResult(`Skill "${args.skill}" not found in the current skill listing.`);
252965
+ if (skill === void 0) {
252966
+ const matches = searchSkills(skills.registry.listInvocableSkills().filter((candidate) => candidate.metadata.isSubSkill !== true), args.skill);
252967
+ if (matches.length === 0) return errorResult(`No registered skill matched "${args.skill}". Try broader search words.`);
252968
+ return { output: renderSkillSearchResult(args.skill, matches) };
252969
+ }
252963
252970
  if (skill.metadata.disableModelInvocation === true) return errorResult(`Skill "${args.skill}" can only be triggered by the user (model invocation is disabled).`);
252964
252971
  const skillArgs = args.args ?? "";
252965
252972
  if (!isInlineSkillType(skill.metadata.type)) return errorResult(`Skill "${skill.name}" is not an inline skill and cannot be invoked by the model in v1.`);
@@ -264349,6 +264356,7 @@ var init_agent = __esmMin((() => {
264349
264356
  personalMemoryHostCapabilityEnabled = false;
264350
264357
  runtimeSystemPromptAppend = "";
264351
264358
  systemPromptContextProvider;
264359
+ systemPromptTimestamp = new Date();
264352
264360
  constructor(options) {
264353
264361
  this.type = options.type ?? "main";
264354
264362
  this._kaos = options.kaos;
@@ -264545,7 +264553,8 @@ var init_agent = __esmMin((() => {
264545
264553
  * Re-render the system prompt with freshly gathered runtime context (cwd
264546
264554
  * listing, AGENTS.md, additional-dirs info, skill list). Called after
264547
264555
  * compaction so the post-compaction turns do not keep a snapshot captured
264548
- * at session bootstrap. Invalidates the prompt-cache prefix by design.
264556
+ * at session bootstrap. The session timestamp stays stable so an otherwise
264557
+ * unchanged refresh can keep the provider prompt cache warm.
264549
264558
  */
264550
264559
  async refreshSystemPrompt() {
264551
264560
  if (this.activeProfile === void 0) return;
@@ -264554,6 +264563,8 @@ var init_agent = __esmMin((() => {
264554
264563
  }
264555
264564
  updateSystemPromptFromProfile(profile, context) {
264556
264565
  const systemPrompt = profile.systemPrompt({
264566
+ ...context,
264567
+ now: this.systemPromptTimestamp,
264557
264568
  osEnv: this.kaos.osEnv,
264558
264569
  cwd: this.config.cwd,
264559
264570
  skills: this.skills?.registry,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.117",
3
+ "version": "9.1.119",
4
4
  "description": "BLUN CLI - your own AI agent with a Telegram channel. Get it done. With BLUN.",
5
5
  "license": "MIT",
6
6
  "bin": {