Skip to content
Open
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
4 changes: 4 additions & 0 deletions npm/packages/ruvbot/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ NODE_ENV=development
# Anthropic Claude (RECOMMENDED)
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxxxxxxxxxx

# Novita AI (OpenAI-compatible endpoint)
NOVITA_API_KEY=nv-xxxxxxxxxxxxxxxxxxxxx
NOVITA_MODEL=deepseek/deepseek-v3.2

# OpenRouter (alternative - access to multiple models)
OPENROUTER_API_KEY=sk-or-xxxxxxxxxxxxxxxxxxxxx
OPENROUTER_DEFAULT_MODEL=anthropic/claude-3.5-sonnet
Expand Down
6 changes: 5 additions & 1 deletion npm/packages/ruvbot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ export OPENROUTER_API_KEY=sk-or-xxx
# Option 2: Anthropic Direct
export ANTHROPIC_API_KEY=sk-ant-xxx

# Option 3: Novita (OpenAI-compatible)
export NOVITA_API_KEY=nv-xxx
export NOVITA_MODEL=deepseek/deepseek-v3.2

# Slack Integration (optional)
export SLACK_BOT_TOKEN=xoxb-xxx
export SLACK_SIGNING_SECRET=xxx
Expand Down Expand Up @@ -1364,7 +1368,7 @@ All 52 Clawdbot skills are compatible with RuvBot. Simply copy your `skills/` di
```
[RuvBot] LLM not configured. Received: "..."
```
Solution: Set `OPENROUTER_API_KEY` or `ANTHROPIC_API_KEY` environment variable.
Solution: Set `NOVITA_API_KEY`, `OPENROUTER_API_KEY`, or `ANTHROPIC_API_KEY` environment variable.

