kiku-agent 1.3.2 → 1.3.4

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.
Files changed (152) hide show
  1. package/README.md +69 -12
  2. package/package.json +2 -1
  3. package/server/agent/agentCore.js +319 -46
  4. package/server/agent/appPaths.js +31 -0
  5. package/server/agent/audioPlayer.js +339 -12
  6. package/server/agent/autoContext.js +193 -0
  7. package/server/agent/catalogEntityResolver.js +170 -28
  8. package/server/agent/clarifyingQuestions.js +137 -35
  9. package/server/agent/cli.js +177 -48
  10. package/server/agent/cloudAdapters.js +116 -0
  11. package/server/agent/commandRegistry.js +409 -80
  12. package/server/agent/commands.js +1056 -125
  13. package/server/agent/config.js +1088 -690
  14. package/server/agent/contextCompactor.js +213 -21
  15. package/server/agent/cpuMetrics.js +199 -0
  16. package/server/agent/engineService.js +591 -0
  17. package/server/agent/eval/modules/evaluation/runner.js +4 -14
  18. package/server/agent/eval/modules/evaluation/scoring.js +15 -3
  19. package/server/agent/eval/modules/server/evalApi.js +5 -5
  20. package/server/agent/eval/modules/ui/evalUi.js +7 -4
  21. package/server/agent/eventBus.js +1 -0
  22. package/server/agent/ink/main.jsx +196 -191
  23. package/server/agent/jobManager.js +11 -1
  24. package/server/agent/lanDiscovery.js +721 -23
  25. package/server/agent/llmClient.js +317 -71
  26. package/server/agent/lmStudioWakeup.js +517 -65
  27. package/server/agent/locationService.js +797 -0
  28. package/server/agent/mcpQuizData.js +509 -0
  29. package/server/agent/memory/contextAllocator.js +19 -7
  30. package/server/agent/memory.js +3 -1
  31. package/server/agent/modelCompatibility.js +352 -0
  32. package/server/agent/modelDefaults.js +1 -0
  33. package/server/agent/modelManager.js +46 -2
  34. package/server/agent/newsWatch.js +9 -3
  35. package/server/agent/processManager.js +229 -0
  36. package/server/agent/prompts.js +174 -8
  37. package/server/agent/routingInterceptor.js +9 -1
  38. package/server/agent/sanitizer.js +41 -6
  39. package/server/agent/searchQueryPlanner.js +202 -0
  40. package/server/agent/session.js +59 -4
  41. package/server/agent/tests/agentFollowUps.test.js +128 -2
  42. package/server/agent/tests/agentMusicControl.test.js +245 -0
  43. package/server/agent/tests/apiRouter.test.js +1 -1
  44. package/server/agent/tests/autoContext.test.js +176 -0
  45. package/server/agent/tests/bilibiliEmbed.test.js +45 -0
  46. package/server/agent/tests/chatHardening.test.js +121 -0
  47. package/server/agent/tests/chineseWebSearchEscalation.test.js +62 -0
  48. package/server/agent/tests/clarifyingQuestions.test.js +33 -0
  49. package/server/agent/tests/cliAutomation.test.js +38 -1
  50. package/server/agent/tests/cloudProviders.test.js +91 -3
  51. package/server/agent/tests/commands.test.js +92 -3
  52. package/server/agent/tests/contextIntelligence.test.js +50 -3
  53. package/server/agent/tests/cpuMetrics.test.js +101 -0
  54. package/server/agent/tests/decisionAndSearchEnhancements.test.js +32 -0
  55. package/server/agent/tests/edgeCasesScenarios.test.js +82 -0
  56. package/server/agent/tests/engineService.test.js +436 -0
  57. package/server/agent/tests/engineUnload.test.js +94 -0
  58. package/server/agent/tests/envCommand.test.js +69 -0
  59. package/server/agent/tests/evalMetrics.test.js +8 -0
  60. package/server/agent/tests/fetchApi.test.js +99 -0
  61. package/server/agent/tests/hybridWebSearch.test.js +2 -0
  62. package/server/agent/tests/lanDiscovery.test.js +5 -0
  63. package/server/agent/tests/lanInterfaces.test.js +510 -0
  64. package/server/agent/tests/lmStudioWakeup.test.js +278 -0
  65. package/server/agent/tests/locationTool.test.js +278 -0
  66. package/server/agent/tests/memoryRoute.test.js +173 -0
  67. package/server/agent/tests/memoryUiNormalization.test.js +75 -0
  68. package/server/agent/tests/modelCompatibility.test.js +148 -0
  69. package/server/agent/tests/modelManager.test.js +32 -0
  70. package/server/agent/tests/musicControlUiBridge.test.js +113 -0
  71. package/server/agent/tests/nextGenArchitecture.test.js +4 -2
  72. package/server/agent/tests/openDomainPrompt.test.js +197 -0
  73. package/server/agent/tests/openDomainSearch.test.js +121 -0
  74. package/server/agent/tests/processManager.test.js +144 -0
  75. package/server/agent/tests/providerPersistence.test.js +10 -5
  76. package/server/agent/tests/quickActionsAndModals.test.js +180 -0
  77. package/server/agent/tests/searchQueryPlanner.test.js +108 -0
  78. package/server/agent/tests/securityAuditRemediation.test.js +16 -9
  79. package/server/agent/tests/securityAuditRemediations2.test.js +154 -0
  80. package/server/agent/tests/securityHardening.test.js +4 -4
  81. package/server/agent/tests/sessionAndCopy.test.js +39 -4
  82. package/server/agent/tests/sidebarControls.test.js +34 -0
  83. package/server/agent/tests/statefulMemory.test.js +8 -1
  84. package/server/agent/tests/textProtocolLoop.test.js +71 -0
  85. package/server/agent/tests/textToolParsing.test.js +48 -0
  86. package/server/agent/tests/toolRoutingRegressions.test.js +41 -0
  87. package/server/agent/tests/unifiedEndpoints.test.js +13 -6
  88. package/server/agent/tests/v110Features.test.js +1 -1
  89. package/server/agent/tests/vramEstimator.test.js +75 -0
  90. package/server/agent/tests/webChatDocs.test.js +199 -0
  91. package/server/agent/tests/webChatInferenceControl.test.js +298 -0
  92. package/server/agent/tests/webChatInspection.test.js +256 -5
  93. package/server/agent/tests/webChatMcp.test.js +94 -0
  94. package/server/agent/tests/webExtract.test.js +23 -0
  95. package/server/agent/tests/webSources.test.js +46 -12
  96. package/server/agent/textToolProtocol.js +173 -46
  97. package/server/agent/toolRouter.js +318 -44
  98. package/server/agent/tools.js +877 -96
  99. package/server/agent/ui.js +39 -34
  100. package/server/agent/vramService.js +35 -54
  101. package/server/agent/webSearch.js +441 -162
  102. package/server/agent/websearch/orchestrator.js +15 -5
  103. package/server/agent/websearch/resilience/cache.js +9 -2
  104. package/server/agent/websearch/security/ssrf.js +41 -10
  105. package/server/agent/youtubeAuth.js +5 -20
  106. package/server/apiRouter.js +5558 -4422
  107. package/server/mcp/data/discography.js +2 -2
  108. package/server/mcp/examples/antigravity.example.json +17 -0
  109. package/server/mcp/handler.js +8 -4
  110. package/server/mcp/security.js +220 -21
  111. package/server/mcp/server.js +2 -1
  112. package/server/mcp/tests/connection.test.js +14 -8
  113. package/server/mcp/tests/mcpKeyAuth.test.js +156 -0
  114. package/server/mcp/tools.js +7 -1
  115. package/server/supabase_migration_prefix.sql +102 -0
  116. package/server/supabase_schema.sql +18 -18
  117. package/server/web-chat/core/connection.js +179 -218
  118. package/server/web-chat/core/conversationContext.js +9 -2
  119. package/server/web-chat/core/directCatalogEngine.js +52 -28
  120. package/server/web-chat/core/dramaKnowledge.js +33 -22
  121. package/server/web-chat/core/followUpEngine.js +735 -81
  122. package/server/web-chat/core/futureEventGuard.js +5 -1
  123. package/server/web-chat/core/musicControlAction.js +70 -0
  124. package/server/web-chat/core/security.js +32 -21
  125. package/server/web-chat/core/toolInspector.js +6 -6
  126. package/server/web-chat/core/urlGuard.js +45 -0
  127. package/server/web-chat/router.js +204 -157
  128. package/server/web-chat/routes/chatRoute.js +885 -488
  129. package/server/web-chat/routes/engineRoute.js +270 -0
  130. package/server/web-chat/routes/exportRoute.js +1 -1
  131. package/server/web-chat/routes/lanDiscoveryRoute.js +17 -2
  132. package/server/web-chat/routes/lmStudioLoadRoute.js +172 -0
  133. package/server/web-chat/routes/mcpRoute.js +386 -0
  134. package/server/web-chat/routes/memoryRoute.js +253 -0
  135. package/server/web-chat/routes/providerRoute.js +49 -16
  136. package/server/web-chat/routes/staticRoute.js +306 -17
  137. package/server/web-chat/routes/statusRoute.js +194 -73
  138. package/server/web-chat/routes/suggestRoute.js +11 -3
  139. package/server/web-chat/routes/verifyRoute.js +26 -4
  140. package/server/web-chat/server.js +7 -6
  141. package/server/web-chat/ui/docsBuilder.js +3558 -0
  142. package/server/web-chat/ui/htmlBuilder.js +12 -0
  143. package/server/web-chat/ui/scripts/client.js +3401 -1302
  144. package/server/web-chat/ui/scripts/webchatI18n.js +155 -153
  145. package/server/web-chat/ui/settingsBuilder.js +7870 -0
  146. package/server/web-chat/ui/styles/lan-card.css +165 -0
  147. package/server/web-chat/ui/styles/main.css +4289 -447
  148. package/server/web-chat/ui/sw.js +64 -0
  149. package/server/web-chat/ui/templates/body.html +407 -281
  150. package/src/data/awardsData.js +146 -146
  151. package/src/data/musicVideoData.js +6 -4
  152. package/src/lib/vram/estimator.js +195 -19
