feat(hf): harvest Hugging Face MCP helpers
Add /hf and /huggingface command routing for Hugging Face MCP setup/status plus a concepts explainer for provider, MCP, and Hub workflows. Document the settings-generated Hugging Face MCP configuration path and keep the slice offline: no Hub search command, no direct Hugging Face HTTP requests, and no custom URL encoding. Refs #2709 Harvested from PR #2782 by @idling11
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
|
helper for future fallback routing. This preserves the requested contract
|
||||||
without enabling silent runtime provider switches yet (#2574, #2777). Thanks
|
without enabling silent runtime provider switches yet (#2574, #2777). Thanks
|
||||||
@hsdbeebou for the request and @idling11 for the data-model draft.
|
@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
|
- 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
|
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
|
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
|
helper for future fallback routing. This preserves the requested contract
|
||||||
without enabling silent runtime provider switches yet (#2574, #2777). Thanks
|
without enabling silent runtime provider switches yet (#2574, #2777). Thanks
|
||||||
@hsdbeebou for the request and @idling11 for the data-model draft.
|
@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
|
- 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
|
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
|
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 debug;
|
||||||
mod feedback;
|
mod feedback;
|
||||||
mod goal;
|
mod goal;
|
||||||
|
mod hf;
|
||||||
mod hooks;
|
mod hooks;
|
||||||
mod init;
|
mod init;
|
||||||
mod jobs;
|
mod jobs;
|
||||||
@@ -224,6 +225,12 @@ pub const COMMANDS: &[CommandInfo] = &[
|
|||||||
usage: "/feedback [bug|feature|security]",
|
usage: "/feedback [bug|feature|security]",
|
||||||
description_id: MessageId::CmdFeedbackDescription,
|
description_id: MessageId::CmdFeedbackDescription,
|
||||||
},
|
},
|
||||||
|
CommandInfo {
|
||||||
|
name: "hf",
|
||||||
|
aliases: &["huggingface"],
|
||||||
|
usage: "/hf [mcp <status|setup>|concepts]",
|
||||||
|
description_id: MessageId::CmdHfDescription,
|
||||||
|
},
|
||||||
CommandInfo {
|
CommandInfo {
|
||||||
name: "home",
|
name: "home",
|
||||||
aliases: &["stats", "overview", "zhuye", "shouye"],
|
aliases: &["stats", "overview", "zhuye", "shouye"],
|
||||||
@@ -577,6 +584,7 @@ pub fn execute(cmd: &str, app: &mut App) -> CommandResult {
|
|||||||
"agent" | "daili" => agent(app, arg),
|
"agent" | "daili" => agent(app, arg),
|
||||||
"links" | "dashboard" | "api" | "lianjie" => core::deepseek_links(app),
|
"links" | "dashboard" | "api" | "lianjie" => core::deepseek_links(app),
|
||||||
"feedback" => feedback::feedback(app, arg),
|
"feedback" => feedback::feedback(app, arg),
|
||||||
|
"hf" | "huggingface" => hf::hf(app, arg),
|
||||||
"home" | "stats" | "overview" | "zhuye" | "shouye" => core::home_dashboard(app),
|
"home" | "stats" | "overview" | "zhuye" | "shouye" => core::home_dashboard(app),
|
||||||
"workspace" | "cwd" => core::workspace_switch(app, arg),
|
"workspace" | "cwd" => core::workspace_switch(app, arg),
|
||||||
"note" => note::note(app, arg),
|
"note" => note::note(app, arg),
|
||||||
@@ -1169,6 +1177,13 @@ mod tests {
|
|||||||
.contains("right sidebar")
|
.contains("right sidebar")
|
||||||
);
|
);
|
||||||
assert!(COMMANDS.iter().any(|cmd| cmd.name == "links"));
|
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 == "memory"));
|
||||||
assert!(!COMMANDS.iter().any(|cmd| cmd.name == "set"));
|
assert!(!COMMANDS.iter().any(|cmd| cmd.name == "set"));
|
||||||
assert!(!COMMANDS.iter().any(|cmd| cmd.name == "deepseek"));
|
assert!(!COMMANDS.iter().any(|cmd| cmd.name == "deepseek"));
|
||||||
@@ -1183,6 +1198,17 @@ mod tests {
|
|||||||
assert_eq!(links.aliases, &["dashboard", "api", "lianjie"]);
|
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]
|
#[test]
|
||||||
fn rlm_slash_command_routes_to_persistent_tool_instruction() {
|
fn rlm_slash_command_routes_to_persistent_tool_instruction() {
|
||||||
let mut app = create_test_app();
|
let mut app = create_test_app();
|
||||||
|
|||||||
@@ -268,6 +268,7 @@ pub enum MessageId {
|
|||||||
CmdExitDescription,
|
CmdExitDescription,
|
||||||
CmdExportDescription,
|
CmdExportDescription,
|
||||||
CmdFeedbackDescription,
|
CmdFeedbackDescription,
|
||||||
|
CmdHfDescription,
|
||||||
CmdHelpDescription,
|
CmdHelpDescription,
|
||||||
CmdHomeDescription,
|
CmdHomeDescription,
|
||||||
CmdHooksDescription,
|
CmdHooksDescription,
|
||||||
@@ -595,6 +596,7 @@ pub const ALL_MESSAGE_IDS: &[MessageId] = &[
|
|||||||
MessageId::CmdExitDescription,
|
MessageId::CmdExitDescription,
|
||||||
MessageId::CmdExportDescription,
|
MessageId::CmdExportDescription,
|
||||||
MessageId::CmdFeedbackDescription,
|
MessageId::CmdFeedbackDescription,
|
||||||
|
MessageId::CmdHfDescription,
|
||||||
MessageId::CmdHelpDescription,
|
MessageId::CmdHelpDescription,
|
||||||
MessageId::CmdHomeDescription,
|
MessageId::CmdHomeDescription,
|
||||||
MessageId::CmdHooksDescription,
|
MessageId::CmdHooksDescription,
|
||||||
@@ -1123,6 +1125,7 @@ fn english(id: MessageId) -> &'static str {
|
|||||||
MessageId::CmdExitDescription => "Exit the application",
|
MessageId::CmdExitDescription => "Exit the application",
|
||||||
MessageId::CmdExportDescription => "Export conversation to markdown",
|
MessageId::CmdExportDescription => "Export conversation to markdown",
|
||||||
MessageId::CmdFeedbackDescription => "Generate a GitHub feedback URL",
|
MessageId::CmdFeedbackDescription => "Generate a GitHub feedback URL",
|
||||||
|
MessageId::CmdHfDescription => "Inspect Hugging Face MCP setup and concepts",
|
||||||
MessageId::CmdHelpDescription => "Show help information",
|
MessageId::CmdHelpDescription => "Show help information",
|
||||||
MessageId::CmdHomeDescription => "Show home dashboard with stats and quick actions",
|
MessageId::CmdHomeDescription => "Show home dashboard with stats and quick actions",
|
||||||
MessageId::CmdHooksDescription => "List configured lifecycle hooks (read-only)",
|
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::CmdExitDescription => "Thoát ứng dụng",
|
||||||
MessageId::CmdExportDescription => "Xuất cuộc trò chuyện sang định dạng Markdown",
|
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::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::CmdHelpDescription => "Hiển thị thông tin trợ giúp",
|
||||||
MessageId::CmdHomeDescription => {
|
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"
|
"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::CmdExitDescription => "アプリを終了",
|
||||||
MessageId::CmdExportDescription => "会話を Markdown にエクスポート",
|
MessageId::CmdExportDescription => "会話を Markdown にエクスポート",
|
||||||
MessageId::CmdFeedbackDescription => "GitHub フィードバック URL を生成",
|
MessageId::CmdFeedbackDescription => "GitHub フィードバック URL を生成",
|
||||||
|
MessageId::CmdHfDescription => "Hugging Face MCP の設定と概念を確認",
|
||||||
MessageId::CmdHelpDescription => "ヘルプを表示",
|
MessageId::CmdHelpDescription => "ヘルプを表示",
|
||||||
MessageId::CmdHomeDescription => "統計とクイックアクション付きのホームダッシュボードを表示",
|
MessageId::CmdHomeDescription => "統計とクイックアクション付きのホームダッシュボードを表示",
|
||||||
MessageId::CmdHooksDescription => {
|
MessageId::CmdHooksDescription => {
|
||||||
@@ -2593,6 +2598,7 @@ fn chinese_simplified(id: MessageId) -> Option<&'static str> {
|
|||||||
MessageId::CmdExitDescription => "退出应用",
|
MessageId::CmdExitDescription => "退出应用",
|
||||||
MessageId::CmdExportDescription => "将对话导出为 Markdown",
|
MessageId::CmdExportDescription => "将对话导出为 Markdown",
|
||||||
MessageId::CmdFeedbackDescription => "生成 GitHub 反馈链接",
|
MessageId::CmdFeedbackDescription => "生成 GitHub 反馈链接",
|
||||||
|
MessageId::CmdHfDescription => "检查 Hugging Face MCP 设置和概念",
|
||||||
MessageId::CmdHelpDescription => "显示帮助信息",
|
MessageId::CmdHelpDescription => "显示帮助信息",
|
||||||
MessageId::CmdHomeDescription => "显示主页面板,含统计与快捷操作",
|
MessageId::CmdHomeDescription => "显示主页面板,含统计与快捷操作",
|
||||||
MessageId::CmdHooksDescription => "列出已配置的生命周期钩子(只读)",
|
MessageId::CmdHooksDescription => "列出已配置的生命周期钩子(只读)",
|
||||||
@@ -3006,6 +3012,7 @@ fn portuguese_brazil(id: MessageId) -> Option<&'static str> {
|
|||||||
MessageId::CmdExitDescription => "Sair do aplicativo",
|
MessageId::CmdExitDescription => "Sair do aplicativo",
|
||||||
MessageId::CmdExportDescription => "Exportar a conversa para markdown",
|
MessageId::CmdExportDescription => "Exportar a conversa para markdown",
|
||||||
MessageId::CmdFeedbackDescription => "Gerar uma URL de feedback no GitHub",
|
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::CmdHelpDescription => "Exibir informações de ajuda",
|
||||||
MessageId::CmdHomeDescription => "Exibir o painel inicial com estatísticas e ações rápidas",
|
MessageId::CmdHomeDescription => "Exibir o painel inicial com estatísticas e ações rápidas",
|
||||||
MessageId::CmdHooksDescription => {
|
MessageId::CmdHooksDescription => {
|
||||||
@@ -3491,6 +3498,7 @@ fn spanish_latin_america(id: MessageId) -> Option<&'static str> {
|
|||||||
MessageId::CmdExitDescription => "Salir de la aplicación",
|
MessageId::CmdExitDescription => "Salir de la aplicación",
|
||||||
MessageId::CmdExportDescription => "Exportar la conversación a markdown",
|
MessageId::CmdExportDescription => "Exportar la conversación a markdown",
|
||||||
MessageId::CmdFeedbackDescription => "Generar una URL de feedback en GitHub",
|
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::CmdHelpDescription => "Mostrar información de ayuda",
|
||||||
MessageId::CmdHomeDescription => {
|
MessageId::CmdHomeDescription => {
|
||||||
"Mostrar el panel inicial con estadísticas y acciones rápidas"
|
"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
|
the model-visible MCP tool pool is not hot-reloaded; the manager marks this as
|
||||||
restart-required until the TUI is restarted.
|
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
|
## Config File Location
|
||||||
|
|
||||||
Default path:
|
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. |
|
| `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. |
|
| `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 Notes
|
||||||
|
|
||||||
`xiaomi-mimo` defaults to `mimo-v2.5-pro` for long-context reasoning and coding
|
`xiaomi-mimo` defaults to `mimo-v2.5-pro` for long-context reasoning and coding
|
||||||
|
|||||||
Reference in New Issue
Block a user