**Agent not found**
```
Expand Down
1 change: 1 addition & 0 deletions npm/packages/ruvbot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
},
"dependencies": {
"@anthropic-ai/sdk": "^0.20.0",
"openai": "^5.20.3",
"aidefence": "^2.1.1",
"commander": "^12.0.0",
"chalk": "^5.3.0",
Expand Down
16 changes: 13 additions & 3 deletions npm/packages/ruvbot/src/RuvBot.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 18 additions & 2 deletions npm/packages/ruvbot/src/RuvBot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
createAnthropicProvider,
createOpenRouterProvider,
createGoogleAIProvider,
createNovitaProvider,
} from './integration/providers/index.js';

type BotState = BotStatus;
Expand Down Expand Up @@ -477,11 +478,22 @@ export class RuvBot extends EventEmitter<RuvBotEvents> {
const { provider, apiKey, model } = config.llm;

// Check for available API keys in priority order
const novitaKey = process.env.NOVITA_API_KEY;
const openrouterKey = process.env.OPENROUTER_API_KEY;
const anthropicKey = process.env.ANTHROPIC_API_KEY || apiKey;
const googleAIKey = process.env.GOOGLE_AI_API_KEY || process.env.GEMINI_API_KEY;

if (openrouterKey) {
if (novitaKey) {
this.llmProvider = createNovitaProvider({
apiKey: novitaKey,
baseUrl: 'https://api.novita.ai/openai',
model: model || process.env.NOVITA_MODEL || 'deepseek/deepseek-v3.2',
});
this.logger.info(
{ provider: 'novita', model: model || process.env.NOVITA_MODEL || 'deepseek/deepseek-v3.2' },
'LLM provider initialized'
);
} else if (openrouterKey) {
// Use OpenRouter for Gemini 2.5 and other models
this.llmProvider = createOpenRouterProvider({
apiKey: openrouterKey,
Expand Down Expand Up @@ -510,7 +522,10 @@ export class RuvBot extends EventEmitter<RuvBotEvents> {
});
this.logger.info({ provider: 'anthropic', model }, 'LLM provider initialized');
} else {
this.logger.warn({}, 'No LLM API key found. Set GOOGLE_AI_API_KEY, ANTHROPIC_API_KEY, or OPENROUTER_API_KEY');
this.logger.warn(
{},
'No LLM API key found. Set NOVITA_API_KEY, GOOGLE_AI_API_KEY, ANTHROPIC_API_KEY, or OPENROUTER_API_KEY'
);
}

// TODO: Initialize memory manager, skill registry, etc.
Expand Down Expand Up @@ -700,6 +715,7 @@ export class RuvBot extends EventEmitter<RuvBotEvents> {

To enable AI responses, please set one of these environment variables:

- \`NOVITA_API_KEY\` - Novita OpenAI-compatible endpoint (\`https://api.novita.ai/openai\`)
- \`GOOGLE_AI_API_KEY\` - Get from [Google AI Studio](https://aistudio.google.com/app/apikey)
- \`ANTHROPIC_API_KEY\` - Get from [Anthropic Console](https://console.anthropic.com/)
- \`OPENROUTER_API_KEY\` - Get from [OpenRouter](https://openrouter.ai/)
Expand Down
2 changes: 1 addition & 1 deletion npm/packages/ruvbot/src/api/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,7 @@ <h1>Welcome to RuvBot</h1>
if (status.llm?.configured) {
console.log('[RuvBot] LLM configured:', status.llm.provider, status.llm.model);
} else {
console.warn('[RuvBot] LLM not configured! Check ANTHROPIC_API_KEY or OPENROUTER_API_KEY');
console.warn('[RuvBot] LLM not configured! Check NOVITA_API_KEY, ANTHROPIC_API_KEY, or OPENROUTER_API_KEY');
}
} catch (err) {
console.warn('[RuvBot] Health check failed:', err);
Expand Down
12 changes: 6 additions & 6 deletions npm/packages/ruvbot/src/core/BotConfig.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ export declare const MemoryConfigSchema: z.ZodObject<{
efSearch?: number | undefined;
}>;
export declare const LLMConfigSchema: z.ZodObject<{
provider: z.ZodDefault<z.ZodEnum<["anthropic", "openai", "google", "local", "ruvllm"]>>;
provider: z.ZodDefault<z.ZodEnum<["anthropic", "openai", "google", "novita", "local", "ruvllm"]>>;
model: z.ZodDefault<z.ZodString>;
apiKey: z.ZodOptional<z.ZodString>;
baseUrl: z.ZodOptional<z.ZodString>;
temperature: z.ZodDefault<z.ZodNumber>;
maxTokens: z.ZodDefault<z.ZodNumber>;
streaming: z.ZodDefault<z.ZodBoolean>;
}, "strip", z.ZodTypeAny, {
provider: "anthropic" | "openai" | "local" | "google" | "ruvllm";
provider: "anthropic" | "openai" | "google" | "novita" | "local" | "ruvllm";
model: string;
streaming: boolean;
temperature: number;
Expand Down Expand Up @@ -216,15 +216,15 @@ export declare const BotConfigSchema: z.ZodObject<{
efSearch?: number | undefined;
}>>;
llm: z.ZodDefault<z.ZodObject<{
provider: z.ZodDefault<z.ZodEnum<["anthropic", "openai", "google", "local", "ruvllm"]>>;
provider: z.ZodDefault<z.ZodEnum<["anthropic", "openai", "google", "novita", "local", "ruvllm"]>>;
model: z.ZodDefault<z.ZodString>;
apiKey: z.ZodOptional<z.ZodString>;
baseUrl: z.ZodOptional<z.ZodString>;
temperature: z.ZodDefault<z.ZodNumber>;
maxTokens: z.ZodDefault<z.ZodNumber>;
streaming: z.ZodDefault<z.ZodBoolean>;
}, "strip", z.ZodTypeAny, {
provider: "anthropic" | "openai" | "local" | "google" | "ruvllm";
provider: "anthropic" | "openai" | "google" | "novita" | "local" | "ruvllm";
model: string;
streaming: boolean;
temperature: number;
Expand Down Expand Up @@ -458,7 +458,7 @@ export declare const BotConfigSchema: z.ZodObject<{
connectionString?: string | undefined;
};
llm: {
provider: "anthropic" | "openai" | "local" | "google" | "ruvllm";
provider: "anthropic" | "openai" | "google" | "novita" | "local" | "ruvllm";
model: string;
streaming: boolean;
temperature: number;
Expand Down Expand Up @@ -608,4 +608,4 @@ export declare class ConfigManager {
*/
toJSON(): string;
}
//# sourceMappingURL=BotConfig.d.ts.map
//# sourceMappingURL=BotConfig.d.ts.map
12 changes: 9 additions & 3 deletions npm/packages/ruvbot/src/core/BotConfig.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions npm/packages/ruvbot/src/core/BotConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const MemoryConfigSchema = z.object({
});

export const LLMConfigSchema = z.object({
provider: z.enum(['anthropic', 'openai', 'google', 'local', 'ruvllm']).default('anthropic'),
provider: z.enum(['anthropic', 'openai', 'google', 'novita', 'local', 'ruvllm']).default('anthropic'),
model: z.string().default('claude-sonnet-4-20250514'),
apiKey: z.string().optional(),
baseUrl: z.string().url().optional(),
Expand Down Expand Up @@ -186,7 +186,12 @@ export class ConfigManager {
const loggingConfig: Partial<z.infer<typeof LoggingConfigSchema>> = {};

// LLM configuration
if (process.env.ANTHROPIC_API_KEY) {
if (process.env.NOVITA_API_KEY) {
llmConfig.provider = 'novita';
llmConfig.apiKey = process.env.NOVITA_API_KEY;
llmConfig.baseUrl = 'https://api.novita.ai/openai';
llmConfig.model = process.env.NOVITA_MODEL || 'deepseek/deepseek-v3.2';
} else if (process.env.ANTHROPIC_API_KEY) {
llmConfig.provider = 'anthropic';
llmConfig.apiKey = process.env.ANTHROPIC_API_KEY;
} else if (process.env.OPENAI_API_KEY) {
Expand Down
4 changes: 2 additions & 2 deletions npm/packages/ruvbot/src/core/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export interface LLMConfig {
maxTokens?: number;
streaming?: boolean;
}
export type LLMProvider = 'anthropic' | 'openai' | 'google' | 'local' | 'ruvllm';
export type LLMProvider = 'anthropic' | 'openai' | 'google' | 'novita' | 'local' | 'ruvllm';
export interface LLMRequest {
messages: LLMMessage[];
systemPrompt?: string;
Expand Down Expand Up @@ -245,4 +245,4 @@ export interface LLMOrchestrator {
stream(request: LLMRequest): AsyncIterable<string>;
embed(text: string): Promise<Float32Array>;
}
//# sourceMappingURL=types.d.ts.map
//# sourceMappingURL=types.d.ts.map
2 changes: 1 addition & 1 deletion npm/packages/ruvbot/src/core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ export interface LLMConfig {
streaming?: boolean;
}

export type LLMProvider = 'anthropic' | 'openai' | 'google' | 'local' | 'ruvllm';
export type LLMProvider = 'anthropic' | 'openai' | 'google' | 'novita' | 'local' | 'ruvllm';

export interface LLMRequest {
messages: LLMMessage[];
Expand Down
Loading