@vybestack/llxprt-code-core 0.4.7 → 0.5.0-nightly.251102.6bb3db7a

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 (219) hide show
  1. package/dist/prompt-config/defaults/default-prompts.json +4 -17
  2. package/dist/src/auth/precedence.d.ts +69 -9
  3. package/dist/src/auth/precedence.js +467 -69
  4. package/dist/src/auth/precedence.js.map +1 -1
  5. package/dist/src/auth/types.d.ts +2 -2
  6. package/dist/src/config/config.d.ts +18 -1
  7. package/dist/src/config/config.js +123 -6
  8. package/dist/src/config/config.js.map +1 -1
  9. package/dist/src/config/index.d.ts +6 -0
  10. package/dist/src/config/index.js +5 -0
  11. package/dist/src/config/index.js.map +1 -1
  12. package/dist/src/config/profileManager.d.ts +23 -3
  13. package/dist/src/config/profileManager.js +54 -7
  14. package/dist/src/config/profileManager.js.map +1 -1
  15. package/dist/src/config/subagentManager.d.ts +96 -0
  16. package/dist/src/config/subagentManager.js +371 -0
  17. package/dist/src/config/subagentManager.js.map +1 -0
  18. package/dist/src/config/types.d.ts +18 -0
  19. package/dist/src/config/types.js +3 -0
  20. package/dist/src/config/types.js.map +1 -0
  21. package/dist/src/core/client.d.ts +27 -7
  22. package/dist/src/core/client.js +235 -56
  23. package/dist/src/core/client.js.map +1 -1
  24. package/dist/src/core/contentGenerator.d.ts +3 -1
  25. package/dist/src/core/contentGenerator.js +3 -0
  26. package/dist/src/core/contentGenerator.js.map +1 -1
  27. package/dist/src/core/coreToolScheduler.d.ts +1 -5
  28. package/dist/src/core/coreToolScheduler.js +95 -23
  29. package/dist/src/core/coreToolScheduler.js.map +1 -1
  30. package/dist/src/core/geminiChat.d.ts +42 -12
  31. package/dist/src/core/geminiChat.js +413 -207
  32. package/dist/src/core/geminiChat.js.map +1 -1
  33. package/dist/src/core/nonInteractiveToolExecutor.d.ts +3 -2
  34. package/dist/src/core/nonInteractiveToolExecutor.js +94 -10
  35. package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
  36. package/dist/src/core/subagent.d.ts +86 -7
  37. package/dist/src/core/subagent.js +809 -79
  38. package/dist/src/core/subagent.js.map +1 -1
  39. package/dist/src/core/subagentOrchestrator.d.ts +73 -0
  40. package/dist/src/core/subagentOrchestrator.js +383 -0
  41. package/dist/src/core/subagentOrchestrator.js.map +1 -0
  42. package/dist/src/core/subagentScheduler.d.ts +16 -0
  43. package/dist/src/core/subagentScheduler.js +7 -0
  44. package/dist/src/core/subagentScheduler.js.map +1 -0
  45. package/dist/src/core/turn.d.ts +5 -1
  46. package/dist/src/core/turn.js +5 -1
  47. package/dist/src/core/turn.js.map +1 -1
  48. package/dist/src/hooks/tool-render-suppression-hook.js +6 -1
  49. package/dist/src/hooks/tool-render-suppression-hook.js.map +1 -1
  50. package/dist/src/ide/ideContext.d.ts +32 -32
  51. package/dist/src/index.d.ts +19 -1
  52. package/dist/src/index.js +15 -2
  53. package/dist/src/index.js.map +1 -1
  54. package/dist/src/interfaces/index.d.ts +1 -0
  55. package/dist/src/interfaces/index.js +4 -0
  56. package/dist/src/interfaces/index.js.map +1 -0
  57. package/dist/src/interfaces/nodejs-error.interface.d.ts +4 -0
  58. package/dist/src/interfaces/nodejs-error.interface.js +2 -0
  59. package/dist/src/interfaces/nodejs-error.interface.js.map +1 -0
  60. package/dist/src/parsers/TextToolCallParser.d.ts +17 -1
  61. package/dist/src/parsers/TextToolCallParser.js +542 -148
  62. package/dist/src/parsers/TextToolCallParser.js.map +1 -1
  63. package/dist/src/prompt-config/defaults/core.md +15 -0
  64. package/dist/src/prompt-config/defaults/providers/gemini/core.md +203 -119
  65. package/dist/src/prompt-config/defaults/tool-defaults.js +2 -0
  66. package/dist/src/prompt-config/defaults/tool-defaults.js.map +1 -1
  67. package/dist/src/prompt-config/defaults/tools/list-subagents.md +7 -0
  68. package/dist/src/prompt-config/defaults/tools/task.md +8 -0
  69. package/dist/src/providers/BaseProvider.d.ts +115 -30
  70. package/dist/src/providers/BaseProvider.js +445 -109
  71. package/dist/src/providers/BaseProvider.js.map +1 -1
  72. package/dist/src/providers/IProvider.d.ts +50 -18
  73. package/dist/src/providers/LoggingProviderWrapper.d.ts +60 -16
  74. package/dist/src/providers/LoggingProviderWrapper.js +213 -60
  75. package/dist/src/providers/LoggingProviderWrapper.js.map +1 -1
  76. package/dist/src/providers/ProviderManager.d.ts +73 -2
  77. package/dist/src/providers/ProviderManager.js +492 -40
  78. package/dist/src/providers/ProviderManager.js.map +1 -1
  79. package/dist/src/providers/anthropic/AnthropicProvider.d.ts +35 -38
  80. package/dist/src/providers/anthropic/AnthropicProvider.js +222 -227
  81. package/dist/src/providers/anthropic/AnthropicProvider.js.map +1 -1
  82. package/dist/src/providers/errors.d.ts +86 -0
  83. package/dist/src/providers/errors.js +89 -0
  84. package/dist/src/providers/errors.js.map +1 -1
  85. package/dist/src/providers/gemini/GeminiProvider.d.ts +101 -41
  86. package/dist/src/providers/gemini/GeminiProvider.js +386 -311
  87. package/dist/src/providers/gemini/GeminiProvider.js.map +1 -1
  88. package/dist/src/providers/openai/ConversationCache.d.ts +5 -3
  89. package/dist/src/providers/openai/ConversationCache.js +93 -32
  90. package/dist/src/providers/openai/ConversationCache.js.map +1 -1
  91. package/dist/src/providers/openai/OpenAIProvider.d.ts +82 -42
  92. package/dist/src/providers/openai/OpenAIProvider.js +392 -457
  93. package/dist/src/providers/openai/OpenAIProvider.js.map +1 -1
  94. package/dist/src/providers/openai/getOpenAIProviderInfo.d.ts +1 -1
  95. package/dist/src/providers/openai/getOpenAIProviderInfo.js +52 -22
  96. package/dist/src/providers/openai/getOpenAIProviderInfo.js.map +1 -1
  97. package/dist/src/providers/openai/openaiRequestParams.d.ts +7 -0
  98. package/dist/src/providers/openai/openaiRequestParams.js +66 -0
  99. package/dist/src/providers/openai/openaiRequestParams.js.map +1 -0
  100. package/dist/src/providers/openai-responses/OpenAIResponsesProvider.d.ts +6 -33
  101. package/dist/src/providers/openai-responses/OpenAIResponsesProvider.js +84 -183
  102. package/dist/src/providers/openai-responses/OpenAIResponsesProvider.js.map +1 -1
  103. package/dist/src/providers/types/providerRuntime.d.ts +17 -0
  104. package/dist/src/providers/types/providerRuntime.js +7 -0
  105. package/dist/src/providers/types/providerRuntime.js.map +1 -0
  106. package/dist/src/providers/utils/authToken.d.ts +12 -0
  107. package/dist/src/providers/utils/authToken.js +17 -0
  108. package/dist/src/providers/utils/authToken.js.map +1 -0
  109. package/dist/src/providers/utils/userMemory.d.ts +8 -0
  110. package/dist/src/providers/utils/userMemory.js +34 -0
  111. package/dist/src/providers/utils/userMemory.js.map +1 -0
  112. package/dist/src/runtime/AgentRuntimeContext.d.ts +213 -0
  113. package/dist/src/runtime/AgentRuntimeContext.js +17 -0
  114. package/dist/src/runtime/AgentRuntimeContext.js.map +1 -0
  115. package/dist/src/runtime/AgentRuntimeLoader.d.ts +47 -0
  116. package/dist/src/runtime/AgentRuntimeLoader.js +122 -0
  117. package/dist/src/runtime/AgentRuntimeLoader.js.map +1 -0
  118. package/dist/src/runtime/AgentRuntimeState.d.ts +232 -0
  119. package/dist/src/runtime/AgentRuntimeState.js +439 -0
  120. package/dist/src/runtime/AgentRuntimeState.js.map +1 -0
  121. package/dist/src/runtime/RuntimeInvocationContext.d.ts +51 -0
  122. package/dist/src/runtime/RuntimeInvocationContext.js +52 -0
  123. package/dist/src/runtime/RuntimeInvocationContext.js.map +1 -0
  124. package/dist/src/runtime/createAgentRuntimeContext.d.ts +7 -0
  125. package/dist/src/runtime/createAgentRuntimeContext.js +65 -0
  126. package/dist/src/runtime/createAgentRuntimeContext.js.map +1 -0
  127. package/dist/src/runtime/index.d.ts +13 -0
  128. package/dist/src/runtime/index.js +14 -0
  129. package/dist/src/runtime/index.js.map +1 -0
  130. package/dist/src/runtime/providerRuntimeContext.d.ts +30 -0
  131. package/dist/src/runtime/providerRuntimeContext.js +70 -0
  132. package/dist/src/runtime/providerRuntimeContext.js.map +1 -0
  133. package/dist/src/runtime/runtimeAdapters.d.ts +22 -0
  134. package/dist/src/runtime/runtimeAdapters.js +81 -0
  135. package/dist/src/runtime/runtimeAdapters.js.map +1 -0
  136. package/dist/src/runtime/runtimeStateFactory.d.ts +21 -0
  137. package/dist/src/runtime/runtimeStateFactory.js +104 -0
  138. package/dist/src/runtime/runtimeStateFactory.js.map +1 -0
  139. package/dist/src/services/history/ContentConverters.js +3 -5
  140. package/dist/src/services/history/ContentConverters.js.map +1 -1
  141. package/dist/src/services/shellExecutionService.js +2 -2
  142. package/dist/src/services/shellExecutionService.js.map +1 -1
  143. package/dist/src/services/todo-context-tracker.d.ts +10 -8
  144. package/dist/src/services/todo-context-tracker.js +26 -10
  145. package/dist/src/services/todo-context-tracker.js.map +1 -1
  146. package/dist/src/services/tool-call-tracker-service.d.ts +11 -7
  147. package/dist/src/services/tool-call-tracker-service.js +89 -29
  148. package/dist/src/services/tool-call-tracker-service.js.map +1 -1
  149. package/dist/src/settings/SettingsService.d.ts +4 -0
  150. package/dist/src/settings/SettingsService.js +65 -2
  151. package/dist/src/settings/SettingsService.js.map +1 -1
  152. package/dist/src/settings/settingsServiceInstance.d.ts +6 -1
  153. package/dist/src/settings/settingsServiceInstance.js +28 -8
  154. package/dist/src/settings/settingsServiceInstance.js.map +1 -1
  155. package/dist/src/telemetry/loggers.d.ts +5 -1
  156. package/dist/src/telemetry/loggers.js.map +1 -1
  157. package/dist/src/telemetry/loggers.test.circular.js +4 -0
  158. package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
  159. package/dist/src/telemetry/metrics.d.ts +3 -1
  160. package/dist/src/telemetry/metrics.js.map +1 -1
  161. package/dist/src/telemetry/types.d.ts +1 -0
  162. package/dist/src/telemetry/types.js +3 -0
  163. package/dist/src/telemetry/types.js.map +1 -1
  164. package/dist/src/test-utils/index.d.ts +2 -0
  165. package/dist/src/test-utils/index.js +2 -0
  166. package/dist/src/test-utils/index.js.map +1 -1
  167. package/dist/src/test-utils/mockWorkspaceContext.d.ts +0 -3
  168. package/dist/src/test-utils/mockWorkspaceContext.js +3 -4
  169. package/dist/src/test-utils/mockWorkspaceContext.js.map +1 -1
  170. package/dist/src/test-utils/providerCallOptions.d.ts +43 -0
  171. package/dist/src/test-utils/providerCallOptions.js +137 -0
  172. package/dist/src/test-utils/providerCallOptions.js.map +1 -0
  173. package/dist/src/test-utils/runtime.d.ts +92 -0
  174. package/dist/src/test-utils/runtime.js +226 -0
  175. package/dist/src/test-utils/runtime.js.map +1 -0
  176. package/dist/src/test-utils/tools.d.ts +4 -4
  177. package/dist/src/test-utils/tools.js +20 -10
  178. package/dist/src/test-utils/tools.js.map +1 -1
  179. package/dist/src/tools/list-subagents.d.ts +31 -0
  180. package/dist/src/tools/list-subagents.js +109 -0
  181. package/dist/src/tools/list-subagents.js.map +1 -0
  182. package/dist/src/tools/task.d.ts +87 -0
  183. package/dist/src/tools/task.js +427 -0
  184. package/dist/src/tools/task.js.map +1 -0
  185. package/dist/src/tools/todo-read.js +1 -1
  186. package/dist/src/tools/todo-read.js.map +1 -1
  187. package/dist/src/tools/todo-store.js +4 -2
  188. package/dist/src/tools/todo-store.js.map +1 -1
  189. package/dist/src/tools/todo-write.js +4 -2
  190. package/dist/src/tools/todo-write.js.map +1 -1
  191. package/dist/src/tools/tool-error.d.ts +1 -0
  192. package/dist/src/tools/tool-error.js +1 -0
  193. package/dist/src/tools/tool-error.js.map +1 -1
  194. package/dist/src/tools/tool-registry.d.ts +2 -0
  195. package/dist/src/tools/tool-registry.js +46 -21
  196. package/dist/src/tools/tool-registry.js.map +1 -1
  197. package/dist/src/types/modelParams.d.ts +4 -0
  198. package/dist/src/utils/editor.js +10 -8
  199. package/dist/src/utils/editor.js.map +1 -1
  200. package/dist/src/utils/gitIgnoreParser.js +15 -3
  201. package/dist/src/utils/gitIgnoreParser.js.map +1 -1
  202. package/dist/src/utils/memoryImportProcessor.js +22 -3
  203. package/dist/src/utils/memoryImportProcessor.js.map +1 -1
  204. package/package.json +1 -1
  205. package/dist/src/prompt-config/defaults/providers/anthropic/core.md +0 -97
  206. package/dist/src/prompt-config/defaults/providers/anthropic/tools/glob.md +0 -34
  207. package/dist/src/prompt-config/defaults/providers/anthropic/tools/list-directory.md +0 -11
  208. package/dist/src/prompt-config/defaults/providers/anthropic/tools/read-file.md +0 -14
  209. package/dist/src/prompt-config/defaults/providers/anthropic/tools/read-many-files.md +0 -31
  210. package/dist/src/prompt-config/defaults/providers/anthropic/tools/replace.md +0 -41
  211. package/dist/src/prompt-config/defaults/providers/anthropic/tools/run-shell-command.md +0 -32
  212. package/dist/src/prompt-config/defaults/providers/anthropic/tools/save-memory.md +0 -35
  213. package/dist/src/prompt-config/defaults/providers/anthropic/tools/search-file-content.md +0 -44
  214. package/dist/src/prompt-config/defaults/providers/anthropic/tools/todo-write.md +0 -45
  215. package/dist/src/prompt-config/defaults/providers/anthropic/tools/write-file.md +0 -11
  216. package/dist/src/prompt-config/defaults/providers/openai/core.md +0 -97
  217. package/dist/src/prompt-config/defaults/providers/openai/tools/todo-pause.md +0 -28
  218. package/dist/src/prompt-config/defaults/providers/openai/tools/todo-read.md +0 -5
  219. package/dist/src/prompt-config/defaults/providers/openai/tools/todo-write.md +0 -45
