| name | add-provider |
| description | Guided checklist for adding a new AI provider to gitai's AIService |
| user-invocable | false |
Add AI Provider Skill
This skill guides you through adding a new AI provider (like OpenAI, Groq, Anthropic) to gitai's AIService abstraction layer.
Prerequisites
- New provider has a Node.js SDK available on npm
- You know the provider's API endpoint signature (messages, models, parameters)
- You have a test API key or sandbox environment
Step 1: Install the Provider SDK
npm install <provider-sdk-package>
Examples:
- OpenAI:
npm install openai
- Groq:
npm install groq-sdk
- Anthropic:
npm install @anthropic-ai/sdk
Update package.json to lock the version.
Step 2: Import in src/services/ai.ts
Add the import at the top with the other SDK imports (lines 1–3):
import NewProvider from 'new-provider-sdk';
Reference: /Users/leandrosilvaferreira/Projetos/gitai-js/src/services/ai.ts lines 1–3
Step 3: Declare Private Client Property in AIService
Add a private property to the class (lines 18–22):
private newProvider?: NewProvider;
Reference: /Users/leandrosilvaferreira/Projetos/gitai-js/src/services/ai.ts lines 20–22
Example:
private openai?: OpenAI;
private groq?: Groq;
private anthropic?: Anthropic;
private newProvider?: NewProvider;
Step 4: Add Provider Case to initializeClient() Switch
In AIService.initializeClient() (lines 29–43), add a new case:
case 'new-provider':
this.newProvider = new NewProvider({ apiKey: this.config.apiKey });
break;
Reference: /Users/leandrosilvaferreira/Projetos/gitai-js/src/services/ai.ts lines 30–43
Pattern to follow:
- String key must match the value in config (e.g.,
'openai', 'groq', 'anthropic')
- Constructor pattern:
new ProviderClass({ apiKey: this.config.apiKey })
- Return
break; to avoid fallthrough
Step 5: Check if Provider Supports Reasoning Models
If the provider has reasoning/o1-style models, update isReasoningModel() (lines 14–16):
export function isReasoningModel(model: string): boolean {
return ['o1', 'o3', 'gpt-5', 'deepseek-reasoner'].some((prefix) => model.startsWith(prefix));
}
Reference: /Users/leandrosilvaferreira/Projetos/gitai-js/src/services/ai.ts lines 14–16
Note: Reasoning models often have different API signatures; see Step 7 for handling.
Step 6: Implement Provider Call in callApi() Method
In the private callApi() method (lines 207–268), add a new branch:
} else if (this.config.provider === 'new-provider' && this.newProvider) {
logger.ai(`Provider: new-provider - Model: ${this.config.model}`);
const completion = await this.newProvider.chat.completions.create({
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt },
],
model: this.config.model,
temperature: 0.5,
max_tokens: 500,
top_p: 1.0,
frequency_penalty: 0.0,
presence_penalty: 0.0,
});
return completion.choices[0].message.content?.trim() || '';
Reference: /Users/leandrosilvaferreira/Projetos/gitai-js/src/services/ai.ts lines 208–265
Key points:
- Use
logger.ai() (imported from ../utils/logger.js) for provider/model logging
- Always log:
Provider: <key> - Model: ${this.config.model}
- Match parameter names to the provider's SDK (e.g., OpenAI uses
max_tokens, newer reasoning models use max_completion_tokens)
- Extract response text from the provider's response structure
6a: Handle Reasoning Model Variants (if applicable)
If the provider supports reasoning models, check isReasoningModel() before the standard call:
} else if (this.config.provider === 'new-provider' && this.newProvider) {
logger.ai(`Provider: new-provider - Model: ${this.config.model}`);
if (isReasoningModel(this.config.model)) {
const response = await this.newProvider.responses.create({
model: this.config.model,
instructions: systemPrompt,
input: userPrompt,
max_output_tokens: 500,
});
return response.output_text?.trim() || '';
}
const completion = await this.newProvider.chat.completions.create({
});
return completion.choices[0].message.content?.trim() || '';
Reference: /Users/leandrosilvaferreira/Projetos/gitai-js/src/services/ai.ts lines 211–219 (OpenAI reasoning model example)
Step 7: Add to Config Parser
In src/utils/config.ts, ensure the AppConfig interface includes PROVIDER (line 9–13).
No changes needed if PROVIDER field already exists. The field is a simple string that matches your case 'new-provider': key.
Reference: /Users/leandrosilvaferreira/Projetos/gitai-js/src/utils/config.ts lines 8–13
Step 8: Add to Setup Wizard
In src/utils/setup.ts, update the PROVIDER prompt choices (lines 72–80):
{
type: 'list',
name: 'PROVIDER',
message: 'Which AI Provider do you want to use?',
choices: [
{ name: 'OpenAI', value: 'openai' },
{ name: 'Anthropic', value: 'anthropic' },
{ name: 'Groq', value: 'groq' },
{ name: 'New Provider', value: 'new-provider' },
],
default: 'openai',
when: () => !currentConfig.PROVIDER
},
Reference: /Users/leandrosilvaferreira/Projetos/gitai-js/src/utils/setup.ts lines 71–81
Also update the MODEL default prompt (lines 91–101) to include a sensible default model for the new provider:
{
type: 'input',
name: 'MODEL',
message: 'Model ID (e.g., gpt-5.2, claude-3-5-sonnet, llama-3.3-70b-versatile):',
default: (answers: any) => {
const provider = answers.PROVIDER || currentConfig.PROVIDER;
if (provider === 'openai') return 'gpt-5.2';
if (provider === 'anthropic') return 'claude-3-5-sonnet-20240620';
if (provider === 'groq') return 'llama-3.3-70b-versatile';
if (provider === 'new-provider') return 'new-provider-model-id';
return 'gpt-5.2';
},
when: () => !currentConfig.MODEL
}
Reference: /Users/leandrosilvaferreira/Projetos/gitai-js/src/utils/setup.ts lines 91–103
Step 9: Update Project CLAUDE.md
In /Users/leandrosilvaferreira/Projetos/gitai-js/CLAUDE.md, update the "Conventions" section to document the new provider:
## Conventions
...
- **Novos provedores de IA** entram no `switch` de `AIService.initializeClient()` + tratamento por-provedor do request (modelos novos da OpenAI usam `max_completion_tokens` em vez de `max_tokens`; novo-provedor usa [inserir parâmetros específicos]).
Reference: /Users/leandrosilvaferreira/Projetos/gitai-js/CLAUDE.md (Conventions section)
Step 10: Verify Type Safety and Lint
Run the project's canonical verification commands:
npx tsc --noEmit
npm run lint
npm run format
Reference: /Users/leandrosilvaferreira/Projetos/gitai-js/CLAUDE.md (Canonical commands section)
Fix any TypeScript errors (type mismatches, missing properties) and lint violations before moving to testing.
Step 11: Add Integration Tests (Optional but Recommended)
If the project has integration tests, add a test that:
- Instantiates
AIService with the new provider config
- Calls
generateCommitMessage() with a mock diff
- Verifies the response is a non-empty string
Example pattern (where test framework is used):
test('generateCommitMessage with new-provider', async () => {
const service = new AIService({
provider: 'new-provider',
model: 'new-provider-model-id',
apiKey: 'test-key',
language: 'en',
});
const message = await service.generateCommitMessage(
'feat: test feature\n\nSample diff',
[],
'TypeScript',
'test commit'
);
expect(message).toBeTruthy();
});
Step 12: Manual Testing (Recommended)
-
Run the setup wizard:
npm run dev
-
Select the new provider from the list.
-
Provide a valid API key.
-
Test by running gitai on a real repository with uncommitted changes.
-
Verify the commit message is generated and properly formatted.
Common Pitfalls
| Issue | Solution |
|---|
| Provider not showing in setup wizard | Check the choices array in setup.ts; ensure value matches the case key in initializeClient() |
TypeScript errors on this.newProvider | Ensure the property is declared in lines 18–22 of AIService |
| API call returns empty string | Check response structure; provider SDKs vary (e.g., message.content[0].text vs choices[0].message.content) |
| Reasoning models fail | Verify isReasoningModel() condition and use the correct API endpoint (e.g., Responses API for o1/o3) |
| Tests fail due to API key | Use mock/stub for provider SDK in tests; do not use real API keys |
| Lint fails | Run npm run format to auto-fix style issues; check ESLint output for type errors |
Checklist for Review
Before marking the task complete:
References
- AIService class:
/Users/leandrosilvaferreira/Projetos/gitai-js/src/services/ai.ts
- Config parser:
/Users/leandrosilvaferreira/Projetos/gitai-js/src/utils/config.ts
- Setup wizard:
/Users/leandrosilvaferreira/Projetos/gitai-js/src/utils/setup.ts
- Project conventions:
/Users/leandrosilvaferreira/Projetos/gitai-js/CLAUDE.md
- Logger utility:
/Users/leandrosilvaferreira/Projetos/gitai-js/src/utils/logger.ts