Skip to content

Commit a70dacb

Browse files
authored
Merge pull request #87 from drivecore/feature/85-add-ollama-support
Add Ollama support via the Vercel AI SDK
2 parents 98e8442 + 5ef8859 commit a70dacb

File tree

6 files changed

+57
-66
lines changed

6 files changed

+57
-66
lines changed

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

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,33 @@ import { execSync } from 'child_process';
22

33
import { anthropic } from '@ai-sdk/anthropic';
44
import { openai } from '@ai-sdk/openai';
5+
import { createOllama, ollama } from 'ollama-ai-provider';
56

67
/**
78
* Available model providers
89
*/
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-
};
10+
export type ModelProvider = 'anthropic' | 'openai' | 'ollama';
1811

1912
/**
2013
* Get the model instance based on provider and model name
2114
*/
22-
export function getModel(provider: ModelProvider, modelName: string) {
15+
export function getModel(
16+
provider: ModelProvider,
17+
modelName: string,
18+
options?: { ollamaBaseUrl?: string },
19+
) {
2320
switch (provider) {
2421
case 'anthropic':
2522
return anthropic(modelName);
2623
case 'openai':
2724
return openai(modelName);
25+
case 'ollama':
26+
if (options?.ollamaBaseUrl) {
27+
return createOllama({
28+
baseURL: options.ollamaBaseUrl,
29+
})(modelName);
30+
}
31+
return ollama(modelName);
2832
default:
2933
throw new Error(`Unknown model provider: ${provider}`);
3034
}

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

Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,14 @@ const parameterSchema = z.object({
1818
projectContext: z
1919
.string()
2020
.describe('Context about the problem or environment'),
21-
fileContext: z
22-
.object({
23-
workingDirectory: z
24-
.string()
25-
.optional()
26-
.describe('The directory where the sub-agent should operate'),
27-
relevantFiles: z
28-
.string()
29-
.optional()
30-
.describe(
31-
'A list of files, which may include ** or * wildcard characters',
32-
),
33-
})
34-
.describe(
35-
'When working with files and directories, it is best to be very specific to avoid sub-agents making incorrect assumptions',
36-
)
37-
.optional(),
21+
workingDirectory: z
22+
.string()
23+
.optional()
24+
.describe('The directory where the sub-agent should operate'),
25+
relevantFilesDirectories: z
26+
.string()
27+
.optional()
28+
.describe('A list of files, which may include ** or * wildcard characters'),
3829
});
3930

4031
const returnSchema = z.object({
@@ -77,25 +68,22 @@ export const subAgentTool: Tool<Parameters, ReturnType> = {
7768
returnsJsonSchema: zodToJsonSchema(returnSchema),
7869
execute: async (params, context) => {
7970
// Validate parameters
80-
const { description, goal, projectContext, fileContext } =
81-
parameterSchema.parse(params);
71+
const {
72+
description,
73+
goal,
74+
projectContext,
75+
workingDirectory,
76+
relevantFilesDirectories,
77+
} = parameterSchema.parse(params);
8278

8379
// Construct a well-structured prompt
8480
const prompt = [
8581
`Description: ${description}`,
8682
`Goal: ${goal}`,
8783
`Project Context: ${projectContext}`,
88-
fileContext
89-
? `\nContext:\n${[
90-
fileContext.workingDirectory
91-
? `- Working Directory: ${fileContext.workingDirectory}`
92-
: '',
93-
fileContext.relevantFiles
94-
? `- Relevant Files:\n ${fileContext.relevantFiles}`
95-
: '',
96-
]
97-
.filter(Boolean)
98-
.join('\n')}`
84+
workingDirectory ? `Working Directory: ${workingDirectory}` : '',
85+
relevantFilesDirectories
86+
? `Relevant Files:\n ${relevantFilesDirectories}`
9987
: '',
10088
]
10189
.filter(Boolean)
@@ -110,8 +98,7 @@ export const subAgentTool: Tool<Parameters, ReturnType> = {
11098

11199
const result = await toolAgent(prompt, tools, config, {
112100
...context,
113-
workingDirectory:
114-
fileContext?.workingDirectory ?? context.workingDirectory,
101+
workingDirectory: workingDirectory ?? context.workingDirectory,
115102
});
116103
return { response: result.result };
117104
},

packages/cli/README.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Command-line interface for AI-powered coding tasks.
44

55
## Features
66

7-
- 🤖 **AI-Powered**: Leverages Anthropic's Claude and OpenAI models for intelligent coding assistance
7+
- 🤖 **AI-Powered**: Leverages Anthropic's Claude, OpenAI models, and Ollama for intelligent coding assistance
88
- 🛠️ **Extensible Tool System**: Modular architecture with various tool categories
99
- 🔄 **Parallel Execution**: Ability to spawn sub-agents for concurrent task processing
1010
- 📝 **Self-Modification**: Can modify code, it was built and tested by writing itself
@@ -82,24 +82,23 @@ mycoder config set modelName gpt-4o-2024-05-13
8282

8383
### Model Selection
8484

85-
MyCoder supports both Anthropic and OpenAI models. You can configure which model to use with the following commands:
85+
MyCoder supports Anthropic, OpenAI, and Ollama models. You can configure which model provider and model name to use with the following commands:
8686

8787
```bash
88-
# Use OpenAI's GPT-4o model
88+
# Use OpenAI models
8989
mycoder config set modelProvider openai
90-
mycoder config set modelName gpt-4o-2024-05-13
91-
92-
# Use OpenAI's o3-mini model
93-
mycoder config set modelProvider openai
94-
mycoder config set modelName o3-mini-2024-07-18
90+
mycoder config set modelName gpt-4o-2024-05-13 # or any other OpenAI model
9591

96-
# Use Anthropic's Claude 3.7 Sonnet model
92+
# Use Anthropic models
9793
mycoder config set modelProvider anthropic
98-
mycoder config set modelName claude-3-7-sonnet-20250219
94+
mycoder config set modelName claude-3-7-sonnet-20250219 # or any other Anthropic model
9995

100-
# Use Anthropic's Claude 3 Opus model
101-
mycoder config set modelProvider anthropic
102-
mycoder config set modelName claude-3-opus-20240229
96+
# Use Ollama models (local)
97+
mycoder config set modelProvider ollama
98+
mycoder config set modelName llama3-groq-tool-use # or any other model available in your Ollama instance
99+
100+
# Configure custom Ollama server URL (default is http://localhost:11434/api)
101+
mycoder config set ollamaBaseUrl http://your-ollama-server:11434/api
103102
```
104103

105104
You can also specify the model provider and name directly when running a command:
@@ -114,6 +113,7 @@ mycoder --modelProvider openai --modelName gpt-4o-2024-05-13 "Your prompt here"
114113
- `headless`: Run browser in headless mode with no UI showing (default: `true`)
115114
- `userSession`: Use user's existing browser session instead of sandboxed session (default: `false`)
116115
- `pageFilter`: Method to process webpage content: 'simple', 'none', or 'readability' (default: `none`)
116+
- `ollamaBaseUrl`: Base URL for Ollama API (default: `http://localhost:11434/api`)
117117

118118
Example:
119119

@@ -126,13 +126,18 @@ mycoder config set userSession true
126126

127127
# Use readability for webpage processing
128128
mycoder config set pageFilter readability
129+
130+
# Set custom Ollama server URL
131+
mycoder config set ollamaBaseUrl http://your-ollama-server:11434/api
129132
```
130133

131134
## Environment Variables
132135

133136
- `ANTHROPIC_API_KEY`: Your Anthropic API key (required when using Anthropic models)
134137
- `OPENAI_API_KEY`: Your OpenAI API key (required when using OpenAI models)
135138

139+
Note: Ollama models do not require an API key as they run locally or on a specified server.
140+
136141
## Development
137142

138143
```bash

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

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
subAgentTool,
1313
errorToString,
1414
getModel,
15-
AVAILABLE_MODELS,
1615
DEFAULT_CONFIG,
1716
} from 'mycoder-agent';
1817
import { TokenTracker } from 'mycoder-agent/dist/core/tokens.js';
@@ -109,15 +108,7 @@ export const command: CommandModule<SharedOptions, DefaultArgs> = {
109108
);
110109
throw new Error('OpenAI API key not found');
111110
}
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}`);
120-
}
111+
// No API key check needed for Ollama as it uses a local server
121112

122113
let prompt: string | undefined;
123114

@@ -166,8 +157,9 @@ export const command: CommandModule<SharedOptions, DefaultArgs> = {
166157
const agentConfig = {
167158
...DEFAULT_CONFIG,
168159
model: getModel(
169-
userModelProvider as 'anthropic' | 'openai',
160+
userModelProvider as 'anthropic' | 'openai' | 'ollama',
170161
userModelName,
162+
{ ollamaBaseUrl: config.ollamaBaseUrl },
171163
),
172164
};
173165

packages/cli/src/settings/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const defaultConfig = {
1414
pageFilter: 'none' as 'simple' | 'none' | 'readability',
1515
modelProvider: 'anthropic',
1616
modelName: 'claude-3-7-sonnet-20250219',
17+
ollamaBaseUrl: 'http://localhost:11434/api',
1718
};
1819

1920
export type Config = typeof defaultConfig;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ describe('Config', () => {
4343
pageFilter: 'none',
4444
modelProvider: 'anthropic',
4545
modelName: 'claude-3-7-sonnet-20250219',
46+
ollamaBaseUrl: 'http://localhost:11434/api',
4647
});
4748
expect(fs.existsSync).toHaveBeenCalledWith(mockConfigFile);
4849
});
@@ -74,6 +75,7 @@ describe('Config', () => {
7475
pageFilter: 'none',
7576
modelProvider: 'anthropic',
7677
modelName: 'claude-3-7-sonnet-20250219',
78+
ollamaBaseUrl: 'http://localhost:11434/api',
7779
});
7880
});
7981
});

0 commit comments

Comments
 (0)