@@ -4,25 +4,8 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
  export class GemmaToolCallParser {
7
- // Support multiple tool call formats
8
- patterns = [
9
- // Format 1: [TOOL_REQUEST] toolName {args} [TOOL_REQUEST_END]
10
- /\[TOOL_REQUEST\]\s*(\w+)\s+({.*?})\s*\[TOOL_REQUEST_END\]/gs,
11
- // Format 2: ✦ tool_call: toolName for key value pairs (more specific to avoid false positives)
12
- /✦\s*tool_call:\s*(\w+)\s+for\s+(.+?)(?=\n|✦|$)/gs,
13
- // Format 3: JSON object with name/arguments followed by [END_TOOL_REQUEST]
14
- /(\d+\s+)?{"name":\s*"(\w+)",\s*"arguments":\s*({.*?})}\s*(?:\n\s*\d+\s+)?\[END_TOOL_REQUEST\]/gs,
15
- // Format 4: Hermes format with <tool_call> tags
16
- /<tool_call>\s*({.*?"name":\s*"(\w+)".*?})\s*<\/tool_call>/gs,
17
- // Format 5: XML with <invoke> tags (Claude-style)
18
- /<invoke\s+name="(\w+)">(.*?)<\/invoke>/gs,
19
- // Format 6: Generic XML tool format
20
- /<tool>\s*<name>(\w+)<\/name>\s*<arguments>(.*?)<\/arguments>\s*<\/tool>/gs,
21
- ];
7
+ keyValuePattern = /✦\s*tool_call:\s*([A-Za-z0-9_.-]+)\s+for\s+([^\n✦]*)/g;
22
8
  parse(content) {
23
- const toolCalls = [];
24
- let cleanedContent = content;
25
- const matches = [];
26
9
  // Quick check: if content doesn't contain any tool call markers, return early
27
10
  if (!content.includes('[TOOL_REQUEST') &&
28
11
  !content.includes('tool_call:') &&
@@ -30,154 +13,449 @@ export class GemmaToolCallParser {
30
13
  !content.includes('{"name":') &&
31
14
  !content.includes('<tool_call>') &&
32
15
  !content.includes('<invoke') &&
33
- !content.includes('<tool>')) {
16
+ !content.includes('<tool>') &&
17
+ !content.includes('<use ')) {
34
18
  return { cleanedContent: content, toolCalls: [] };
35
19
  }
36
- // Try each pattern
37
- for (const pattern of this.patterns) {
38
- let match;
39
- while ((match = pattern.exec(content)) !== null) {
40
- if (pattern === this.patterns[1]) {
41
- // Format 2: Parse key-value pairs from "for key value key2 value2" format
42
- const [fullMatch, toolName, argsStr] = match;
43
- const args = this.parseKeyValuePairs(argsStr);
44
- matches.push({ fullMatch, toolName, args });
45
- }
46
- else if (pattern === this.patterns[2]) {
47
- // Format 3: JSON object format {"name": "tool", "arguments": {...}}
48
- const [fullMatch, , toolName, jsonArgs] = match;
49
- matches.push({ fullMatch, toolName, args: jsonArgs });
50
- }
51
- else if (pattern === this.patterns[3]) {
52
- // Format 4: Hermes format <tool_call>{"arguments": {...}, "name": "tool"}</tool_call>
53
- const [fullMatch, hermesJson, toolName] = match;
54
- try {
55
- const parsed = JSON.parse(hermesJson);
56
- matches.push({
57
- fullMatch,
58
- toolName,
59
- args: JSON.stringify(parsed.arguments || {}),
60
- });
61
- }
62
- catch (error) {
63
- console.error(`[GemmaToolCallParser] Failed to parse Hermes format: ${error}`);
64
- // Still need to track the match to remove it from content
65
- matches.push({ fullMatch, toolName: '', args: '' });
66
- }
67
- }
68
- else if (pattern === this.patterns[4]) {
69
- // Format 5: XML with <invoke> tags (Claude-style)
70
- const [fullMatch, toolName, xmlContent] = match;
71
- matches.push({ fullMatch, toolName, args: xmlContent });
72
- }
73
- else if (pattern === this.patterns[5]) {
74
- // Format 6: Generic XML tool format
75
- const [fullMatch, toolName, xmlArgs] = match;
76
- matches.push({ fullMatch, toolName, args: xmlArgs });
77
- }
78
- else {
79
- // Format 1: tool name followed by JSON arguments
80
- const [fullMatch, toolName, jsonArgs] = match;
81
- matches.push({ fullMatch, toolName, args: jsonArgs });
82
- }
20
+ const matches = this.collectMatches(content);
21
+ const toolCalls = [];
22
+ const ranges = [];
23
+ for (const match of matches) {
24
+ ranges.push({ start: match.start, end: match.end });
25
+ if (!match.toolName) {
26
+ continue;
27
+ }
28
+ const parsedArgs = this.normalizeArguments(match.rawArgs, match.toolName, match.fullMatch);
29
+ if (!parsedArgs) {
30
+ continue;
83
31
  }
84
- // Reset the regex state for next use
85
- pattern.lastIndex = 0;
32
+ toolCalls.push({
33
+ name: match.toolName,
34
+ arguments: parsedArgs,
35
+ });
86
36
  }
87
- // Process each match
88
- for (const { fullMatch, toolName, args } of matches) {
89
- // Remove the tool call pattern from the content regardless of parsing success so markers are always stripped
90
- cleanedContent = cleanedContent.replace(fullMatch, '');
91
- // Skip if toolName is empty (failed parsing)
92
- if (!toolName) {
37
+ const withoutMatches = this.removeMatchedRanges(content, ranges);
38
+ const cleanedContent = this.postProcessCleanedContent(withoutMatches);
39
+ return { cleanedContent, toolCalls };
40
+ }
41
+ collectMatches(content) {
42
+ const matches = [
43
+ ...this.findBracketToolRequests(content),
44
+ ...this.findJsonToolRequests(content),
45
+ ...this.findHermesToolRequests(content),
46
+ ...this.findInvokeToolRequests(content),
47
+ ...this.findGenericXmlToolRequests(content),
48
+ ...this.findUseToolRequests(content),
49
+ ...this.findUseUnderscoreToolRequests(content),
50
+ ...this.findKeyValueToolRequests(content),
51
+ ];
52
+ return matches.sort((a, b) => a.start - b.start);
53
+ }
54
+ findBracketToolRequests(content) {
55
+ const matches = [];
56
+ const startMarker = '[TOOL_REQUEST]';
57
+ const endMarker = '[TOOL_REQUEST_END]';
58
+ let searchIndex = 0;
59
+ while (searchIndex < content.length) {
60
+ const start = content.indexOf(startMarker, searchIndex);
61
+ if (start === -1)
62
+ break;
63
+ const afterStart = start + startMarker.length;
64
+ const endMarkerIndex = content.indexOf(endMarker, afterStart);
65
+ if (endMarkerIndex === -1)
66
+ break;
67
+ const segment = content.slice(afterStart, endMarkerIndex);
68
+ const toolNameMatch = segment.match(/^\s*([^\s{]+)\s+/);
69
+ if (!toolNameMatch) {
70
+ searchIndex = endMarkerIndex + endMarker.length;
71
+ continue;
72
+ }
73
+ const toolName = toolNameMatch[1];
74
+ const braceOffset = segment.indexOf('{', toolNameMatch[0].length);
75
+ if (braceOffset === -1) {
76
+ searchIndex = endMarkerIndex + endMarker.length;
77
+ continue;
78
+ }
79
+ const jsonStart = afterStart + braceOffset;
80
+ const jsonSegment = this.extractBalancedSegment(content, jsonStart, '{', '}');
81
+ if (!jsonSegment || jsonSegment.endIndex > endMarkerIndex) {
82
+ searchIndex = endMarkerIndex + endMarker.length;
83
+ continue;
84
+ }
85
+ const fullEnd = endMarkerIndex + endMarker.length;
86
+ matches.push({
87
+ start,
88
+ end: fullEnd,
89
+ toolName,
90
+ rawArgs: jsonSegment.segment,
91
+ fullMatch: content.slice(start, fullEnd),
92
+ });
93
+ searchIndex = fullEnd;
94
+ }
95
+ return matches;
96
+ }
97
+ findJsonToolRequests(content) {
98
+ const matches = [];
99
+ const marker = '{"name":';
100
+ const endMarker = '[END_TOOL_REQUEST]';
101
+ let searchIndex = 0;
102
+ while (searchIndex < content.length) {
103
+ const candidateIndex = content.indexOf(marker, searchIndex);
104
+ if (candidateIndex === -1) {
105
+ break;
106
+ }
107
+ let startIndex = candidateIndex;
108
+ let backPointer = candidateIndex;
109
+ while (backPointer > 0 && /\s/.test(content.charAt(backPointer - 1))) {
110
+ backPointer--;
111
+ }
112
+ let digitPointer = backPointer;
113
+ while (digitPointer > 0 && /\d/.test(content.charAt(digitPointer - 1))) {
114
+ digitPointer--;
115
+ }
116
+ if (digitPointer < backPointer) {
117
+ startIndex = digitPointer;
118
+ }
119
+ const jsonSegment = this.extractBalancedSegment(content, candidateIndex, '{', '}');
120
+ if (!jsonSegment) {
121
+ searchIndex = candidateIndex + marker.length;
93
122
  continue;
94
123
  }
95
124
  try {
96
- let parsedArgs;
97
- if (typeof args === 'string') {
98
- // Check if it's XML content (Claude-style or generic)
99
- if (args.includes('<parameter') ||
100
- (args.includes('<') && args.includes('>'))) {
101
- parsedArgs = this.parseXMLParameters(args);
102
- }
103
- else {
104
- // Handle JSON string arguments
105
- parsedArgs = JSON.parse(args);
106
- }
107
- }
108
- else {
109
- // Already parsed (from key-value format)
110
- parsedArgs = args;
125
+ const parsed = JSON.parse(jsonSegment.segment);
126
+ const toolName = String(parsed.name ?? '');
127
+ const argsText = JSON.stringify(parsed.arguments ?? {});
128
+ const endMarkerIndex = content.indexOf(endMarker, jsonSegment.endIndex);
129
+ if (toolName && endMarkerIndex !== -1) {
130
+ const fullEnd = endMarkerIndex + endMarker.length;
131
+ matches.push({
132
+ start: startIndex,
133
+ end: fullEnd,
134
+ toolName,
135
+ rawArgs: argsText,
136
+ fullMatch: content.slice(startIndex, fullEnd),
137
+ });
138
+ searchIndex = fullEnd;
139
+ continue;
111
140
  }
112
- toolCalls.push({
113
- name: toolName,
114
- arguments: parsedArgs,
115
- });
116
141
  }
117
142
  catch (error) {
118
- if (typeof args === 'string') {
119
- // Attempt targeted repair for common unescaped inner quotes in JSON strings
120
- const repaired = this.tryRepairJson(args);
121
- if (repaired) {
122
- try {
123
- const parsedArgs = JSON.parse(repaired);
124
- toolCalls.push({
125
- name: toolName,
126
- arguments: parsedArgs,
127
- });
128
- continue;
129
- }
130
- catch (_ignored) {
131
- // fall through to legacy fallback
132
- }
133
- }
134
- // Try to extract a simpler JSON pattern if the full match fails
135
- const simpleJsonMatch = args.match(/^{[^{]*}$/);
136
- if (simpleJsonMatch) {
137
- try {
138
- const parsedArgs = JSON.parse(simpleJsonMatch[0]);
139
- toolCalls.push({
140
- name: toolName,
141
- arguments: parsedArgs,
142
- });
143
- cleanedContent = cleanedContent.replace(fullMatch, '');
144
- }
145
- catch (_secondError) {
146
- console.error(`[GemmaToolCallParser] Failed to parse tool arguments for ${toolName}:`, error);
147
- console.error(`[GemmaToolCallParser] Raw arguments: ${args}`);
148
- // Keep the original text if we can't parse it
149
- }
150
- }
151
- else {
152
- console.error(`[GemmaToolCallParser] Failed to parse tool arguments for ${toolName}:`, error);
153
- console.error(`[GemmaToolCallParser] Raw arguments: ${args}`);
154
- }
155
- }
143
+ console.error(`[GemmaToolCallParser] Failed to parse structured tool call JSON: ${error}`);
144
+ }
145
+ searchIndex = candidateIndex + marker.length;
146
+ }
147
+ return matches;
148
+ }
149
+ findHermesToolRequests(content) {
150
+ const matches = [];
151
+ const startTag = '<tool_call>';
152
+ const endTag = '</tool_call>';
153
+ let searchIndex = 0;
154
+ while (searchIndex < content.length) {
155
+ const start = content.indexOf(startTag, searchIndex);
156
+ if (start === -1)
157
+ break;
158
+ const end = content.indexOf(endTag, start + startTag.length);
159
+ if (end === -1)
160
+ break;
161
+ const jsonText = content.slice(start + startTag.length, end).trim();
162
+ let toolName = '';
163
+ let args = '{}';
164
+ try {
165
+ const parsed = JSON.parse(jsonText);
166
+ toolName = String(parsed.name ?? '');
167
+ args = JSON.stringify(parsed.arguments ?? {});
168
+ }
169
+ catch (error) {
170
+ console.error(`[GemmaToolCallParser] Failed to parse Hermes format: ${error}`);
171
+ }
172
+ const fullEnd = end + endTag.length;
173
+ matches.push({
174
+ start,
175
+ end: fullEnd,
176
+ toolName,
177
+ rawArgs: args,
178
+ fullMatch: content.slice(start, fullEnd),
179
+ });
180
+ searchIndex = fullEnd;
181
+ }
182
+ return matches;
183
+ }
184
+ findInvokeToolRequests(content) {
185
+ const matches = [];
186
+ const tagPrefix = '<invoke';
187
+ const closing = '</invoke>';
188
+ let searchIndex = 0;
189
+ while (searchIndex < content.length) {
190
+ const start = content.indexOf(tagPrefix, searchIndex);
191
+ if (start === -1) {
192
+ break;
193
+ }
194
+ const tagEnd = this.findTagClose(content, start + tagPrefix.length);
195
+ if (tagEnd === -1) {
196
+ break;
197
+ }
198
+ const header = content.slice(start + tagPrefix.length, tagEnd);
199
+ const attributes = this.parseAttributeArguments(header);
200
+ const toolNameValue = attributes.name;
201
+ const toolName = typeof toolNameValue === 'string' ? toolNameValue.trim() : '';
202
+ const bodyStart = tagEnd + 1;
203
+ const closingIndex = content.indexOf(closing, bodyStart);
204
+ if (!toolName || closingIndex === -1) {
205
+ searchIndex = bodyStart;
206
+ continue;
207
+ }
208
+ const fullEnd = closingIndex + closing.length;
209
+ matches.push({
210
+ start,
211
+ end: fullEnd,
212
+ toolName,
213
+ rawArgs: content.slice(bodyStart, closingIndex),
214
+ fullMatch: content.slice(start, fullEnd),
215
+ });
216
+ searchIndex = fullEnd;
217
+ }
218
+ return matches;
219
+ }
220
+ findGenericXmlToolRequests(content) {
221
+ const matches = [];
222
+ const startTag = '<tool>';
223
+ const endTag = '</tool>';
224
+ let searchIndex = 0;
225
+ while (searchIndex < content.length) {
226
+ const start = content.indexOf(startTag, searchIndex);
227
+ if (start === -1)
228
+ break;
229
+ const end = content.indexOf(endTag, start + startTag.length);
230
+ if (end === -1)
231
+ break;
232
+ const inner = content.slice(start + startTag.length, end);
233
+ const nameMatch = inner.match(/<name>([^<]+)<\/name>/i);
234
+ const argsMatch = inner.match(/<arguments>([\s\S]*?)<\/arguments>/i);
235
+ if (!nameMatch || !argsMatch) {
236
+ searchIndex = end + endTag.length;
237
+ continue;
238
+ }
239
+ const fullEnd = end + endTag.length;
240
+ matches.push({
241
+ start,
242
+ end: fullEnd,
243
+ toolName: nameMatch[1].trim(),
244
+ rawArgs: argsMatch[1],
245
+ fullMatch: content.slice(start, fullEnd),
246
+ });
247
+ searchIndex = fullEnd;
248
+ }
249
+ return matches;
250
+ }
251
+ findUseToolRequests(content) {
252
+ const matches = [];
253
+ const prefix = '<use';
254
+ const closing = '</use>';
255
+ let searchIndex = 0;
256
+ while (searchIndex < content.length) {
257
+ const start = content.indexOf(prefix, searchIndex);
258
+ if (start === -1)
259
+ break;
260
+ const tagEnd = this.findTagClose(content, start + prefix.length);
261
+ if (tagEnd === -1)
262
+ break;
263
+ const header = content.slice(start + prefix.length, tagEnd);
264
+ const { toolName, attributeText } = this.extractToolNameAndAttributes(header);
265
+ const closingIndex = content.startsWith(closing, tagEnd + 1)
266
+ ? tagEnd + 1 + closing.length
267
+ : tagEnd + 1;
268
+ if (!toolName) {
269
+ searchIndex = tagEnd + 1;
270
+ continue;
271
+ }
272
+ matches.push({
273
+ start,
274
+ end: closingIndex,
275
+ toolName,
276
+ rawArgs: this.parseAttributeArguments(attributeText),
277
+ fullMatch: content.slice(start, closingIndex),
278
+ });
279
+ searchIndex = closingIndex;
280
+ }
281
+ return matches;
282
+ }
283
+ findUseUnderscoreToolRequests(content) {
284
+ const matches = [];
285
+ const prefix = '<use_';
286
+ let searchIndex = 0;
287
+ while (searchIndex < content.length) {
288
+ const start = content.indexOf(prefix, searchIndex);
289
+ if (start === -1)
290
+ break;
291
+ let nameEnd = start + prefix.length;
292
+ while (nameEnd < content.length &&
293
+ /[A-Za-z0-9_.-]/.test(content[nameEnd])) {
294
+ nameEnd++;
295
+ }
296
+ const toolName = content.slice(start + prefix.length, nameEnd);
297
+ const tagEnd = this.findTagClose(content, nameEnd);
298
+ if (tagEnd === -1)
299
+ break;
300
+ const attributeText = content.slice(nameEnd, tagEnd);
301
+ const closingTag = `</use_${toolName}>`;
302
+ const bodyEnd = tagEnd + 1;
303
+ const closingIndex = content.startsWith(closingTag, bodyEnd)
304
+ ? bodyEnd + closingTag.length
305
+ : bodyEnd;
306
+ if (!toolName) {
307
+ searchIndex = bodyEnd;
308
+ continue;
309
+ }
310
+ matches.push({
311
+ start,
312
+ end: closingIndex,
313
+ toolName,
314
+ rawArgs: this.parseAttributeArguments(attributeText),
315
+ fullMatch: content.slice(start, closingIndex),
316
+ });
317
+ searchIndex = closingIndex;
318
+ }
319
+ return matches;
320
+ }
321
+ findKeyValueToolRequests(content) {
322
+ const matches = [];
323
+ let match;
324
+ while ((match = this.keyValuePattern.exec(content)) !== null) {
325
+ const fullMatch = match[0];
326
+ matches.push({
327
+ start: match.index,
328
+ end: match.index + fullMatch.length,
329
+ toolName: match[1],
330
+ rawArgs: this.parseKeyValuePairs(match[2]),
331
+ fullMatch,
332
+ });
333
+ }
334
+ this.keyValuePattern.lastIndex = 0;
335
+ return matches;
336
+ }
337
+ removeMatchedRanges(content, ranges) {
338
+ if (ranges.length === 0) {
339
+ return content;
340
+ }
341
+ const sorted = ranges
342
+ .filter(({ start, end }) => start < end)
343
+ .sort((a, b) => a.start - b.start);
344
+ const merged = [];
345
+ for (const range of sorted) {
346
+ const last = merged[merged.length - 1];
347
+ if (last && range.start <= last.end) {
348
+ last.end = Math.max(last.end, range.end);
349
+ }
350
+ else {
351
+ merged.push({ ...range });
156
352
  }
157
353
  }
158
- // Clean up stray markers that were not matched (best effort) but preserve original whitespace
159
- cleanedContent = cleanedContent
354
+ let cursor = 0;
355
+ const pieces = [];
356
+ for (const range of merged) {
357
+ if (cursor < range.start) {
358
+ pieces.push(content.slice(cursor, range.start));
359
+ }
360
+ cursor = Math.max(cursor, range.end);
361
+ }
362
+ pieces.push(content.slice(cursor));
363
+ return pieces.join('');
364
+ }
365
+ postProcessCleanedContent(content) {
366
+ return content
160
367
  .replace(/\[TOOL_REQUEST(?:_END)?]/g, '')
161
368
  .replace(/<\|im_start\|>assistant/g, '')
162
369
  .replace(/<\|im_end\|>/g, '')
163
- .replace(/<tool_call>[\s\S]*?<\/tool_call>/g, '') // Remove any remaining tool_call tags
164
- .replace(/<function_calls>[\s\S]*?<\/function_calls>/g, '') // Remove function_calls wrapper
165
- .replace(/<invoke[\s\S]*?<\/invoke>/g, '') // Remove any remaining invoke tags
166
- .replace(/<tool>[\s\S]*?<\/tool>/g, '') // Remove any remaining tool tags
167
- // .replace(/<think>[\s\S]*?<\/think>/g, '') // Keep think tags visible by default
168
- .replace(/<tool_call>\s*\{[^}]*$/gm, '') // Remove incomplete tool calls
169
- .replace(/\{"name"\s*:\s*"[^"]*"\s*,?\s*"arguments"\s*:\s*\{[^}]*$/gm, '') // Remove incomplete JSON tool calls
370
+ .replace(/<tool_call>[\s\S]*?<\/tool_call>/g, '')
371
+ .replace(/<function_calls>[\s\S]*?<\/function_calls>/g, '')
372
+ .replace(/<invoke[\s\S]*?<\/invoke>/g, '')
373
+ .replace(/<tool>[\s\S]*?<\/tool>/g, '')
374
+ .replace(/<\/use_[A-Za-z0-9_.-]+>/g, '')
375
+ .replace(/<\/use>/g, '')
376
+ .replace(/<tool_call>\s*\{[^}]*$/gm, '')
377
+ .replace(/\{"name"\s*:\s*"[^"]*"\s*,?\s*"arguments"\s*:\s*\{[^}]*$/gm, '')
170
378
  .replace(/✦\s*<think>/g, '')
171
- .trim();
172
- // Collapse multiple consecutive newlines/spaces after removing tool calls
173
- cleanedContent = cleanedContent
174
379
  .replace(/\n\s*\n/g, '\n')
175
380
  .replace(/\n/g, ' ')
176
381
  .trim();
177
- return {
178
- cleanedContent,
179
- toolCalls,
180
- };
382
+ }
383
+ normalizeArguments(args, toolName, fullMatch) {
384
+ if (typeof args !== 'string') {
385
+ return args;
386
+ }
387
+ try {
388
+ if (args.includes('<parameter') ||
389
+ (args.includes('<') && args.includes('>'))) {
390
+ return this.parseXMLParameters(args);
391
+ }
392
+ return JSON.parse(args);
393
+ }
394
+ catch (error) {
395
+ const repaired = this.tryRepairJson(args);
396
+ if (repaired) {
397
+ try {
398
+ return JSON.parse(repaired);
399
+ }
400
+ catch {
401
+ // ignore and fall through
402
+ }
403
+ }
404
+ const simpleJsonMatch = args.match(/^{[^{]*}$/);
405
+ if (simpleJsonMatch) {
406
+ try {
407
+ return JSON.parse(simpleJsonMatch[0]);
408
+ }
409
+ catch {
410
+ // fall through to logging
411
+ }
412
+ }
413
+ console.error(`[GemmaToolCallParser] Failed to parse tool arguments for ${toolName}:`, error);
414
+ console.error(`[GemmaToolCallParser] Raw arguments excerpt: ${fullMatch.slice(0, 200)}`);
415
+ return null;
416
+ }
417
+ }
418
+ extractBalancedSegment(content, startIndex, openChar, closeChar) {
419
+ if (content[startIndex] !== openChar) {
420
+ return null;
421
+ }
422
+ let depth = 0;
423
+ let inString = null;
424
+ let escapeNext = false;
425
+ for (let i = startIndex; i < content.length; i++) {
426
+ const char = content[i];
427
+ if (escapeNext) {
428
+ escapeNext = false;
429
+ continue;
430
+ }
431
+ if (char === '\\' && inString) {
432
+ escapeNext = true;
433
+ continue;
434
+ }
435
+ if (inString) {
436
+ if (char === inString) {
437
+ inString = null;
438
+ }
439
+ continue;
440
+ }
441
+ if (char === '"' || char === "'") {
442
+ inString = char;
443
+ continue;
444
+ }
445
+ if (char === openChar) {
446
+ depth++;
447
+ }
448
+ else if (char === closeChar) {
449
+ depth--;
450
+ if (depth === 0) {
451
+ return {
452
+ segment: content.slice(startIndex, i + 1),
453
+ endIndex: i + 1,
454
+ };
455
+ }
456
+ }
457
+ }
458
+ return null;
181
459
  }
182
460
  // Best-effort repair for JSON with unescaped inner quotes in string values.
183
461
  tryRepairJson(args) {
@@ -188,7 +466,7 @@ export class GemmaToolCallParser {
188
466
  catch {
189
467
  // Target only inner quotes within JSON string values, preserving multibyte and spacing
190
468
  // e.g., { "command": "printf "ありがとう 世界"" } -> { "command": "printf \"ありがとう 世界\"" }
191
- const repaired = args.replace(/:(\s)*"((?:\\.|[^"])*?)"(\s*)([,}])/gs, (_m, s1, val, s2, tail) => {
469
+ const repaired = args.replace(/:(\s*)"((?:\\.|[^"\\])*)"(\s*)([,}])/g, (_m, s1, val, s2, tail) => {
192
470
  // Escape only unescaped quotes inside the value
193
471
  const fixed = val.replace(/(?<!\\)"/g, '\\"');
194
472
  return `:${s1}"${fixed}"${s2}${tail}`;
@@ -239,6 +517,88 @@ export class GemmaToolCallParser {
239
517
  }
240
518
  return args;
241
519
  }
520
+ parseAttributeArguments(attributeText) {
521
+ const args = {};
522
+ const text = attributeText ?? '';
523
+ const length = text.length;
524
+ let index = 0;
525
+ const readIdentifier = () => {
526
+ const start = index;
527
+ while (index < length && /[A-Za-z0-9_.-]/.test(text.charAt(index))) {
528
+ index++;
529
+ }
530
+ return text.slice(start, index);
531
+ };
532
+ const skipWhitespace = () => {
533
+ while (index < length && /\s/.test(text.charAt(index))) {
534
+ index++;
535
+ }
536
+ };
537
+ while (index < length) {
538
+ skipWhitespace();
539
+ const key = readIdentifier();
540
+ if (!key) {
541
+ index++;
542
+ continue;
543
+ }
544
+ skipWhitespace();
545
+ if (text.charAt(index) !== '=') {
546
+ index++;
547
+ continue;
548
+ }
549
+ index++;
550
+ skipWhitespace();
551
+ const quote = text.charAt(index);
552
+ if (quote !== '"' && quote !== "'") {
553
+ index++;
554
+ continue;
555
+ }
556
+ index++;
557
+ let value = '';
558
+ let escaped = false;
559
+ while (index < length) {
560
+ const char = text.charAt(index);
561
+ index++;
562
+ if (escaped) {
563
+ value += char;
564
+ escaped = false;
565
+ continue;
566
+ }
567
+ if (char === '\\') {
568
+ escaped = true;
569
+ continue;
570
+ }
571
+ if (char === quote) {
572
+ break;
573
+ }
574
+ value += char;
575
+ }
576
+ const unescaped = value.trim();
577
+ if (!key) {
578
+ continue;
579
+ }
580
+ if (unescaped.startsWith('{') || unescaped.startsWith('[')) {
581
+ try {
582
+ args[key] = JSON.parse(unescaped);
583
+ continue;
584
+ }
585
+ catch {
586
+ // fall through to scalar handling
587
+ }
588
+ }
589
+ if (/^-?\d+(\.\d+)?$/.test(unescaped)) {
590
+ args[key] = Number(unescaped);
591
+ }
592
+ else if (unescaped.toLowerCase() === 'true' ||
593
+ unescaped.toLowerCase() === 'false') {
594
+ args[key] = unescaped.toLowerCase() === 'true';
595
+ }
596
+ else {
597
+ args[key] = unescaped;
598
+ }
599
+ }
600
+ return args;
601
+ }
242
602
  parseXMLParameters(xmlContent) {
243
603
  const args = {};
244
604
  // Parse Claude-style <parameter name="key">value</parameter>
@@ -276,5 +636,39 @@ export class GemmaToolCallParser {
276
636
  .replace(/&quot;/g, '"')
277
637
  .replace(/&#39;/g, "'");
278
638
  }
639
+ findTagClose(content, fromIndex) {
640
+ let inQuote = null;
641
+ for (let i = fromIndex; i < content.length; i++) {
642
+ const char = content[i];
643
+ if (inQuote) {
644
+ if (char === inQuote && content[i - 1] !== '\\') {
645
+ inQuote = null;
646
+ }
647
+ continue;
648
+ }
649
+ if (char === '"' || char === "'") {
650
+ inQuote = char;
651
+ continue;
652
+ }
653
+ if (char === '>') {
654
+ return i;
655
+ }
656
+ }
657
+ return -1;
658
+ }
659
+ extractToolNameAndAttributes(header) {
660
+ let index = 0;
661
+ const length = header.length;
662
+ while (index < length && /\s/.test(header.charAt(index))) {
663
+ index++;
664
+ }
665
+ const nameStart = index;
666
+ while (index < length && /[A-Za-z0-9_.-]/.test(header.charAt(index))) {
667
+ index++;
668
+ }
669
+ const toolName = header.slice(nameStart, index).trim();
670
+ const attributeText = header.slice(index);
671
+ return { toolName, attributeText };
672
+ }
279
673
  }
280
674
  //# sourceMappingURL=TextToolCallParser.js.map