Merge remote-tracking branch 'upstream/main' into pr-70

# Conflicts:
#	src/config/index.ts
#	src/llm/index.ts
#	src/server.ts
#	src/setup.ts
#	src/types/index.ts
This commit is contained in:
Joseph Magly committed 2026-07-17 01:39:59 -04:00
commit be3eb7cb44
75 files changed
+7788 -586

No files matched your search

+42 -4
View File
@@ -4,6 +4,7 @@
* Multi-provider LLM integration supporting:
* - OpenRouter (recommended - access to Claude, GPT-4, Llama, etc.)
* - Venice (OpenAI-compatible, privacy-focused / uncensored models)
* - LiteLLM (OpenAI-compatible AI gateway — 100+ providers via unified proxy)
* - Anthropic (direct Claude access)
* - OpenAI (GPT models)
* - Mock (for testing)
@@ -360,6 +361,28 @@ class VeniceAdapter extends OpenRouterAdapter {
}
}
// =============================================================================
// LITELLM ADAPTER
// =============================================================================
// LiteLLM is an AI gateway proxy that routes to 100+ LLM providers through a
// single OpenAI-compatible API. Same wire shape as OpenRouter (Bearer auth,
// POST /chat/completions, identical request/response + tool-calling + SSE
// stream), so it reuses the entire OpenRouter adapter and only differs in its
// default base URL and the key-required error message.
class LiteLLMAdapter extends OpenRouterAdapter {
name = 'litellm';
validateConfig(): { valid: boolean; error?: string } {
if (!this.config.baseUrl) {
return {
valid: false,
error: 'LiteLLM proxy base URL is required. Set LITELLM_BASE_URL or configure via tempest setup. Docs: https://docs.litellm.ai/docs/proxy/quick_start',
};
}
return { valid: true };
}
}
// =============================================================================
// ANTHROPIC ADAPTER
// =============================================================================
@@ -744,9 +767,12 @@ class LocalAdapter implements LLMProviderAdapter {
+ (contract
? ' You drive a ReAct loop: REQUEST tools, the harness runs them and returns results, you reason until the surface is exhausted.' + contract
: ' Operate in planning and analysis mode; when JSON is requested, return ONLY the requested block — no preamble.');
const out: { role: string; content: string }[] = [{ role: 'system', content: preamble }];
const systemParts = [preamble];
const out: { role: string; content: string }[] = [];
for (const m of messages) {
if (m.role === 'assistant' && m.toolCalls?.length) {
if (m.role === 'system') {
if (m.content.trim()) systemParts.push(m.content);
} else if (m.role === 'assistant' && m.toolCalls?.length) {
out.push({ role: 'assistant', content: `[requested tools: ${m.toolCalls.map(t => t.name).join(', ')}]` });
} else if (m.role === 'tool') {
out.push({ role: 'user', content: `TOOL RESULT (${m.name || 'tool'}):\n${m.content}` });
@@ -754,7 +780,7 @@ class LocalAdapter implements LLMProviderAdapter {
out.push({ role: m.role, content: m.content });
}
}
return out;
return [{ role: 'system', content: systemParts.join('\n\n') }, ...out];
}
async chat(messages: LLMMessage[], options?: ChatOptions): Promise<LLMResponse> {
@@ -1201,6 +1227,8 @@ export class LLMBackbone extends EventEmitter<LLMEvents> {
return new OpenRouterAdapter(config);
case 'venice':
return new VeniceAdapter(config);
case 'litellm':
return new LiteLLMAdapter(config);
case 'anthropic':
return new AnthropicAdapter(config);
case 'openai':
@@ -1491,6 +1519,13 @@ export function createDeepSeekBackbone(apiKey?: string, model?: string): LLMBack
return new LLMBackbone(llmConfig);
}
export function createLiteLLMBackbone(apiKey?: string, model?: string, baseUrl?: string): LLMBackbone {
const llmConfig = config.getLLMConfig('litellm', model);
if (apiKey) llmConfig.apiKey = apiKey;
if (baseUrl) llmConfig.baseUrl = baseUrl;
return new LLMBackbone(llmConfig);
}
export function createMockBackbone(): LLMBackbone {
return new LLMBackbone({
provider: 'mock',
@@ -1514,7 +1549,7 @@ export function createLocalBackbone(model?: string, baseUrl?: string): LLMBackbo
* Create the best available backbone based on configured API keys
*/
export function createBestAvailableBackbone(): LLMBackbone {
// Priority: OpenRouter > Venice > Anthropic > OpenAI > Local > Mock
// Priority: OpenRouter > Venice > LiteLLM > Anthropic > OpenAI > DeepSeek > Local > Mock
const providers = config.getConfiguredProviders();
if (providers.includes('openrouter')) {
@@ -1523,6 +1558,9 @@ export function createBestAvailableBackbone(): LLMBackbone {
if (providers.includes('venice')) {
return createVeniceBackbone();
}
if (providers.includes('litellm')) {
return createLiteLLMBackbone();
}
if (providers.includes('anthropic')) {
return createAnthropicBackbone();
}