fix:Telegram channel start failed #133 (#134)

* fix:Telegram channel start failed #133

* refactor: simplify bus thread and add nest_asyncio warning

- Remove unnecessary _run_as_task() wrapper; run_until_complete()
  already creates a Task internally via ensure_future()
- Add comment noting nest_asyncio.apply() is global and irreversible

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Xi Zhang <zacharyzhang2022@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Xi Zhang <106144707+X-iZhang@users.noreply.github.com>
This commit is contained in:
Allen
2026-04-03 15:47:15 +02:00
committed by GitHub
parent 5aa8353613
commit d08ca535c6
4 changed files with 38 additions and 13 deletions
+10 -1
View File
@@ -757,7 +757,16 @@ class ChannelManager:
"""Start the HTTP health-check endpoint (if configured)."""
if self._health_port and self._health_server is None:
self._health_server = _HealthServer(self, self._health_port)
await self._health_server.start()
try:
await self._health_server.start()
except OSError as e:
logger.warning(
"Health server failed to bind on port %s: %s — "
"health endpoint disabled, channel will still start normally.",
self._health_port,
e,
)
self._health_server = None
async def stop_health(self) -> None:
"""Stop the HTTP health-check endpoint."""
+4 -1
View File
@@ -445,8 +445,11 @@ def _start_channels_bus_mode(
try:
loop.run_until_complete(_run())
except Exception as e:
_channel_logger.error(f"Bus thread error: {e}")
_channel_logger.error(
"Bus thread terminated with error: %s", e, exc_info=True
)
finally:
_channel_logger.debug("Bus thread event loop closed")
loop.close()
thread = threading.Thread(target=_bus_thread_entry, daemon=True)
-4
View File
@@ -504,10 +504,6 @@ def serve(
Starts all configured channels and processes messages via the agent.
Press Ctrl+C to shut down.
"""
import nest_asyncio # type: ignore[import-untyped]
nest_asyncio.apply()
from ..config import apply_config_to_env, get_effective_config
cli_overrides = {}
+24 -7
View File
@@ -1068,10 +1068,6 @@ def _run_streaming(
Returns:
The final response text.
"""
import nest_asyncio
nest_asyncio.apply()
state = _state if _state is not None else StreamState()
_thinking_sent = False
_todo_sent = False
@@ -1180,11 +1176,32 @@ def _run_streaming(
vertical_overflow="visible",
) as live:
live.update(create_streaming_display(is_waiting=True))
# Determine how to run the async streaming coroutine.
# - In TUI mode (Textual), there's already a running event loop;
# nest_asyncio is needed to allow run_until_complete inside it.
# - In serve/CLI mode, the main thread has no running loop;
# use a fresh event loop directly (no nest_asyncio needed or wanted,
# since nest_asyncio.apply() patches globally and breaks the bus
# thread's event loop Task-context detection).
try:
loop = _get_event_loop()
running_loop = asyncio.get_running_loop()
except RuntimeError:
# No current event loop
loop = _create_event_loop()
running_loop = None
if running_loop is not None:
# Already inside a running loop (TUI) — must use nest_asyncio.
# NOTE: nest_asyncio.apply() is global and irreversible within
# the process; avoid mixing TUI and serve modes in one process.
import nest_asyncio # type: ignore[import-untyped]
nest_asyncio.apply()
loop = running_loop
else:
# No running loop (serve/CLI) — create a fresh one
try:
loop = _get_event_loop()
except RuntimeError:
loop = _create_event_loop()
async def _run_with_refresh() -> None:
async def _periodic_refresh() -> None: