@noorm/marie-cli 0.1.18 → 0.1.25

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 (251) hide show
  1. package/README.md +7 -15
  2. package/SENTINEL.md +4 -7
  3. package/dist/cli-new/components/App.js +16 -63
  4. package/dist/cli-new/components/App.js.map +1 -1
  5. package/dist/cli-new/components/ApprovalDialog.js +2 -1
  6. package/dist/cli-new/components/ApprovalDialog.js.map +1 -1
  7. package/dist/cli-new/components/Banner.js +4 -3
  8. package/dist/cli-new/components/Banner.js.map +1 -1
  9. package/dist/cli-new/components/ChatArea.js +6 -7
  10. package/dist/cli-new/components/ChatArea.js.map +1 -1
  11. package/dist/cli-new/components/Header.js +13 -7
  12. package/dist/cli-new/components/Header.js.map +1 -1
  13. package/dist/cli-new/components/InputArea.js +73 -12
  14. package/dist/cli-new/components/InputArea.js.map +1 -1
  15. package/dist/cli-new/components/MessageBubble.js +26 -18
  16. package/dist/cli-new/components/MessageBubble.js.map +1 -1
  17. package/dist/cli-new/components/SessionSwitcher.js +4 -7
  18. package/dist/cli-new/components/SessionSwitcher.js.map +1 -1
  19. package/dist/cli-new/components/SetupWizard.js +80 -257
  20. package/dist/cli-new/components/SetupWizard.js.map +1 -1
  21. package/dist/cli-new/components/ToolCallDisplay.js +20 -5
  22. package/dist/cli-new/components/ToolCallDisplay.js.map +1 -1
  23. package/dist/cli-new/components/WizardSteps.js +22 -0
  24. package/dist/cli-new/components/WizardSteps.js.map +1 -0
  25. package/dist/cli-new/constants/SetupConstants.js +42 -0
  26. package/dist/cli-new/constants/SetupConstants.js.map +1 -0
  27. package/dist/cli-new/hooks/useGit.js +19 -62
  28. package/dist/cli-new/hooks/useGit.js.map +1 -1
  29. package/dist/cli-new/hooks/useMarie.js +26 -18
  30. package/dist/cli-new/hooks/useMarie.js.map +1 -1
  31. package/dist/cli-new/hooks/useSessions.js +1 -1
  32. package/dist/cli-new/hooks/useSessions.js.map +1 -1
  33. package/dist/cli-new/hooks/useSetupWizard.js +88 -0
  34. package/dist/cli-new/hooks/useSetupWizard.js.map +1 -0
  35. package/dist/cli-new/hooks/useUpdateCheck.js +4 -3
  36. package/dist/cli-new/hooks/useUpdateCheck.js.map +1 -1
  37. package/dist/cli-new/index.js +2 -4
  38. package/dist/cli-new/index.js.map +1 -1
  39. package/dist/cli-new/services/CommandService.js +104 -0
  40. package/dist/cli-new/services/CommandService.js.map +1 -0
  41. package/dist/cli-new/services/GitService.js +91 -0
  42. package/dist/cli-new/services/GitService.js.map +1 -0
  43. package/dist/cli-new/services/MarieService.js +77 -0
  44. package/dist/cli-new/services/MarieService.js.map +1 -0
  45. package/dist/cli-new/services/auth-server.js +128 -0
  46. package/dist/cli-new/services/auth-server.js.map +1 -0
  47. package/dist/cli-new/utils/version.js +24 -0
  48. package/dist/cli-new/utils/version.js.map +1 -0
  49. package/dist/monolith/adapters/CliMarieAdapter.js +12 -11
  50. package/dist/monolith/adapters/CliMarieAdapter.js.map +1 -1
  51. package/dist/monolith/cli/CliFileSystemPort.js +17 -3
  52. package/dist/monolith/cli/CliFileSystemPort.js.map +1 -1
  53. package/dist/monolith/cli/MarieToolDefinitionsCLI.js +39 -31
  54. package/dist/monolith/cli/MarieToolDefinitionsCLI.js.map +1 -1
  55. package/dist/monolith/cli/index.js +5 -20
  56. package/dist/monolith/cli/index.js.map +1 -1
  57. package/dist/monolith/cli/services/JoyAutomationServiceCLI.js +15 -62
  58. package/dist/monolith/cli/services/JoyAutomationServiceCLI.js.map +1 -1
  59. package/dist/monolith/cli/storage.js +142 -72
  60. package/dist/monolith/cli/storage.js.map +1 -1
  61. package/dist/monolith/domain/joy/RitualService.js +44 -46
  62. package/dist/monolith/domain/joy/RitualService.js.map +1 -1
  63. package/dist/monolith/domain/marie/MarieCortex.js +148 -0
  64. package/dist/monolith/domain/marie/MarieCortex.js.map +1 -0
  65. package/dist/monolith/domain/marie/PersonalityRenderer.js +97 -0
  66. package/dist/monolith/domain/marie/PersonalityRenderer.js.map +1 -0
  67. package/dist/monolith/infrastructure/Configuration.js +68 -0
  68. package/dist/monolith/infrastructure/Configuration.js.map +1 -0
  69. package/dist/monolith/infrastructure/CoreInfrastructure.js +204 -0
  70. package/dist/monolith/infrastructure/CoreInfrastructure.js.map +1 -0
  71. package/dist/monolith/infrastructure/ai/agents/MarieAscendant.js +3 -3
  72. package/dist/monolith/infrastructure/ai/agents/MarieAscendant.js.map +1 -1
  73. package/dist/monolith/infrastructure/ai/context/ContextArchiveService.js +6 -27
  74. package/dist/monolith/infrastructure/ai/context/ContextArchiveService.js.map +1 -1
  75. package/dist/monolith/infrastructure/ai/context/ContextManager.js +142 -131
  76. package/dist/monolith/infrastructure/ai/context/ContextManager.js.map +1 -1
  77. package/dist/monolith/infrastructure/ai/core/MarieEngine.js +115 -1077
  78. package/dist/monolith/infrastructure/ai/core/MarieEngine.js.map +1 -1
  79. package/dist/monolith/infrastructure/ai/core/MarieEventDispatcher.js +1 -37
  80. package/dist/monolith/infrastructure/ai/core/MarieEventDispatcher.js.map +1 -1
  81. package/dist/monolith/infrastructure/ai/core/MarieLockManager.js +6 -1
  82. package/dist/monolith/infrastructure/ai/core/MarieLockManager.js.map +1 -1
  83. package/dist/monolith/infrastructure/ai/core/MarieProgressTracker.js +172 -221
  84. package/dist/monolith/infrastructure/ai/core/MarieProgressTracker.js.map +1 -1
  85. package/dist/monolith/infrastructure/ai/core/MarieSanitizer.js +292 -141
  86. package/dist/monolith/infrastructure/ai/core/MarieSanitizer.js.map +1 -1
  87. package/dist/monolith/infrastructure/ai/core/MarieToolProcessor.js +331 -614
  88. package/dist/monolith/infrastructure/ai/core/MarieToolProcessor.js.map +1 -1
  89. package/dist/monolith/infrastructure/ai/core/MarieVitality.js +238 -0
  90. package/dist/monolith/infrastructure/ai/core/MarieVitality.js.map +1 -0
  91. package/dist/monolith/infrastructure/ai/core/SessionLogService.js +9 -2
  92. package/dist/monolith/infrastructure/ai/core/SessionLogService.js.map +1 -1
  93. package/dist/monolith/infrastructure/ai/providers/AIProvider.js +402 -1
  94. package/dist/monolith/infrastructure/ai/providers/AIProvider.js.map +1 -1
  95. package/dist/monolith/infrastructure/ai/providers/DreamBeesProvider.js +114 -0
  96. package/dist/monolith/infrastructure/ai/providers/DreamBeesProvider.js.map +1 -0
  97. package/dist/monolith/infrastructure/ai/providers/OpenRouterProvider.js +426 -392
  98. package/dist/monolith/infrastructure/ai/providers/OpenRouterProvider.js.map +1 -1
  99. package/dist/monolith/infrastructure/ai/providers/OpenRouterStreamParser.js +235 -241
  100. package/dist/monolith/infrastructure/ai/providers/OpenRouterStreamParser.js.map +1 -1
  101. package/dist/monolith/infrastructure/ai/workerAi.js +185 -0
  102. package/dist/monolith/infrastructure/ai/workerAi.js.map +1 -0
  103. package/dist/monolith/infrastructure/config/ConfigService.js +216 -503
  104. package/dist/monolith/infrastructure/config/ConfigService.js.map +1 -1
  105. package/dist/monolith/infrastructure/joy/CognitiveRituals.js +4 -165
  106. package/dist/monolith/infrastructure/joy/CognitiveRituals.js.map +1 -1
  107. package/dist/monolith/infrastructure/joy/JoyTools.js +14 -47
  108. package/dist/monolith/infrastructure/joy/JoyTools.js.map +1 -1
  109. package/dist/monolith/infrastructure/persistence/MarieMindAutonomics.js +4 -0
  110. package/dist/monolith/infrastructure/persistence/MarieMindAutonomics.js.map +1 -0
  111. package/dist/monolith/infrastructure/persistence/MarieMindEngine.js +11 -0
  112. package/dist/monolith/infrastructure/persistence/MarieMindEngine.js.map +1 -0
  113. package/dist/monolith/infrastructure/persistence/NoormmeAutonomics.js +123 -106
  114. package/dist/monolith/infrastructure/persistence/NoormmeAutonomics.js.map +1 -1
  115. package/dist/monolith/infrastructure/persistence/NoormmeEngine.js +508 -63
  116. package/dist/monolith/infrastructure/persistence/NoormmeEngine.js.map +1 -1
  117. package/dist/monolith/infrastructure/persistence/NoormmeSchema.js +68 -39
  118. package/dist/monolith/infrastructure/persistence/NoormmeSchema.js.map +1 -1
  119. package/dist/monolith/infrastructure/persistence/NoormmeSeeder.js +80 -67
  120. package/dist/monolith/infrastructure/persistence/NoormmeSeeder.js.map +1 -1
  121. package/dist/monolith/infrastructure/persistence/NoormmeTools.js +122 -75
  122. package/dist/monolith/infrastructure/persistence/NoormmeTools.js.map +1 -1
  123. package/dist/monolith/infrastructure/services/MarieMemoryStore.js +133 -134
  124. package/dist/monolith/infrastructure/services/MarieMemoryStore.js.map +1 -1
  125. package/dist/monolith/infrastructure/tools/MarieToolDefinitions.js +6 -30
  126. package/dist/monolith/infrastructure/tools/MarieToolDefinitions.js.map +1 -1
  127. package/dist/monolith/infrastructure/tools/PureStreamParser.js +68 -80
  128. package/dist/monolith/infrastructure/tools/PureStreamParser.js.map +1 -1
  129. package/dist/monolith/infrastructure/tools/SharedToolDefinitions.js +12 -11
  130. package/dist/monolith/infrastructure/tools/SharedToolDefinitions.js.map +1 -1
  131. package/dist/monolith/infrastructure/tools/SovereignTools.js +326 -0
  132. package/dist/monolith/infrastructure/tools/SovereignTools.js.map +1 -0
  133. package/dist/monolith/infrastructure/tools/ToolRegistry.js +45 -26
  134. package/dist/monolith/infrastructure/tools/ToolRegistry.js.map +1 -1
  135. package/dist/monolith/infrastructure/tools/definitions/AnalysisTools.js +39 -153
  136. package/dist/monolith/infrastructure/tools/definitions/AnalysisTools.js.map +1 -1
  137. package/dist/monolith/infrastructure/tools/definitions/AutomationTools.js +31 -46
  138. package/dist/monolith/infrastructure/tools/definitions/AutomationTools.js.map +1 -1
  139. package/dist/monolith/infrastructure/tools/definitions/ContextTools.js +41 -13
  140. package/dist/monolith/infrastructure/tools/definitions/ContextTools.js.map +1 -1
  141. package/dist/monolith/infrastructure/tools/definitions/CoreTools.js +10 -14
  142. package/dist/monolith/infrastructure/tools/definitions/CoreTools.js.map +1 -1
  143. package/dist/monolith/infrastructure/tools/definitions/DiagnosticTools.js +39 -70
  144. package/dist/monolith/infrastructure/tools/definitions/DiagnosticTools.js.map +1 -1
  145. package/dist/monolith/infrastructure/tools/definitions/NavigationTools.js +30 -181
  146. package/dist/monolith/infrastructure/tools/definitions/NavigationTools.js.map +1 -1
  147. package/dist/monolith/infrastructure/tools/definitions/PlanningTools.js +12 -9
  148. package/dist/monolith/infrastructure/tools/definitions/PlanningTools.js.map +1 -1
  149. package/dist/monolith/plumbing/Plumbing.js +238 -0
  150. package/dist/monolith/plumbing/Plumbing.js.map +1 -0
  151. package/dist/monolith/plumbing/PlumbingAnalysis.js +109 -0
  152. package/dist/monolith/plumbing/PlumbingAnalysis.js.map +1 -0
  153. package/dist/monolith/plumbing/PlumbingSystem.js +169 -0
  154. package/dist/monolith/plumbing/PlumbingSystem.js.map +1 -0
  155. package/dist/monolith/plumbing/analysis/ComplexityService.js +30 -34
  156. package/dist/monolith/plumbing/analysis/ComplexityService.js.map +1 -1
  157. package/dist/monolith/plumbing/analysis/DependencyService.js +55 -44
  158. package/dist/monolith/plumbing/analysis/DependencyService.js.map +1 -1
  159. package/dist/monolith/plumbing/analysis/DiscoveryService.js +40 -42
  160. package/dist/monolith/plumbing/analysis/DiscoveryService.js.map +1 -1
  161. package/dist/monolith/plumbing/analysis/JoyMapService.js +52 -56
  162. package/dist/monolith/plumbing/analysis/JoyMapService.js.map +1 -1
  163. package/dist/monolith/plumbing/analysis/LintService.js +118 -118
  164. package/dist/monolith/plumbing/analysis/LintService.js.map +1 -1
  165. package/dist/monolith/plumbing/analysis/MarieSentinelService.js +278 -268
  166. package/dist/monolith/plumbing/analysis/MarieSentinelService.js.map +1 -1
  167. package/dist/monolith/plumbing/analysis/QualityGuardrailService.js +116 -114
  168. package/dist/monolith/plumbing/analysis/QualityGuardrailService.js.map +1 -1
  169. package/dist/monolith/plumbing/analysis/SurgicalMender.js +57 -59
  170. package/dist/monolith/plumbing/analysis/SurgicalMender.js.map +1 -1
  171. package/dist/monolith/plumbing/analysis/TestService.js +89 -89
  172. package/dist/monolith/plumbing/analysis/TestService.js.map +1 -1
  173. package/dist/monolith/plumbing/filesystem/FileService.js +123 -195
  174. package/dist/monolith/plumbing/filesystem/FileService.js.map +1 -1
  175. package/dist/monolith/plumbing/filesystem/PathResolver.js +7 -8
  176. package/dist/monolith/plumbing/filesystem/PathResolver.js.map +1 -1
  177. package/dist/monolith/plumbing/git/GitService.js +4 -4
  178. package/dist/monolith/plumbing/git/GitService.js.map +1 -1
  179. package/dist/monolith/plumbing/lsp/SymbolService.js +5 -34
  180. package/dist/monolith/plumbing/lsp/SymbolService.js.map +1 -1
  181. package/dist/monolith/plumbing/terminal/ProcessRegistry.js +20 -22
  182. package/dist/monolith/plumbing/terminal/ProcessRegistry.js.map +1 -1
  183. package/dist/monolith/plumbing/terminal/TerminalService.js +127 -141
  184. package/dist/monolith/plumbing/terminal/TerminalService.js.map +1 -1
  185. package/dist/monolith/plumbing/utils/EnvironmentUtils.js +3 -23
  186. package/dist/monolith/plumbing/utils/EnvironmentUtils.js.map +1 -1
  187. package/dist/monolith/plumbing/utils/JsonUtils.js +252 -311
  188. package/dist/monolith/plumbing/utils/JsonUtils.js.map +1 -1
  189. package/dist/monolith/plumbing/utils/PlumbingCore.js +549 -0
  190. package/dist/monolith/plumbing/utils/PlumbingCore.js.map +1 -0
  191. package/dist/monolith/plumbing/utils/PrefixTree.js +61 -114
  192. package/dist/monolith/plumbing/utils/PrefixTree.js.map +1 -1
  193. package/dist/monolith/plumbing/utils/StreamTagDetector.js +89 -127
  194. package/dist/monolith/plumbing/utils/StreamTagDetector.js.map +1 -1
  195. package/dist/monolith/plumbing/utils/StringUtils.js +87 -89
  196. package/dist/monolith/plumbing/utils/StringUtils.js.map +1 -1
  197. package/dist/monolith/runtime/MarieRuntime.js +76 -499
  198. package/dist/monolith/runtime/MarieRuntime.js.map +1 -1
  199. package/dist/monolith/runtime/RuntimeAdapterBase.js +1 -1
  200. package/dist/monolith/runtime/RuntimeAdapterBase.js.map +1 -1
  201. package/dist/monolith/runtime/providerFactory.js +1 -7
  202. package/dist/monolith/runtime/providerFactory.js.map +1 -1
  203. package/dist/monolith/services/HealthService.js +29 -32
  204. package/dist/monolith/services/HealthService.js.map +1 -1
  205. package/dist/monolith/services/JoyAutomationService.js +58 -95
  206. package/dist/monolith/services/JoyAutomationService.js.map +1 -1
  207. package/dist/monolith/services/MarieAutomationService.js +59 -0
  208. package/dist/monolith/services/MarieAutomationService.js.map +1 -0
  209. package/dist/monolith/services/MarieGhostService.js +46 -173
  210. package/dist/monolith/services/MarieGhostService.js.map +1 -1
  211. package/dist/monolith/services/MarieServices.js +102 -0
  212. package/dist/monolith/services/MarieServices.js.map +1 -0
  213. package/dist/monolith/services/MarieTypes.js +2 -0
  214. package/dist/monolith/services/MarieTypes.js.map +1 -0
  215. package/dist/monolith/services/UpdateService.js +47 -49
  216. package/dist/monolith/services/UpdateService.js.map +1 -1
  217. package/dist/prompts.js +11 -5
  218. package/dist/prompts.js.map +1 -1
  219. package/dist/test_prefix_tree.js +9 -9
  220. package/dist/test_prefix_tree.js.map +1 -1
  221. package/package.json +18 -89
  222. package/run_test.js +5 -0
  223. package/.marie_visual_verify_1771225696548/progress_bar_check.txt +0 -1
  224. package/dist/extension.cjs +0 -1155
  225. package/dist/extension.js +0 -474
  226. package/dist/extension.js.map +0 -1
  227. package/dist/monolith/adapters/VscodeMarieAdapter.js +0 -81
  228. package/dist/monolith/adapters/VscodeMarieAdapter.js.map +0 -1
  229. package/dist/monolith/infrastructure/ai/core/GhostPort.js +0 -2
  230. package/dist/monolith/infrastructure/ai/core/GhostPort.js.map +0 -1
  231. package/dist/monolith/infrastructure/ai/core/VscodeFileSystemPort.js +0 -33
  232. package/dist/monolith/infrastructure/ai/core/VscodeFileSystemPort.js.map +0 -1
  233. package/dist/monolith/infrastructure/ai/providers/AnthropicProvider.js +0 -154
  234. package/dist/monolith/infrastructure/ai/providers/AnthropicProvider.js.map +0 -1
  235. package/dist/monolith/infrastructure/ai/providers/CerebrasProvider.js +0 -214
  236. package/dist/monolith/infrastructure/ai/providers/CerebrasProvider.js.map +0 -1
  237. package/dist/monolith/plumbing/ui/DecorationService.js +0 -54
  238. package/dist/monolith/plumbing/ui/DecorationService.js.map +0 -1
  239. package/dist/monolith/services/JoyLogService.js +0 -48
  240. package/dist/monolith/services/JoyLogService.js.map +0 -1
  241. package/dist/monolith/services/JoyService.js +0 -209
  242. package/dist/monolith/services/JoyService.js.map +0 -1
  243. package/dist/monolith/services/MarieSCMProvider.js +0 -41
  244. package/dist/monolith/services/MarieSCMProvider.js.map +0 -1
  245. package/dist/webview-ui/main.css +0 -1
  246. package/dist/webview-ui/main.js +0 -108
  247. package/lint_output.txt +0 -705
  248. package/lint_output_v2.txt +0 -711
  249. package/test-mind-p6.sqlite +0 -0
  250. package/test-mind-p6.sqlite-shm +0 -0
  251. package/test-mind-p6.sqlite-wal +0 -0
