Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/openai-models.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'mycoder': minor
'mycoder-agent': minor
---

Add support for OpenAI models (o3 mini and GPT-4o) via Vercel AI SDK
28 changes: 28 additions & 0 deletions packages/agent/src/core/toolAgent/config.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down
1 change: 1 addition & 0 deletions packages/agent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
4 changes: 2 additions & 2 deletions packages/agent/src/tools/interaction/subAgent.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -50,7 +50,7 @@ type ReturnType = z.infer<typeof returnSchema>;
// 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: () => {
Expand Down
42 changes: 39 additions & 3 deletions packages/cli/src/commands/$default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -86,10 +90,33 @@ export const command: CommandModule<SharedOptions, DefaultArgs> = {
);

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;
Expand Down Expand Up @@ -134,7 +161,16 @@ export const command: CommandModule<SharedOptions, DefaultArgs> = {
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,
Expand Down
11 changes: 11 additions & 0 deletions packages/cli/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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',
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/settings/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 10 additions & 2 deletions packages/cli/tests/settings/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});

Expand All @@ -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',
});
});
});

Expand Down
Loading