Skip to content

Commit a2a34ee

Browse files
authored
feat: add Kimi OpenAI-compatible provider
Story 184.1 implementation: generic OpenAI-compatible provider with Kimi/Moonshot preset, factory aliases, dispatcher fallback support, docs/config updates, tests, and CodeRabbit feedback addressed in 2e4447b.
1 parent e773670 commit a2a34ee

13 files changed

Lines changed: 1103 additions & 115 deletions

File tree

.aiox-core/core/execution/subagent-dispatcher.js

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,37 @@ class SubagentDispatcher extends EventEmitter {
321321
}
322322
}
323323

324+
/**
325+
* Resolve fallback provider from configuration before using the legacy pair.
326+
* @param {string} providerName - Current provider name
327+
* @returns {string|null} Fallback provider name
328+
*/
329+
getFallbackProviderName(providerName) {
330+
if (AIProviderFactory?.getConfig) {
331+
const config = AIProviderFactory.getConfig();
332+
const configuredFallback = config.ai_providers?.fallback;
333+
const configuredPrimary = config.ai_providers?.primary;
334+
335+
if (configuredFallback && configuredFallback !== providerName) {
336+
return configuredFallback;
337+
}
338+
339+
if (configuredPrimary && configuredPrimary !== providerName) {
340+
return configuredPrimary;
341+
}
342+
}
343+
344+
if (providerName === 'claude') {
345+
return 'gemini';
346+
}
347+
348+
if (providerName === 'gemini') {
349+
return 'claude';
350+
}
351+
352+
return null;
353+
}
354+
324355
/**
325356
* Enrich context with memory and gotchas
326357
* @param {Object} task - Task being dispatched
@@ -432,8 +463,6 @@ class SubagentDispatcher extends EventEmitter {
432463
* @returns {Promise<Object>} - Execution result
433464
*/
434465
async executeWithProvider(prompt, providerName, task) {
435-
const startTime = Date.now();
436-
437466
// Get primary provider
438467
const provider = this.getAIProvider(providerName);
439468

@@ -450,8 +479,8 @@ class SubagentDispatcher extends EventEmitter {
450479
this.log('provider_not_available', { provider: providerName });
451480

452481
// Try fallback provider
453-
const fallbackName = providerName === 'claude' ? 'gemini' : 'claude';
454-
const fallback = this.getAIProvider(fallbackName);
482+
const fallbackName = this.getFallbackProviderName(providerName);
483+
const fallback = fallbackName ? this.getAIProvider(fallbackName) : null;
455484

456485
if (fallback && (await fallback.checkAvailability())) {
457486
this.log('using_fallback_provider', { original: providerName, fallback: fallbackName });
@@ -563,10 +592,10 @@ class SubagentDispatcher extends EventEmitter {
563592
* Select result from parallel execution based on mode
564593
* @param {Object|null} claudeResult - Claude result
565594
* @param {Object|null} geminiResult - Gemini result
566-
* @param {Object} task - Original task
595+
* @param {Object} _task - Original task
567596
* @returns {Object} - Selected result
568597
*/
569-
selectParallelResult(claudeResult, geminiResult, task) {
598+
selectParallelResult(claudeResult, geminiResult, _task) {
570599
switch (this.parallelMode) {
571600
case 'race':
572601
// Return first successful result
@@ -698,7 +727,11 @@ class SubagentDispatcher extends EventEmitter {
698727

699728
child.on('error', rejectOnce);
700729

701-
if (!child.stdin || typeof child.stdin.write !== 'function' || typeof child.stdin.end !== 'function') {
730+
if (
731+
!child.stdin ||
732+
typeof child.stdin.write !== 'function' ||
733+
typeof child.stdin.end !== 'function'
734+
) {
702735
rejectOnce(new Error('Claude CLI stdin is not available'));
703736
return;
704737
}

.aiox-core/infrastructure/integrations/ai-providers/README.md

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# AI Providers
22

3-
Multi-provider AI integration for AIOX. Supports Claude Code and Gemini CLI with automatic fallback and task-based routing.
3+
Multi-provider AI integration for AIOX. Supports Claude Code, Gemini CLI and OpenAI-compatible HTTP APIs with automatic fallback and task-based routing.
44

55
## Architecture
66

@@ -9,6 +9,7 @@ ai-providers/
99
├── ai-provider.js # Base abstract class
1010
├── claude-provider.js # Claude Code implementation
1111
├── gemini-provider.js # Gemini CLI implementation
12+
├── openai-compatible-provider.js # OpenAI-compatible HTTP implementation
1213
├── ai-provider-factory.js # Factory with routing and fallback
1314
└── index.js # Module exports
1415
```
@@ -35,13 +36,13 @@ const { getProviderForTask } = require('./ai-providers');
3536

3637
// Get optimal provider for task type
3738
const provider = getProviderForTask('code_generation'); // Returns Gemini (faster)
38-
const provider = getProviderForTask('security'); // Returns Claude (deeper reasoning)
39+
const provider = getProviderForTask('security'); // Returns Claude (deeper reasoning)
3940
```
4041

4142
### Direct Provider Access
4243

4344
```javascript
44-
const { ClaudeProvider, GeminiProvider } = require('./ai-providers');
45+
const { ClaudeProvider, GeminiProvider, OpenAICompatibleProvider } = require('./ai-providers');
4546

4647
// Claude
4748
const claude = new ClaudeProvider({ model: 'claude-3-5-sonnet' });
@@ -50,6 +51,15 @@ const response = await claude.execute('Explain this function');
5051
// Gemini with JSON output
5152
const gemini = new GeminiProvider({ jsonOutput: true });
5253
const response = await gemini.executeJson('List 5 best practices');
54+
55+
// Kimi/Moonshot through the OpenAI-compatible contract
56+
const kimi = new OpenAICompatibleProvider({
57+
name: 'kimi',
58+
baseURL: 'https://api.moonshot.ai/v1',
59+
apiKeyEnv: 'MOONSHOT_API_KEY',
60+
model: 'kimi-k2.5',
61+
});
62+
const response = await kimi.execute('Explain this function');
5363
```
5464

5565
### Check Provider Status
@@ -84,16 +94,23 @@ claude:
8494
gemini:
8595
model: gemini-2.0-flash
8696
previewFeatures: true
97+
98+
kimi:
99+
provider: openai-compatible
100+
baseURL: https://api.moonshot.ai/v1
101+
endpoint: /chat/completions
102+
apiKeyEnv: MOONSHOT_API_KEY
103+
model: kimi-k2.5
87104
```
88105
89106
## Provider Comparison
90107
91-
| Feature | Claude | Gemini |
92-
|---------|--------|--------|
93-
| Best for | Complex reasoning, security | Speed, cost efficiency |
94-
| JSON output | Manual parsing | Native `--output-format json` |
95-
| Cost | Higher | ~4x cheaper (Flash) |
96-
| SWE-bench | ~70% | 78% (Flash) |
108+
| Feature | Claude | Gemini |
109+
| ----------- | --------------------------- | ----------------------------- |
110+
| Best for | Complex reasoning, security | Speed, cost efficiency |
111+
| JSON output | Manual parsing | Native `--output-format json` |
112+
| Cost | Higher | ~4x cheaper (Flash) |
113+
| SWE-bench | ~70% | 78% (Flash) |
97114

98115
## Epic Reference
99116

0 commit comments

Comments
 (0)