@@ -1,426 +1,460 @@
1
- import { ConfigService } from "../../config/ConfigService.js";
2
- import { getErrorMessage } from "../../../plumbing/utils/ErrorUtils.js";
3
- import { JsonUtils } from "../../../plumbing/utils/JsonUtils.js";
4
- import { OpenRouterStreamParser } from "./OpenRouterStreamParser.js";
5
- export class OpenRouterProvider {
6
- apiKey;
7
- baseUrl = "https://openrouter.ai/api/v1";
8
- constructor(apiKey) {
9
- this.apiKey = apiKey;
1
+ import { getTokensPerChar } from "../../config/ConfigService.js";
2
+ import { getErrorMessage, safeParseJson, extractToolCall, createStreamTagDetector, safeStringify, safeGetValues } from "../../../plumbing/utils/PlumbingCore.js";
3
+ const BASE_URL = "https://openrouter.ai/api/v1";
4
+ /**
5
+ * Translates Anthropic model names to OpenRouter format.
6
+ * OpenRouter expects format like "anthropic/claude-3.5-sonnet"
7
+ */
8
+ function translateModelName(model) {
9
+ const normalized = (model || "").trim();
10
+ if (!normalized) {
11
+ return "anthropic/claude-3.5-sonnet";
10
12
  }
11
- async createMessage(params) {
12
- const translatedModel = this.translateModelName(params.model);
13
- const response = await fetch(`${this.baseUrl}/chat/completions`, {
14
- method: "POST",
15
- headers: {
16
- Authorization: `Bearer ${this.apiKey}`,
17
- "HTTP-Referer": "https://github.com/bozoegg/MarieCoder",
18
- "X-Title": "MarieCoder VS Code Extension",
19
- "Content-Type": "application/json",
20
- Accept: "application/json",
21
- },
22
- body: JSON.stringify({
23
- model: translatedModel,
24
- messages: this.getOpenAiMessages(params),
25
- tools: this.getOpenAiTools(params),
26
- max_tokens: params.max_tokens || 1024,
27
- }),
28
- });
29
- if (!response.ok) {
30
- let errorMsg = `OpenRouter API error: ${response.status} ${response.statusText} (model: ${translatedModel})`;
31
- try {
32
- const errorJson = (await response.json());
33
- if (errorJson.error?.message)
34
- errorMsg = `OpenRouter API error: ${errorJson.error.message} (model: ${translatedModel})`;
35
- }
36
- catch (e) {
37
- const text = await response.text().catch(() => "");
38
- if (text)
39
- errorMsg += ` - ${text}`;
40
- }
41
- throw new Error(errorMsg);
13
+ // If already in OpenRouter format, return as-is
14
+ if (normalized.includes("/")) {
15
+ return normalized;
16
+ }
17
+ // Map Anthropic model names to OpenRouter format
18
+ const modelMap = {
19
+ "claude-3-5-sonnet-20241022": "anthropic/claude-3.5-sonnet",
20
+ "claude-3-5-sonnet": "anthropic/claude-3.5-sonnet",
21
+ "claude-3-5-haiku-20241022": "anthropic/claude-3.5-haiku",
22
+ "claude-3-5-haiku": "anthropic/claude-3.5-haiku",
23
+ "claude-3-opus-20240229": "anthropic/claude-3-opus",
24
+ "claude-3-opus": "anthropic/claude-3-opus",
25
+ "claude-3-sonnet-20240229": "anthropic/claude-3-sonnet",
26
+ "claude-3-sonnet": "anthropic/claude-3-sonnet",
27
+ "claude-3-haiku-20240307": "anthropic/claude-3-haiku",
28
+ "claude-3-haiku": "anthropic/claude-3-haiku",
29
+ };
30
+ if (modelMap[normalized]) {
31
+ return modelMap[normalized];
32
+ }
33
+ // Try to convert claude models that aren't in the map.
34
+ if (normalized.startsWith("claude-")) {
35
+ const withoutDateSuffix = normalized.replace(/-20\d{6}$/, "");
36
+ const claudeVersioned = withoutDateSuffix.match(/^claude-(\d+)-(\d+)(-.+)$/);
37
+ if (claudeVersioned) {
38
+ const major = claudeVersioned[1];
39
+ const minor = claudeVersioned[2];
40
+ const variant = claudeVersioned[3];
41
+ return `anthropic/claude-${major}.${minor}${variant}`;
42
42
  }
43
- const data = (await response.json());
44
- if (!data.choices || data.choices.length === 0)
45
- throw new Error("OpenRouter API returned no choices.");
46
- const choice = data.choices[0].message;
47
- if (choice.tool_calls && choice.tool_calls.length > 0) {
48
- try {
49
- const toolUses = choice.tool_calls.map((tc) => ({
50
- id: tc.id,
51
- name: tc.function.name,
52
- input: JsonUtils.safeParseJson(tc.function.arguments),
53
- }));
54
- return {
55
- role: "assistant",
56
- content: choice.content || "",
57
- tool_uses: toolUses,
58
- };
43
+ return `anthropic/${withoutDateSuffix}`;
44
+ }
45
+ // Return as-is if we can't translate
46
+ return normalized;
47
+ }
48
+ function getOpenAiMessages(params) {
49
+ const messages = [];
50
+ if (params.system)
51
+ messages.push({ role: "system", content: params.system });
52
+ for (const msg of params.messages) {
53
+ if (typeof msg.content === "string") {
54
+ messages.push({ role: msg.role, content: msg.content });
55
+ }
56
+ else if (Array.isArray(msg.content)) {
57
+ let text = "";
58
+ const tools = [];
59
+ for (const block of msg.content) {
60
+ if (block.type === "text")
61
+ text += block.text;
62
+ else if (block.type === "tool_use")
63
+ tools.push({
64
+ id: block.id,
65
+ type: "function",
66
+ function: {
67
+ name: block.name,
68
+ arguments: safeStringify(block.input),
69
+ },
70
+ });
71
+ else if (block.type === "tool_result") {
72
+ messages.push({
73
+ role: "tool",
74
+ tool_call_id: block.tool_use_id,
75
+ content: typeof block.content === "string"
76
+ ? block.content
77
+ : safeStringify(block.content),
78
+ });
79
+ }
59
80
  }
60
- catch (error) {
61
- console.error("Failed to parse tool arguments from OpenRouter:", getErrorMessage(error));
62
- return {
63
- role: "assistant",
64
- content: choice.content || `(Message error: Malformed tool arguments)`,
65
- };
81
+ if (msg.role === "assistant" && (text || tools.length > 0)) {
82
+ const m = { role: "assistant", content: text || null };
83
+ if (tools.length > 0)
84
+ m.tool_calls = tools;
85
+ messages.push(m);
86
+ }
87
+ else if (msg.role === "user" && text) {
88
+ messages.push({ role: "user", content: text });
66
89
  }
67
90
  }
68
- return {
69
- role: "assistant",
70
- content: choice.content || "",
71
- };
72
91
  }
73
- async createMessageStream(params, onUpdate, signal) {
74
- const controller = new AbortController();
75
- let isTimeout = false;
76
- const timeoutId = setTimeout(() => {
77
- isTimeout = true;
78
- controller.abort();
79
- }, 120000);
80
- let isUserAbort = false;
81
- const onAbort = () => {
82
- isUserAbort = true;
83
- controller.abort();
84
- };
85
- if (signal)
86
- signal.addEventListener("abort", onAbort);
87
- try {
88
- const translatedModel = this.translateModelName(params.model);
89
- const response = await fetch(`${this.baseUrl}/chat/completions`, {
92
+ return messages;
93
+ }
94
+ function getOpenAiTools(params) {
95
+ if (!params.tools)
96
+ return undefined;
97
+ return params.tools.map((tool) => ({
98
+ type: "function",
99
+ function: {
100
+ name: tool.name,
101
+ description: tool.description,
102
+ parameters: tool.input_schema,
103
+ },
104
+ }));
105
+ }
106
+ function stripToolWrapperTags(text) {
107
+ if (!text)
108
+ return "";
109
+ return text
110
+ .replace(/<\|tool_calls_section_begin\|>/g, "")
111
+ .replace(/<\|tool_calls_section_end\|>/g, "")
112
+ .replace(/<\|tool_call_begin\|>/g, "")
113
+ .replace(/<\|tool_call_end\|>/g, "")
114
+ .replace(/<\|tool_call_argument_begin\|>/g, "")
115
+ .replace(/<\|tool_call_arguments_begin\|>/g, "")
116
+ .replace(/<tool_call>/g, "")
117
+ .replace(/<\/tool_call>/g, "")
118
+ .replace(/<tool>/g, "")
119
+ .replace(/<\/tool>/g, "")
120
+ .replace(/<function\b[^>]*>/g, "")
121
+ .replace(/<\/function>/g, "")
122
+ .replace(/<function_calls>/g, "")
123
+ .replace(/<\/function_calls>/g, "")
124
+ .trim();
125
+ }
126
+ function createStreamParser() {
127
+ const tagDetector = createStreamTagDetector();
128
+ let llamaToolMode = false;
129
+ let thinkingMode = false;
130
+ let llamaBufferParts = [];
131
+ const toolCalls = {};
132
+ let indexCount = 0;
133
+ function finalizeCurrentBuffer(events) {
134
+ if (llamaBufferParts.length === 0)
135
+ return;
136
+ const bufferContent = llamaBufferParts.join("");
137
+ const extracted = extractToolCall(bufferContent);
138
+ if (extracted) {
139
+ const id = extracted.id || `call_${Date.now()}_${indexCount}`;
140
+ events.push({ type: "tool_call_delta", index: indexCount, id, name: extracted.name, argumentsDelta: safeStringify(extracted.input) });
141
+ toolCalls[indexCount] = { id, name: extracted.name, arguments: safeStringify(extracted.input) };
142
+ indexCount++;
143
+ }
144
+ else {
145
+ const cleaned = stripToolWrapperTags(bufferContent);
146
+ if (cleaned)
147
+ events.push({ type: "content_delta", text: cleaned });
148
+ }
149
+ llamaBufferParts = [];
150
+ llamaToolMode = false;
151
+ }
152
+ return {
153
+ process(chunk, onUpdate, contentParts, reasoningParts) {
154
+ let currentChunk = chunk;
155
+ while (true) {
156
+ const detection = tagDetector.process(currentChunk);
157
+ currentChunk = "";
158
+ if (detection.text) {
159
+ if (llamaToolMode)
160
+ llamaBufferParts.push(detection.text);
161
+ else if (thinkingMode) {
162
+ reasoningParts.push(detection.text);
163
+ onUpdate({ type: "reasoning_delta", text: detection.text });
164
+ }
165
+ else {
166
+ contentParts.push(detection.text);
167
+ onUpdate({ type: "content_delta", text: detection.text });
168
+ }
169
+ }
170
+ if (detection.type === "tag") {
171
+ const tag = detection.tag;
172
+ if (tag === "<thought>") {
173
+ thinkingMode = true;
174
+ onUpdate({ type: "stage_change", stage: "thinking", label: "Thinking..." });
175
+ }
176
+ else if (tag === "</thought>") {
177
+ thinkingMode = false;
178
+ onUpdate({ type: "stage_change", stage: "responding", label: "Generating response..." });
179
+ }
180
+ else if (tag.startsWith("[Tool Use:") || tag.startsWith("[Tool Result:")) {
181
+ if (llamaToolMode)
182
+ finalizeCurrentBuffer([]); // Logic merger simplification
183
+ if (tag.startsWith("[Tool Use:")) {
184
+ llamaToolMode = true;
185
+ llamaBufferParts.push(tag);
186
+ onUpdate({ type: "stage_change", stage: "calling_tool", label: "Using tool..." });
187
+ }
188
+ else
189
+ onUpdate({ type: "content_delta", text: tag });
190
+ }
191
+ else {
192
+ const isEnd = ["</tool>", "<|tool_call_end|>", "</invoke>", "</function>", "</tool_code>", "</tool_call>", "</call>"].includes(tag) || tag === "<|tool_calls_section_end|>";
193
+ const isStart = ["<tool>", "<|tool_call_begin|>", "<function_calls>", "<tool_code>", "<tool_call>"].includes(tag) || tag === "<|tool_calls_section_begin|>" || tag.startsWith("<function") || tag === "<invoke";
194
+ if (isEnd) {
195
+ llamaBufferParts.push(tag);
196
+ const bufferContent = llamaBufferParts.join("");
197
+ const extracted = extractToolCall(bufferContent);
198
+ if (extracted) {
199
+ const id = extracted.id || `call_${Date.now()}_${indexCount}`;
200
+ onUpdate({ type: "tool_call_delta", index: indexCount, id, name: extracted.name, argumentsDelta: safeStringify(extracted.input) });
201
+ toolCalls[indexCount] = { id, name: extracted.name, arguments: safeStringify(extracted.input) };
202
+ indexCount++;
203
+ }
204
+ else {
205
+ const cleaned = stripToolWrapperTags(bufferContent);
206
+ if (cleaned)
207
+ onUpdate({ type: "content_delta", text: cleaned });
208
+ }
209
+ llamaToolMode = false;
210
+ llamaBufferParts = [];
211
+ }
212
+ else if (isStart) {
213
+ llamaToolMode = true;
214
+ onUpdate({ type: "stage_change", stage: "calling_tool", label: "Using tool..." });
215
+ llamaBufferParts.push(tag);
216
+ }
217
+ else if (llamaToolMode)
218
+ llamaBufferParts.push(tag);
219
+ else
220
+ onUpdate({ type: "content_delta", text: tag });
221
+ }
222
+ continue;
223
+ }
224
+ break;
225
+ }
226
+ },
227
+ finalize(fullContent, onUpdate) {
228
+ const bufferContent = llamaBufferParts.join("");
229
+ let extracted = extractToolCall(bufferContent) || extractToolCall(fullContent);
230
+ if (extracted) {
231
+ const id = extracted.id || `call_${Date.now()}_${indexCount}_final`;
232
+ const collectedValues = safeGetValues(toolCalls, 50);
233
+ const already = collectedValues.some(tc => tc.name === extracted.name && (tc.arguments === safeStringify(extracted.input)));
234
+ if (!already) {
235
+ onUpdate({ type: "tool_call_delta", index: indexCount, id, name: extracted.name, argumentsDelta: safeStringify(extracted.input) });
236
+ toolCalls[indexCount] = { id, name: extracted.name, arguments: safeStringify(extracted.input) };
237
+ indexCount++;
238
+ }
239
+ llamaBufferParts = [];
240
+ }
241
+ else if (llamaToolMode) {
242
+ const cleaned = stripToolWrapperTags(llamaBufferParts.join(""));
243
+ if (cleaned)
244
+ onUpdate({ type: "content_delta", text: cleaned });
245
+ }
246
+ llamaToolMode = false;
247
+ llamaBufferParts = [];
248
+ },
249
+ getToolCalls: () => toolCalls
250
+ };
251
+ }
252
+ export function createOpenRouterProvider(apiKey) {
253
+ return {
254
+ async createMessage(params) {
255
+ const translatedModel = translateModelName(params.model);
256
+ const response = await fetch(`${BASE_URL}/chat/completions`, {
90
257
  method: "POST",
91
258
  headers: {
92
- Authorization: `Bearer ${this.apiKey}`,
93
- "HTTP-Referer": "https://github.com/bozoegg/MarieCoder",
94
- "X-Title": "MarieCoder VS Code Extension",
259
+ Authorization: `Bearer ${apiKey}`,
260
+ "HTTP-Referer": "https://github.com/CardSorting/Marie-Coder-New-the-vatican",
261
+ "X-Title": "DreamBees CLI",
95
262
  "Content-Type": "application/json",
96
- Accept: "text/event-stream",
97
- "Cache-Control": "no-cache",
98
- Connection: "keep-alive",
263
+ Accept: "application/json",
99
264
  },
100
- body: JSON.stringify({
265
+ body: safeStringify({
101
266
  model: translatedModel,
102
- messages: this.getOpenAiMessages(params),
103
- tools: this.getOpenAiTools(params),
267
+ messages: getOpenAiMessages(params),
268
+ tools: getOpenAiTools(params),
104
269
  max_tokens: params.max_tokens || 1024,
105
- stream: true,
106
- include_reasoning: true,
107
270
  }),
108
- signal: controller.signal,
109
271
  });
110
272
  if (!response.ok) {
111
- throw new Error(`OpenRouter API error: ${response.status} (model: ${translatedModel})`);
112
- }
113
- if (!response.body)
114
- throw new Error("OpenRouter API returned no body.");
115
- const reader = response.body.getReader();
116
- const decoder = new TextDecoder();
117
- const contentParts = [];
118
- const reasoningParts = [];
119
- const bufferParts = [];
120
- const toolCalls = {};
121
- const startTime = Date.now();
122
- onUpdate({ type: "run_started", timestamp: startTime });
123
- onUpdate({
124
- type: "stage_change",
125
- stage: "thinking",
126
- label: "Processing request...",
127
- });
128
- const streamParser = new OpenRouterStreamParser();
129
- try {
130
- while (true) {
131
- const { done, value } = await reader.read();
132
- if (done)
133
- break;
134
- const chunk = decoder.decode(value, { stream: true });
135
- bufferParts.push(chunk);
136
- const buffer = bufferParts.join("");
137
- const lines = buffer.split("\n");
138
- const remainder = lines.pop() || "";
139
- bufferParts.length = 0;
140
- if (remainder)
141
- bufferParts.push(remainder);
142
- for (const line of lines) {
143
- const trimmedLine = line.trim();
144
- if (!trimmedLine || trimmedLine.startsWith(":"))
145
- continue;
146
- if (trimmedLine.startsWith("data: ")) {
147
- const dataStr = trimmedLine.slice(6);
148
- if (dataStr === "[DONE]")
149
- continue;
150
- try {
151
- const data = JSON.parse(dataStr);
152
- const choice = data.choices?.[0];
153
- if (!choice)
154
- continue;
155
- const delta = choice.delta;
156
- if (delta?.content) {
157
- const events = streamParser.processContent(delta.content);
158
- for (const event of events) {
159
- if (event.type === "content_delta")
160
- contentParts.push(event.text);
161
- if (event.type === "reasoning_delta")
162
- reasoningParts.push(event.text);
163
- onUpdate(event);
164
- }
165
- }
166
- if (delta?.tool_calls) {
167
- onUpdate({
168
- type: "stage_change",
169
- stage: "calling_tool",
170
- label: "Using tool...",
171
- });
172
- for (const tc of delta.tool_calls) {
173
- const idx = tc.index;
174
- if (!toolCalls[idx]) {
175
- toolCalls[idx] = {
176
- id: tc.id || "",
177
- name: tc.function?.name || "",
178
- argumentsParts: [],
179
- };
180
- }
181
- else {
182
- if (tc.id)
183
- toolCalls[idx].id = tc.id;
184
- if (tc.function?.name)
185
- toolCalls[idx].name += tc.function.name;
186
- }
187
- if (tc.function?.arguments) {
188
- toolCalls[idx].argumentsParts.push(tc.function.arguments);
189
- onUpdate({
190
- type: "tool_call_delta",
191
- index: idx,
192
- id: toolCalls[idx].id,
193
- name: toolCalls[idx].name,
194
- argumentsDelta: tc.function.arguments,
195
- });
196
- }
197
- }
198
- }
199
- if (data.usage) {
200
- onUpdate({
201
- type: "usage",
202
- usage: {
203
- inputTokens: data.usage.prompt_tokens,
204
- outputTokens: data.usage.completion_tokens,
205
- totalTokens: data.usage.total_tokens,
206
- reasoningTokens: data.usage.reasoning_tokens,
207
- },
208
- });
209
- }
210
- }
211
- catch (e) {
212
- // Ignore parsing errors for individual chunks
213
- }
214
- }
215
- }
273
+ let errorMsg = `OpenRouter API error: ${response.status} ${response.statusText} (model: ${translatedModel})`;
274
+ try {
275
+ const errorJson = (await response.json());
276
+ if (errorJson.error?.message)
277
+ errorMsg = `OpenRouter API error: ${errorJson.error.message} (model: ${translatedModel})`;
216
278
  }
279
+ catch (e) {
280
+ const text = await response.text().catch(() => "");
281
+ if (text)
282
+ errorMsg += ` - ${text}`;
283
+ }
284
+ throw new Error(errorMsg);
217
285
  }
218
- finally {
219
- reader.releaseLock();
220
- }
221
- // Join all array buffers into final strings
222
- const fullContent = contentParts.join("");
223
- const fullReasoning = reasoningParts.join("");
224
- const finalEvents = streamParser.finalize(fullContent);
225
- for (const event of finalEvents)
226
- onUpdate(event);
227
- const endTime = Date.now();
228
- onUpdate({
229
- type: "run_completed",
230
- timestamp: endTime,
231
- durationMs: endTime - startTime,
232
- });
233
- const llamaCalls = streamParser.getCollectedToolCalls();
234
- for (const idx in llamaCalls) {
235
- const call = llamaCalls[idx];
236
- toolCalls[parseInt(idx) + 1000] = {
237
- id: call.id,
238
- name: call.name,
239
- argumentsParts: [call.arguments], // Wrap string as array for consistency
240
- };
241
- }
242
- const finalToolUses = [];
243
- for (const idx in toolCalls) {
244
- const tc = toolCalls[idx];
286
+ const data = (await response.json());
287
+ if (!data.choices || data.choices.length === 0)
288
+ throw new Error("OpenRouter API returned no choices.");
289
+ const choice = data.choices[0].message;
290
+ if (choice.tool_calls && choice.tool_calls.length > 0) {
245
291
  try {
246
- const args = tc.argumentsParts.join("");
247
- finalToolUses.push({
292
+ const toolUses = choice.tool_calls.map((tc) => ({
248
293
  id: tc.id,
249
- name: tc.name,
250
- input: JsonUtils.safeParseJson(args),
251
- });
294
+ name: tc.function.name,
295
+ input: safeParseJson(tc.function.arguments).result,
296
+ }));
297
+ return {
298
+ role: "assistant",
299
+ content: choice.content || "",
300
+ tool_uses: toolUses,
301
+ };
252
302
  }
253
- catch (e) {
254
- // Ignore tool call parsing errors in stream
303
+ catch (error) {
304
+ console.error("Failed to parse tool arguments from OpenRouter:", getErrorMessage(error));
305
+ return {
306
+ role: "assistant",
307
+ content: choice.content || `(Message error: Malformed tool arguments)`,
308
+ };
255
309
  }
256
310
  }
257
- const blocks = [];
258
- if (fullReasoning)
259
- blocks.push({ type: "thought", text: fullReasoning });
260
- if (fullContent)
261
- blocks.push({ type: "text", text: fullContent });
262
311
  return {
263
312
  role: "assistant",
264
- content: blocks.length > 0 ? blocks : fullContent,
265
- tool_uses: finalToolUses.length > 0 ? finalToolUses : undefined,
313
+ content: choice.content || "",
266
314
  };
267
- }
268
- catch (error) {
269
- if (error instanceof Error && error.name === "AbortError") {
270
- // Distinguish between user manual stop and actual timeout
271
- if (isUserAbort) {
272
- throw new Error("Request stopped by user");
315
+ },
316
+ async createMessageStream(params, onUpdate, signal) {
317
+ const controller = new AbortController();
318
+ let isTimeout = false;
319
+ const timeoutId = setTimeout(() => {
320
+ isTimeout = true;
321
+ controller.abort();
322
+ }, 120000);
323
+ let isUserAbort = false;
324
+ const onAbort = () => {
325
+ isUserAbort = true;
326
+ controller.abort();
327
+ };
328
+ if (signal)
329
+ signal.addEventListener("abort", onAbort);
330
+ try {
331
+ const translatedModel = translateModelName(params.model);
332
+ const response = await fetch(`${BASE_URL}/chat/completions`, {
333
+ method: "POST",
334
+ headers: {
335
+ Authorization: `Bearer ${apiKey}`,
336
+ "HTTP-Referer": "https://github.com/CardSorting/Marie-Coder-New-the-vatican",
337
+ "X-Title": "DreamBees CLI",
338
+ "Content-Type": "application/json",
339
+ Accept: "text/event-stream",
340
+ "Cache-Control": "no-cache",
341
+ Connection: "keep-alive",
342
+ },
343
+ body: safeStringify({
344
+ model: translatedModel,
345
+ messages: getOpenAiMessages(params),
346
+ tools: getOpenAiTools(params),
347
+ max_tokens: params.max_tokens || 1024,
348
+ stream: true,
349
+ include_reasoning: true,
350
+ }),
351
+ signal: controller.signal,
352
+ });
353
+ if (!response.ok) {
354
+ throw new Error(`OpenRouter API error: ${response.status} (model: ${translatedModel})`);
273
355
  }
274
- else if (isTimeout) {
275
- throw new Error("OpenRouter timeout");
356
+ if (!response.body)
357
+ throw new Error("OpenRouter API returned no body.");
358
+ const reader = response.body.getReader();
359
+ const decoder = new TextDecoder();
360
+ const contentParts = [];
361
+ const reasoningParts = [];
362
+ const bufferParts = [];
363
+ const toolCalls = {};
364
+ const startTime = Date.now();
365
+ onUpdate({ type: "run_started", timestamp: startTime });
366
+ onUpdate({
367
+ type: "stage_change",
368
+ stage: "thinking",
369
+ label: "Processing request...",
370
+ });
371
+ const streamParser = createStreamParser();
372
+ try {
373
+ while (true) {
374
+ const { done, value } = await reader.read();
375
+ if (done)
376
+ break;
377
+ const chunk = decoder.decode(value, { stream: true });
378
+ streamParser.process(chunk, onUpdate, contentParts, reasoningParts);
379
+ }
276
380
  }
277
- else {
278
- throw new Error("Request aborted");
381
+ finally {
382
+ reader.releaseLock();
279
383
  }
280
- }
281
- throw error;
282
- }
283
- finally {
284
- clearTimeout(timeoutId);
285
- if (signal)
286
- signal.removeEventListener("abort", onAbort);
287
- }
288
- }
289
- /**
290
- * Translates Anthropic model names to OpenRouter format.
291
- * OpenRouter expects format like "anthropic/claude-3.5-sonnet"
292
- */
293
- translateModelName(model) {
294
- const normalized = (model || "").trim();
295
- if (!normalized) {
296
- return "anthropic/claude-3.5-sonnet";
297
- }
298
- // If already in OpenRouter format, return as-is
299
- if (normalized.includes("/")) {
300
- return normalized;
301
- }
302
- // Map Anthropic model names to OpenRouter format
303
- const modelMap = {
304
- "claude-3-5-sonnet-20241022": "anthropic/claude-3.5-sonnet",
305
- "claude-3-5-sonnet": "anthropic/claude-3.5-sonnet",
306
- "claude-3-5-haiku-20241022": "anthropic/claude-3.5-haiku",
307
- "claude-3-5-haiku": "anthropic/claude-3.5-haiku",
308
- "claude-3-opus-20240229": "anthropic/claude-3-opus",
309
- "claude-3-opus": "anthropic/claude-3-opus",
310
- "claude-3-sonnet-20240229": "anthropic/claude-3-sonnet",
311
- "claude-3-sonnet": "anthropic/claude-3-sonnet",
312
- "claude-3-haiku-20240307": "anthropic/claude-3-haiku",
313
- "claude-3-haiku": "anthropic/claude-3-haiku",
314
- };
315
- if (modelMap[normalized]) {
316
- return modelMap[normalized];
317
- }
318
- // Try to convert claude models that aren't in the map.
319
- // Examples:
320
- // - claude-3-5-sonnet-20241022 => anthropic/claude-3.5-sonnet
321
- // - claude-3-7-sonnet => anthropic/claude-3.7-sonnet
322
- if (normalized.startsWith("claude-")) {
323
- const withoutDateSuffix = normalized.replace(/-20\d{6}$/, "");
324
- const claudeVersioned = withoutDateSuffix.match(/^claude-(\d+)-(\d+)(-.+)$/);
325
- if (claudeVersioned) {
326
- const major = claudeVersioned[1];
327
- const minor = claudeVersioned[2];
328
- const variant = claudeVersioned[3];
329
- return `anthropic/claude-${major}.${minor}${variant}`;
330
- }
331
- return `anthropic/${withoutDateSuffix}`;
332
- }
333
- // Return as-is if we can't translate
334
- return normalized;
335
- }
336
- getOpenAiMessages(params) {
337
- const messages = [];
338
- if (params.system)
339
- messages.push({ role: "system", content: params.system });
340
- for (const msg of params.messages) {
341
- if (typeof msg.content === "string") {
342
- messages.push({ role: msg.role, content: msg.content });
343
- }
344
- else if (Array.isArray(msg.content)) {
345
- let text = "";
346
- const tools = [];
347
- for (const block of msg.content) {
348
- if (block.type === "text")
349
- text += block.text;
350
- else if (block.type === "tool_use")
351
- tools.push({
352
- id: block.id,
353
- type: "function",
354
- function: {
355
- name: block.name,
356
- arguments: JSON.stringify(block.input),
357
- },
358
- });
359
- else if (block.type === "tool_result") {
360
- messages.push({
361
- role: "tool",
362
- tool_call_id: block.tool_use_id,
363
- content: typeof block.content === "string"
364
- ? block.content
365
- : JSON.stringify(block.content),
366
- });
384
+ const fullContent = contentParts.join("");
385
+ streamParser.finalize(fullContent, onUpdate);
386
+ const endTime = Date.now();
387
+ onUpdate({ type: "run_completed", timestamp: endTime, durationMs: endTime - startTime });
388
+ const finalToolUses = [];
389
+ for (const tc of Object.values(streamParser.getToolCalls())) {
390
+ try {
391
+ finalToolUses.push({ id: tc.id, name: tc.name, input: safeParseJson(tc.arguments).result });
367
392
  }
393
+ catch { }
368
394
  }
369
- if (msg.role === "assistant" && (text || tools.length > 0)) {
370
- const m = { role: "assistant", content: text || null };
371
- if (tools.length > 0)
372
- m.tool_calls = tools;
373
- messages.push(m);
374
- }
375
- else if (msg.role === "user" && text) {
376
- messages.push({ role: "user", content: text });
395
+ const blocks = [];
396
+ if (reasoningParts.length > 0)
397
+ blocks.push({ type: "thought", text: reasoningParts.join("") });
398
+ if (contentParts.length > 0)
399
+ blocks.push({ type: "text", text: contentParts.join("") });
400
+ return {
401
+ role: "assistant",
402
+ content: blocks.length > 0 ? blocks : fullContent,
403
+ tool_uses: finalToolUses.length > 0 ? finalToolUses : undefined,
404
+ };
405
+ }
406
+ catch (error) {
407
+ if (error instanceof Error && error.name === "AbortError") {
408
+ // Distinguish between user manual stop and actual timeout
409
+ if (isUserAbort) {
410
+ throw new Error("Request stopped by user");
411
+ }
412
+ else if (isTimeout) {
413
+ throw new Error("OpenRouter timeout");
414
+ }
415
+ else {
416
+ throw new Error("Request aborted");
417
+ }
377
418
  }
419
+ throw error;
378
420
  }
379
- }
380
- return messages;
381
- }
382
- getOpenAiTools(params) {
383
- if (!params.tools)
384
- return undefined;
385
- return params.tools.map((tool) => ({
386
- type: "function",
387
- function: {
388
- name: tool.name,
389
- description: tool.description,
390
- parameters: tool.input_schema,
391
- },
392
- }));
393
- }
394
- estimateTokens(text) {
395
- return Math.ceil(text.length * ConfigService.getTokensPerChar());
396
- }
397
- async listModels() {
398
- return [
399
- { id: "anthropic/claude-3.5-sonnet", name: "Claude 3.5 Sonnet" },
400
- { id: "google/gemini-2.0-flash-001", name: "Gemini 2.0 Flash" },
401
- ];
402
- }
403
- async createEmbedding(text) {
404
- const response = await fetch(`${this.baseUrl}/embeddings`, {
405
- method: "POST",
406
- headers: {
407
- Authorization: `Bearer ${this.apiKey}`,
408
- "HTTP-Referer": "https://github.com/bozoegg/MarieCoder",
409
- "X-Title": "MarieCoder VS Code Extension",
410
- "Content-Type": "application/json",
411
- },
412
- body: JSON.stringify({
413
- model: "openai/text-embedding-3-small",
414
- input: text,
415
- }),
416
- });
417
- if (!response.ok) {
418
- throw new Error(`OpenRouter Embedding error: ${response.status}`);
419
- }
420
- const data = (await response.json());
421
- if (!data.data || data.data.length === 0)
422
- throw new Error("OpenRouter Embedding returned no data.");
423
- return data.data[0].embedding;
424
- }
421
+ finally {
422
+ clearTimeout(timeoutId);
423
+ if (signal)
424
+ signal.removeEventListener("abort", onAbort);
425
+ }
426
+ },
427
+ estimateTokens(text) {
428
+ return Math.ceil(text.length * getTokensPerChar());
429
+ },
430
+ async listModels() {
431
+ return [
432
+ { id: "anthropic/claude-3.5-sonnet", name: "Claude 3.5 Sonnet" },
433
+ { id: "google/gemini-2.0-flash-001", name: "Gemini 2.0 Flash" },
434
+ ];
435
+ },
436
+ async createEmbedding(text) {
437
+ const response = await fetch(`${BASE_URL}/embeddings`, {
438
+ method: "POST",
439
+ headers: {
440
+ Authorization: `Bearer ${apiKey}`,
441
+ "HTTP-Referer": "https://github.com/CardSorting/Marie-Coder-New-the-vatican",
442
+ "X-Title": "DreamBees CLI",
443
+ "Content-Type": "application/json",
444
+ },
445
+ body: safeStringify({
446
+ model: "openai/text-embedding-3-small",
447
+ input: text,
448
+ }),
449
+ });
450
+ if (!response.ok) {
451
+ throw new Error(`OpenRouter Embedding error: ${response.status}`);
452
+ }
453
+ const data = (await response.json());
454
+ if (!data.data || data.data.length === 0)
455
+ throw new Error("OpenRouter Embedding returned no data.");
456
+ return data.data[0].embedding;
457
+ },
458
+ };
425
459
  }
426
460
  //# sourceMappingURL=OpenRouterProvider.js.map