@vybestack/llxprt-code 0.4.8 → 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 (269) hide show
  1. package/dist/package.json +5 -3
  2. package/dist/src/auth/__tests__/oauthManager.safety.test.d.ts +6 -0
  3. package/dist/src/auth/__tests__/oauthManager.safety.test.js +49 -0
  4. package/dist/src/auth/__tests__/oauthManager.safety.test.js.map +1 -0
  5. package/dist/src/auth/oauth-manager.d.ts +11 -0
  6. package/dist/src/auth/oauth-manager.js +62 -29
  7. package/dist/src/auth/oauth-manager.js.map +1 -1
  8. package/dist/src/auth/oauth-manager.spec.js +7 -2
  9. package/dist/src/auth/oauth-manager.spec.js.map +1 -1
  10. package/dist/src/config/__tests__/nonInteractiveTools.test.d.ts +6 -0
  11. package/dist/src/config/__tests__/nonInteractiveTools.test.js +13 -0
  12. package/dist/src/config/__tests__/nonInteractiveTools.test.js.map +1 -0
  13. package/dist/src/config/__tests__/profileBootstrap.test.d.ts +6 -0
  14. package/dist/src/config/__tests__/profileBootstrap.test.js +91 -0
  15. package/dist/src/config/__tests__/profileBootstrap.test.js.map +1 -0
  16. package/dist/src/config/config.d.ts +6 -2
  17. package/dist/src/config/config.js +219 -18
  18. package/dist/src/config/config.js.map +1 -1
  19. package/dist/src/config/profileBootstrap.d.ts +64 -0
  20. package/dist/src/config/profileBootstrap.js +140 -0
  21. package/dist/src/config/profileBootstrap.js.map +1 -0
  22. package/dist/src/gemini.js +68 -23
  23. package/dist/src/gemini.js.map +1 -1
  24. package/dist/src/gemini.test.js +1 -2
  25. package/dist/src/gemini.test.js.map +1 -1
  26. package/dist/src/generated/git-commit.d.ts +1 -1
  27. package/dist/src/generated/git-commit.js +1 -1
  28. package/dist/src/integration-tests/base-url-behavior.integration.test.js +110 -450
  29. package/dist/src/integration-tests/base-url-behavior.integration.test.js.map +1 -1
  30. package/dist/src/integration-tests/model-params-isolation.integration.test.js +101 -539
  31. package/dist/src/integration-tests/model-params-isolation.integration.test.js.map +1 -1
  32. package/dist/src/integration-tests/modelParams.integration.test.js +86 -761
  33. package/dist/src/integration-tests/modelParams.integration.test.js.map +1 -1
  34. package/dist/src/integration-tests/provider-multi-runtime.integration.test.d.ts +6 -0
  35. package/dist/src/integration-tests/provider-multi-runtime.integration.test.js +198 -0
  36. package/dist/src/integration-tests/provider-multi-runtime.integration.test.js.map +1 -0
  37. package/dist/src/integration-tests/provider-switching.integration.test.js +97 -151
  38. package/dist/src/integration-tests/provider-switching.integration.test.js.map +1 -1
  39. package/dist/src/integration-tests/runtime-isolation.test.d.ts +13 -0
  40. package/dist/src/integration-tests/runtime-isolation.test.js +170 -0
  41. package/dist/src/integration-tests/runtime-isolation.test.js.map +1 -0
  42. package/dist/src/integration-tests/test-utils.js +19 -2
  43. package/dist/src/integration-tests/test-utils.js.map +1 -1
  44. package/dist/src/integration-tests/test-utils.test.js +9 -8
  45. package/dist/src/integration-tests/test-utils.test.js.map +1 -1
  46. package/dist/src/integration-tests/todo-continuation.integration.test.js +5 -2
  47. package/dist/src/integration-tests/todo-continuation.integration.test.js.map +1 -1
  48. package/dist/src/integration-tests/tools-governance.integration.test.d.ts +6 -0
  49. package/dist/src/integration-tests/tools-governance.integration.test.js +98 -0
  50. package/dist/src/integration-tests/tools-governance.integration.test.js.map +1 -0
  51. package/dist/src/nonInteractiveCli.js +36 -11
  52. package/dist/src/nonInteractiveCli.js.map +1 -1
  53. package/dist/src/providers/logging/git-stats.test.js +11 -1
  54. package/dist/src/providers/logging/git-stats.test.js.map +1 -1
  55. package/dist/src/providers/logging/multi-provider-logging.integration.test.js +1 -2
  56. package/dist/src/providers/logging/multi-provider-logging.integration.test.js.map +1 -1
  57. package/dist/src/providers/logging/performance.test.js +1 -1
  58. package/dist/src/providers/logging/performance.test.js.map +1 -1
  59. package/dist/src/providers/oauth-provider-registration.d.ts +2 -2
  60. package/dist/src/providers/oauth-provider-registration.js +25 -9
  61. package/dist/src/providers/oauth-provider-registration.js.map +1 -1
  62. package/dist/src/providers/provider-gemini-switching.test.js +67 -89
  63. package/dist/src/providers/provider-gemini-switching.test.js.map +1 -1
  64. package/dist/src/providers/provider-switching.integration.test.js +42 -98
  65. package/dist/src/providers/provider-switching.integration.test.js.map +1 -1
  66. package/dist/src/providers/providerConfigUtils.d.ts +12 -7
  67. package/dist/src/providers/providerConfigUtils.js +31 -99
  68. package/dist/src/providers/providerConfigUtils.js.map +1 -1
  69. package/dist/src/providers/providerManagerInstance.d.ts +17 -1
  70. package/dist/src/providers/providerManagerInstance.js +157 -175
  71. package/dist/src/providers/providerManagerInstance.js.map +1 -1
  72. package/dist/src/providers/providerManagerInstance.oauthRegistration.test.js +19 -15
  73. package/dist/src/providers/providerManagerInstance.oauthRegistration.test.js.map +1 -1
  74. package/dist/src/providers/providerManagerInstance.test.js +2 -5
  75. package/dist/src/providers/providerManagerInstance.test.js.map +1 -1
  76. package/dist/src/runtime/__tests__/profileApplication.test.d.ts +5 -0
  77. package/dist/src/runtime/__tests__/profileApplication.test.js +232 -0
  78. package/dist/src/runtime/__tests__/profileApplication.test.js.map +1 -0
  79. package/dist/src/runtime/__tests__/runtimeIsolation.test.d.ts +5 -0
  80. package/dist/src/runtime/__tests__/runtimeIsolation.test.js +376 -0
  81. package/dist/src/runtime/__tests__/runtimeIsolation.test.js.map +1 -0
  82. package/dist/src/runtime/agentRuntimeAdapter.d.ts +249 -0
  83. package/dist/src/runtime/agentRuntimeAdapter.js +506 -0
  84. package/dist/src/runtime/agentRuntimeAdapter.js.map +1 -0
  85. package/dist/src/runtime/agentRuntimeAdapter.spec.d.ts +6 -0
  86. package/dist/src/runtime/agentRuntimeAdapter.spec.js +866 -0
  87. package/dist/src/runtime/agentRuntimeAdapter.spec.js.map +1 -0
  88. package/dist/src/runtime/messages.d.ts +28 -0
  89. package/dist/src/runtime/messages.js +64 -0
  90. package/dist/src/runtime/messages.js.map +1 -0
  91. package/dist/src/runtime/profileApplication.d.ts +33 -0
  92. package/dist/src/runtime/profileApplication.js +191 -0
  93. package/dist/src/runtime/profileApplication.js.map +1 -0
  94. package/dist/src/runtime/providerConfigUtils.test.d.ts +1 -0
  95. package/dist/src/runtime/providerConfigUtils.test.js +68 -0
  96. package/dist/src/runtime/providerConfigUtils.test.js.map +1 -0
  97. package/dist/src/runtime/runtimeContextFactory.d.ts +102 -0
  98. package/dist/src/runtime/runtimeContextFactory.js +190 -0
  99. package/dist/src/runtime/runtimeContextFactory.js.map +1 -0
  100. package/dist/src/runtime/runtimeSettings.d.ts +217 -0
  101. package/dist/src/runtime/runtimeSettings.js +1094 -0
  102. package/dist/src/runtime/runtimeSettings.js.map +1 -0
  103. package/dist/src/runtime/runtimeSettings.test.d.ts +1 -0
  104. package/dist/src/runtime/runtimeSettings.test.js +320 -0
  105. package/dist/src/runtime/runtimeSettings.test.js.map +1 -0
  106. package/dist/src/services/BuiltinCommandLoader.d.ts +13 -4
  107. package/dist/src/services/BuiltinCommandLoader.js +17 -4
  108. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  109. package/dist/src/services/McpPromptLoader.js +34 -13
  110. package/dist/src/services/McpPromptLoader.js.map +1 -1
  111. package/dist/src/test-utils/mockCommandContext.js +5 -2
  112. package/dist/src/test-utils/mockCommandContext.js.map +1 -1
  113. package/dist/src/ui/App.js +29 -49
  114. package/dist/src/ui/App.js.map +1 -1
  115. package/dist/src/ui/commands/aboutCommand.js +59 -38
  116. package/dist/src/ui/commands/aboutCommand.js.map +1 -1
  117. package/dist/src/ui/commands/authCommand.js +7 -9
  118. package/dist/src/ui/commands/authCommand.js.map +1 -1
  119. package/dist/src/ui/commands/baseurlCommand.js +8 -44
  120. package/dist/src/ui/commands/baseurlCommand.js.map +1 -1
  121. package/dist/src/ui/commands/chatCommand.js +28 -12
  122. package/dist/src/ui/commands/chatCommand.js.map +1 -1
  123. package/dist/src/ui/commands/diagnosticsCommand.d.ts +0 -3
  124. package/dist/src/ui/commands/diagnosticsCommand.js +45 -191
  125. package/dist/src/ui/commands/diagnosticsCommand.js.map +1 -1
  126. package/dist/src/ui/commands/keyCommand.js +9 -58
  127. package/dist/src/ui/commands/keyCommand.js.map +1 -1
  128. package/dist/src/ui/commands/keyCommand.test.js +48 -102
  129. package/dist/src/ui/commands/keyCommand.test.js.map +1 -1
  130. package/dist/src/ui/commands/keyfileCommand.js +42 -93
  131. package/dist/src/ui/commands/keyfileCommand.js.map +1 -1
  132. package/dist/src/ui/commands/logoutCommand.js +2 -2
  133. package/dist/src/ui/commands/logoutCommand.js.map +1 -1
  134. package/dist/src/ui/commands/mcpCommand.js +29 -7
  135. package/dist/src/ui/commands/mcpCommand.js.map +1 -1
  136. package/dist/src/ui/commands/modelCommand.js +8 -59
  137. package/dist/src/ui/commands/modelCommand.js.map +1 -1
  138. package/dist/src/ui/commands/profileCommand.js +151 -267
  139. package/dist/src/ui/commands/profileCommand.js.map +1 -1
  140. package/dist/src/ui/commands/profileCommand.test.js +88 -344
  141. package/dist/src/ui/commands/profileCommand.test.js.map +1 -1
  142. package/dist/src/ui/commands/providerCommand.js +9 -3
  143. package/dist/src/ui/commands/providerCommand.js.map +1 -1
  144. package/dist/src/ui/commands/restoreCommand.js +38 -18
  145. package/dist/src/ui/commands/restoreCommand.js.map +1 -1
  146. package/dist/src/ui/commands/schema/argumentResolver.test.d.ts +6 -0
  147. package/dist/src/ui/commands/schema/argumentResolver.test.js +619 -0
  148. package/dist/src/ui/commands/schema/argumentResolver.test.js.map +1 -0
  149. package/dist/src/ui/commands/schema/index.d.ts +15 -0
  150. package/dist/src/ui/commands/schema/index.js +320 -0
  151. package/dist/src/ui/commands/schema/index.js.map +1 -0
  152. package/dist/src/ui/commands/schema/types.d.ts +61 -0
  153. package/dist/src/ui/commands/schema/types.js +12 -0
  154. package/dist/src/ui/commands/schema/types.js.map +1 -0
  155. package/dist/src/ui/commands/setCommand.js +641 -325
  156. package/dist/src/ui/commands/setCommand.js.map +1 -1
  157. package/dist/src/ui/commands/setCommand.test.js +92 -388
  158. package/dist/src/ui/commands/setCommand.test.js.map +1 -1
  159. package/dist/src/ui/commands/statusCommand.js +2 -2
  160. package/dist/src/ui/commands/statusCommand.js.map +1 -1
  161. package/dist/src/ui/commands/subagentCommand.d.ts +16 -0
  162. package/dist/src/ui/commands/subagentCommand.js +674 -0
  163. package/dist/src/ui/commands/subagentCommand.js.map +1 -0
  164. package/dist/src/ui/commands/test/setCommand.mutation.test.d.ts +6 -0
  165. package/dist/src/ui/commands/test/setCommand.mutation.test.js +132 -0
  166. package/dist/src/ui/commands/test/setCommand.mutation.test.js.map +1 -0
  167. package/dist/src/ui/commands/test/setCommand.phase09.test.d.ts +6 -0
  168. package/dist/src/ui/commands/test/setCommand.phase09.test.js +222 -0
  169. package/dist/src/ui/commands/test/setCommand.phase09.test.js.map +1 -0
  170. package/dist/src/ui/commands/test/subagentCommand.schema.test.d.ts +6 -0
  171. package/dist/src/ui/commands/test/subagentCommand.schema.test.js +125 -0
  172. package/dist/src/ui/commands/test/subagentCommand.schema.test.js.map +1 -0
  173. package/dist/src/ui/commands/test/subagentCommand.test.d.ts +1 -0
  174. package/dist/src/ui/commands/test/subagentCommand.test.js +598 -0
  175. package/dist/src/ui/commands/test/subagentCommand.test.js.map +1 -0
  176. package/dist/src/ui/commands/toolformatCommand.js +25 -98
  177. package/dist/src/ui/commands/toolformatCommand.js.map +1 -1
  178. package/dist/src/ui/commands/toolformatCommand.test.js +56 -102
  179. package/dist/src/ui/commands/toolformatCommand.test.js.map +1 -1
  180. package/dist/src/ui/commands/toolsCommand.js +187 -31
  181. package/dist/src/ui/commands/toolsCommand.js.map +1 -1
  182. package/dist/src/ui/commands/types.d.ts +11 -2
  183. package/dist/src/ui/commands/types.js.map +1 -1
  184. package/dist/src/ui/components/AuthDialog.js +16 -55
  185. package/dist/src/ui/components/AuthDialog.js.map +1 -1
  186. package/dist/src/ui/components/Footer.js +4 -5
  187. package/dist/src/ui/components/Footer.js.map +1 -1
  188. package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
  189. package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
  190. package/dist/src/ui/components/InputPrompt.js +1 -1
  191. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  192. package/dist/src/ui/components/StatsDisplay.js +6 -11
  193. package/dist/src/ui/components/StatsDisplay.js.map +1 -1
  194. package/dist/src/ui/components/SuggestionsDisplay.d.ts +13 -1
  195. package/dist/src/ui/components/SuggestionsDisplay.js +22 -3
  196. package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -1
  197. package/dist/src/ui/components/messages/ToolGroupMessage.d.ts +1 -0
  198. package/dist/src/ui/components/messages/ToolGroupMessage.js +14 -14
  199. package/dist/src/ui/components/messages/ToolGroupMessage.js.map +1 -1
  200. package/dist/src/ui/components/messages/ToolGroupMessage.test.js +1 -0
  201. package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
  202. package/dist/src/ui/containers/SessionController.js +61 -117
  203. package/dist/src/ui/containers/SessionController.js.map +1 -1
  204. package/dist/src/ui/contexts/RuntimeContext.d.ts +61 -0
  205. package/dist/src/ui/contexts/RuntimeContext.js +118 -0
  206. package/dist/src/ui/contexts/RuntimeContext.js.map +1 -0
  207. package/dist/src/ui/contexts/TodoProvider.d.ts +1 -0
  208. package/dist/src/ui/contexts/TodoProvider.js +10 -8
  209. package/dist/src/ui/contexts/TodoProvider.js.map +1 -1
  210. package/dist/src/ui/contexts/ToolCallProvider.d.ts +1 -0
  211. package/dist/src/ui/contexts/ToolCallProvider.js +10 -9
  212. package/dist/src/ui/contexts/ToolCallProvider.js.map +1 -1
  213. package/dist/src/ui/hooks/__tests__/useSlashCompletion.set.phase09.test.d.ts +6 -0
  214. package/dist/src/ui/hooks/__tests__/useSlashCompletion.set.phase09.test.js +39 -0
  215. package/dist/src/ui/hooks/__tests__/useSlashCompletion.set.phase09.test.js.map +1 -0
  216. package/dist/src/ui/hooks/atCommandProcessor.js +11 -3
  217. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  218. package/dist/src/ui/hooks/atCommandProcessor.test.js +3 -1
  219. package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
  220. package/dist/src/ui/hooks/shellCommandProcessor.js +4 -1
  221. package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -1
  222. package/dist/src/ui/hooks/shellCommandProcessor.test.js +1 -0
  223. package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
  224. package/dist/src/ui/hooks/slashCommandProcessor.js +27 -1
  225. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  226. package/dist/src/ui/hooks/useAuthCommand.js +11 -3
  227. package/dist/src/ui/hooks/useAuthCommand.js.map +1 -1
  228. package/dist/src/ui/hooks/useCommandCompletion.d.ts +1 -0
  229. package/dist/src/ui/hooks/useCommandCompletion.js +2 -0
  230. package/dist/src/ui/hooks/useCommandCompletion.js.map +1 -1
  231. package/dist/src/ui/hooks/useGeminiStream.js +37 -11
  232. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  233. package/dist/src/ui/hooks/useGeminiStream.subagent.spec.d.ts +6 -0
  234. package/dist/src/ui/hooks/useGeminiStream.subagent.spec.js +232 -0
  235. package/dist/src/ui/hooks/useGeminiStream.subagent.spec.js.map +1 -0
  236. package/dist/src/ui/hooks/useLoadProfileDialog.d.ts +1 -1
  237. package/dist/src/ui/hooks/useLoadProfileDialog.js +18 -57
  238. package/dist/src/ui/hooks/useLoadProfileDialog.js.map +1 -1
  239. package/dist/src/ui/hooks/useOpenAIProviderInfo.d.ts +1 -1
  240. package/dist/src/ui/hooks/useOpenAIProviderInfo.js +12 -7
  241. package/dist/src/ui/hooks/useOpenAIProviderInfo.js.map +1 -1
  242. package/dist/src/ui/hooks/useProviderDialog.d.ts +1 -1
  243. package/dist/src/ui/hooks/useProviderDialog.js +17 -90
  244. package/dist/src/ui/hooks/useProviderDialog.js.map +1 -1
  245. package/dist/src/ui/hooks/useProviderModelDialog.d.ts +2 -2
  246. package/dist/src/ui/hooks/useProviderModelDialog.js +11 -12
  247. package/dist/src/ui/hooks/useProviderModelDialog.js.map +1 -1
  248. package/dist/src/ui/hooks/useReactToolScheduler.d.ts +3 -1
  249. package/dist/src/ui/hooks/useReactToolScheduler.js +144 -34
  250. package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
  251. package/dist/src/ui/hooks/useSlashCompletion.d.ts +32 -0
  252. package/dist/src/ui/hooks/useSlashCompletion.js +154 -77
  253. package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
  254. package/dist/src/ui/hooks/useSlashCompletion.test.js +39 -14
  255. package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
  256. package/dist/src/ui/hooks/useToolScheduler.test.js +108 -79
  257. package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
  258. package/dist/src/ui/types.d.ts +1 -0
  259. package/dist/src/ui/types.js.map +1 -1
  260. package/dist/src/utils/sandbox.js +7 -5
  261. package/dist/src/utils/sandbox.js.map +1 -1
  262. package/dist/src/validateNonInterActiveAuth.js +4 -2
  263. package/dist/src/validateNonInterActiveAuth.js.map +1 -1
  264. package/dist/src/zed-integration/schema.d.ts +30 -30
  265. package/dist/src/zed-integration/zedIntegration.js +112 -39
  266. package/dist/src/zed-integration/zedIntegration.js.map +1 -1
  267. package/dist/tsconfig.build.tsbuildinfo +1 -0
  268. package/package.json +5 -3
  269. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -3,26 +3,27 @@