@@ -80,8 +80,69 @@ export function sanitizeToolArguments(toolName, rawArgs = {}, toolsSchema = [])
80
80
  return cleanArgs;
81
81
  }
82
82
 
83
+ export const TOOL_NAME_ALIASES = Object.freeze({
84
+ websearch: 'web_search',
85
+ searchweb: 'web_search',
86
+ search_web: 'web_search',
87
+ google_search: 'web_search',
88
+ bing_search: 'web_search',
89
+ webimages: 'search_web_images',
90
+ web_images: 'search_web_images',
91
+ search_images: 'search_web_images',
92
+ search_image: 'search_web_images',
93
+ image_search: 'search_web_images',
94
+ works: 'search_works',
95
+ search_works: 'search_works',
96
+ dramas: 'search_works',
97
+ get_works: 'search_works',
98
+ songs: 'search_discography',
99
+ discography: 'search_discography',
100
+ search_discography: 'search_discography',
101
+ brands: 'get_brand_endorsements',
102
+ get_brand_endorsements: 'get_brand_endorsements',
103
+ news: 'search_news',
104
+ search_news: 'search_news',
105
+ timeline: 'get_career_timeline',
106
+ get_timeline: 'get_career_timeline',
107
+ awards: 'get_awards',
108
+ get_awards: 'get_awards',
109
+ profile: 'get_artist_profile',
110
+ get_profile: 'get_artist_profile',
111
+ gallery: 'get_gallery_photos',
112
+ get_photos: 'get_gallery_photos',
113
+ photos: 'get_gallery_photos',
114
+ });
115
+
116
+ export function resolveCanonicalToolName(rawName) {
117
+ if (!rawName) return null;
118
+ const cleaned = String(rawName).trim().replace(/^call:/i, '').toLowerCase();
119
+ return TOOL_NAME_ALIASES[cleaned] || String(rawName).trim().replace(/^call:/i, '');
120
+ }
121
+
122
+ export function parseCustomToolArgs(rawArgs) {
123
+ if (!rawArgs) return {};
124
+ let clean = String(rawArgs).replace(/<\|["']\|>/g, '"').trim();
125
+ if (clean.startsWith('{') && clean.endsWith('}')) {
126
+ try {
127
+ const parsed = JSON.parse(clean);
128
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) return parsed;
129
+ } catch {}
130
+ }
131
+
132
+ const args = {};
133
+ const kvRegex = /([a-zA-Z0-9_]+)\s*:\s*(?:"([^"]*)"|'([^']*)'|([^,}\s]+))/g;
134
+ for (const m of clean.matchAll(kvRegex)) {
135
+ let key = m[1].trim();
136
+ if (key === 'targetlanguage') key = 'target_language';
137
+ if (key === 'domainfilter') key = 'domain_filter';
138
+ const val = m[2] !== undefined ? m[2] : (m[3] !== undefined ? m[3] : m[4]);
139
+ args[key] = val;
140
+ }
141
+ return args;
142
+ }
143
+
83
144
  /**
84
- * Parse text-emitted tool calls (fenced JSON or ReAct "Action:" blocks).
145
+ * Parse text-emitted tool calls (fenced JSON, ReAct "Action:" blocks, or [TOOLCALL] tags).
85
146
  * Returns { calls, malformed } — malformed counts blocks that LOOK like tool
86
147
  * calls but could not be parsed, so the caller can feed that back to the model
87
148
  * instead of silently treating the message as the final answer.
@@ -92,63 +153,124 @@ export function parseTextToolCallsFromContent(content, toolsSchema) {
92
153
  const allTools = toolsSchema || [];
93
154
  const isValidTool = (name) => allTools.some(t => t.function?.name === name);
94
155
 
95
- const pushCall = (prefix, toolName, args) => {
96
- const cleanArgs = sanitizeToolArguments(toolName, args, allTools);
156
+ const pushCall = (prefix, rawToolName, args) => {
157
+ const canonicalName = resolveCanonicalToolName(rawToolName);
158
+ if (!canonicalName || !isValidTool(canonicalName)) return false;
159
+ const cleanArgs = sanitizeToolArguments(canonicalName, args, allTools);
97
160
  result.calls.push({
98
161
  id: `${prefix}_${Date.now()}_${result.calls.length}`,
99
- function: { name: toolName, arguments: JSON.stringify(cleanArgs) }
162
+ function: { name: canonicalName, arguments: JSON.stringify(cleanArgs) }
100
163
  });
164
+ return true;
101
165
  };
102
166
 
103
- const fenceRegex = /```(?:json)?\s*([\s\S]*?)```/g;
104
- for (const match of content.matchAll(fenceRegex)) {
105
- const body = match[1];
106
- if (!body.includes('{')) continue;
107
- const { objects, unbalanced } = extractTopLevelJsonObjects(body);
108
- if (unbalanced) result.malformed++;
109
- for (const obj of objects) {
110
- let parsed = null;
167
+ // 1. [TOOLCALL] or <tool_call> with toolName{...}
168
+ const inlineToolCallRegex = /(?:\[TOOLCALL\]|<tool_call>|<toolcall>|<\|tool_call\|>)\s*(?:call:)?([a-zA-Z0-9_]+)\s*\{([\s\S]*?)\}\s*(?:<toolcall\|?>|<\/tool_call>|<\/toolcall>|\[\/TOOLCALL\]|$)/gi;
169
+ for (const match of content.matchAll(inlineToolCallRegex)) {
170
+ const toolName = match[1];
171
+ const args = parseCustomToolArgs(match[2]);
172
+ pushCall('call_tc', toolName, args);
173
+ }
174
+
175
+ // 2. <tool_call> or [TOOLCALL] containing JSON object
176
+ if (result.calls.length === 0) {
177
+ const tagJsonRegex = /(?:<tool_call>|\[TOOLCALL\]|<\|tool_call\|>)\s*(\{[\s\S]*?\})\s*(?:<\/tool_call>|<toolcall\|?>|\[\/TOOLCALL\]|$)/gi;
178
+ for (const match of content.matchAll(tagJsonRegex)) {
111
179
  try {
112
- parsed = JSON.parse(obj.raw);
113
- } catch {
114
- parsed = null;
115
- }
116
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
117
- result.malformed++;
118
- continue;
119
- }
120
- const toolName = parsed.action || parsed.tool || parsed.name || parsed.function;
121
- if (!toolName) continue;
122
- let toolArgs = parsed.action_input ?? parsed.parameters ?? parsed.arguments ?? parsed.args ?? {};
123
- if (toolArgs && typeof toolArgs === 'string') {
124
- try { toolArgs = JSON.parse(toolArgs); } catch { toolArgs = { query: toolArgs }; }
125
- }
126
- if (!toolArgs || typeof toolArgs !== 'object' || Array.isArray(toolArgs)) toolArgs = {};
127
- if (isValidTool(String(toolName))) {
180
+ const obj = JSON.parse(match[1].replace(/<\|["']\|>/g, '"'));
181
+ const toolName = obj.name || obj.action || obj.tool || obj.function;
182
+ let args = obj.arguments || obj.parameters || obj.action_input || obj.args || {};
183
+ if (typeof args === 'string') {
184
+ try { args = JSON.parse(args); } catch {}
185
+ }
186
+ if (toolName) pushCall('call_tag_json', toolName, args);
187
+ } catch {}
188
+ }
189
+ }
190
+
191
+ // 3. [TOOL_CALLS] array format
192
+ if (result.calls.length === 0) {
193
+ const arrayRegex = /\[TOOL_CALLS\]\s*(\[[\s\S]*?\])/gi;
194
+ for (const match of content.matchAll(arrayRegex)) {
195
+ try {
196
+ const arr = JSON.parse(match[1].replace(/<\|["']\|>/g, '"'));
197
+ if (Array.isArray(arr)) {
198
+ for (const item of arr) {
199
+ const toolName = item.name || item.function?.name || item.action;
200
+ let args = item.arguments || item.parameters || item.function?.arguments || {};
201
+ if (typeof args === 'string') {
202
+ try { args = JSON.parse(args); } catch {}
203
+ }
204
+ if (toolName) pushCall('call_arr', toolName, args);
205
+ }
206
+ }
207
+ } catch {}
208
+ }
209
+ }
210
+
211
+ // 4. Standalone tool_name{...}<toolcall|>
212
+ if (result.calls.length === 0) {
213
+ const standaloneRegex = /(?:^|\n)(?:call:)?([a-zA-Z0-9_]+)\s*\{([\s\S]*?)\}\s*<toolcall\|?>/gi;
214
+ for (const match of content.matchAll(standaloneRegex)) {
215
+ const toolName = match[1];
216
+ const args = parseCustomToolArgs(match[2]);
217
+ pushCall('call_standalone', toolName, args);
218
+ }
219
+ }
220
+
221
+ // 5. Fenced JSON: ```json ... ```
222
+ if (result.calls.length === 0) {
223
+ const fenceRegex = /```(?:json)?\s*([\s\S]*?)```/g;
224
+ for (const match of content.matchAll(fenceRegex)) {
225
+ const body = match[1];
226
+ if (!body.includes('{')) continue;
227
+ const { objects, unbalanced } = extractTopLevelJsonObjects(body);
228
+ if (unbalanced) result.malformed++;
229
+ for (const obj of objects) {
230
+ let parsed = null;
231
+ try {
232
+ parsed = JSON.parse(obj.raw);
233
+ } catch {
234
+ parsed = null;
235
+ }
236
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
237
+ result.malformed++;
238
+ continue;
239
+ }
240
+ const toolName = parsed.action || parsed.tool || parsed.name || parsed.function;
241
+ if (!toolName) continue;
242
+ let toolArgs = parsed.action_input ?? parsed.parameters ?? parsed.arguments ?? parsed.args ?? {};
243
+ if (toolArgs && typeof toolArgs === 'string') {
244
+ try { toolArgs = JSON.parse(toolArgs); } catch { toolArgs = { query: toolArgs }; }
245
+ }
246
+ if (!toolArgs || typeof toolArgs !== 'object' || Array.isArray(toolArgs)) toolArgs = {};
128
247
  pushCall('call_txt', String(toolName), toolArgs);
129
248
  }
130
249
  }
131
250
  }
132
251
 
133
- const actionRegex = /Action:\s*([a-zA-Z0-9_]+)\s*\nAction Input:\s*([\s\S]*?)(?=\nAction:|\nObservation:|$)/g;
134
- for (const match of content.matchAll(actionRegex)) {
135
- const toolName = match[1].trim();
136
- const rawInput = match[2].trim();
137
- if (!isValidTool(toolName)) continue;
138
- if (rawInput.startsWith('{')) {
139
- const { objects, unbalanced } = extractTopLevelJsonObjects(rawInput);
140
- const candidate = objects.length > 0 ? objects[0].raw : unbalanced;
141
- let parsed = null;
142
- if (candidate) {
143
- try { parsed = JSON.parse(candidate); } catch { parsed = null; }
144
- }
145
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
146
- result.malformed++;
147
- continue;
252
+ // 6. Action: ... \n Action Input: ...
253
+ if (result.calls.length === 0) {
254
+ const actionRegex = /Action:\s*([a-zA-Z0-9_]+)\s*\nAction Input:\s*([\s\S]*?)(?=\nAction:|\nObservation:|$)/g;
255
+ for (const match of content.matchAll(actionRegex)) {
256
+ const toolName = match[1].trim();
257
+ const rawInput = match[2].trim();
258
+ if (!isValidTool(resolveCanonicalToolName(toolName))) continue;
259
+ if (rawInput.startsWith('{')) {
260
+ const { objects, unbalanced } = extractTopLevelJsonObjects(rawInput);
261
+ const candidate = objects.length > 0 ? objects[0].raw : unbalanced;
262
+ let parsed = null;
263
+ if (candidate) {
264
+ try { parsed = JSON.parse(candidate); } catch { parsed = null; }
265
+ }
266
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
267
+ result.malformed++;
268
+ continue;
269
+ }
270
+ pushCall('call_act', toolName, parsed);
271
+ } else {
272
+ pushCall('call_act', toolName, { query: rawInput });
148
273
  }
149
- pushCall('call_act', toolName, parsed);
150
- } else {
151
- pushCall('call_act', toolName, { query: rawInput });
152
274
  }
153
275
  }
154
276
 
@@ -186,5 +308,10 @@ export function stripToolCallBlocks(content) {
186
308
  let cleaned = String(content || '');
187
309
  cleaned = cleaned.replace(/```(?:json)?\s*[\s\S]*?```/g, '');
188
310
  cleaned = cleaned.replace(/Action:\s*[a-zA-Z0-9_]+\s*\nAction Input:[\s\S]*?(?=\nAction:|\nObservation:|$)/g, '');
311
+ cleaned = cleaned.replace(/(?:\[TOOLCALL\]|<tool_call>|<toolcall>|<\|tool_call\|>)\s*(?:call:)?[a-zA-Z0-9_]+\s*\{[\s\S]*?\}\s*(?:<toolcall\|?>|<\/tool_call>|<\/toolcall>|\[\/TOOLCALL\]|$)/gi, '');
312
+ cleaned = cleaned.replace(/(?:<tool_call>|\[TOOLCALL\]|<\|tool_call\|>)\s*\{[\s\S]*?\}\s*(?:<\/tool_call>|<toolcall\|?>|\[\/TOOLCALL\]|$)/gi, '');
313
+ cleaned = cleaned.replace(/\[TOOL_CALLS\]\s*\[[\s\S]*?\]/gi, '');
314
+ cleaned = cleaned.replace(/(?:^|\n)(?:call:)?[a-zA-Z0-9_]+\s*\{[\s\S]*?\}\s*<toolcall\|?>/gi, '');
315
+ cleaned = cleaned.replace(/<\|?toolcall\|?>|<\/?tool_call>|<\/?toolcall>|\[\/?TOOLCALL\]|\[TOOL_CALLS\]|<\|["']\|>/gi, '');
189
316
  return cleaned.trim();
190
317
  }