* 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:
@@ -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."""
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 = {}
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user