Skip to content

Commit 1da2e60

Browse files
committed
Merge main into throw-exceptions-in-tools
2 parents 444defa + fa9aecd commit 1da2e60

File tree

8 files changed

+92
-5
lines changed

8 files changed

+92
-5
lines changed

.changeset/openai-models.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'mycoder': minor
3+
'mycoder-agent': minor
4+
---
5+
6+
Add support for OpenAI models (o3 mini and GPT-4o) via Vercel AI SDK

packages/agent/src/core/toolAgent/config.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,34 @@
11
import { execSync } from 'child_process';
22

33
import { anthropic } from '@ai-sdk/anthropic';
4+
import { openai } from '@ai-sdk/openai';
5+
6+
/**
7+
* Available model providers
8+
*/
9+
export type ModelProvider = 'anthropic' | 'openai';
10+
11+
/**
12+
* Available models by provider
13+
*/
14+
export const AVAILABLE_MODELS = {
15+
anthropic: ['claude-3-7-sonnet-20250219', 'claude-3-opus-20240229'],
16+
openai: ['gpt-4o-2024-05-13', 'o3-mini-2024-07-18'],
17+
};
18+
19+
/**
20+
* Get the model instance based on provider and model name
21+
*/
22+
export function getModel(provider: ModelProvider, modelName: string) {
23+
switch (provider) {
24+
case 'anthropic':
25+
return anthropic(modelName);
26+
case 'openai':
27+
return openai(modelName);
28+
default:
29+
throw new Error(`Unknown model provider: ${provider}`);
30+
}
31+
}
432

533
import { ToolContext } from '../types';
634

packages/agent/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export * from './tools/interaction/userPrompt.js';
2626
export * from './core/executeToolCall.js';
2727
export * from './core/types.js';
2828
export * from './core/toolAgent.js';
29+
export * from './core/toolAgent/config.js';
2930

3031
// Utils
3132
export * from './tools/getTools.js';

packages/agent/src/tools/interaction/subAgent.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { anthropic } from '@ai-sdk/anthropic';
21
import { z } from 'zod';
32
import { zodToJsonSchema } from 'zod-to-json-schema';
43

54
import { getDefaultSystemPrompt } from '../../core/toolAgent/index.js';
5+
import { getModel } from '../../core/toolAgent/config.js';
66
import { toolAgent } from '../../core/toolAgent.js';
77
import { Tool, ToolContext } from '../../core/types.js';
88
import { getTools } from '../getTools.js';
@@ -51,7 +51,7 @@ type ReturnType = z.infer<typeof returnSchema>;
5151
// Sub-agent specific configuration
5252
const subAgentConfig = {
5353
maxIterations: 50,
54-
model: anthropic('claude-3-7-sonnet-20250219'),
54+
model: getModel('anthropic', 'claude-3-7-sonnet-20250219'),
5555
maxTokens: 4096,
5656
temperature: 0.7,
5757
getSystemPrompt: (context: ToolContext) => {

packages/cli/src/commands/$default.ts

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import {
1111
LogLevel,
1212
subAgentTool,
1313
errorToString,
14+
getModel,
15+
AVAILABLE_MODELS,
16+
DEFAULT_CONFIG,
1417
} from 'mycoder-agent';
1518
import { TokenTracker } from 'mycoder-agent/dist/core/tokens.js';
1619

@@ -87,10 +90,33 @@ export const command: CommandModule<SharedOptions, DefaultArgs> = {
8790
);
8891

8992
try {
90-
// Early API key check
91-
if (!process.env.ANTHROPIC_API_KEY) {
93+
// Get configuration for model provider and name
94+
const userConfig = getConfig();
95+
const userModelProvider = argv.modelProvider || userConfig.modelProvider;
96+
const userModelName = argv.modelName || userConfig.modelName;
97+
98+
// Early API key check based on model provider
99+
if (userModelProvider === 'anthropic' && !process.env.ANTHROPIC_API_KEY) {
92100
logger.error(getAnthropicApiKeyError());
93101
throw new Error('Anthropic API key not found');
102+
} else if (
103+
userModelProvider === 'openai' &&
104+
!process.env.OPENAI_API_KEY
105+
) {
106+
logger.error(
107+
'No OpenAI API key found. Please set the OPENAI_API_KEY environment variable.',
108+
'You can get an API key from https://platform.openai.com/api-keys',
109+
);
110+
throw new Error('OpenAI API key not found');
111+
}
112+
113+
// Validate model name
114+
if (!AVAILABLE_MODELS[userModelProvider].includes(userModelName)) {
115+
logger.error(
116+
`Invalid model name: ${userModelName} for provider ${userModelProvider}`,
117+
`Available models for ${userModelProvider}: ${AVAILABLE_MODELS[userModelProvider].join(', ')}`,
118+
);
119+
throw new Error(`Invalid model name: ${userModelName}`);
94120
}
95121

96122
let prompt: string | undefined;
@@ -136,7 +162,16 @@ export const command: CommandModule<SharedOptions, DefaultArgs> = {
136162
});
137163
const config = await getConfig();
138164

139-
const result = await toolAgent(prompt, tools, undefined, {
165+
// Create a config with the selected model
166+
const agentConfig = {
167+
...DEFAULT_CONFIG,
168+
model: getModel(
169+
userModelProvider as 'anthropic' | 'openai',
170+
userModelName,
171+
),
172+
};
173+
174+
const result = await toolAgent(prompt, tools, agentConfig, {
140175
logger,
141176
headless: argv.headless ?? config.headless,
142177
userSession: argv.userSession ?? config.userSession,

packages/cli/src/options.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ export type SharedOptions = {
77
readonly userSession?: boolean;
88
readonly pageFilter?: 'simple' | 'none' | 'readability';
99
readonly sentryDsn?: string;
10+
readonly modelProvider?: string;
11+
readonly modelName?: string;
1012
};
1113

1214
export const sharedOptions = {
@@ -17,6 +19,15 @@ export const sharedOptions = {
1719
default: 'info',
1820
choices: ['debug', 'verbose', 'info', 'warn', 'error'],
1921
} as const,
22+
modelProvider: {
23+
type: 'string',
24+
description: 'AI model provider to use',
25+
choices: ['anthropic', 'openai'],
26+
} as const,
27+
modelName: {
28+
type: 'string',
29+
description: 'AI model name to use',
30+
} as const,
2031
interactive: {
2132
type: 'boolean',
2233
alias: 'i',

packages/cli/src/settings/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ const defaultConfig = {
1212
headless: true,
1313
userSession: false,
1414
pageFilter: 'none' as 'simple' | 'none' | 'readability',
15+
modelProvider: 'anthropic',
16+
modelName: 'claude-3-7-sonnet-20250219',
1517
};
1618

1719
export type Config = typeof defaultConfig;

packages/cli/tests/settings/config.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ describe('Config', () => {
4141
headless: true,
4242
userSession: false,
4343
pageFilter: 'none',
44+
modelProvider: 'anthropic',
45+
modelName: 'claude-3-7-sonnet-20250219',
4446
});
4547
expect(fs.existsSync).toHaveBeenCalledWith(mockConfigFile);
4648
});
@@ -70,6 +72,8 @@ describe('Config', () => {
7072
headless: true,
7173
userSession: false,
7274
pageFilter: 'none',
75+
modelProvider: 'anthropic',
76+
modelName: 'claude-3-7-sonnet-20250219',
7377
});
7478
});
7579
});

0 commit comments

Comments
 (0)