Wire NotificationBus into main and Gradio UI
Create NotificationBus in __main__.py and inject into scheduler and UI. Gradio subscribes as the "gradio" listener with a 10-second polling timer that displays notifications in a banner above the chatbot. ClickUp status shown in the header bar. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>cora-start
parent
a67e714045
commit
7864ca2461
|
|
@ -58,17 +58,26 @@ def main():
|
|||
except Exception as e:
|
||||
log.warning("Tool system not available: %s", e)
|
||||
|
||||
# Notification bus (UI-agnostic)
|
||||
notification_bus = None
|
||||
try:
|
||||
from .notifications import NotificationBus
|
||||
log.info("Initializing notification bus...")
|
||||
notification_bus = NotificationBus(db)
|
||||
except Exception as e:
|
||||
log.warning("Notification bus not available: %s", e)
|
||||
|
||||
# Phase 3+: Scheduler
|
||||
try:
|
||||
from .scheduler import Scheduler
|
||||
log.info("Starting scheduler...")
|
||||
scheduler = Scheduler(config, db, agent)
|
||||
scheduler = Scheduler(config, db, agent, notification_bus=notification_bus)
|
||||
scheduler.start()
|
||||
except Exception as e:
|
||||
log.warning("Scheduler not available: %s", e)
|
||||
|
||||
log.info("Launching Gradio UI on %s:%s...", config.host, config.port)
|
||||
app, css = create_ui(agent, config, llm)
|
||||
app, css = create_ui(agent, config, llm, notification_bus=notification_bus)
|
||||
app.launch(
|
||||
server_name=config.host,
|
||||
server_port=config.port,
|
||||
|
|
|
|||
|
|
@ -13,16 +13,26 @@ if TYPE_CHECKING:
|
|||
from .agent import Agent
|
||||
from .config import Config
|
||||
from .llm import LLMAdapter
|
||||
from .notifications import NotificationBus
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
_CSS = """
|
||||
.contain { max-width: 900px; margin: auto; }
|
||||
footer { display: none !important; }
|
||||
.notification-banner {
|
||||
background: #1a1a2e;
|
||||
border: 1px solid #16213e;
|
||||
border-radius: 8px;
|
||||
padding: 10px 16px;
|
||||
margin-bottom: 8px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def create_ui(agent: Agent, config: Config, llm: LLMAdapter) -> gr.Blocks:
|
||||
def create_ui(agent: Agent, config: Config, llm: LLMAdapter,
|
||||
notification_bus: NotificationBus | None = None) -> gr.Blocks:
|
||||
"""Build and return the Gradio app."""
|
||||
|
||||
available_models = llm.list_chat_models()
|
||||
|
|
@ -30,15 +40,24 @@ def create_ui(agent: Agent, config: Config, llm: LLMAdapter) -> gr.Blocks:
|
|||
current_model = llm.current_model
|
||||
|
||||
exec_status = "available" if llm.is_execution_brain_available() else "unavailable"
|
||||
clickup_status = "enabled" if config.clickup.enabled else "disabled"
|
||||
|
||||
with gr.Blocks(title="CheddahBot") as app:
|
||||
gr.Markdown("# CheddahBot", elem_classes=["contain"])
|
||||
gr.Markdown(
|
||||
f"*Chat Brain:* `{current_model}` | "
|
||||
f"*Execution Brain (Claude Code CLI):* `{exec_status}`",
|
||||
f"*Execution Brain (Claude Code CLI):* `{exec_status}` | "
|
||||
f"*ClickUp:* `{clickup_status}`",
|
||||
elem_classes=["contain"],
|
||||
)
|
||||
|
||||
# -- Notification banner --
|
||||
notification_display = gr.Markdown(
|
||||
value="",
|
||||
visible=False,
|
||||
elem_classes=["contain", "notification-banner"],
|
||||
)
|
||||
|
||||
with gr.Row(elem_classes=["contain"]):
|
||||
model_dropdown = gr.Dropdown(
|
||||
choices=model_choices,
|
||||
|
|
@ -191,6 +210,22 @@ def create_ui(agent: Agent, config: Config, llm: LLMAdapter) -> gr.Blocks:
|
|||
except Exception as e:
|
||||
return None, f"Voice chat error: {e}"
|
||||
|
||||
def poll_notifications():
|
||||
"""Poll the notification bus for pending messages."""
|
||||
if not notification_bus:
|
||||
return gr.update(value="", visible=False)
|
||||
|
||||
messages = notification_bus.get_pending("gradio")
|
||||
if not messages:
|
||||
return gr.update() # No change
|
||||
|
||||
# Format notifications as markdown
|
||||
lines = []
|
||||
for msg in messages[-5:]: # Show last 5 notifications max
|
||||
lines.append(f"**Notification:** {msg}")
|
||||
banner = "\n\n".join(lines)
|
||||
return gr.update(value=banner, visible=True)
|
||||
|
||||
# -- Wire events --
|
||||
|
||||
model_dropdown.change(on_model_change, [model_dropdown], None)
|
||||
|
|
@ -209,6 +244,12 @@ def create_ui(agent: Agent, config: Config, llm: LLMAdapter) -> gr.Blocks:
|
|||
[voice_output, voice_status],
|
||||
)
|
||||
|
||||
# Notification polling timer (every 10 seconds)
|
||||
if notification_bus:
|
||||
notification_bus.subscribe("gradio", lambda msg, cat: None) # Register listener
|
||||
timer = gr.Timer(10)
|
||||
timer.tick(poll_notifications, None, [notification_display])
|
||||
|
||||
# Load conversation list on app start
|
||||
app.load(_load_conversations, None, [conv_list])
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue