blun-king-cli 9.1.168 → 9.1.169

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.
@@ -4,6 +4,16 @@ const TOOL_SCHEMA_BUDGET_RATIO = 0.25;
4
4
  const TOOL_SCHEMA_MAX_TOKENS = 32_000;
5
5
  const DEFERRED_TOOL_LOADER_NAME = 'ToolSearch';
6
6
  const MAX_PERSISTENT_DEFERRED_TOOLS = 12;
7
+ const TOOL_SEARCH_INTENT_WORDS = new Set([
8
+ 'find', 'fetch', 'get', 'holen', 'list', 'read', 'search', 'show', 'anzeigen', 'lesen', 'suchen',
9
+ ]);
10
+ const TOOL_SEARCH_RELATED_TERM_GROUPS = Object.freeze([
11
+ Object.freeze([
12
+ 'current', 'inbox', 'latest', 'message', 'messages', 'nachricht', 'nachrichten', 'queue', 'queued',
13
+ 'recent', 'update', 'updates',
14
+ ]),
15
+ Object.freeze(['history', 'log', 'logs', 'protokoll', 'transcript', 'verlauf']),
16
+ ]);
7
17
  const CORE_TOOL_NAMES = Object.freeze([
8
18
  'Bash',
9
19
  'Read',
@@ -66,6 +76,56 @@ function searchDeferredTools(tools, query) {
66
76
  }).filter(Boolean).sort((left, right) => right.score - left.score || String(left.tool.name).localeCompare(String(right.tool.name))).slice(0, 5).map((entry) => entry.tool);
67
77
  }
68
78
 
79
+ function relatedSearchTerms(token) {
80
+ const group = TOOL_SEARCH_RELATED_TERM_GROUPS.find((terms) => terms.includes(token));
81
+ return group || [token];
82
+ }
83
+
84
+ function searchRelatedDeferredTools(tools, query) {
85
+ const normalized = String(query || '').trim().toLowerCase();
86
+ if (!normalized || normalized.startsWith('select:')) return [];
87
+ const tokens = normalized.split(/\s+/).filter(Boolean);
88
+ const requiredNameTokens = tokens.filter((token) => token.startsWith('+')).map((token) => token.slice(1)).filter(Boolean);
89
+ const searchTokens = tokens
90
+ .filter((token) => !token.startsWith('+'))
91
+ .filter((token) => !TOOL_SEARCH_INTENT_WORDS.has(token));
92
+ if (searchTokens.length < 2) return [];
93
+ const minimumMatchedTokens = Math.max(2, Math.ceil(searchTokens.length * 0.75));
94
+
95
+ return tools.map((tool) => {
96
+ const name = String(tool?.name || '').toLowerCase();
97
+ const description = String(tool?.description || '').toLowerCase();
98
+ if (!requiredNameTokens.every((token) => name.includes(token))) return null;
99
+ let matchedTokens = 0;
100
+ let score = requiredNameTokens.length * 8;
101
+ for (const token of searchTokens) {
102
+ if (name.includes(token)) {
103
+ matchedTokens += 1;
104
+ score += 8;
105
+ continue;
106
+ }
107
+ if (description.includes(token)) {
108
+ matchedTokens += 1;
109
+ score += 4;
110
+ continue;
111
+ }
112
+ const related = relatedSearchTerms(token).filter((term) => term !== token);
113
+ if (related.some((term) => name.includes(term))) {
114
+ matchedTokens += 1;
115
+ score += 3;
116
+ } else if (related.some((term) => description.includes(term))) {
117
+ matchedTokens += 1;
118
+ score += 2;
119
+ }
120
+ }
121
+ return matchedTokens >= minimumMatchedTokens ? { tool, score, matchedTokens } : null;
122
+ }).filter(Boolean).sort((left, right) => (
123
+ right.matchedTokens - left.matchedTokens
124
+ || right.score - left.score
125
+ || String(left.tool.name).localeCompare(String(right.tool.name))
126
+ )).slice(0, 5).map((entry) => entry.tool);
127
+ }
128
+
69
129
  function rememberLoadedTool(loadedToolNames, name) {
70
130
  loadedToolNames.delete(name);
71
131
  loadedToolNames.add(name);
@@ -109,7 +169,12 @@ function createDeferredToolLoader(selectedTools, deferredTools, loadedToolNames
109
169
  description: query ? `Searching tool schemas for ${query}` : 'Searching tool schemas',
110
170
  approvalRule: DEFERRED_TOOL_LOADER_NAME,
111
171
  execute: async () => {
112
- const matches = searchDeferredTools([...available.values()], query);
172
+ let matches = searchDeferredTools([...available.values()], query);
173
+ let relatedFallback = false;
174
+ if (matches.length === 0) {
175
+ matches = searchRelatedDeferredTools([...available.values()], query);
176
+ relatedFallback = matches.length > 0;
177
+ }
113
178
  if (matches.length === 0) {
114
179
  const alreadyLoaded = query.toLowerCase().startsWith('select:')
115
180
  ? searchDeferredTools(
@@ -143,7 +208,7 @@ function createDeferredToolLoader(selectedTools, deferredTools, loadedToolNames
143
208
  }
144
209
  return {
145
210
  isError: false,
146
- output: `Loaded tool schemas: ${loaded.join(', ')}. Invoke them in the next step.`,
211
+ output: `${relatedFallback ? 'Loaded related tool schemas' : 'Loaded tool schemas'}: ${loaded.join(', ')}. Invoke them in the next step.`,
147
212
  };
148
213
  },
149
214
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.168",
3
+ "version": "9.1.169",
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": {