feat(llm): add Hugging Face provider + selectable local Claude Code models (#127)
* feat(llm): add Hugging Face provider + selectable local Claude Code models Adds two operator-selectable LLM backbones, wired through both the backend and the War Room UI. Hugging Face (OpenAI-compatible Inference Providers router): - New `huggingface` provider reusing OpenAIAdapter (router.huggingface.co/v1) - HF_TOKEN / HUGGINGFACE_API_KEY / HUGGINGFACE_TOKEN env resolution, config, setup wizard, CLI, factory, best-available, and .env.example - Settings key card + 4 inference models in the picker + direct client routing - Tests: src/__tests__/huggingface-provider.test.ts Local Claude from Claude Code: - Explicit "active backbone" pin in Settings so a connected agent (Claude Code) can be chosen; a pin outranks stored API keys in both the client resolver and mission dispatch - Claude Code model picker (Account default / Opus / Sonnet / Haiku), threaded to the CLI's --model via an "agentId::model" encoding parsed by LocalAgentAdapter; requireLiveLocalAgent strips the suffix for connected-agent validation * fix(llm): address PR #127 review — self-contained keyless path + centralized pin/model routing Finding 1 — keyless mission path was not self-contained: - Add the `local-agent` case to ConfigManager.getLLMConfig so provider:'local-agent' resolves (keyless, agent id — optionally "agentId::model" — in `model`) instead of hitting the default "Unknown provider" throw. Finding 2 — inconsistent pin/model routing across dispatch surfaces: - Centralize backend agent resolution in window.t3mpDispatchAgent (single source of truth). It honors an explicit pin OVER a stored API key and encodes the picked local model as "agentId::model" so it is never dropped. - Route all three surfaces through it: mission dispatch, General (getGeneralConfig), and Admiral (_admBackbone). Previously General/Admiral only picked an agent when no key existed and sent the bare agent id, so a stored key overrode the pin and the selected Claude model was lost. Tests: - getLLMConfig('local-agent') regression coverage (self-contained keyless path) - LocalAgentAdapter "agentId::model" passthrough reaches the CLI --model flag - t3mpDispatchAgent behavior: pin>key precedence, model encoding, fallbacks (evaluated from the shipped docs/index.html) - centralization invariant: mission/General/Admiral all route through t3mpDispatchAgent - update the Op-Admiral keyless-routing static test to the centralized resolver --------- Co-authored-by: Joseph Magly <1159087+jmagly@users.noreply.github.com>
This commit is contained in:
1 parent
e52c2fb2b7
commit
8ccea7c82a
13 files changed
+630
-44
No files matched your search
+3
-1
@@ -524,6 +524,7 @@ async function openSettings(): Promise<void> {
|
||||
console.log(chalk.cyan(' Anthropic:'), hasApiKey('anthropic') ? chalk.green('configured') : chalk.red('not set'));
|
||||
console.log(chalk.cyan(' OpenAI:'), hasApiKey('openai') ? chalk.green('configured') : chalk.red('not set'));
|
||||
console.log(chalk.cyan(' DeepSeek:'), hasApiKey('deepseek') ? chalk.green('configured') : chalk.red('not set'));
|
||||
console.log(chalk.cyan(' HuggingFace:'), hasApiKey('huggingface') ? chalk.green('configured') : chalk.red('not set'));
|
||||
console.log('');
|
||||
break;
|
||||
|
||||
@@ -576,7 +577,7 @@ async function openSettings(): Promise<void> {
|
||||
type: 'list',
|
||||
name: 'keyProvider',
|
||||
message: 'Which provider?',
|
||||
choices: ['openrouter', 'venice', 'anthropic', 'openai', 'deepseek'],
|
||||
choices: ['openrouter', 'venice', 'anthropic', 'openai', 'deepseek', 'huggingface'],
|
||||
},
|
||||
]);
|
||||
const { apiKey } = await inquirer.prompt([
|
||||
@@ -644,6 +645,7 @@ program
|
||||
[chalk.cyan('Anthropic API Key'), hasApiKey('anthropic') ? chalk.green('✓ Configured') : chalk.red('✗ Not set')],
|
||||
[chalk.cyan('OpenAI API Key'), hasApiKey('openai') ? chalk.green('✓ Configured') : chalk.red('✗ Not set')],
|
||||
[chalk.cyan('DeepSeek API Key'), hasApiKey('deepseek') ? chalk.green('✓ Configured') : chalk.red('✗ Not set')],
|
||||
[chalk.cyan('HuggingFace API Key'), hasApiKey('huggingface') ? chalk.green('✓ Configured') : chalk.red('✗ Not set')],
|
||||
[chalk.cyan('Config Path'), config.getConfigPath()],
|
||||
);
|
||||
|
||||
|
||||
Reference in new issue
Block a user