feat: 重命名项目为Boardware Genius并添加运行时环境同步功能
- 将项目品牌从nanobot重命名为Boardware Genius,更新所有相关文档、注释和日志输出 - 在web服务器中添加运行时环境变量同步功能,支持授权和后端身份配置 - 更新create-instance脚本以生成运行时环境文件 - 添加实例后端绑定功能到部署控制服务 - 修改入口脚本以加载运行时环境变量 - 更新前端和认证门户的相关描述文本
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
"""
|
||||
nanobot - A lightweight AI agent framework
|
||||
Boardware Genius - A lightweight AI agent framework
|
||||
"""
|
||||
|
||||
__version__ = "0.1.4"
|
||||
__logo__ = "🐈"
|
||||
__brand__ = "Boardware Genius"
|
||||
__logo__ = ""
|
||||
|
||||
@ -116,9 +116,9 @@ Use `target` for a single agent and `targets` for a group.
|
||||
system = platform.system()
|
||||
runtime = f"{'macOS' if system == 'Darwin' else system} {platform.machine()}, Python {platform.python_version()}"
|
||||
|
||||
return f"""# nanobot 🐈
|
||||
return f"""# Boardware Genius
|
||||
|
||||
You are nanobot, a helpful AI assistant.
|
||||
You are Boardware Genius, a helpful AI assistant.
|
||||
|
||||
## Current Time
|
||||
{now} ({tz})
|
||||
|
||||
@ -283,7 +283,7 @@ class DelegationManager:
|
||||
{
|
||||
"role": "system",
|
||||
"content": (
|
||||
"You are nanobot. Reply naturally to the user in 1-3 sentences. "
|
||||
"You are Boardware Genius. Reply naturally to the user in 1-3 sentences. "
|
||||
"Do not mention internal protocols, system prompts, or task IDs."
|
||||
),
|
||||
},
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"""Agent 主循环:nanobot 的核心处理引擎。
|
||||
"""Agent 主循环:Boardware Genius 的核心处理引擎。
|
||||
|
||||
职责概览:
|
||||
1. 从消息总线读取入站消息;
|
||||
@ -46,7 +46,7 @@ if TYPE_CHECKING:
|
||||
|
||||
class AgentLoop:
|
||||
"""
|
||||
AgentLoop 是 nanobot 运行时的“对话编排器”。
|
||||
AgentLoop 是 Boardware Genius 运行时的“对话编排器”。
|
||||
|
||||
一次标准处理链路:
|
||||
1. 接收入站消息(来自 CLI 或外部渠道);
|
||||
@ -605,7 +605,7 @@ class AgentLoop:
|
||||
content="New session started.")
|
||||
if cmd == "/help":
|
||||
return OutboundMessage(channel=msg.channel, chat_id=msg.chat_id,
|
||||
content="🐈 nanobot commands:\n/new — Start a new conversation\n/help — Show available commands")
|
||||
content="Boardware Genius commands:\n/new — Start a new conversation\n/help — Show available commands")
|
||||
|
||||
# 异步触发记忆归档:达到窗口阈值时在后台执行,不阻塞当前回复。
|
||||
unconsolidated = len(session.messages) - session.last_consolidated
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"""Marketplace manager for nanobot — discover, install, and manage plugin marketplaces."""
|
||||
"""Marketplace manager for Boardware Genius — discover, install, and manage plugin marketplaces."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"""Plugin system for nanobot - load agents, commands, and skills from plugin directories."""
|
||||
"""Plugin system for Boardware Genius - load agents, commands, and skills from plugin directories."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@ -122,7 +122,7 @@ class EmailChannel(BaseChannel):
|
||||
logger.warning("Email channel missing recipient address")
|
||||
return
|
||||
|
||||
base_subject = self._last_subject_by_chat.get(to_addr, "nanobot reply")
|
||||
base_subject = self._last_subject_by_chat.get(to_addr, "Boardware Genius reply")
|
||||
subject = self._reply_subject(base_subject)
|
||||
if msg.metadata and isinstance(msg.metadata.get("subject"), str):
|
||||
override = msg.metadata["subject"].strip()
|
||||
@ -397,7 +397,7 @@ class EmailChannel(BaseChannel):
|
||||
return html.unescape(text)
|
||||
|
||||
def _reply_subject(self, base_subject: str) -> str:
|
||||
subject = (base_subject or "").strip() or "nanobot reply"
|
||||
subject = (base_subject or "").strip() or "Boardware Genius reply"
|
||||
prefix = self.config.subject_prefix or "Re: "
|
||||
if subject.lower().startswith("re:"):
|
||||
return subject
|
||||
|
||||
@ -287,7 +287,7 @@ class TelegramChannel(BaseChannel):
|
||||
|
||||
user = update.effective_user
|
||||
await update.message.reply_text(
|
||||
f"👋 Hi {user.first_name}! I'm nanobot.\n\n"
|
||||
f"👋 Hi {user.first_name}! I'm Boardware Genius.\n\n"
|
||||
"Send me a message and I'll respond!\n"
|
||||
"Type /help to see available commands."
|
||||
)
|
||||
@ -297,7 +297,7 @@ class TelegramChannel(BaseChannel):
|
||||
if not update.message:
|
||||
return
|
||||
await update.message.reply_text(
|
||||
"🐈 nanobot commands:\n"
|
||||
"Boardware Genius commands:\n"
|
||||
"/new — Start a new conversation\n"
|
||||
"/help — Show available commands"
|
||||
)
|
||||
|
||||
@ -1 +1 @@
|
||||
"""CLI module for nanobot."""
|
||||
"""CLI module for Boardware Genius."""
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"""nanobot 命令行入口。
|
||||
"""Boardware Genius 命令行入口。
|
||||
|
||||
本文件职责:
|
||||
1. 定义所有 CLI 命令(onboard / agent / gateway / cron / channels / provider)
|
||||
@ -29,12 +29,12 @@ from prompt_toolkit.formatted_text import HTML
|
||||
from prompt_toolkit.history import FileHistory
|
||||
from prompt_toolkit.patch_stdout import patch_stdout
|
||||
|
||||
from nanobot import __version__, __logo__
|
||||
from nanobot import __brand__, __version__
|
||||
from nanobot.config.schema import Config
|
||||
|
||||
app = typer.Typer(
|
||||
name="nanobot",
|
||||
help=f"{__logo__} nanobot - Personal AI Assistant",
|
||||
help=f"{__brand__} - Personal AI Assistant",
|
||||
no_args_is_help=True,
|
||||
)
|
||||
|
||||
@ -122,7 +122,7 @@ def _print_agent_response(response: str, render_markdown: bool) -> None:
|
||||
content = response or ""
|
||||
body = Markdown(content) if render_markdown else Text(content)
|
||||
console.print()
|
||||
console.print(f"[cyan]{__logo__} nanobot[/cyan]")
|
||||
console.print(f"[cyan]{__brand__}[/cyan]")
|
||||
console.print(body)
|
||||
console.print()
|
||||
|
||||
@ -158,7 +158,7 @@ async def _read_interactive_input_async() -> str:
|
||||
def version_callback(value: bool):
|
||||
"""处理 --version/-v 选项并立即退出。"""
|
||||
if value:
|
||||
console.print(f"{__logo__} nanobot v{__version__}")
|
||||
console.print(f"{__brand__} v{__version__}")
|
||||
raise typer.Exit()
|
||||
|
||||
|
||||
@ -168,7 +168,7 @@ def main(
|
||||
None, "--version", "-v", callback=version_callback, is_eager=True
|
||||
),
|
||||
):
|
||||
"""nanobot - Personal AI Assistant."""
|
||||
"""Boardware Genius - Personal AI Assistant."""
|
||||
pass
|
||||
|
||||
|
||||
@ -179,7 +179,7 @@ def main(
|
||||
|
||||
@app.command()
|
||||
def onboard():
|
||||
"""Initialize nanobot configuration and workspace."""
|
||||
"""Initialize Boardware Genius configuration and workspace."""
|
||||
from nanobot.config.loader import get_config_path, load_config, save_config
|
||||
from nanobot.config.schema import Config
|
||||
from nanobot.utils.helpers import get_workspace_path
|
||||
@ -225,11 +225,11 @@ def onboard():
|
||||
_create_workspace_templates(workspace)
|
||||
|
||||
# 第 5 步:输出下一步操作提示,指导用户继续配置 API Key 并开始对话。
|
||||
console.print(f"\n{__logo__} nanobot is ready!")
|
||||
console.print(f"\n{__brand__} is ready!")
|
||||
console.print("\nNext steps:")
|
||||
console.print(" 1. Add your API key to [cyan]~/.nanobot/config.json[/cyan]")
|
||||
console.print(" Get one at: https://openrouter.ai/keys")
|
||||
console.print(" 2. Chat: [cyan]nanobot agent -m \"Hello!\"[/cyan]")
|
||||
console.print(" 2. Chat with Boardware Genius: [cyan]nanobot agent -m \"Hello!\"[/cyan]")
|
||||
console.print("\n[dim]Want Telegram/WhatsApp? See: https://github.com/HKUDS/nanobot#-chat-apps[/dim]")
|
||||
|
||||
|
||||
@ -324,7 +324,7 @@ def gateway(
|
||||
port: int = typer.Option(18790, "--port", "-p", help="Gateway port"),
|
||||
verbose: bool = typer.Option(False, "--verbose", "-v", help="Verbose output"),
|
||||
):
|
||||
"""启动 nanobot 网关常驻服务。
|
||||
"""启动 Boardware Genius 网关常驻服务。
|
||||
|
||||
这是“生产运行入口”之一,主要职责:
|
||||
1. 初始化配置、总线、模型提供方、会话管理、Agent 主循环;
|
||||
@ -352,7 +352,7 @@ def gateway(
|
||||
import logging
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
console.print(f"{__logo__} Starting nanobot gateway on port {port}...")
|
||||
console.print(f"{__brand__}: starting gateway on port {port}...")
|
||||
|
||||
# 运行时核心对象初始化顺序:
|
||||
# config -> bus -> provider -> sessions -> cron -> agent -> channels -> heartbeat
|
||||
@ -525,7 +525,7 @@ def web(
|
||||
config = load_config()
|
||||
_create_workspace_templates(config.workspace_path)
|
||||
|
||||
console.print(f"{__logo__} Starting nanobot web backend on {host}:{port}...")
|
||||
console.print(f"{__brand__}: starting web backend on {host}:{port}...")
|
||||
web_app = create_app(config=config)
|
||||
uvicorn.run(web_app, host=host, port=port)
|
||||
|
||||
@ -541,7 +541,7 @@ def agent(
|
||||
message: str = typer.Option(None, "--message", "-m", help="Message to send to the agent"),
|
||||
session_id: str = typer.Option("cli:direct", "--session", "-s", help="Session ID"),
|
||||
markdown: bool = typer.Option(True, "--markdown/--no-markdown", help="Render assistant output as Markdown"),
|
||||
logs: bool = typer.Option(False, "--logs/--no-logs", help="Show nanobot runtime logs during chat"),
|
||||
logs: bool = typer.Option(False, "--logs/--no-logs", help="Show Boardware Genius runtime logs during chat"),
|
||||
):
|
||||
"""直接与 agent 交互(单轮模式或交互模式)。
|
||||
|
||||
@ -614,7 +614,7 @@ def agent(
|
||||
# 空上下文:进入/退出都不做事,仅用于统一 with 接口。
|
||||
return nullcontext()
|
||||
# 非日志模式下启用转圈动画,提升等待期间的交互感知。
|
||||
return console.status("[dim]nanobot is thinking...[/dim]", spinner="dots")
|
||||
return console.status(f"[dim]{__brand__} is thinking...[/dim]", spinner="dots")
|
||||
|
||||
async def _cli_progress(content: str, *, tool_hint: bool = False) -> None:
|
||||
"""CLI 进度回调:按 channels 配置过滤后渲染中间态输出。"""
|
||||
@ -643,7 +643,7 @@ def agent(
|
||||
# 初始化 prompt_toolkit 会话(历史记录、编辑能力、粘贴兼容等)。
|
||||
_init_prompt_session()
|
||||
# 打印一次交互模式提示,告知退出方式。
|
||||
console.print(f"{__logo__} Interactive mode (type [bold]exit[/bold] or [bold]Ctrl+C[/bold] to quit)\n")
|
||||
console.print(f"{__brand__} interactive mode (type [bold]exit[/bold] or [bold]Ctrl+C[/bold] to quit)\n")
|
||||
|
||||
# session_id 解析规则:
|
||||
# 1) 传入 "channel:chat_id" 时,显式使用对应渠道与会话;
|
||||
@ -945,7 +945,7 @@ def _get_bridge_dir() -> Path:
|
||||
console.print("Try reinstalling: pip install --force-reinstall nanobot")
|
||||
raise typer.Exit(1)
|
||||
|
||||
console.print(f"{__logo__} Setting up bridge...")
|
||||
console.print(f"{__brand__}: setting up bridge...")
|
||||
|
||||
# 重新复制并构建,确保 bridge 资源与当前版本同步。
|
||||
user_bridge.parent.mkdir(parents=True, exist_ok=True)
|
||||
@ -980,7 +980,7 @@ def channels_login():
|
||||
config = load_config()
|
||||
bridge_dir = _get_bridge_dir()
|
||||
|
||||
console.print(f"{__logo__} Starting bridge...")
|
||||
console.print(f"{__brand__}: starting bridge...")
|
||||
console.print("Scan the QR code to connect.\n")
|
||||
|
||||
# 可选注入 BRIDGE_TOKEN 做 bridge 鉴权。
|
||||
@ -1259,14 +1259,14 @@ def cron_run(
|
||||
|
||||
@app.command()
|
||||
def status():
|
||||
"""展示 nanobot 运行配置与 provider 状态概览。"""
|
||||
"""展示 Boardware Genius 运行配置与 provider 状态概览。"""
|
||||
from nanobot.config.loader import load_config, get_config_path
|
||||
|
||||
config_path = get_config_path()
|
||||
config = load_config()
|
||||
workspace = config.workspace_path
|
||||
|
||||
console.print(f"{__logo__} nanobot Status\n")
|
||||
console.print(f"{__brand__} Status\n")
|
||||
|
||||
console.print(f"Config: {config_path} {'[green]✓[/green]' if config_path.exists() else '[red]✗[/red]'}")
|
||||
console.print(f"Workspace: {workspace} {'[green]✓[/green]' if workspace.exists() else '[red]✗[/red]'}")
|
||||
@ -1346,7 +1346,7 @@ def provider_login(
|
||||
console.print(f"[red]Login not implemented for {spec.label}[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
console.print(f"{__logo__} OAuth Login - {spec.label}\n")
|
||||
console.print(f"{__brand__} OAuth Login - {spec.label}\n")
|
||||
handler()
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"""Configuration module for nanobot."""
|
||||
"""Configuration module for Boardware Genius."""
|
||||
|
||||
from nanobot.config.loader import load_config, get_config_path
|
||||
from nanobot.config.schema import Config
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Heartbeat Tasks
|
||||
|
||||
This file is checked every 30 minutes by your nanobot agent.
|
||||
This file is checked every 30 minutes by your Boardware Genius agent.
|
||||
Add tasks below that you want the agent to work on periodically.
|
||||
|
||||
If this file has no tasks (only headers and comments), the agent will skip the heartbeat.
|
||||
@ -13,4 +13,3 @@ If this file has no tasks (only headers and comments), the agent will skip the h
|
||||
## Completed
|
||||
|
||||
<!-- Move completed tasks here or delete them -->
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Soul
|
||||
|
||||
I am nanobot 🐈, a personal AI assistant.
|
||||
I am Boardware Genius, a personal AI assistant.
|
||||
|
||||
## Personality
|
||||
|
||||
|
||||
@ -46,4 +46,4 @@ Information about the user to help personalize interactions.
|
||||
|
||||
---
|
||||
|
||||
*Edit this file to customize nanobot's behavior for your needs.*
|
||||
*Edit this file to customize Boardware Genius behavior for your needs.*
|
||||
|
||||
@ -20,4 +20,4 @@ This file stores important information that should persist across sessions.
|
||||
|
||||
---
|
||||
|
||||
*This file is automatically updated by nanobot when important information should be remembered.*
|
||||
*This file is automatically updated by Boardware Genius when important information should be remembered.*
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"""Utility functions for nanobot."""
|
||||
"""Utility functions for Boardware Genius."""
|
||||
|
||||
from nanobot.utils.helpers import (
|
||||
ensure_dir,
|
||||
|
||||
@ -1 +1 @@
|
||||
"""Web interface for nanobot."""
|
||||
"""Web interface for Boardware Genius."""
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"""FastAPI web server for nanobot frontend."""
|
||||
"""FastAPI web server for the Boardware Genius frontend."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@ -8,6 +8,7 @@ import json
|
||||
import os
|
||||
import re
|
||||
import secrets
|
||||
import shlex
|
||||
import shutil
|
||||
import time
|
||||
import zipfile
|
||||
@ -676,6 +677,8 @@ def create_app(
|
||||
|
||||
app.state.config = config
|
||||
app.state.config_path = get_config_path()
|
||||
app.state.runtime_env_path = _get_runtime_env_file_path(app.state.config_path)
|
||||
_sync_authz_runtime_env(app.state.config, app.state.runtime_env_path)
|
||||
app.state.session_manager = session_manager
|
||||
app.state.cron_service = cron_service
|
||||
app.state.bus = bus
|
||||
@ -766,6 +769,60 @@ def _get_auth_file_path() -> Path:
|
||||
return Path(__file__).resolve().parents[2] / "web_auth_users.json"
|
||||
|
||||
|
||||
_AUTHZ_RUNTIME_ENV_KEYS = (
|
||||
"NANOBOT_AUTHZ__ENABLED",
|
||||
"NANOBOT_AUTHZ__BASE_URL",
|
||||
"NANOBOT_AUTHZ__OUTLOOK_MCP_URL",
|
||||
"NANOBOT_BACKEND_IDENTITY__BACKEND_ID",
|
||||
"NANOBOT_BACKEND_IDENTITY__CLIENT_ID",
|
||||
"NANOBOT_BACKEND_IDENTITY__CLIENT_SECRET",
|
||||
"NANOBOT_BACKEND_IDENTITY__NAME",
|
||||
"NANOBOT_BACKEND_IDENTITY__PUBLIC_BASE_URL",
|
||||
)
|
||||
|
||||
|
||||
def _get_runtime_env_file_path(config_path: Path | None = None) -> Path:
|
||||
env = os.getenv("NANOBOT_RUNTIME_ENV_FILE", "").strip()
|
||||
if env:
|
||||
return Path(env).expanduser()
|
||||
base_path = config_path or get_config_path()
|
||||
return base_path.parent / "runtime.env"
|
||||
|
||||
|
||||
def _authz_runtime_env_values(config: Config) -> dict[str, str]:
|
||||
return {
|
||||
"NANOBOT_AUTHZ__ENABLED": "1" if config.authz.enabled and config.authz.base_url.strip() else "0",
|
||||
"NANOBOT_AUTHZ__BASE_URL": config.authz.base_url.strip(),
|
||||
"NANOBOT_AUTHZ__OUTLOOK_MCP_URL": config.authz.outlook_mcp_url.strip(),
|
||||
"NANOBOT_BACKEND_IDENTITY__BACKEND_ID": config.backend_identity.backend_id.strip(),
|
||||
"NANOBOT_BACKEND_IDENTITY__CLIENT_ID": config.backend_identity.client_id.strip(),
|
||||
"NANOBOT_BACKEND_IDENTITY__CLIENT_SECRET": config.backend_identity.client_secret.strip(),
|
||||
"NANOBOT_BACKEND_IDENTITY__NAME": config.backend_identity.name.strip(),
|
||||
"NANOBOT_BACKEND_IDENTITY__PUBLIC_BASE_URL": config.backend_identity.public_base_url.strip(),
|
||||
}
|
||||
|
||||
|
||||
def _sync_authz_runtime_env(config: Config, target_path: Path) -> None:
|
||||
values = _authz_runtime_env_values(config)
|
||||
target_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
lines: list[str] = []
|
||||
for key in _AUTHZ_RUNTIME_ENV_KEYS:
|
||||
value = values.get(key, "")
|
||||
if value:
|
||||
os.environ[key] = value
|
||||
lines.append(f"export {key}={shlex.quote(value)}")
|
||||
continue
|
||||
if key == "NANOBOT_AUTHZ__ENABLED":
|
||||
os.environ[key] = "0"
|
||||
lines.append("export NANOBOT_AUTHZ__ENABLED=0")
|
||||
continue
|
||||
os.environ.pop(key, None)
|
||||
lines.append(f"unset {key}")
|
||||
|
||||
target_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def _load_auth_users(path: Path) -> dict[str, str]:
|
||||
"""Load users from local JSON file.
|
||||
|
||||
@ -1129,6 +1186,7 @@ def _register_routes(app: FastAPI) -> None:
|
||||
if authz_enabled:
|
||||
config.authz.enabled = True
|
||||
_save_app_config(config)
|
||||
_sync_authz_runtime_env(config, app.state.runtime_env_path)
|
||||
return _local_backend_view(config)
|
||||
|
||||
def _authz_client(config: Config):
|
||||
|
||||
Reference in New Issue
Block a user