From e5f752a0b45c75bf364a3a6a999a717d6db83461 Mon Sep 17 00:00:00 2001 From: Michael Suchacz <134246071+coderjoe-bot@users.noreply.github.com> Date: Fri, 7 Nov 2025 19:31:40 +0000 Subject: [PATCH 1/3] fix: map baseUrl to baseURL for AI provider configuration The AI SDK expects baseURL (uppercase) but config uses baseUrl (lowercase) for consistency. This change maps the field when creating providers while preserving backward compatibility. --- src/services/aiService.test.ts | 8 --- src/services/aiService.ts | 8 ++- tests/ipcMain/baseUrlMapping.test.ts | 86 ++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 9 deletions(-) create mode 100644 tests/ipcMain/baseUrlMapping.test.ts diff --git a/src/services/aiService.test.ts b/src/services/aiService.test.ts index fab2bfb6a..8ec83075d 100644 --- a/src/services/aiService.test.ts +++ b/src/services/aiService.test.ts @@ -1,7 +1,3 @@ -// Bun test file - doesn't support Jest mocking, so we skip this test for now -// These tests would need to be rewritten to work with Bun's test runner -// For now, the commandProcessor tests demonstrate our testing approach - import { describe, it, expect, beforeEach } from "bun:test"; import { AIService } from "./aiService"; import { HistoryService } from "./historyService"; @@ -20,10 +16,6 @@ describe("AIService", () => { service = new AIService(config, historyService, partialService, initStateManager); }); - // Note: These tests are placeholders as Bun doesn't support Jest mocking - // In a production environment, we'd use dependency injection or other patterns - // to make the code more testable without mocking - it("should create an AIService instance", () => { expect(service).toBeDefined(); expect(service).toBeInstanceOf(AIService); diff --git a/src/services/aiService.ts b/src/services/aiService.ts index e5cc098f8..3bcf3f656 100644 --- a/src/services/aiService.ts +++ b/src/services/aiService.ts @@ -239,7 +239,13 @@ export class AIService extends EventEmitter { // Load providers configuration - the ONLY source of truth const providersConfig = this.config.loadProvidersConfig(); - const providerConfig = providersConfig?.[providerName] ?? {}; + let providerConfig = providersConfig?.[providerName] ?? {}; + + // Map baseUrl to baseURL if present (SDK expects baseURL) + const { baseUrl, ...configWithoutBaseUrl } = providerConfig; + providerConfig = baseUrl + ? { ...configWithoutBaseUrl, baseURL: baseUrl } + : configWithoutBaseUrl; // Handle Anthropic provider if (providerName === "anthropic") { diff --git a/tests/ipcMain/baseUrlMapping.test.ts b/tests/ipcMain/baseUrlMapping.test.ts new file mode 100644 index 000000000..c3ce6087b --- /dev/null +++ b/tests/ipcMain/baseUrlMapping.test.ts @@ -0,0 +1,86 @@ +import { describe, it, expect, beforeAll } from "@jest/globals"; +import { createTestEnvironment } from "./setup"; +import { IPC_CHANNELS } from "../../src/constants/ipc-constants"; +import type { TestEnvironment } from "./setup"; +import * as path from "path"; +import * as fs from "fs"; + +describe("baseUrl to baseURL mapping", () => { + let env: TestEnvironment; + + beforeAll(async () => { + env = await createTestEnvironment(); + }); + + it("should map baseUrl to baseURL when configured in providers.jsonc", async () => { + // Create a providers config with baseUrl (lowercase) + const providersPath = path.join(env.tempDir, "providers.jsonc"); + const providersConfig = { + anthropic: { + apiKey: "test-anthropic-key", + baseUrl: "https://custom-anthropic.example.com/v1", + }, + openai: { + apiKey: "test-openai-key", + baseUrl: "https://custom-openai.example.com/v1", + }, + }; + fs.writeFileSync(providersPath, JSON.stringify(providersConfig, null, 2)); + + // Create a workspace to test with + const projectName = "test-project"; + const projectPath = path.join(env.tempDir, "src", projectName); + + // Initialize git repo with main branch + fs.mkdirSync(projectPath, { recursive: true }); + const execSync = require("child_process").execSync; + execSync("git init -b main", { cwd: projectPath }); + execSync("git config user.name 'Test User'", { cwd: projectPath }); + execSync("git config user.email 'test@example.com'", { cwd: projectPath }); + + // Create a test file and commit + fs.writeFileSync(path.join(projectPath, "README.md"), "# Test Project"); + execSync("git add .", { cwd: projectPath }); + execSync("git commit -m 'Initial commit'", { cwd: projectPath }); + + // Create a workspace + const createResult = await env.mockIpcRenderer.invoke( + IPC_CHANNELS.WORKSPACE_CREATE, + projectPath, + "test-branch", + "main" + ); + if (!createResult.success) { + console.error("Workspace creation failed:", createResult.error); + } + expect(createResult.success).toBe(true); + const workspaceId = createResult.metadata.id; + + // Try to send a message - this will fail due to invalid API keys, + // but we're testing that the baseUrl gets mapped to baseURL correctly + // and doesn't cause a configuration error + const result = await env.mockIpcRenderer.invoke( + IPC_CHANNELS.WORKSPACE_SEND_MESSAGE, + workspaceId, + "Hello", + { + model: "anthropic/claude-3-5-sonnet-20241022", + mode: "edit", + thinkingLevel: "normal", + } + ); + + // The request should fail, but we mainly care that it doesn't fail + // due to baseUrl/baseURL mapping issues + expect(result.success).toBe(false); + + // The error should not be about configuration structure + // (which would indicate baseUrl wasn't properly mapped to baseURL) + if (!result.success) { + const errorString = JSON.stringify(result.error); + // These would appear if the SDK rejected the config due to wrong field names + expect(errorString).not.toContain("Invalid configuration"); + expect(errorString).not.toContain("baseUrl is not a valid"); + } + }); +}); From 897346a966b7327583f77df56f57265ceb590433 Mon Sep 17 00:00:00 2001 From: Michael Suchacz <134246071+coderjoe-bot@users.noreply.github.com> Date: Fri, 7 Nov 2025 19:39:56 +0000 Subject: [PATCH 2/3] fix: map baseUrl to baseURL for AI provider configuration The AI SDK expects baseURL (uppercase) but config uses baseUrl (lowercase) for consistency. This change maps the field when creating providers while preserving backward compatibility. --- tests/ipcMain/baseUrlMapping.test.ts | 86 ---------------------------- 1 file changed, 86 deletions(-) delete mode 100644 tests/ipcMain/baseUrlMapping.test.ts diff --git a/tests/ipcMain/baseUrlMapping.test.ts b/tests/ipcMain/baseUrlMapping.test.ts deleted file mode 100644 index c3ce6087b..000000000 --- a/tests/ipcMain/baseUrlMapping.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { describe, it, expect, beforeAll } from "@jest/globals"; -import { createTestEnvironment } from "./setup"; -import { IPC_CHANNELS } from "../../src/constants/ipc-constants"; -import type { TestEnvironment } from "./setup"; -import * as path from "path"; -import * as fs from "fs"; - -describe("baseUrl to baseURL mapping", () => { - let env: TestEnvironment; - - beforeAll(async () => { - env = await createTestEnvironment(); - }); - - it("should map baseUrl to baseURL when configured in providers.jsonc", async () => { - // Create a providers config with baseUrl (lowercase) - const providersPath = path.join(env.tempDir, "providers.jsonc"); - const providersConfig = { - anthropic: { - apiKey: "test-anthropic-key", - baseUrl: "https://custom-anthropic.example.com/v1", - }, - openai: { - apiKey: "test-openai-key", - baseUrl: "https://custom-openai.example.com/v1", - }, - }; - fs.writeFileSync(providersPath, JSON.stringify(providersConfig, null, 2)); - - // Create a workspace to test with - const projectName = "test-project"; - const projectPath = path.join(env.tempDir, "src", projectName); - - // Initialize git repo with main branch - fs.mkdirSync(projectPath, { recursive: true }); - const execSync = require("child_process").execSync; - execSync("git init -b main", { cwd: projectPath }); - execSync("git config user.name 'Test User'", { cwd: projectPath }); - execSync("git config user.email 'test@example.com'", { cwd: projectPath }); - - // Create a test file and commit - fs.writeFileSync(path.join(projectPath, "README.md"), "# Test Project"); - execSync("git add .", { cwd: projectPath }); - execSync("git commit -m 'Initial commit'", { cwd: projectPath }); - - // Create a workspace - const createResult = await env.mockIpcRenderer.invoke( - IPC_CHANNELS.WORKSPACE_CREATE, - projectPath, - "test-branch", - "main" - ); - if (!createResult.success) { - console.error("Workspace creation failed:", createResult.error); - } - expect(createResult.success).toBe(true); - const workspaceId = createResult.metadata.id; - - // Try to send a message - this will fail due to invalid API keys, - // but we're testing that the baseUrl gets mapped to baseURL correctly - // and doesn't cause a configuration error - const result = await env.mockIpcRenderer.invoke( - IPC_CHANNELS.WORKSPACE_SEND_MESSAGE, - workspaceId, - "Hello", - { - model: "anthropic/claude-3-5-sonnet-20241022", - mode: "edit", - thinkingLevel: "normal", - } - ); - - // The request should fail, but we mainly care that it doesn't fail - // due to baseUrl/baseURL mapping issues - expect(result.success).toBe(false); - - // The error should not be about configuration structure - // (which would indicate baseUrl wasn't properly mapped to baseURL) - if (!result.success) { - const errorString = JSON.stringify(result.error); - // These would appear if the SDK rejected the config due to wrong field names - expect(errorString).not.toContain("Invalid configuration"); - expect(errorString).not.toContain("baseUrl is not a valid"); - } - }); -}); From 175203c3c0d65417f002f06c1b72d45f082a09fc Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Fri, 7 Nov 2025 20:42:37 +0100 Subject: [PATCH 3/3] revert comment removal Added notes regarding Bun test limitations and placeholders. --- src/services/aiService.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/services/aiService.test.ts b/src/services/aiService.test.ts index 8ec83075d..fab2bfb6a 100644 --- a/src/services/aiService.test.ts +++ b/src/services/aiService.test.ts @@ -1,3 +1,7 @@ +// Bun test file - doesn't support Jest mocking, so we skip this test for now +// These tests would need to be rewritten to work with Bun's test runner +// For now, the commandProcessor tests demonstrate our testing approach + import { describe, it, expect, beforeEach } from "bun:test"; import { AIService } from "./aiService"; import { HistoryService } from "./historyService"; @@ -16,6 +20,10 @@ describe("AIService", () => { service = new AIService(config, historyService, partialService, initStateManager); }); + // Note: These tests are placeholders as Bun doesn't support Jest mocking + // In a production environment, we'd use dependency injection or other patterns + // to make the code more testable without mocking + it("should create an AIService instance", () => { expect(service).toBeDefined(); expect(service).toBeInstanceOf(AIService);