mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-18 18:10:37 +08:00
fix: standardize dashboard env vars to ASTRBOT_* prefix only
- Remove all DASHBOARD_* and ASTRBOT_DASHBOARD_* fallback chains - server.py now only checks ASTRBOT_HOST, ASTRBOT_PORT, ASTRBOT_SSL_* - cmd_run.py no longer sets legacy DASHBOARD_* environment variables - Clean up import paths for agent runners
This commit is contained in:
@@ -196,24 +196,6 @@ def run(
|
||||
# after this point and will take precedence.
|
||||
load_dotenv(dotenv_path=str(svc_path), override=True)
|
||||
|
||||
# Normalize environment variables for backward compatibility
|
||||
# If legacy env vars are set but the preferred new ones aren't, copy them over.
|
||||
env_map = {
|
||||
# Dashboard legacy -> standardized dashboard-prefixed
|
||||
"DASHBOARD_ENABLE": "ASTRBOT_DASHBOARD_ENABLE",
|
||||
"DASHBOARD_HOST": "ASTRBOT_HOST",
|
||||
"DASHBOARD_PORT": "ASTRBOT_PORT",
|
||||
"DASHBOARD_SSL_ENABLE": "ASTRBOT_SSL_ENABLE",
|
||||
"DASHBOARD_SSL_CERT": "ASTRBOT_SSL_CERT",
|
||||
"DASHBOARD_SSL_KEY": "ASTRBOT_SSL_KEY",
|
||||
"DASHBOARD_SSL_CA_CERTS": "ASTRBOT_SSL_CA_CERTS",
|
||||
# Some packages used alternate names
|
||||
"ASTRBOT_DASHBOARD_SSL_CERT": "ASTRBOT_SSL_CERT",
|
||||
}
|
||||
for legacy, new in env_map.items():
|
||||
if legacy in os.environ and new not in os.environ:
|
||||
os.environ[new] = os.environ[legacy]
|
||||
|
||||
# Mark CLI execution
|
||||
os.environ["ASTRBOT_CLI"] = "1"
|
||||
|
||||
@@ -243,29 +225,20 @@ def run(
|
||||
# Host/Port precedence: CLI args > parsed service config/env/.env > defaults.
|
||||
if port is not None:
|
||||
os.environ["ASTRBOT_PORT"] = port
|
||||
os.environ["DASHBOARD_PORT"] = port # legacy
|
||||
# If CLI didn't provide port but env/.env provided ASTRBOT_DASHBOARD_PORT, leave it as-is.
|
||||
|
||||
if host is not None:
|
||||
os.environ["ASTRBOT_HOST"] = host
|
||||
os.environ["DASHBOARD_HOST"] = host # legacy
|
||||
# If CLI didn't provide host but env/.env provided ASTRBOT_DASHBOARD_HOST, leave it as-is.
|
||||
|
||||
# CLI-provided SSL paths should set backend-standard env names (preferred),
|
||||
# and also set legacy/dashboard names for compatibility.
|
||||
# CLI-provided SSL paths should set backend-standard env names.
|
||||
if ssl_cert is not None:
|
||||
os.environ["ASTRBOT_SSL_CERT"] = ssl_cert
|
||||
os.environ["DASHBOARD_SSL_CERT"] = ssl_cert
|
||||
if ssl_key is not None:
|
||||
os.environ["ASTRBOT_SSL_KEY"] = ssl_key
|
||||
os.environ["DASHBOARD_SSL_KEY"] = ssl_key
|
||||
if ssl_ca is not None:
|
||||
os.environ["ASTRBOT_SSL_CA_CERTS"] = ssl_ca
|
||||
os.environ["DASHBOARD_SSL_CA_CERTS"] = ssl_ca
|
||||
|
||||
# Dashboard enable is derived from CLI flag (--backend-only). CLI decision should win.
|
||||
os.environ["ASTRBOT_DASHBOARD_ENABLE"] = str(not backend_only)
|
||||
os.environ["DASHBOARD_ENABLE"] = str(not backend_only) # legacy
|
||||
|
||||
os.environ["ASTRBOT_LOG_LEVEL"] = log_level
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import abc
|
||||
import typing as T
|
||||
from collections.abc import AsyncGenerator
|
||||
from enum import Enum, auto
|
||||
from typing import Any, Generic
|
||||
|
||||
from astrbot import logger
|
||||
from astrbot.core.provider.entities import LLMResponse
|
||||
|
||||
from ..hooks import BaseAgentRunHooks
|
||||
from ..response import AgentResponse
|
||||
from ..run_context import ContextWrapper, TContext
|
||||
from astrbot.core.agent.hooks import BaseAgentRunHooks
|
||||
from astrbot.core.agent.response import AgentResponse
|
||||
from astrbot.core.agent.run_context import ContextWrapper, TContext
|
||||
from astrbot.core.agent.tool_executor import BaseFunctionToolExecutor
|
||||
from astrbot.core.provider.entities import LLMResponse, ProviderRequest
|
||||
from astrbot.core.provider.provider import Provider
|
||||
|
||||
|
||||
class AgentState(Enum):
|
||||
@@ -19,7 +21,7 @@ class AgentState(Enum):
|
||||
ERROR = auto() # Error state
|
||||
|
||||
|
||||
class BaseAgentRunner(T.Generic[TContext]):
|
||||
class BaseAgentRunner(Generic[TContext]):
|
||||
def __init__(
|
||||
self,
|
||||
):
|
||||
@@ -28,9 +30,23 @@ class BaseAgentRunner(T.Generic[TContext]):
|
||||
@abc.abstractmethod
|
||||
async def reset(
|
||||
self,
|
||||
provider: Provider,
|
||||
request: ProviderRequest,
|
||||
run_context: ContextWrapper[TContext],
|
||||
tool_executor: BaseFunctionToolExecutor[TContext],
|
||||
agent_hooks: BaseAgentRunHooks[TContext],
|
||||
**kwargs: T.Any,
|
||||
streaming: bool = False,
|
||||
enforce_max_turns: int = -1,
|
||||
llm_compress_instruction: str | None = None,
|
||||
llm_compress_keep_recent: int = 0,
|
||||
llm_compress_provider: Provider | None = None,
|
||||
truncate_turns: int = 1,
|
||||
custom_token_counter: Any = None,
|
||||
custom_compressor: Any = None,
|
||||
tool_schema_mode: str | None = "full",
|
||||
fallback_providers: list[Provider] | None = None,
|
||||
provider_config: dict | None = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Reset the agent to its initial state.
|
||||
This method should be called before starting a new run.
|
||||
@@ -38,14 +54,14 @@ class BaseAgentRunner(T.Generic[TContext]):
|
||||
...
|
||||
|
||||
@abc.abstractmethod
|
||||
async def step(self) -> T.AsyncGenerator[AgentResponse, None]:
|
||||
async def step(self) -> AsyncGenerator[AgentResponse, None]:
|
||||
"""Process a single step of the agent."""
|
||||
...
|
||||
|
||||
@abc.abstractmethod
|
||||
async def step_until_done(
|
||||
self, max_step: int
|
||||
) -> T.AsyncGenerator[AgentResponse, None]:
|
||||
) -> AsyncGenerator[AgentResponse, None]:
|
||||
"""Process steps until the agent is done."""
|
||||
...
|
||||
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
import base64
|
||||
import json
|
||||
import sys
|
||||
import typing as T
|
||||
from collections.abc import AsyncGenerator
|
||||
from typing import Any
|
||||
|
||||
import astrbot.core.message.components as Comp
|
||||
from astrbot import logger
|
||||
from astrbot.core import sp
|
||||
from astrbot.core.agent.hooks import BaseAgentRunHooks
|
||||
from astrbot.core.agent.response import AgentResponseData
|
||||
from astrbot.core.agent.run_context import ContextWrapper, TContext
|
||||
from astrbot.core.agent.runners.base import AgentResponse, AgentState, BaseAgentRunner
|
||||
from astrbot.core.agent.tool_executor import BaseFunctionToolExecutor
|
||||
from astrbot.core.message.message_event_result import MessageChain
|
||||
from astrbot.core.provider.entities import (
|
||||
LLMResponse,
|
||||
ProviderRequest,
|
||||
)
|
||||
from astrbot.core.provider.provider import Provider
|
||||
|
||||
from ...hooks import BaseAgentRunHooks
|
||||
from ...response import AgentResponseData
|
||||
from ...run_context import ContextWrapper, TContext
|
||||
from ..base import AgentResponse, AgentState, BaseAgentRunner
|
||||
from .coze_api_client import CozeAPIClient
|
||||
|
||||
if sys.version_info >= (3, 12):
|
||||
@@ -30,19 +33,32 @@ class CozeAgentRunner(BaseAgentRunner[TContext]):
|
||||
@override
|
||||
async def reset(
|
||||
self,
|
||||
provider: Provider,
|
||||
request: ProviderRequest,
|
||||
run_context: ContextWrapper[TContext],
|
||||
tool_executor: BaseFunctionToolExecutor[TContext],
|
||||
agent_hooks: BaseAgentRunHooks[TContext],
|
||||
provider_config: dict,
|
||||
**kwargs: T.Any,
|
||||
streaming: bool = False,
|
||||
enforce_max_turns: int = -1,
|
||||
llm_compress_instruction: str | None = None,
|
||||
llm_compress_keep_recent: int = 0,
|
||||
llm_compress_provider: Provider | None = None,
|
||||
truncate_turns: int = 1,
|
||||
custom_token_counter: Any = None,
|
||||
custom_compressor: Any = None,
|
||||
tool_schema_mode: str | None = "full",
|
||||
fallback_providers: list[Provider] | None = None,
|
||||
provider_config: dict | None = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
self.req = request
|
||||
self.streaming = kwargs.get("streaming", False)
|
||||
self.streaming = streaming
|
||||
self.final_llm_resp = None
|
||||
self._state = AgentState.IDLE
|
||||
self.agent_hooks = agent_hooks
|
||||
self.run_context = run_context
|
||||
|
||||
provider_config = provider_config or {}
|
||||
self.api_key = provider_config.get("coze_api_key", "")
|
||||
if not self.api_key:
|
||||
raise Exception("Coze API Key 不能为空。")
|
||||
@@ -107,8 +123,8 @@ class CozeAgentRunner(BaseAgentRunner[TContext]):
|
||||
|
||||
@override
|
||||
async def step_until_done(
|
||||
self, max_step: int = 3
|
||||
) -> T.AsyncGenerator[AgentResponse, None]:
|
||||
self, max_step: int
|
||||
) -> AsyncGenerator[AgentResponse, None]:
|
||||
while not self.done():
|
||||
async for resp in self.step():
|
||||
yield resp
|
||||
|
||||
@@ -4,7 +4,8 @@ import queue
|
||||
import re
|
||||
import sys
|
||||
import threading
|
||||
import typing as T
|
||||
from collections.abc import AsyncGenerator
|
||||
from typing import Any
|
||||
|
||||
from dashscope import Application
|
||||
from dashscope.app.application_response import ApplicationResponse
|
||||
@@ -16,11 +17,13 @@ from astrbot.core.provider.entities import (
|
||||
LLMResponse,
|
||||
ProviderRequest,
|
||||
)
|
||||
from astrbot.core.provider.provider import Provider
|
||||
|
||||
from ...hooks import BaseAgentRunHooks
|
||||
from ...response import AgentResponseData
|
||||
from ...run_context import ContextWrapper, TContext
|
||||
from ..base import AgentResponse, AgentState, BaseAgentRunner
|
||||
from ..tool_executor import BaseFunctionToolExecutor
|
||||
|
||||
if sys.version_info >= (3, 12):
|
||||
from typing import override
|
||||
@@ -34,19 +37,32 @@ class DashscopeAgentRunner(BaseAgentRunner[TContext]):
|
||||
@override
|
||||
async def reset(
|
||||
self,
|
||||
provider: Provider,
|
||||
request: ProviderRequest,
|
||||
run_context: ContextWrapper[TContext],
|
||||
tool_executor: BaseFunctionToolExecutor[TContext],
|
||||
agent_hooks: BaseAgentRunHooks[TContext],
|
||||
provider_config: dict,
|
||||
**kwargs: T.Any,
|
||||
streaming: bool = False,
|
||||
enforce_max_turns: int = -1,
|
||||
llm_compress_instruction: str | None = None,
|
||||
llm_compress_keep_recent: int = 0,
|
||||
llm_compress_provider: Provider | None = None,
|
||||
truncate_turns: int = 1,
|
||||
custom_token_counter: Any = None,
|
||||
custom_compressor: Any = None,
|
||||
tool_schema_mode: str | None = "full",
|
||||
fallback_providers: list[Provider] | None = None,
|
||||
provider_config: dict | None = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
self.req = request
|
||||
self.streaming = kwargs.get("streaming", False)
|
||||
self.streaming = streaming
|
||||
self.final_llm_resp = None
|
||||
self._state = AgentState.IDLE
|
||||
self.agent_hooks = agent_hooks
|
||||
self.run_context = run_context
|
||||
|
||||
provider_config = provider_config or {}
|
||||
self.api_key = provider_config.get("dashscope_api_key", "")
|
||||
if not self.api_key:
|
||||
raise Exception("阿里云百炼 API Key 不能为空。")
|
||||
@@ -117,14 +133,14 @@ class DashscopeAgentRunner(BaseAgentRunner[TContext]):
|
||||
|
||||
@override
|
||||
async def step_until_done(
|
||||
self, max_step: int = 3
|
||||
) -> T.AsyncGenerator[AgentResponse, None]:
|
||||
self, max_step: int
|
||||
) -> AsyncGenerator[AgentResponse, None]:
|
||||
while not self.done():
|
||||
async for resp in self.step():
|
||||
yield resp
|
||||
|
||||
def _consume_sync_generator(
|
||||
self, response: T.Any, response_queue: queue.Queue
|
||||
self, response: Any, response_queue: queue.Queue
|
||||
) -> None:
|
||||
"""在线程中消费同步generator,将结果放入队列
|
||||
|
||||
@@ -278,7 +294,7 @@ class DashscopeAgentRunner(BaseAgentRunner[TContext]):
|
||||
return payload
|
||||
|
||||
async def _handle_streaming_response(
|
||||
self, response: T.Any, session_id: str
|
||||
self, response: Any, session_id: str
|
||||
) -> T.AsyncGenerator[AgentResponse, None]:
|
||||
"""处理流式响应
|
||||
|
||||
|
||||
@@ -153,9 +153,7 @@ class AstrBotDashboard:
|
||||
|
||||
def _check_webui_enabled(self) -> bool:
|
||||
cfg = self.config.get("dashboard", {})
|
||||
_env = os.environ.get(
|
||||
"ASTRBOT_DASHBOARD_ENABLE", os.environ.get("DASHBOARD_ENABLE")
|
||||
)
|
||||
_env = os.environ.get("ASTRBOT_DASHBOARD_ENABLE")
|
||||
if _env is not None:
|
||||
return _env.lower() in ("true", "1", "yes")
|
||||
return cfg.get("enable", True)
|
||||
@@ -477,13 +475,12 @@ class AstrBotDashboard:
|
||||
"""Run dashboard server (blocking)"""
|
||||
if not self.enable_webui:
|
||||
logger.warning(
|
||||
"WebUI 已禁用 (dashboard.enable=false or DASHBOARD_ENABLE=false)"
|
||||
"WebUI 已禁用 (dashboard.enable=false or ASTRBOT_DASHBOARD_ENABLE=false)"
|
||||
)
|
||||
|
||||
dashboard_config = self.config.get("dashboard", {})
|
||||
host_value = (
|
||||
os.environ.get("ASTRBOT_HOST")
|
||||
or os.environ.get("DASHBOARD_HOST")
|
||||
or dashboard_config.get("host", "0.0.0.0")
|
||||
)
|
||||
host = _resolve_dashboard_value(host_value, field_name="host")
|
||||
@@ -492,7 +489,6 @@ class AstrBotDashboard:
|
||||
|
||||
port_value = (
|
||||
os.environ.get("ASTRBOT_PORT")
|
||||
or os.environ.get("DASHBOARD_PORT")
|
||||
or dashboard_config.get("port", 6185)
|
||||
)
|
||||
resolved_port = _resolve_dashboard_value(port_value, field_name="port")
|
||||
@@ -501,8 +497,7 @@ class AstrBotDashboard:
|
||||
port = int(resolved_port)
|
||||
ssl_config = dashboard_config.get("ssl", {})
|
||||
ssl_enable = _parse_env_bool(
|
||||
os.environ.get("ASTRBOT_SSL_ENABLE")
|
||||
or os.environ.get("DASHBOARD_SSL_ENABLE"),
|
||||
os.environ.get("ASTRBOT_SSL_ENABLE"),
|
||||
ssl_config.get("enable", False),
|
||||
)
|
||||
|
||||
@@ -539,19 +534,16 @@ class AstrBotDashboard:
|
||||
if ssl_enable:
|
||||
cert_file = (
|
||||
os.environ.get("ASTRBOT_SSL_CERT")
|
||||
or os.environ.get("DASHBOARD_SSL_CERT")
|
||||
or ssl_config.get("cert_file", "")
|
||||
)
|
||||
cert_file = _resolve_dashboard_value(cert_file, field_name="ssl.cert_file")
|
||||
key_file = (
|
||||
os.environ.get("ASTRBOT_SSL_KEY")
|
||||
or os.environ.get("DASHBOARD_SSL_KEY")
|
||||
or ssl_config.get("key_file", "")
|
||||
)
|
||||
key_file = _resolve_dashboard_value(key_file, field_name="ssl.key_file")
|
||||
ca_certs = (
|
||||
os.environ.get("ASTRBOT_SSL_CA_CERTS")
|
||||
or os.environ.get("DASHBOARD_SSL_CA_CERTS")
|
||||
or ssl_config.get("ca_certs", "")
|
||||
)
|
||||
ca_certs = _resolve_dashboard_value(ca_certs, field_name="ssl.ca_certs")
|
||||
|
||||
Reference in New Issue
Block a user