v0.1.4-p2
parent
a806ffcabf
commit
5673cb49b6
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
Loading…
Reference in New Issue