3
3
  * Copyright 2025 Vybestack LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
7
- import { Config, ProfileManager, ProviderManager, } from '@vybestack/llxprt-code-core';
6
+ import { beforeEach, afterEach, describe, expect, it } from 'vitest';
7
+ import { Config, ProfileManager, createProviderRuntimeContext, } from '@vybestack/llxprt-code-core';
8
8
  import { createTempDirectory, cleanupTempDirectory } from './test-utils.js';
9
- describe('Base URL Behavior Integration Tests', () => {
9
+ import { createProviderManager } from '../providers/providerManagerInstance.js';
10
+ import { setCliRuntimeContext, switchActiveProvider, registerCliProviderInfrastructure, resetCliProviderInfrastructure, } from '../runtime/runtimeSettings.js';
11
+ import { setProviderBaseUrl } from '../providers/providerConfigUtils.js';
12
+ /**
13
+ * @plan:PLAN-20250218-STATELESSPROVIDER.P07
14
+ * @requirement:REQ-SP-005
15
+ * Validates that runtime helpers control provider base-url behavior rather
16
+ * than direct provider mutations.
17
+ * @pseudocode:cli-runtime.md lines 9-15
18
+ */
19
+ describe('Base URL Runtime Helper Integration', () => {
10
20
  let tempDir;
11
21
  let config;
12
- let profileManager;
13
22
  let providerManager;
14
- let originalHome;
23
+ let profileManager;
24
+ let settingsService;
15
25
  beforeEach(async () => {
16
- // Store original HOME environment variable
17
- originalHome = process.env.HOME;
18
- // Create a temporary directory for our test
19
26
  tempDir = await createTempDirectory();
20
- // Set HOME to our temp directory so ProfileManager uses it
21
- process.env.HOME = tempDir;
22
- // Create instances
23
- profileManager = new ProfileManager();
24
- providerManager = new ProviderManager();
25
- // Create a basic config instance
26
27
  config = new Config({
27
28
  sessionId: 'test-session',
28
29
  targetDir: tempDir,
@@ -30,465 +31,124 @@ describe('Base URL Behavior Integration Tests', () => {
30
31
  model: 'test-model',
31
32
  cwd: tempDir,
32
33
  });
33
- // Set provider manager on config
34
- config.setProviderManager(providerManager);
35
- // Initialize the config
36
34
  await config.initialize();
37
- });
38
- afterEach(async () => {
39
- // Restore original HOME
40
- if (originalHome !== undefined) {
41
- process.env.HOME = originalHome;
42
- }
43
- else {
44
- delete process.env.HOME;
45
- }
46
- // Clean up temp directory
47
- await cleanupTempDirectory(tempDir);
48
- });
49
- describe('Base URL Setting via Ephemeral Settings', () => {
50
- it('should set custom base URL on provider via ephemeral settings', async () => {
51
- // Create and register a mock provider
52
- const provider = createMockProvider('openai');
53
- providerManager.registerProvider(provider);
54
- providerManager.setActiveProvider('openai');
55
- // Set base URL via ephemeral settings
56
- const customBaseUrl = 'https://custom.openai.api.com/v1';
57
- config.setEphemeralSetting('base-url', customBaseUrl);
58
- // Apply base URL to provider (simulating what the CLI does)
59
- const baseUrl = config.getEphemeralSetting('base-url');
60
- if (baseUrl && baseUrl !== 'none' && provider.setBaseUrl) {
61
- provider.setBaseUrl(baseUrl);
62
- }
63
- // Verify the provider received the base URL
64
- expect(provider.baseUrl).toBe(customBaseUrl);
35
+ settingsService = config.getSettingsService();
36
+ const runtime = createProviderRuntimeContext({
37
+ settingsService,
38
+ config,
39
+ metadata: { source: 'base-url-test' },
65
40
  });
66
- it('should clear base URL when set to empty string', async () => {
67
- // Create and register a mock provider with initial base URL
68
- const provider = createMockProvider('openai');
69
- provider.baseUrl = 'https://initial.api.com';
70
- providerManager.registerProvider(provider);
71
- providerManager.setActiveProvider('openai');
72
- // Clear base URL by setting to empty string
73
- config.setEphemeralSetting('base-url', '');
74
- // Apply clearing logic (simulating what the CLI does)
75
- const baseUrl = config.getEphemeralSetting('base-url');
76
- if (!baseUrl || baseUrl.trim() === '') {
77
- provider.setBaseUrl?.(undefined);
78
- }
79
- // Verify the provider's base URL was cleared
80
- expect(provider.baseUrl).toBeUndefined();
41
+ const { manager, oauthManager } = createProviderManager(runtime, {
42
+ allowBrowserEnvironment: true,
81
43
  });
82
- });
83
- describe('Base URL "none" Value Handling', () => {
84
- it('should ignore/clear base URL when value is "none"', async () => {
85
- // Create and register a mock provider
86
- const provider = createMockProvider('openai');
87
- provider.baseUrl = 'https://existing.api.com';
88
- providerManager.registerProvider(provider);
89
- providerManager.setActiveProvider('openai');
90
- // Set base URL to "none"
91
- config.setEphemeralSetting('base-url', 'none');
92
- // Apply "none" handling logic (simulating what the CLI does)
93
- const baseUrl = config.getEphemeralSetting('base-url');
94
- if (baseUrl && baseUrl !== 'none' && provider.setBaseUrl) {
95
- provider.setBaseUrl(baseUrl);
96
- }
97
- else if (baseUrl === 'none' && provider.setBaseUrl) {
98
- // Clear base URL when "none"
99
- provider.setBaseUrl(undefined);
100
- }
101
- // Verify the provider's base URL was cleared
102
- expect(provider.baseUrl).toBeUndefined();
103
- });
104
- it('should not cause Invalid URL error when loading profile with base-url: "none"', async () => {
105
- // Create a profile with base-url: "none"
106
- const profile = {
107
- version: 1,
108
- provider: 'openai',
109
- model: 'gpt-4',
110
- modelParams: {},
111
- ephemeralSettings: {
112
- 'base-url': 'none',
113
- 'auth-key': 'test-key',
114
- },
115
- };
116
- // Save the profile
117
- await profileManager.saveProfile('test-none-profile', profile);
118
- // Create and register provider
119
- const provider = createMockProvider('openai');
120
- providerManager.registerProvider(provider);
121
- providerManager.setActiveProvider('openai');
122
- // Load the profile
123
- const loadedProfile = await profileManager.loadProfile('test-none-profile');
124
- // Apply ephemeral settings from profile (simulating profileCommand logic)
125
- for (const [key, value] of Object.entries(loadedProfile.ephemeralSettings)) {
126
- config.setEphemeralSetting(key, value);
127
- // Special handling for base-url
128
- if (key === 'base-url' && provider.setBaseUrl) {
129
- if (value === 'none') {
130
- provider.setBaseUrl(undefined);
131
- }
132
- else if (value) {
133
- provider.setBaseUrl(value);
134
- }
135
- }
136
- }
137
- // Verify no errors occurred and base URL is undefined
138
- expect(provider.baseUrl).toBeUndefined();
139
- expect(config.getEphemeralSetting('base-url')).toBe('none');
140
- expect(config.getEphemeralSetting('auth-key')).toBe('test-key');
44
+ providerManager = manager;
45
+ registerCliProviderInfrastructure(providerManager, oauthManager);
46
+ setCliRuntimeContext(settingsService, config, {
47
+ metadata: { source: 'base-url-test' },
141
48
  });
49
+ profileManager = new ProfileManager();
142
50
  });
143
- describe('Base URL Behavior with Different Providers', () => {
144
- it('should handle base URLs for OpenAI provider', async () => {
145
- const openaiProvider = createMockProvider('openai');
146
- providerManager.registerProvider(openaiProvider);
147
- providerManager.setActiveProvider('openai');
148
- // Set custom OpenAI-compatible base URL
149
- const openaiBaseUrl = 'https://api.openai.com/v1';
150
- config.setEphemeralSetting('base-url', openaiBaseUrl);
151
- openaiProvider.setBaseUrl?.(openaiBaseUrl);
152
- expect(openaiProvider.baseUrl).toBe(openaiBaseUrl);
153
- });
154
- it('should handle base URLs for Azure OpenAI provider', async () => {
155
- const azureProvider = createMockProvider('azure-openai');
156
- providerManager.registerProvider(azureProvider);
157
- providerManager.setActiveProvider('azure-openai');
158
- // Set custom Azure deployment URL
159
- const azureBaseUrl = 'https://myazure.openai.azure.com/';
160
- config.setEphemeralSetting('base-url', azureBaseUrl);
161
- azureProvider.setBaseUrl?.(azureBaseUrl);
162
- expect(azureProvider.baseUrl).toBe(azureBaseUrl);
163
- });
164
- it('should handle base URLs for OpenRouter provider', async () => {
165
- const openRouterProvider = createMockProvider('openrouter');
166
- providerManager.registerProvider(openRouterProvider);
167
- providerManager.setActiveProvider('openrouter');
168
- // Set custom OpenRouter URL
169
- const openRouterBaseUrl = 'https://openrouter.ai/api/v1';
170
- config.setEphemeralSetting('base-url', openRouterBaseUrl);
171
- openRouterProvider.setBaseUrl?.(openRouterBaseUrl);
172
- expect(openRouterProvider.baseUrl).toBe(openRouterBaseUrl);
173
- });
174
- it('should handle providers that do not support custom base URLs', async () => {
175
- const geminiProvider = createMockProvider('gemini');
176
- // Remove setBaseUrl method to simulate provider without base URL support
177
- delete geminiProvider.setBaseUrl;
178
- providerManager.registerProvider(geminiProvider);
179
- providerManager.setActiveProvider('gemini');
180
- // Try to set base URL
181
- config.setEphemeralSetting('base-url', 'https://custom.url.com');
182
- // Verify nothing breaks when provider doesn't support setBaseUrl
183
- expect(geminiProvider.baseUrl).toBeUndefined();
184
- expect(config.getEphemeralSetting('base-url')).toBe('https://custom.url.com');
185
- });
51
+ afterEach(async () => {
52
+ resetCliProviderInfrastructure();
53
+ await cleanupTempDirectory(tempDir);
186
54
  });
187
- describe('Provider Switching Clears Base URL', () => {
188
- it('should clear previous provider base URL when switching providers', async () => {
189
- // Create and register two providers
190
- const providerA = createMockProvider('openai');
191
- const providerB = createMockProvider('anthropic');
192
- providerManager.registerProvider(providerA);
193
- providerManager.registerProvider(providerB);
194
- // Set provider A as active with custom base URL
195
- providerManager.setActiveProvider('openai');
196
- const baseUrlA = 'https://api.provider-a.com';
197
- config.setEphemeralSetting('base-url', baseUrlA);
198
- providerA.setBaseUrl?.(baseUrlA);
199
- expect(providerA.baseUrl).toBe(baseUrlA);
200
- // Switch to provider B
201
- providerManager.setActiveProvider('anthropic');
202
- // Simulate clearing provider A's state (as done in real provider switching)
203
- providerA.clearState?.();
204
- // Set different base URL for provider B
205
- const baseUrlB = 'https://api.provider-b.com';
206
- config.setEphemeralSetting('base-url', baseUrlB);
207
- providerB.setBaseUrl?.(baseUrlB);
208
- // Verify provider A's base URL is cleared and provider B has its own
209
- expect(providerA.baseUrl).toBeUndefined();
210
- expect(providerB.baseUrl).toBe(baseUrlB);
211
- });
212
- it('should not affect base URL of server tools provider when switching active provider', async () => {
213
- // Create providers
214
- const geminiProvider = createMockProvider('gemini');
215
- geminiProvider.getServerTools = () => ['web-search'];
216
- const openaiProvider = createMockProvider('openai');
217
- providerManager.registerProvider(geminiProvider);
218
- providerManager.registerProvider(openaiProvider);
219
- // Set Gemini as server tools provider with base URL
220
- providerManager.setServerToolsProvider(geminiProvider);
221
- const geminiBaseUrl = 'https://gemini.api.com';
222
- geminiProvider.setBaseUrl?.(geminiBaseUrl);
223
- // Set OpenAI as active provider with different base URL
224
- providerManager.setActiveProvider('openai');
225
- const openaiBaseUrl = 'https://openai.api.com';
226
- config.setEphemeralSetting('base-url', openaiBaseUrl);
227
- openaiProvider.setBaseUrl?.(openaiBaseUrl);
228
- // Switch active provider to another one
229
- const anthropicProvider = createMockProvider('anthropic');
230
- providerManager.registerProvider(anthropicProvider);
231
- providerManager.setActiveProvider('anthropic');
232
- // Clear OpenAI's state
233
- openaiProvider.clearState?.();
234
- // Verify Gemini (server tools) retains its base URL while OpenAI's is cleared
235
- expect(geminiProvider.baseUrl).toBe(geminiBaseUrl);
236
- expect(openaiProvider.baseUrl).toBeUndefined();
237
- });
55
+ it('applies custom base URL via runtime helper', async () => {
56
+ const provider = createMockProvider('openai');
57
+ providerManager.registerProvider(provider);
58
+ providerManager.setActiveProvider('openai');
59
+ const customUrl = 'https://custom.openai.api/v1';
60
+ const result = await setProviderBaseUrl(customUrl);
61
+ expect(result.success).toBe(true);
62
+ expect(config.getSettingsService().getProviderSettings('openai').baseUrl).toBe(customUrl);
63
+ expect(config.getEphemeralSetting('base-url')).toBe(customUrl);
238
64
  });
239
- describe('Profile Save/Load with Base URLs', () => {
240
- it('should save and restore base URL in profile', async () => {
241
- // Set up provider and base URL
242
- const provider = createMockProvider('openai');
243
- providerManager.registerProvider(provider);
244
- providerManager.setActiveProvider('openai');
245
- const customBaseUrl = 'https://profile.api.com';
246
- config.setEphemeralSetting('base-url', customBaseUrl);
247
- // Create profile with current settings
248
- const profile = {
249
- version: 1,
250
- provider: 'openai',
251
- model: 'gpt-4',
252
- modelParams: {
253
- temperature: 0.7,
254
- },
255
- ephemeralSettings: {
256
- 'base-url': config.getEphemeralSetting('base-url'),
257
- 'auth-key': 'profile-api-key',
258
- },
259
- };
260
- // Save profile
261
- await profileManager.saveProfile('base-url-profile', profile);
262
- // Create new config instance (simulating restart)
263
- const newConfig = new Config({
264
- sessionId: 'new-session',
265
- targetDir: tempDir,
266
- debugMode: false,
267
- model: 'test-model',
268
- cwd: tempDir,
269
- });
270
- await newConfig.initialize();
271
- // Verify base URL is not there initially
272
- expect(newConfig.getEphemeralSetting('base-url')).toBeUndefined();
273
- // Load profile
274
- const loadedProfile = await profileManager.loadProfile('base-url-profile');
275
- // Apply settings from profile
276
- for (const [key, value] of Object.entries(loadedProfile.ephemeralSettings)) {
277
- newConfig.setEphemeralSetting(key, value);
278
- }
279
- // Verify base URL is restored
280
- expect(newConfig.getEphemeralSetting('base-url')).toBe(customBaseUrl);
281
- expect(newConfig.getEphemeralSetting('auth-key')).toBe('profile-api-key');
282
- });
283
- it('should handle profile with base-url: "none" without errors', async () => {
284
- // Create and save profile with "none" base URL
285
- const profile = {
286
- version: 1,
287
- provider: 'openai',
288
- model: 'gpt-4o',
289
- modelParams: {},
290
- ephemeralSettings: {
291
- 'base-url': 'none',
292
- },
293
- };
294
- await profileManager.saveProfile('none-base-url-profile', profile);
295
- // Load profile
296
- const loadedProfile = await profileManager.loadProfile('none-base-url-profile');
297
- // Verify "none" value is preserved
298
- expect(loadedProfile.ephemeralSettings['base-url']).toBe('none');
299
- // Apply to config
300
- config.setEphemeralSetting('base-url', loadedProfile.ephemeralSettings['base-url']);
301
- // Create provider and handle "none" value
302
- const provider = createMockProvider('openai');
303
- providerManager.registerProvider(provider);
304
- const baseUrl = config.getEphemeralSetting('base-url');
305
- if (baseUrl === 'none') {
306
- provider.setBaseUrl?.(undefined);
307
- }
308
- // Verify provider has no base URL set
309
- expect(provider.baseUrl).toBeUndefined();
310
- });
65
+ it('clears base URL when helper receives empty or "none" values', async () => {
66
+ const provider = createMockProvider('openai');
67
+ providerManager.registerProvider(provider);
68
+ providerManager.setActiveProvider('openai');
69
+ await setProviderBaseUrl('https://custom.openai.api/v1');
70
+ expect(config.getSettingsService().getProviderSettings('openai').baseUrl).toBe('https://custom.openai.api/v1');
71
+ const clearResult = await setProviderBaseUrl('none');
72
+ expect(clearResult.success).toBe(true);
73
+ expect(config.getSettingsService().getProviderSettings('openai').baseUrl).toBeUndefined();
74
+ expect(config.getEphemeralSetting('base-url')).toBeUndefined();
75
+ const emptyResult = await setProviderBaseUrl('');
76
+ expect(emptyResult.success).toBe(true);
77
+ expect(config.getSettingsService().getProviderSettings('openai').baseUrl).toBeUndefined();
311
78
  });
312
- describe('CLI Args Override Profile Base URLs', () => {
313
- it('should override profile base URL with CLI argument', async () => {
314
- // Create profile with base URL
315
- const profile = {
316
- version: 1,
317
- provider: 'openai',
318
- model: 'gpt-4',
319
- modelParams: {},
320
- ephemeralSettings: {
321
- 'base-url': 'https://profile.base.url.com',
322
- },
323
- };
324
- await profileManager.saveProfile('override-test-profile', profile);
325
- // Load profile
326
- const loadedProfile = await profileManager.loadProfile('override-test-profile');
327
- // Apply profile settings
328
- for (const [key, value] of Object.entries(loadedProfile.ephemeralSettings)) {
329
- config.setEphemeralSetting(key, value);
330
- }
331
- // Simulate CLI override (--base-url argument)
332
- const cliBaseUrl = 'https://cli.override.url.com';
333
- config.setEphemeralSetting('base-url', cliBaseUrl);
334
- // Create provider and apply final base URL
335
- const provider = createMockProvider('openai');
336
- providerManager.registerProvider(provider);
337
- providerManager.setActiveProvider('openai');
338
- provider.setBaseUrl?.(config.getEphemeralSetting('base-url'));
339
- // Verify CLI base URL takes precedence
340
- expect(provider.baseUrl).toBe(cliBaseUrl);
341
- expect(provider.baseUrl).not.toBe('https://profile.base.url.com');
342
- });
343
- it('should clear profile base URL when CLI provides empty string', async () => {
344
- // Create profile with base URL
345
- const profile = {
346
- version: 1,
347
- provider: 'anthropic',
348
- model: 'claude-3-opus-20240229',
349
- modelParams: {},
350
- ephemeralSettings: {
351
- 'base-url': 'https://profile.anthropic.url.com',
352
- },
353
- };
354
- await profileManager.saveProfile('clear-override-profile', profile);
355
- // Load profile
356
- const loadedProfile = await profileManager.loadProfile('clear-override-profile');
357
- // Apply profile settings
358
- for (const [key, value] of Object.entries(loadedProfile.ephemeralSettings)) {
359
- config.setEphemeralSetting(key, value);
360
- }
361
- // Simulate CLI override with empty string (--base-url "")
362
- config.setEphemeralSetting('base-url', '');
363
- // Create provider and apply final base URL
364
- const provider = createMockProvider('anthropic');
365
- providerManager.registerProvider(provider);
366
- providerManager.setActiveProvider('anthropic');
367
- const baseUrl = config.getEphemeralSetting('base-url');
368
- if (!baseUrl || baseUrl.trim() === '') {
369
- provider.setBaseUrl?.(undefined);
370
- }
371
- else {
372
- provider.setBaseUrl?.(baseUrl);
373
- }
374
- // Verify base URL is cleared
375
- expect(provider.baseUrl).toBeUndefined();
376
- });
79
+ it('stores base URL even when provider lacks direct override hook', async () => {
80
+ const provider = createMockProvider('gemini');
81
+ providerManager.registerProvider(provider);
82
+ providerManager.setActiveProvider('gemini');
83
+ const result = await setProviderBaseUrl('https://gemini.example/v1');
84
+ expect(result.success).toBe(true);
85
+ expect(config.getSettingsService().getProviderSettings('gemini').baseUrl).toBe('https://gemini.example/v1');
377
86
  });
378
- describe('Base URL Validation and Error Handling', () => {
379
- it('should handle invalid URL formats gracefully', async () => {
380
- const provider = createMockProvider('openai');
381
- providerManager.registerProvider(provider);
382
- providerManager.setActiveProvider('openai');
383
- // Try to set invalid URLs
384
- const invalidUrls = [
385
- 'not-a-url',
386
- 'http://',
387
- 'ftp://invalid.protocol.com',
388
- '//missing-protocol.com',
389
- ];
390
- for (const invalidUrl of invalidUrls) {
391
- config.setEphemeralSetting('base-url', invalidUrl);
392
- // Provider should validate and potentially reject invalid URLs
393
- // For this test, we'll assume the provider stores whatever is given
394
- provider.setBaseUrl?.(invalidUrl);
395
- // In a real implementation, the provider might throw or sanitize
396
- expect(provider.baseUrl).toBe(invalidUrl);
397
- }
398
- });
399
- it('should preserve trailing slashes in base URLs', async () => {
400
- const provider = createMockProvider('openai');
401
- providerManager.registerProvider(provider);
402
- providerManager.setActiveProvider('openai');
403
- // Test URLs with and without trailing slashes
404
- const urlsToTest = [
405
- 'https://api.example.com/',
406
- 'https://api.example.com',
407
- 'https://api.example.com/v1/',
408
- 'https://api.example.com/v1',
409
- ];
410
- for (const url of urlsToTest) {
411
- config.setEphemeralSetting('base-url', url);
412
- provider.setBaseUrl?.(url);
413
- // Verify exact URL is preserved
414
- expect(provider.baseUrl).toBe(url);
415
- }
416
- });
87
+ it('clears previous provider base URL when switching providers', async () => {
88
+ const providerA = createMockProvider('openai');
89
+ const providerB = createMockProvider('anthropic');
90
+ providerManager.registerProvider(providerA);
91
+ providerManager.registerProvider(providerB);
92
+ providerManager.setActiveProvider('openai');
93
+ await setProviderBaseUrl('https://provider-a.example');
94
+ expect(config.getSettingsService().getProviderSettings('openai').baseUrl).toBe('https://provider-a.example');
95
+ await switchActiveProvider('anthropic');
96
+ expect(config.getSettingsService().getProviderSettings('openai').baseUrl).toBeUndefined();
97
+ expect(config.getSettingsService().getProviderSettings('anthropic').baseUrl).toBeUndefined();
417
98
  });
418
- describe('Base URL Integration with Model Parameters', () => {
419
- it('should maintain base URL when updating model parameters', async () => {
420
- const provider = createMockProvider('openai');
421
- providerManager.registerProvider(provider);
422
- providerManager.setActiveProvider('openai');
423
- // Set base URL
424
- const baseUrl = 'https://stable.api.com';
425
- config.setEphemeralSetting('base-url', baseUrl);
426
- provider.setBaseUrl?.(baseUrl);
427
- // Set model parameters
428
- const modelParams = {
429
- temperature: 0.8,
430
- max_tokens: 2000,
431
- top_p: 0.95,
432
- };
433
- provider.setModelParams?.(modelParams);
434
- // Verify both base URL and model params are set
435
- expect(provider.baseUrl).toBe(baseUrl);
436
- expect(provider.getModelParams?.()).toEqual(modelParams);
437
- // Update model params
438
- const newParams = {
439
- temperature: 0.5,
440
- max_tokens: 4000,
441
- };
442
- provider.setModelParams?.(newParams);
443
- // Verify base URL is maintained
444
- expect(provider.baseUrl).toBe(baseUrl);
445
- expect(provider.getModelParams?.()).toEqual(newParams);
446
- });
99
+ it('preserves profile base URL when loading via ProfileManager', async () => {
100
+ const provider = createMockProvider('openai');
101
+ providerManager.registerProvider(provider);
102
+ providerManager.setActiveProvider('openai');
103
+ const profile = {
104
+ version: 1,
105
+ provider: 'openai',
106
+ model: 'gpt-4o-mini',
107
+ modelParams: {},
108
+ ephemeralSettings: {
109
+ 'base-url': 'https://profile.base.url',
110
+ },
111
+ };
112
+ await profileManager.saveProfile('profile-with-base', profile);
113
+ const loaded = await profileManager.loadProfile('profile-with-base');
114
+ expect(loaded.ephemeralSettings['base-url']).toBe('https://profile.base.url');
115
+ const result = await setProviderBaseUrl(loaded.ephemeralSettings['base-url']);
116
+ expect(result.success).toBe(true);
117
+ expect(config.getSettingsService().getProviderSettings('openai').baseUrl).toBe('https://profile.base.url');
447
118
  });
448
119
  });
449
- // Helper function to create a mock provider with base URL support
450
120
  function createMockProvider(name) {
451
121
  const provider = {
452
122
  name,
453
123
  baseUrl: undefined,
454
- apiKey: undefined,
455
- modelParams: undefined,
456
- state: {},
457
- setApiKey(key) {
458
- provider.apiKey = key;
459
- },
460
- setBaseUrl(url) {
461
- provider.baseUrl = url;
462
- },
463
- setModelParams(params) {
464
- provider.modelParams = params;
465
- },
466
- getModelParams() {
467
- return provider.modelParams;
468
- },
469
- clearState() {
470
- provider.apiKey = undefined;
471
- provider.baseUrl = undefined;
472
- provider.modelParams = undefined;
473
- provider.state = {};
124
+ async getModels() {
125
+ return [
126
+ {
127
+ id: 'test-model',
128
+ name: 'Test Model',
129
+ provider: name,
130
+ supportedToolFormats: [],
131
+ },
132
+ ];
474
133
  },
475
- getModels: async () => [
476
- {
477
- id: 'test-model',
478
- name: 'Test Model',
479
- provider: name,
480
- supportedToolFormats: [],
481
- },
482
- ],
483
- getDefaultModel: () => 'test-model',
484
134
  async *generateChatCompletion() {
485
135
  yield {
486
136
  speaker: 'ai',
487
137
  blocks: [{ type: 'text', text: 'test response' }],
488
138
  };
489
139
  },
490
- getServerTools: () => [],
491
- invokeServerTool: async () => ({ result: 'test' }),
140
+ getServerTools() {
141
+ return [];
142
+ },
143
+ async invokeServerTool() {
144
+ return {};
145
+ },
146
+ getDefaultModel() {
147
+ return 'test-model';
148
+ },
149
+ };
150
+ provider.clearState = () => {
151
+ provider.baseUrl = undefined;
492
152
  };
493
153
  return provider;
494
154
  }