v0.1.4-p2

main
mula.liu 2026-03-13 15:40:30 +08:00
parent a806ffcabf
commit 5673cb49b6
4 changed files with 36 additions and 13 deletions

View File

@ -18,8 +18,11 @@ PROJECT_ROOT: Final[Path] = BACKEND_ROOT.parent
#
# We keep process-provided env untouched, while allowing .env.prod to override backend/.env.
_process_env_keys = set(os.environ.keys())
_backend_env_values = dotenv_values(BACKEND_ROOT / ".env")
_prod_env_values = dotenv_values(PROJECT_ROOT / ".env.prod")
load_dotenv(BACKEND_ROOT / ".env", override=False)
for _k, _v in dotenv_values(PROJECT_ROOT / ".env.prod").items():
for _k, _v in _prod_env_values.items():
if _v is None:
continue
if _k in _process_env_keys:
@ -52,6 +55,10 @@ def _env_int(name: str, default: int, min_value: int, max_value: int) -> int:
return max(min_value, min(max_value, value))
def _is_truthy(raw: object) -> bool:
return str(raw or "").strip().lower() in {"1", "true", "yes", "on", "y"}
def _normalize_extension(raw: str) -> str:
text = str(raw or "").strip().lower()
if not text:
@ -216,9 +223,18 @@ REDIS_URL: Final[str] = str(os.getenv("REDIS_URL") or "").strip()
REDIS_PREFIX: Final[str] = str(os.getenv("REDIS_PREFIX") or "dashboard_nanobot").strip() or "dashboard_nanobot"
REDIS_DEFAULT_TTL: Final[int] = _env_int("REDIS_DEFAULT_TTL", 60, 1, 86400)
PANEL_ACCESS_PASSWORD: Final[str] = str(os.getenv("PANEL_ACCESS_PASSWORD") or "").strip()
TOPIC_MCP_INTERNAL_URL: Final[str] = str(
os.getenv("TOPIC_MCP_INTERNAL_URL") or "http://host.docker.internal:8000/api/mcp/topic"
).strip()
_topic_mcp_default = "http://host.docker.internal:8000/api/mcp/topic"
_topic_mcp_from_env = str(os.getenv("TOPIC_MCP_INTERNAL_URL") or "").strip()
_topic_mcp_from_backend_env = str(_backend_env_values.get("TOPIC_MCP_INTERNAL_URL") or "").strip()
_dev_mode = _is_truthy(os.getenv("APP_RELOAD")) or str(os.getenv("APP_ENV") or "").strip().lower() in {
"dev",
"development",
"local",
}
if _dev_mode and _topic_mcp_from_backend_env:
TOPIC_MCP_INTERNAL_URL: Final[str] = _topic_mcp_from_backend_env
else:
TOPIC_MCP_INTERNAL_URL: Final[str] = _topic_mcp_from_env or _topic_mcp_default
TEMPLATE_ROOT: Final[Path] = (BACKEND_ROOT / "templates").resolve()
AGENT_MD_TEMPLATES_FILE: Final[Path] = TEMPLATE_ROOT / "agent_md_templates.json"

View File

@ -517,7 +517,6 @@ async def on_startup():
with Session(engine) as session:
for bot in session.exec(select(BotInstance)).all():
_migrate_bot_resources_store(bot.id)
_ensure_topic_mcp_server(bot.id)
running_bots = session.exec(select(BotInstance).where(BotInstance.docker_status == "RUNNING")).all()
for bot in running_bots:
docker_manager.ensure_monitor(bot.id, docker_callback)
@ -1471,7 +1470,6 @@ def _sync_workspace_channels(
bot_data=bot_data,
channels=normalized_channels,
)
_ensure_topic_mcp_server(bot_id)
_write_bot_resources(
bot_id,
bot_data.get("cpu_cores"),
@ -2391,8 +2389,6 @@ def update_bot_mcp_config(bot_id: str, payload: BotMcpConfigUpdateRequest, sessi
if not isinstance(tools_cfg, dict):
tools_cfg = {}
mcp_servers = _normalize_mcp_servers(payload.mcp_servers or {})
locked_server = _ensure_topic_mcp_server(bot_id, config_data=config_data, persist=False)
mcp_servers[TOPIC_MCP_SERVER_NAME] = locked_server
tools_cfg["mcpServers"] = mcp_servers
config_data["tools"] = tools_cfg
_write_bot_config(bot_id, config_data)
@ -2401,7 +2397,7 @@ def update_bot_mcp_config(bot_id: str, payload: BotMcpConfigUpdateRequest, sessi
"status": "updated",
"bot_id": bot_id,
"mcp_servers": _annotate_locked_mcp_servers(mcp_servers),
"locked_servers": [TOPIC_MCP_SERVER_NAME],
"locked_servers": [],
"restart_required": True,
}

View File

@ -24,8 +24,7 @@ services:
REDIS_PREFIX: ${REDIS_PREFIX:-dashboard_nanobot}
REDIS_DEFAULT_TTL: ${REDIS_DEFAULT_TTL:-60}
PANEL_ACCESS_PASSWORD: ${PANEL_ACCESS_PASSWORD:-}
AGENT_MD_TEMPLATES_FILE: ${AGENT_MD_TEMPLATES_FILE:-templates/agent_md_templates.json}
TOPIC_PRESETS_TEMPLATES_FILE: ${TOPIC_PRESETS_TEMPLATES_FILE:-templates/topic_presets.json}
TOPIC_MCP_INTERNAL_URL: ${TOPIC_MCP_INTERNAL_URL:-http://host.docker.internal:8000/api/mcp/topic}
STT_ENABLED: ${STT_ENABLED:-true}
STT_MODEL: ${STT_MODEL:-ggml-small-q8_0.bin}
STT_MODEL_DIR: ${STT_MODEL_DIR:-${HOST_DATA_ROOT}/model}

View File

@ -2854,9 +2854,21 @@ export function BotDashboardModule({
setMcpTestByIndex((prev) => ({ ...prev, [index]: { status: 'idle', message: '' } }));
};
const isTopicMcpServerRow = (row?: MCPServerDraft | null) => {
if (!row) return false;
const name = String(row.name || row.originName || '').trim().toLowerCase();
return name === 'topic_mcp';
};
const canRemoveMcpServer = (row?: MCPServerDraft | null) => {
if (!row) return false;
if (!row.locked) return true;
return isTopicMcpServerRow(row);
};
const removeMcpServer = (index: number) => {
const row = mcpServers[index];
if (row?.locked) {
if (!canRemoveMcpServer(row)) {
notify(isZh ? '内置 MCP 服务不可删除。' : 'Built-in MCP server cannot be removed.', { tone: 'warning' });
return;
}
@ -6120,7 +6132,7 @@ export function BotDashboardModule({
</button>
<LucentIconButton
className="btn btn-danger btn-sm wizard-icon-btn"
disabled={row.locked}
disabled={isSavingMcp || !canRemoveMcpServer(row)}
onClick={() => removeMcpServer(idx)}
tooltip={t.removeSkill}
aria-label={t.removeSkill}