From 093dab3c9813b080ee3d56b9c8d6ad59b1608788 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:54:40 +0000 Subject: [PATCH 1/6] Initial plan From b8eb110cf43b56ef9b7faedcb5d111273117cfd1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:59:17 +0000 Subject: [PATCH 2/6] feat: add global unified context mode configuration and implementation Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com> --- astrbot/core/astr_main_agent.py | 30 +++++++++++++++++++++ astrbot/core/config/default.py | 4 +++ astrbot/core/pipeline/waking_check/stage.py | 15 +++++++++++ 3 files changed, 49 insertions(+) diff --git a/astrbot/core/astr_main_agent.py b/astrbot/core/astr_main_agent.py index 1ea36ff7a..13ea6ac70 100644 --- a/astrbot/core/astr_main_agent.py +++ b/astrbot/core/astr_main_agent.py @@ -830,6 +830,33 @@ def _get_compress_provider( return provider +def _apply_global_context_info(event: AstrMessageEvent, req: ProviderRequest) -> None: + """Add platform and session information to user prompt when in global unified context mode.""" + from astrbot.core.config.default import GLOBAL_UNIFIED_CONTEXT_UMO + + if event.unified_msg_origin != GLOBAL_UNIFIED_CONTEXT_UMO: + return + + # Get original UMO from extras + original_umo = event.get_extra("original_umo") + if not original_umo: + return + + # Parse the original UMO to extract platform, message type, and session info + try: + parts = original_umo.split(":", 2) + if len(parts) == 3: + platform_id, message_type, session_id = parts + context_info = f"[Context: Platform={platform_id}, Type={message_type}, Session={session_id}]" + # Prepend context info to the user prompt + if req.prompt: + req.prompt = f"{context_info} {req.prompt}" + else: + req.prompt = context_info + except Exception as e: + logger.warning(f"Failed to parse original UMO for global context: {e}") + + async def build_main_agent( *, event: AstrMessageEvent, @@ -888,6 +915,9 @@ async def build_main_agent( if isinstance(req.contexts, str): req.contexts = json.loads(req.contexts) + # Apply global context information if enabled + _apply_global_context_info(event, req) + if config.file_extract_enabled: try: await _apply_file_extract(event, req, config) diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index 12056a04e..435bf8b7c 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -17,11 +17,15 @@ "lark", ] +# Constant UMO for global unified context mode +GLOBAL_UNIFIED_CONTEXT_UMO = "global::global" + # 默认配置 DEFAULT_CONFIG = { "config_version": 2, "platform_settings": { "unique_session": False, + "global_unified_context_mode": False, "rate_limit": { "time": 60, "count": 30, diff --git a/astrbot/core/pipeline/waking_check/stage.py b/astrbot/core/pipeline/waking_check/stage.py index 2dcb840e9..fe2915b1e 100644 --- a/astrbot/core/pipeline/waking_check/stage.py +++ b/astrbot/core/pipeline/waking_check/stage.py @@ -72,11 +72,26 @@ async def initialize(self, ctx: PipelineContext) -> None: ) platform_settings = self.ctx.astrbot_config.get("platform_settings", {}) self.unique_session = platform_settings.get("unique_session", False) + self.global_unified_context_mode = platform_settings.get( + "global_unified_context_mode", False + ) async def process( self, event: AstrMessageEvent, ) -> None | AsyncGenerator[None, None]: + # apply global unified context mode + if self.global_unified_context_mode: + from astrbot.core.config.default import GLOBAL_UNIFIED_CONTEXT_UMO + + original_umo = event.unified_msg_origin + event.unified_msg_origin = GLOBAL_UNIFIED_CONTEXT_UMO + # Store original UMO for reference in later stages + event.set_extra("original_umo", original_umo) + logger.debug( + f"Global unified context mode enabled. Changed UMO from {original_umo} to {GLOBAL_UNIFIED_CONTEXT_UMO}" + ) + # apply unique session if self.unique_session and event.message_obj.type == MessageType.GROUP_MESSAGE: sid = build_unique_session_id(event) From eb667d310c4dc05129b4d8e826a8f3df69e01937 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:01:47 +0000 Subject: [PATCH 3/6] refactor: improve error handling in global context info function Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com> --- astrbot/core/astr_main_agent.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/astrbot/core/astr_main_agent.py b/astrbot/core/astr_main_agent.py index 13ea6ac70..5abd3eda3 100644 --- a/astrbot/core/astr_main_agent.py +++ b/astrbot/core/astr_main_agent.py @@ -845,14 +845,16 @@ def _apply_global_context_info(event: AstrMessageEvent, req: ProviderRequest) -> # Parse the original UMO to extract platform, message type, and session info try: parts = original_umo.split(":", 2) - if len(parts) == 3: - platform_id, message_type, session_id = parts - context_info = f"[Context: Platform={platform_id}, Type={message_type}, Session={session_id}]" - # Prepend context info to the user prompt - if req.prompt: - req.prompt = f"{context_info} {req.prompt}" - else: - req.prompt = context_info + if len(parts) != 3: + logger.warning( + f"Original UMO format is invalid (expected 3 parts): {original_umo}" + ) + return + + platform_id, message_type, session_id = parts + context_info = f"[Context: Platform={platform_id}, Type={message_type}, Session={session_id}]" + # Prepend context info to the user prompt + req.prompt = f"{context_info} {req.prompt or ''}" except Exception as e: logger.warning(f"Failed to parse original UMO for global context: {e}") From 3091b92158077c4fd473e05bc672d47cb00ad30a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:14:25 +0000 Subject: [PATCH 4/6] feat: restore original UMO in respond stage and update send_message_to_user tool Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com> --- astrbot/core/astr_main_agent_resources.py | 9 ++++++++- astrbot/core/pipeline/respond/stage.py | 8 ++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/astrbot/core/astr_main_agent_resources.py b/astrbot/core/astr_main_agent_resources.py index 1d5c085ce..c6f8fbd2b 100644 --- a/astrbot/core/astr_main_agent_resources.py +++ b/astrbot/core/astr_main_agent_resources.py @@ -212,6 +212,10 @@ class SendMessageToUserTool(FunctionTool[AstrAgentContext]): "required": ["type"], }, }, + "session": { + "type": "string", + "description": "Target session ID in format 'platform:type:session_id'. If not specified, sends to the current session.", + }, }, "required": ["messages"], } @@ -253,7 +257,10 @@ async def _resolve_path_from_sandbox( async def call( self, context: ContextWrapper[AstrAgentContext], **kwargs ) -> ToolExecResult: - session = kwargs.get("session") or context.context.event.unified_msg_origin + # In global context mode, default to original UMO if session not specified + original_umo = context.context.event.get_extra("original_umo") + default_session = original_umo or context.context.event.unified_msg_origin + session = kwargs.get("session") or default_session messages = kwargs.get("messages") if not isinstance(messages, list) or not messages: diff --git a/astrbot/core/pipeline/respond/stage.py b/astrbot/core/pipeline/respond/stage.py index 60ab168b3..573d2fa14 100644 --- a/astrbot/core/pipeline/respond/stage.py +++ b/astrbot/core/pipeline/respond/stage.py @@ -169,6 +169,14 @@ async def process( f"Prepare to send - {event.get_sender_name()}/{event.get_sender_id()}: {event._outline_chain(result.chain)}", ) + # Restore original UMO before sending if in global context mode + original_umo = event.get_extra("original_umo") + if original_umo: + logger.debug( + f"Restoring original UMO before sending: {event.unified_msg_origin} -> {original_umo}" + ) + event.unified_msg_origin = original_umo + if result.result_content_type == ResultContentType.STREAMING_RESULT: if result.async_stream is None: logger.warning("async_stream 为空,跳过发送。") From bb9f2623d8a3db4d11f1456d531d898a0168d50e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:16:04 +0000 Subject: [PATCH 5/6] refactor: extract hardcoded original_umo key to constant Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com> --- astrbot/core/astr_main_agent.py | 7 +++++-- astrbot/core/astr_main_agent_resources.py | 4 +++- astrbot/core/config/default.py | 2 ++ astrbot/core/pipeline/respond/stage.py | 4 +++- astrbot/core/pipeline/waking_check/stage.py | 7 +++++-- 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/astrbot/core/astr_main_agent.py b/astrbot/core/astr_main_agent.py index 5abd3eda3..dfec4b94a 100644 --- a/astrbot/core/astr_main_agent.py +++ b/astrbot/core/astr_main_agent.py @@ -832,13 +832,16 @@ def _get_compress_provider( def _apply_global_context_info(event: AstrMessageEvent, req: ProviderRequest) -> None: """Add platform and session information to user prompt when in global unified context mode.""" - from astrbot.core.config.default import GLOBAL_UNIFIED_CONTEXT_UMO + from astrbot.core.config.default import ( + GLOBAL_UNIFIED_CONTEXT_UMO, + ORIGINAL_UMO_KEY, + ) if event.unified_msg_origin != GLOBAL_UNIFIED_CONTEXT_UMO: return # Get original UMO from extras - original_umo = event.get_extra("original_umo") + original_umo = event.get_extra(ORIGINAL_UMO_KEY) if not original_umo: return diff --git a/astrbot/core/astr_main_agent_resources.py b/astrbot/core/astr_main_agent_resources.py index c6f8fbd2b..c989c91bc 100644 --- a/astrbot/core/astr_main_agent_resources.py +++ b/astrbot/core/astr_main_agent_resources.py @@ -258,7 +258,9 @@ async def call( self, context: ContextWrapper[AstrAgentContext], **kwargs ) -> ToolExecResult: # In global context mode, default to original UMO if session not specified - original_umo = context.context.event.get_extra("original_umo") + from astrbot.core.config.default import ORIGINAL_UMO_KEY + + original_umo = context.context.event.get_extra(ORIGINAL_UMO_KEY) default_session = original_umo or context.context.event.unified_msg_origin session = kwargs.get("session") or default_session messages = kwargs.get("messages") diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index 435bf8b7c..0a3bb42fb 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -19,6 +19,8 @@ # Constant UMO for global unified context mode GLOBAL_UNIFIED_CONTEXT_UMO = "global::global" +# Key for storing original UMO in event extras when global context mode is enabled +ORIGINAL_UMO_KEY = "original_umo" # 默认配置 DEFAULT_CONFIG = { diff --git a/astrbot/core/pipeline/respond/stage.py b/astrbot/core/pipeline/respond/stage.py index 573d2fa14..3e8a5a916 100644 --- a/astrbot/core/pipeline/respond/stage.py +++ b/astrbot/core/pipeline/respond/stage.py @@ -170,7 +170,9 @@ async def process( ) # Restore original UMO before sending if in global context mode - original_umo = event.get_extra("original_umo") + from astrbot.core.config.default import ORIGINAL_UMO_KEY + + original_umo = event.get_extra(ORIGINAL_UMO_KEY) if original_umo: logger.debug( f"Restoring original UMO before sending: {event.unified_msg_origin} -> {original_umo}" diff --git a/astrbot/core/pipeline/waking_check/stage.py b/astrbot/core/pipeline/waking_check/stage.py index fe2915b1e..4fa412652 100644 --- a/astrbot/core/pipeline/waking_check/stage.py +++ b/astrbot/core/pipeline/waking_check/stage.py @@ -82,12 +82,15 @@ async def process( ) -> None | AsyncGenerator[None, None]: # apply global unified context mode if self.global_unified_context_mode: - from astrbot.core.config.default import GLOBAL_UNIFIED_CONTEXT_UMO + from astrbot.core.config.default import ( + GLOBAL_UNIFIED_CONTEXT_UMO, + ORIGINAL_UMO_KEY, + ) original_umo = event.unified_msg_origin event.unified_msg_origin = GLOBAL_UNIFIED_CONTEXT_UMO # Store original UMO for reference in later stages - event.set_extra("original_umo", original_umo) + event.set_extra(ORIGINAL_UMO_KEY, original_umo) logger.debug( f"Global unified context mode enabled. Changed UMO from {original_umo} to {GLOBAL_UNIFIED_CONTEXT_UMO}" ) From 04b95d7bc152ed16f634a4e3ebf510929b538f39 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 17:07:59 +0000 Subject: [PATCH 6/6] style: update dark theme color scheme to match light theme Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com> --- dashboard/src/theme/DarkTheme.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dashboard/src/theme/DarkTheme.ts b/dashboard/src/theme/DarkTheme.ts index 177bee39c..ab9ae8737 100644 --- a/dashboard/src/theme/DarkTheme.ts +++ b/dashboard/src/theme/DarkTheme.ts @@ -4,12 +4,12 @@ const PurpleThemeDark: ThemeTypes = { name: 'PurpleThemeDark', dark: true, variables: { - 'border-color': '#1677ff', + 'border-color': '#3c96ca', 'carousel-control-size': 10 }, colors: { - primary: '#1677ff', - secondary: '#722ed1', + primary: '#3c96ca', + secondary: '#2288b7', info: '#03c9d7', success: '#52c41a', accent: '#FFAB91',