Merge pull request #2802 from Hmbown/codex/harvest-2782-hf-mcp-concepts
feat(hf): add Hugging Face MCP helpers
This commit is contained in:
@@ -57,6 +57,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
helper for future fallback routing. This preserves the requested contract
|
||||
without enabling silent runtime provider switches yet (#2574, #2777). Thanks
|
||||
@hsdbeebou for the request and @idling11 for the data-model draft.
|
||||
- Added `/hf` with `/huggingface` alias for Hugging Face MCP status/setup
|
||||
helpers and `/hf concepts` provider/MCP/Hub guidance. The helper points users
|
||||
to Hugging Face's settings-generated MCP configuration and intentionally does
|
||||
not include Hub search, direct Hugging Face HTTP requests, or upload behavior
|
||||
(#2709, #2782). Thanks @idling11 for the original Hugging Face MCP draft.
|
||||
- Added `/sidebar` so users can toggle, show, hide, and optionally persist the
|
||||
TUI sidebar from the command line instead of relying on copy-hostile sidebar
|
||||
state during long transcript work (#2766, #2788). Thanks @mo-vic for the
|
||||
|
||||
@@ -57,6 +57,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
helper for future fallback routing. This preserves the requested contract
|
||||
without enabling silent runtime provider switches yet (#2574, #2777). Thanks
|
||||
@hsdbeebou for the request and @idling11 for the data-model draft.
|
||||
- Added `/hf` with `/huggingface` alias for Hugging Face MCP status/setup
|
||||
helpers and `/hf concepts` provider/MCP/Hub guidance. The helper points users
|
||||
to Hugging Face's settings-generated MCP configuration and intentionally does
|
||||
not include Hub search, direct Hugging Face HTTP requests, or upload behavior
|
||||
(#2709, #2782). Thanks @idling11 for the original Hugging Face MCP draft.
|
||||
- Added `/sidebar` so users can toggle, show, hide, and optionally persist the
|
||||
TUI sidebar from the command line instead of relying on copy-hostile sidebar
|
||||
state during long transcript work (#2766, #2788). Thanks @mo-vic for the
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
//! `/hf` - Hugging Face MCP and provider concept helpers.
|
||||
|
||||
use crate::mcp::{McpConfig, McpServerConfig};
|
||||
use crate::tui::app::App;
|
||||
|
||||
use super::CommandResult;
|
||||
|
||||
const HF_MCP_SETTINGS_URL: &str = "https://huggingface.co/settings/mcp";
|
||||
const HF_MCP_DOCS_URL: &str = "https://huggingface.co/docs/hub/hf-mcp-server";
|
||||
const HF_MCP_SERVER_URL: &str = "https://huggingface.co/mcp";
|
||||
|
||||
const HF_MCP_CONFIG_SKELETON: &str = r#"{
|
||||
"servers": {
|
||||
"huggingface": {
|
||||
"url": "https://huggingface.co/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${HF_TOKEN}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
|
||||
/// Explainer shown by `/hf concepts`.
|
||||
const HF_CONCEPTS: &str = "\
|
||||
CodeWhale has three distinct Hugging Face surfaces:
|
||||
|
||||
1. Hugging Face provider route - chat inference
|
||||
Switch the active LLM backend to Hugging Face Inference Providers.
|
||||
Use: /provider huggingface
|
||||
Config: provider = \"huggingface\" or [providers.huggingface]
|
||||
Auth: HF_TOKEN or HUGGINGFACE_API_KEY
|
||||
|
||||
2. Hugging Face MCP - Hub, docs, datasets, Spaces, and community tools
|
||||
Connect CodeWhale to Hugging Face's MCP server through mcp.json.
|
||||
Use: /hf mcp status or /hf mcp setup
|
||||
Then: /mcp validate or restart CodeWhale so model-visible tools reload.
|
||||
|
||||
3. Hugging Face Hub workflows - publish, upload, or manage repositories
|
||||
Use explicit Hub tooling such as huggingface_hub or git-based flows.
|
||||
CodeWhale does not upload to the Hub through /hf.";
|
||||
|
||||
pub fn hf(app: &mut App, args: Option<&str>) -> CommandResult {
|
||||
let raw = args.unwrap_or("").trim();
|
||||
if raw.is_empty() {
|
||||
return usage();
|
||||
}
|
||||
|
||||
let mut parts = raw.split_whitespace();
|
||||
let subcommand = parts.next().unwrap_or_default().to_ascii_lowercase();
|
||||
match subcommand.as_str() {
|
||||
"mcp" => hf_mcp(app, parts.next()),
|
||||
"concepts" | "explain" => CommandResult::message(HF_CONCEPTS),
|
||||
_ => CommandResult::error(format!(
|
||||
"Unknown /hf subcommand: {subcommand}. Use /hf mcp <status|setup> or /hf concepts."
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn usage() -> CommandResult {
|
||||
CommandResult::message(
|
||||
"Usage: /hf mcp <status|setup>\n\
|
||||
/hf concepts\n\n\
|
||||
Hugging Face MCP settings: https://huggingface.co/settings/mcp",
|
||||
)
|
||||
}
|
||||
|
||||
fn hf_mcp(app: &mut App, action: Option<&str>) -> CommandResult {
|
||||
match action.unwrap_or("status").to_ascii_lowercase().as_str() {
|
||||
"status" => hf_mcp_status(app),
|
||||
"setup" => CommandResult::message(hf_mcp_setup_message(app)),
|
||||
other => CommandResult::error(format!(
|
||||
"Unknown /hf mcp subcommand: {other}. Use status or setup."
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn hf_mcp_status(app: &App) -> CommandResult {
|
||||
match crate::mcp::load_config(&app.mcp_config_path) {
|
||||
Ok(config) => {
|
||||
if let Some(server_name) = configured_hf_mcp_server(&config) {
|
||||
CommandResult::message(format!(
|
||||
"Hugging Face MCP appears configured as `{server_name}` in {}.\n\
|
||||
Run /mcp validate or restart CodeWhale if tools are not visible yet.",
|
||||
app.mcp_config_path.display()
|
||||
))
|
||||
} else {
|
||||
CommandResult::message(format!(
|
||||
"Hugging Face MCP is not configured in {}.\n\
|
||||
Run /hf mcp setup for the settings-generated config workflow.",
|
||||
app.mcp_config_path.display()
|
||||
))
|
||||
}
|
||||
}
|
||||
Err(err) => CommandResult::error(format!(
|
||||
"Could not read MCP config {}: {err}",
|
||||
app.mcp_config_path.display()
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn hf_mcp_setup_message(app: &App) -> String {
|
||||
format!(
|
||||
"Use Hugging Face's settings-generated MCP configuration when available:\n\
|
||||
1. Open {HF_MCP_SETTINGS_URL} while signed in.\n\
|
||||
2. Choose your MCP client and copy the generated configuration snippet.\n\
|
||||
3. Paste the Hugging Face server entry into {}.\n\
|
||||
4. Restart CodeWhale, or run /mcp reload for the TUI manager snapshot.\n\n\
|
||||
CodeWhale-compatible placeholder shape:\n\n\
|
||||
```json\n{HF_MCP_CONFIG_SKELETON}\n```\n\n\
|
||||
The placeholder is intentionally not runnable until your private MCP config has a real token value. \
|
||||
Do not commit real Hugging Face tokens.\n\n\
|
||||
Docs: {HF_MCP_DOCS_URL}\n\
|
||||
Server: {HF_MCP_SERVER_URL}",
|
||||
app.mcp_config_path.display()
|
||||
)
|
||||
}
|
||||
|
||||
fn configured_hf_mcp_server(config: &McpConfig) -> Option<&str> {
|
||||
config
|
||||
.servers
|
||||
.iter()
|
||||
.find(|(name, server)| looks_like_hf_mcp_server(name, server))
|
||||
.map(|(name, _)| name.as_str())
|
||||
}
|
||||
|
||||
fn looks_like_hf_mcp_server(name: &str, server: &McpServerConfig) -> bool {
|
||||
let compact_name: String = name
|
||||
.chars()
|
||||
.filter(|ch| ch.is_ascii_alphanumeric())
|
||||
.flat_map(|ch| ch.to_lowercase())
|
||||
.collect();
|
||||
if matches!(
|
||||
compact_name.as_str(),
|
||||
"huggingface" | "huggingfacemcp" | "hfmcp" | "hfmcpserver"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
server.url.as_deref().is_some_and(|url| {
|
||||
let url = url.to_ascii_lowercase();
|
||||
url.contains("huggingface.co/mcp") || url.contains("huggingface.co/api/mcp")
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::tui::app::TuiOptions;
|
||||
use tempfile::tempdir;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn app_with_mcp_path(mcp_config_path: PathBuf) -> App {
|
||||
App::new(
|
||||
TuiOptions {
|
||||
model: "deepseek-v4-pro".to_string(),
|
||||
workspace: PathBuf::from("."),
|
||||
config_path: None,
|
||||
config_profile: None,
|
||||
allow_shell: false,
|
||||
use_alt_screen: false,
|
||||
use_mouse_capture: false,
|
||||
use_bracketed_paste: true,
|
||||
max_subagents: 2,
|
||||
skills_dir: PathBuf::from("."),
|
||||
memory_path: PathBuf::from("memory.md"),
|
||||
notes_path: PathBuf::from("notes.txt"),
|
||||
mcp_config_path,
|
||||
use_memory: false,
|
||||
start_in_agent_mode: false,
|
||||
skip_onboarding: true,
|
||||
yolo: false,
|
||||
resume_session_id: None,
|
||||
initial_input: None,
|
||||
},
|
||||
&Config::default(),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hf_mcp_config_skeleton_keeps_token_placeholder_only() {
|
||||
assert!(HF_MCP_CONFIG_SKELETON.contains("${HF_TOKEN}"));
|
||||
assert!(!HF_MCP_CONFIG_SKELETON.contains("hf_"));
|
||||
assert!(!HF_MCP_CONFIG_SKELETON.contains("Bearer hf_"));
|
||||
serde_json::from_str::<serde_json::Value>(HF_MCP_CONFIG_SKELETON)
|
||||
.expect("skeleton should be valid JSON");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hf_concepts_explains_provider_mcp_and_hub_surfaces() {
|
||||
assert!(HF_CONCEPTS.contains("provider route"));
|
||||
assert!(HF_CONCEPTS.contains("Hugging Face MCP"));
|
||||
assert!(HF_CONCEPTS.contains("Hub workflows"));
|
||||
assert!(HF_CONCEPTS.contains("/provider huggingface"));
|
||||
assert!(HF_CONCEPTS.contains("/hf mcp"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hf_mcp_status_detects_settings_named_server() {
|
||||
let dir = tempdir().expect("tempdir");
|
||||
let path = dir.path().join("mcp.json");
|
||||
fs::write(
|
||||
&path,
|
||||
r#"{"mcpServers":{"hf-mcp-server":{"url":"https://huggingface.co/mcp"}}}"#,
|
||||
)
|
||||
.expect("write mcp config");
|
||||
let app = app_with_mcp_path(path);
|
||||
|
||||
let result = hf_mcp_status(&app);
|
||||
|
||||
assert!(!result.is_error);
|
||||
let message = result.message.expect("status message");
|
||||
assert!(message.contains("appears configured"));
|
||||
assert!(message.contains("hf-mcp-server"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hf_mcp_status_reports_missing_server_without_network() {
|
||||
let dir = tempdir().expect("tempdir");
|
||||
let path = dir.path().join("mcp.json");
|
||||
fs::write(&path, r#"{"servers":{"local":{"command":"node"}}}"#).expect("write mcp config");
|
||||
let app = app_with_mcp_path(path);
|
||||
|
||||
let result = hf_mcp_status(&app);
|
||||
|
||||
assert!(!result.is_error);
|
||||
assert!(
|
||||
result
|
||||
.message
|
||||
.as_deref()
|
||||
.unwrap_or_default()
|
||||
.contains("not configured")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hf_usage_and_setup_do_not_advertise_hub_search() {
|
||||
let app = app_with_mcp_path(PathBuf::from("mcp.json"));
|
||||
let usage = usage().message.expect("usage");
|
||||
let setup = hf_mcp_setup_message(&app);
|
||||
|
||||
assert!(!usage.contains("/hf search"));
|
||||
assert!(!setup.contains("/hf search"));
|
||||
assert!(setup.contains(HF_MCP_SETTINGS_URL));
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ mod core;
|
||||
mod debug;
|
||||
mod feedback;
|
||||
mod goal;
|
||||
mod hf;
|
||||
mod hooks;
|
||||
mod init;
|
||||
mod jobs;
|
||||
@@ -224,6 +225,12 @@ pub const COMMANDS: &[CommandInfo] = &[
|
||||
usage: "/feedback [bug|feature|security]",
|
||||
description_id: MessageId::CmdFeedbackDescription,
|
||||
},
|
||||
CommandInfo {
|
||||
name: "hf",
|
||||
aliases: &["huggingface"],
|
||||
usage: "/hf [mcp <status|setup>|concepts]",
|
||||
description_id: MessageId::CmdHfDescription,
|
||||
},
|
||||
CommandInfo {
|
||||
name: "home",
|
||||
aliases: &["stats", "overview", "zhuye", "shouye"],
|
||||
@@ -577,6 +584,7 @@ pub fn execute(cmd: &str, app: &mut App) -> CommandResult {
|
||||
"agent" | "daili" => agent(app, arg),
|
||||
"links" | "dashboard" | "api" | "lianjie" => core::deepseek_links(app),
|
||||
"feedback" => feedback::feedback(app, arg),
|
||||
"hf" | "huggingface" => hf::hf(app, arg),
|
||||
"home" | "stats" | "overview" | "zhuye" | "shouye" => core::home_dashboard(app),
|
||||
"workspace" | "cwd" => core::workspace_switch(app, arg),
|
||||
"note" => note::note(app, arg),
|
||||
@@ -1169,6 +1177,13 @@ mod tests {
|
||||
.contains("right sidebar")
|
||||
);
|
||||
assert!(COMMANDS.iter().any(|cmd| cmd.name == "links"));
|
||||
let hf = COMMANDS
|
||||
.iter()
|
||||
.find(|cmd| cmd.name == "hf")
|
||||
.expect("hf command should exist");
|
||||
assert_eq!(hf.aliases, &["huggingface"]);
|
||||
assert_eq!(hf.description_id, MessageId::CmdHfDescription);
|
||||
assert!(hf.description_for(Locale::En).contains("Hugging Face"));
|
||||
assert!(COMMANDS.iter().any(|cmd| cmd.name == "memory"));
|
||||
assert!(!COMMANDS.iter().any(|cmd| cmd.name == "set"));
|
||||
assert!(!COMMANDS.iter().any(|cmd| cmd.name == "deepseek"));
|
||||
@@ -1183,6 +1198,17 @@ mod tests {
|
||||
assert_eq!(links.aliases, &["dashboard", "api", "lianjie"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hf_alias_dispatches_to_concepts_helper() {
|
||||
let mut app = create_test_app();
|
||||
let result = execute("/huggingface concepts", &mut app);
|
||||
assert!(!result.is_error);
|
||||
let message = result.message.expect("concepts message");
|
||||
assert!(message.contains("Hugging Face provider route"));
|
||||
assert!(message.contains("Hugging Face MCP"));
|
||||
assert!(message.contains("Hub workflows"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rlm_slash_command_routes_to_persistent_tool_instruction() {
|
||||
let mut app = create_test_app();
|
||||
|
||||
@@ -268,6 +268,7 @@ pub enum MessageId {
|
||||
CmdExitDescription,
|
||||
CmdExportDescription,
|
||||
CmdFeedbackDescription,
|
||||
CmdHfDescription,
|
||||
CmdHelpDescription,
|
||||
CmdHomeDescription,
|
||||
CmdHooksDescription,
|
||||
@@ -595,6 +596,7 @@ pub const ALL_MESSAGE_IDS: &[MessageId] = &[
|
||||
MessageId::CmdExitDescription,
|
||||
MessageId::CmdExportDescription,
|
||||
MessageId::CmdFeedbackDescription,
|
||||
MessageId::CmdHfDescription,
|
||||
MessageId::CmdHelpDescription,
|
||||
MessageId::CmdHomeDescription,
|
||||
MessageId::CmdHooksDescription,
|
||||
@@ -1123,6 +1125,7 @@ fn english(id: MessageId) -> &'static str {
|
||||
MessageId::CmdExitDescription => "Exit the application",
|
||||
MessageId::CmdExportDescription => "Export conversation to markdown",
|
||||
MessageId::CmdFeedbackDescription => "Generate a GitHub feedback URL",
|
||||
MessageId::CmdHfDescription => "Inspect Hugging Face MCP setup and concepts",
|
||||
MessageId::CmdHelpDescription => "Show help information",
|
||||
MessageId::CmdHomeDescription => "Show home dashboard with stats and quick actions",
|
||||
MessageId::CmdHooksDescription => "List configured lifecycle hooks (read-only)",
|
||||
@@ -1590,6 +1593,7 @@ fn vietnamese(id: MessageId) -> Option<&'static str> {
|
||||
MessageId::CmdExitDescription => "Thoát ứng dụng",
|
||||
MessageId::CmdExportDescription => "Xuất cuộc trò chuyện sang định dạng Markdown",
|
||||
MessageId::CmdFeedbackDescription => "Tạo một URL để gửi phản hồi trên GitHub",
|
||||
MessageId::CmdHfDescription => "Kiểm tra thiết lập và khái niệm Hugging Face MCP",
|
||||
MessageId::CmdHelpDescription => "Hiển thị thông tin trợ giúp",
|
||||
MessageId::CmdHomeDescription => {
|
||||
"Hiển thị bảng điều khiển trang chủ với số liệu thống kê và hành động nhanh"
|
||||
@@ -2142,6 +2146,7 @@ fn japanese(id: MessageId) -> Option<&'static str> {
|
||||
MessageId::CmdExitDescription => "アプリを終了",
|
||||
MessageId::CmdExportDescription => "会話を Markdown にエクスポート",
|
||||
MessageId::CmdFeedbackDescription => "GitHub フィードバック URL を生成",
|
||||
MessageId::CmdHfDescription => "Hugging Face MCP の設定と概念を確認",
|
||||
MessageId::CmdHelpDescription => "ヘルプを表示",
|
||||
MessageId::CmdHomeDescription => "統計とクイックアクション付きのホームダッシュボードを表示",
|
||||
MessageId::CmdHooksDescription => {
|
||||
@@ -2593,6 +2598,7 @@ fn chinese_simplified(id: MessageId) -> Option<&'static str> {
|
||||
MessageId::CmdExitDescription => "退出应用",
|
||||
MessageId::CmdExportDescription => "将对话导出为 Markdown",
|
||||
MessageId::CmdFeedbackDescription => "生成 GitHub 反馈链接",
|
||||
MessageId::CmdHfDescription => "检查 Hugging Face MCP 设置和概念",
|
||||
MessageId::CmdHelpDescription => "显示帮助信息",
|
||||
MessageId::CmdHomeDescription => "显示主页面板,含统计与快捷操作",
|
||||
MessageId::CmdHooksDescription => "列出已配置的生命周期钩子(只读)",
|
||||
@@ -3006,6 +3012,7 @@ fn portuguese_brazil(id: MessageId) -> Option<&'static str> {
|
||||
MessageId::CmdExitDescription => "Sair do aplicativo",
|
||||
MessageId::CmdExportDescription => "Exportar a conversa para markdown",
|
||||
MessageId::CmdFeedbackDescription => "Gerar uma URL de feedback no GitHub",
|
||||
MessageId::CmdHfDescription => "Inspecionar configuracao e conceitos do Hugging Face MCP",
|
||||
MessageId::CmdHelpDescription => "Exibir informações de ajuda",
|
||||
MessageId::CmdHomeDescription => "Exibir o painel inicial com estatísticas e ações rápidas",
|
||||
MessageId::CmdHooksDescription => {
|
||||
@@ -3491,6 +3498,7 @@ fn spanish_latin_america(id: MessageId) -> Option<&'static str> {
|
||||
MessageId::CmdExitDescription => "Salir de la aplicación",
|
||||
MessageId::CmdExportDescription => "Exportar la conversación a markdown",
|
||||
MessageId::CmdFeedbackDescription => "Generar una URL de feedback en GitHub",
|
||||
MessageId::CmdHfDescription => "Inspeccionar configuracion y conceptos de Hugging Face MCP",
|
||||
MessageId::CmdHelpDescription => "Mostrar información de ayuda",
|
||||
MessageId::CmdHomeDescription => {
|
||||
"Mostrar el panel inicial con estadísticas y acciones rápidas"
|
||||
|
||||
+50
@@ -61,6 +61,56 @@ manager snapshot. Config edits made from the TUI are written immediately, but
|
||||
the model-visible MCP tool pool is not hot-reloaded; the manager marks this as
|
||||
restart-required until the TUI is restarted.
|
||||
|
||||
## Hugging Face MCP
|
||||
|
||||
Hugging Face provides a hosted MCP server for Hub resources, documentation,
|
||||
datasets, Spaces, and community tools. CodeWhale does not call Hugging Face's
|
||||
Hub HTTP APIs from `/hf`; it only helps you inspect and set up the MCP config
|
||||
that the regular MCP manager will load.
|
||||
|
||||
The recommended setup path is Hugging Face's settings-generated configuration:
|
||||
|
||||
1. Visit <https://huggingface.co/settings/mcp> while signed in.
|
||||
2. Choose the MCP client closest to your CodeWhale config shape and copy the
|
||||
generated server snippet.
|
||||
3. Paste the Hugging Face server entry into your resolved MCP config file.
|
||||
4. Restart CodeWhale, or run `/mcp reload` for the manager snapshot and restart
|
||||
if the model-visible tool pool still needs to rebuild.
|
||||
|
||||
CodeWhale reads both `servers` and `mcpServers`, so settings-generated snippets
|
||||
can be adapted without changing the rest of the MCP file. A placeholder-only
|
||||
shape looks like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"servers": {
|
||||
"huggingface": {
|
||||
"url": "https://huggingface.co/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${HF_TOKEN}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The placeholder above is not a runnable secret. Use the settings-generated
|
||||
value in your private MCP config and never commit real Hugging Face tokens.
|
||||
|
||||
Interactive helpers:
|
||||
|
||||
```text
|
||||
/hf mcp status
|
||||
/hf mcp setup
|
||||
/hf concepts
|
||||
```
|
||||
|
||||
`/hf mcp status` checks the configured MCP file for common Hugging Face server
|
||||
names or Hugging Face MCP URLs. `/hf concepts` explains the difference between
|
||||
the Hugging Face provider route, Hugging Face MCP, and explicit Hub workflows.
|
||||
|
||||
Official docs: <https://huggingface.co/docs/hub/hf-mcp-server>
|
||||
|
||||
## Config File Location
|
||||
|
||||
Default path:
|
||||
|
||||
@@ -130,6 +130,24 @@ endpoint.
|
||||
| `ollama` | `[providers.ollama]` | Optional `OLLAMA_API_KEY` | `OLLAMA_BASE_URL`; default `http://localhost:11434/v1` | `deepseek-coder:1.3b`; provider-hinted custom tags pass through | Self-hosted Ollama OpenAI-compatible route. Localhost deployments commonly omit auth. `OLLAMA_MODEL` is accepted. |
|
||||
| `huggingface` | `[providers.huggingface]` | `HUGGINGFACE_API_KEY`, `HF_TOKEN` | `HUGGINGFACE_BASE_URL`; default `https://router.huggingface.co/v1` | `deepseek-ai/DeepSeek-V4-Pro`, `deepseek-ai/DeepSeek-V4-Flash` | Hugging Face Inference Providers OpenAI-compatible route. Org-prefixed model IDs pass through. |
|
||||
|
||||
### Hugging Face Provider vs MCP vs Hub
|
||||
|
||||
CodeWhale's `huggingface` provider ID is only the OpenAI-compatible chat
|
||||
inference route through Hugging Face Inference Providers. It is selected with
|
||||
`/provider huggingface`, `CODEWHALE_PROVIDER=huggingface`, or
|
||||
`provider = "huggingface"`.
|
||||
|
||||
Hugging Face MCP is a separate external-tool route. Configure it through the
|
||||
MCP config described in `docs/MCP.md`, preferably using the settings-generated
|
||||
snippet from <https://huggingface.co/settings/mcp>. In the TUI, `/hf mcp status`
|
||||
checks whether the Hugging Face MCP server appears in the resolved MCP config,
|
||||
`/hf mcp setup` prints the settings workflow and a placeholder-only shape, and
|
||||
`/hf concepts` explains the provider/MCP/Hub distinction.
|
||||
|
||||
Hub publishing or repository management remains explicit user action through
|
||||
Hub-native tooling such as `huggingface_hub` or git. The `/hf` helper does not
|
||||
upload to Hugging Face and does not perform direct Hugging Face Hub HTTP search.
|
||||
|
||||
### Xiaomi MiMo Notes
|
||||
|
||||
`xiaomi-mimo` defaults to `mimo-v2.5-pro` for long-context reasoning and coding
|
||||
|
||||
Reference in New Issue
Block a user