From 66ff39eaee1461ac1f82c50fd750349cead104cf Mon Sep 17 00:00:00 2001 From: Ben Houston Date: Tue, 4 Mar 2025 11:28:08 -0500 Subject: [PATCH 1/2] Add support for OpenAI models (o3 mini and GPT-4o) --- .changeset/openai-models.md | 6 +++ packages/agent/src/core/toolAgent/config.ts | 28 +++++++++++++ packages/agent/src/index.ts | 1 + .../agent/src/tools/interaction/subAgent.ts | 4 +- packages/cli/src/commands/$default.ts | 42 +++++++++++++++++-- packages/cli/src/options.ts | 11 +++++ packages/cli/src/settings/config.ts | 2 + packages/cli/tests/settings/config.test.ts | 12 +++++- 8 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 .changeset/openai-models.md diff --git a/.changeset/openai-models.md b/.changeset/openai-models.md new file mode 100644 index 0000000..c7e1128 --- /dev/null +++ b/.changeset/openai-models.md @@ -0,0 +1,6 @@ +--- +"mycoder": minor +"mycoder-agent": minor +--- + +Add support for OpenAI models (o3 mini and GPT-4o) via Vercel AI SDK \ No newline at end of file diff --git a/packages/agent/src/core/toolAgent/config.ts b/packages/agent/src/core/toolAgent/config.ts index 596d878..6bb7785 100644 --- a/packages/agent/src/core/toolAgent/config.ts +++ b/packages/agent/src/core/toolAgent/config.ts @@ -1,6 +1,34 @@ import { execSync } from 'child_process'; import { anthropic } from '@ai-sdk/anthropic'; +import { openai } from '@ai-sdk/openai'; + +/** + * Available model providers + */ +export type ModelProvider = 'anthropic' | 'openai'; + +/** + * Available models by provider + */ +export const AVAILABLE_MODELS = { + anthropic: ['claude-3-7-sonnet-20250219', 'claude-3-opus-20240229'], + openai: ['gpt-4o-2024-05-13', 'o3-mini-2024-07-18'], +}; + +/** + * Get the model instance based on provider and model name + */ +export function getModel(provider: ModelProvider, modelName: string) { + switch (provider) { + case 'anthropic': + return anthropic(modelName); + case 'openai': + return openai(modelName); + default: + throw new Error(`Unknown model provider: ${provider}`); + } +} /** * Default configuration for the tool agent diff --git a/packages/agent/src/index.ts b/packages/agent/src/index.ts index 8447faa..28ee7e0 100644 --- a/packages/agent/src/index.ts +++ b/packages/agent/src/index.ts @@ -26,6 +26,7 @@ export * from './tools/interaction/userPrompt.js'; export * from './core/executeToolCall.js'; export * from './core/types.js'; export * from './core/toolAgent.js'; +export * from './core/toolAgent/config.js'; // Utils export * from './tools/getTools.js'; diff --git a/packages/agent/src/tools/interaction/subAgent.ts b/packages/agent/src/tools/interaction/subAgent.ts index 8d8de08..d808e0f 100644 --- a/packages/agent/src/tools/interaction/subAgent.ts +++ b/packages/agent/src/tools/interaction/subAgent.ts @@ -1,7 +1,7 @@ -import { anthropic } from '@ai-sdk/anthropic'; import { z } from 'zod'; import { zodToJsonSchema } from 'zod-to-json-schema'; +import { getModel } from '../../core/toolAgent/config.js'; import { toolAgent } from '../../core/toolAgent.js'; import { Tool } from '../../core/types.js'; import { getTools } from '../getTools.js'; @@ -50,7 +50,7 @@ type ReturnType = z.infer; // Sub-agent specific configuration const subAgentConfig = { maxIterations: 50, - model: anthropic('claude-3-7-sonnet-20250219'), + model: getModel('anthropic', 'claude-3-7-sonnet-20250219'), maxTokens: 4096, temperature: 0.7, getSystemPrompt: () => { diff --git a/packages/cli/src/commands/$default.ts b/packages/cli/src/commands/$default.ts index 8b06b2d..1113ace 100644 --- a/packages/cli/src/commands/$default.ts +++ b/packages/cli/src/commands/$default.ts @@ -11,11 +11,15 @@ import { LogLevel, subAgentTool, errorToString, + getModel, + AVAILABLE_MODELS, + DEFAULT_CONFIG, } from 'mycoder-agent'; import { TokenTracker } from 'mycoder-agent/dist/core/tokens.js'; import { SharedOptions } from '../options.js'; import { initSentry, captureException } from '../sentry/index.js'; +import { getConfig } from '../settings/config.js'; import { hasUserConsented, saveUserConsent } from '../settings/settings.js'; import { nameToLogIndex } from '../utils/nameToLogIndex.js'; import { checkForUpdates, getPackageInfo } from '../utils/versionCheck.js'; @@ -86,10 +90,33 @@ export const command: CommandModule = { ); try { - // Early API key check - if (!process.env.ANTHROPIC_API_KEY) { + // Get configuration for model provider and name + const userConfig = getConfig(); + const userModelProvider = argv.modelProvider || userConfig.modelProvider; + const userModelName = argv.modelName || userConfig.modelName; + + // Early API key check based on model provider + if (userModelProvider === 'anthropic' && !process.env.ANTHROPIC_API_KEY) { logger.error(getAnthropicApiKeyError()); throw new Error('Anthropic API key not found'); + } else if ( + userModelProvider === 'openai' && + !process.env.OPENAI_API_KEY + ) { + logger.error( + 'No OpenAI API key found. Please set the OPENAI_API_KEY environment variable.', + 'You can get an API key from https://platform.openai.com/api-keys', + ); + throw new Error('OpenAI API key not found'); + } + + // Validate model name + if (!AVAILABLE_MODELS[userModelProvider].includes(userModelName)) { + logger.error( + `Invalid model name: ${userModelName} for provider ${userModelProvider}`, + `Available models for ${userModelProvider}: ${AVAILABLE_MODELS[userModelProvider].join(', ')}`, + ); + throw new Error(`Invalid model name: ${userModelName}`); } let prompt: string | undefined; @@ -134,7 +161,16 @@ export const command: CommandModule = { process.exit(0); }); - const result = await toolAgent(prompt, tools, undefined, { + // Create a config with the selected model + const agentConfig = { + ...DEFAULT_CONFIG, + model: getModel( + userModelProvider as 'anthropic' | 'openai', + userModelName, + ), + }; + + const result = await toolAgent(prompt, tools, agentConfig, { logger, headless: argv.headless ?? true, userSession: argv.userSession ?? false, diff --git a/packages/cli/src/options.ts b/packages/cli/src/options.ts index 7d802a8..b5a12a5 100644 --- a/packages/cli/src/options.ts +++ b/packages/cli/src/options.ts @@ -7,6 +7,8 @@ export type SharedOptions = { readonly userSession?: boolean; readonly pageFilter?: 'simple' | 'none' | 'readability'; readonly sentryDsn?: string; + readonly modelProvider?: string; + readonly modelName?: string; }; export const sharedOptions = { @@ -17,6 +19,15 @@ export const sharedOptions = { default: 'info', choices: ['debug', 'verbose', 'info', 'warn', 'error'], } as const, + modelProvider: { + type: 'string', + description: 'AI model provider to use', + choices: ['anthropic', 'openai'], + } as const, + modelName: { + type: 'string', + description: 'AI model name to use', + } as const, interactive: { type: 'boolean', alias: 'i', diff --git a/packages/cli/src/settings/config.ts b/packages/cli/src/settings/config.ts index df55fd5..e950125 100644 --- a/packages/cli/src/settings/config.ts +++ b/packages/cli/src/settings/config.ts @@ -9,6 +9,8 @@ const configFile = path.join(getSettingsDir(), 'config.json'); const defaultConfig = { // Add default configuration values here githubMode: false, + modelProvider: 'anthropic', + modelName: 'claude-3-7-sonnet-20250219', }; export type Config = typeof defaultConfig; diff --git a/packages/cli/tests/settings/config.test.ts b/packages/cli/tests/settings/config.test.ts index f056918..f079271 100644 --- a/packages/cli/tests/settings/config.test.ts +++ b/packages/cli/tests/settings/config.test.ts @@ -36,7 +36,11 @@ describe('Config', () => { const config = getConfig(); - expect(config).toEqual({ githubMode: false }); + expect(config).toEqual({ + githubMode: false, + modelProvider: 'anthropic', + modelName: 'claude-3-7-sonnet-20250219', + }); expect(fs.existsSync).toHaveBeenCalledWith(mockConfigFile); }); @@ -60,7 +64,11 @@ describe('Config', () => { const config = getConfig(); - expect(config).toEqual({ githubMode: false }); + expect(config).toEqual({ + githubMode: false, + modelProvider: 'anthropic', + modelName: 'claude-3-7-sonnet-20250219', + }); }); }); From 9f5a14a52d8aebf583c8343045f749e3c0c03498 Mon Sep 17 00:00:00 2001 From: Ben Houston Date: Tue, 4 Mar 2025 12:50:53 -0500 Subject: [PATCH 2/2] add changeset --- .changeset/openai-models.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.changeset/openai-models.md b/.changeset/openai-models.md index c7e1128..3133fdb 100644 --- a/.changeset/openai-models.md +++ b/.changeset/openai-models.md @@ -1,6 +1,6 @@ --- -"mycoder": minor -"mycoder-agent": minor +'mycoder': minor +'mycoder-agent': minor --- -Add support for OpenAI models (o3 mini and GPT-4o) via Vercel AI SDK \ No newline at end of file +Add support for OpenAI models (o3 mini and GPT-4o) via Vercel AI SDK