geniusbot 3.37.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
geniusbot/__init__.py ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env python
2
+ from geniusbot.geniusbot import GeniusBot, geniusbot
3
+
4
+ """
5
+ geniusbot
6
+
7
+ The unified cockpit dashboard for our multi-agent ecosystem.
8
+ """
9
+
10
+ __version__ = "3.37.0"
11
+ __author__ = "Audel Rouhi"
12
+ __credits__ = "Audel Rouhi"
13
+
14
+ __all__ = ["geniusbot", "GeniusBot"]
@@ -0,0 +1 @@
1
+ # All plugin documentation will be downloaded here
geniusbot/geniusbot.py ADDED
@@ -0,0 +1,605 @@
1
+ #!/usr/bin/env python3
2
+ import logging
3
+ import os
4
+ import sys
5
+ import warnings
6
+
7
+ from PySide6.QtCore import QObject, Qt, QTimer, Signal, Slot
8
+ from PySide6.QtWidgets import (
9
+ QApplication,
10
+ QCompleter,
11
+ QFrame,
12
+ QHBoxLayout,
13
+ QLabel,
14
+ QLineEdit,
15
+ QMainWindow,
16
+ QPushButton,
17
+ QScrollArea,
18
+ QSplitter,
19
+ QStackedWidget,
20
+ QSystemTrayIcon,
21
+ QTextEdit,
22
+ QVBoxLayout,
23
+ QWidget,
24
+ )
25
+
26
+ # Suppress annoying library warnings
27
+ warnings.filterwarnings("ignore", message="Couldn't find ffmpeg or avconv.*")
28
+
29
+ # Append directories for local execution
30
+ sys.path.append(os.path.dirname(__file__))
31
+
32
+ # Local imports
33
+ from geniusbot.qt.colors import BG_SECONDARY, BORDER_COLOR, DARK_COCKPIT_STYLE
34
+ from geniusbot.qt.terminal_widget import TerminalWidget
35
+ from geniusbot.qt.widget_mapper import WidgetSchemaMapper
36
+ from geniusbot.services.gateway_client import GatewayClient
37
+ from geniusbot.utils.agent_bridge import AgentBridgeWorker
38
+ from geniusbot.utils.daemon import GeniusBotDaemon
39
+
40
+ __version__ = "6.0.0"
41
+
42
+
43
+ # Resolve centralized log directory via the single backend seam
44
+ from geniusbot.services.backend_adapter import backend
45
+
46
+ geniusbot_log_dir = backend.resolve_log_dir()
47
+ geniusbot_log_dir.mkdir(parents=True, exist_ok=True)
48
+ geniusbot_log_path = geniusbot_log_dir / "geniusbot.log"
49
+
50
+ logger = logging.getLogger("geniusbot")
51
+ logger.setLevel(logging.DEBUG)
52
+ formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
53
+ fh = logging.FileHandler(geniusbot_log_path)
54
+ fh.setLevel(logging.DEBUG)
55
+ fh.setFormatter(formatter)
56
+ logger.addHandler(fh)
57
+
58
+
59
+ class OutputWrapper(QObject):
60
+ """Bridge standard output streams into Qt Signals thread-safely."""
61
+
62
+ outputWritten = Signal(str, bool)
63
+
64
+ def __init__(self, parent, stdout=True):
65
+ super().__init__(parent)
66
+ self._stdout = stdout
67
+ if stdout:
68
+ self._stream = sys.stdout
69
+ sys.stdout = self
70
+ else:
71
+ self._stream = sys.stderr
72
+ sys.stderr = self
73
+
74
+ def write(self, text):
75
+ self._stream.write(text)
76
+ self.outputWritten.emit(text, self._stdout)
77
+
78
+ def __getattr__(self, name):
79
+ return getattr(self._stream, name)
80
+
81
+ def __del__(self):
82
+ try:
83
+ if self._stdout:
84
+ sys.stdout = self._stream
85
+ else:
86
+ sys.stderr = self._stream
87
+ except AttributeError:
88
+ pass
89
+
90
+
91
+ class GeniusBot(QMainWindow):
92
+ """
93
+ CONCEPT:GBOT-6.0
94
+ GeniusBot Cockpit Dashboard Window.
95
+ """
96
+
97
+ def __init__(self, parent=None):
98
+ super().__init__(parent)
99
+ self.worker = AgentBridgeWorker()
100
+ self.daemon = GeniusBotDaemon(self)
101
+ self.gateway = GatewayClient()
102
+ self.discovered_specialists = []
103
+ self.active_agent_card = None
104
+
105
+ self.initialize_user_interface()
106
+ self.setup_tray_daemon()
107
+
108
+ # Asynchronously load specialists from Knowledge Graph after application startup
109
+ QTimer.singleShot(100, self.async_load_specialists)
110
+
111
+ def initialize_user_interface(self):
112
+ """
113
+ CONCEPT:GBOT-6.0
114
+ Initialize the main user interface components.
115
+ Refactored to orchestrate sub-components.
116
+ """
117
+ self.setWindowTitle("GeniusBot Multi-Agent Cockpit")
118
+ self.resize(1200, 800)
119
+ self.setStyleSheet(DARK_COCKPIT_STYLE)
120
+
121
+ self.centralSplitter = QSplitter(Qt.Horizontal)
122
+
123
+ self._setup_sidebar()
124
+ self._setup_central_pane()
125
+ self._setup_detail_drawer()
126
+ self._setup_console_wrapper()
127
+
128
+ def _setup_sidebar(self):
129
+ """
130
+ CONCEPT:GBOT-6.0
131
+ Setup the left navigation sidebar.
132
+ """
133
+ self.sidebar = QFrame()
134
+ self.sidebar.setObjectName("Sidebar")
135
+ self.sidebar.setMinimumWidth(180)
136
+ self.sidebar.setMaximumWidth(220)
137
+ sidebar_layout = QVBoxLayout(self.sidebar)
138
+ sidebar_layout.setContentsMargins(10, 20, 10, 20)
139
+ sidebar_layout.setSpacing(12)
140
+
141
+ # Sidebar Title
142
+ title_label = QLabel("๐Ÿš€ GENIUSBOT")
143
+ title_label.setStyleSheet(
144
+ "font-size: 18px; font-weight: bold; color: #7C4DFF; padding-left: 10px; margin-bottom: 10px;"
145
+ )
146
+ sidebar_layout.addWidget(title_label)
147
+
148
+ # Navigation buttons
149
+ self.btn_deck = QPushButton("๐ŸŒŒ Specialist Deck")
150
+ self.btn_deck.clicked.connect(lambda: self.switch_view(0))
151
+ sidebar_layout.addWidget(self.btn_deck)
152
+
153
+ self.btn_term = QPushButton("๐Ÿ–ฅ๏ธ CLI Terminal")
154
+ self.btn_term.clicked.connect(lambda: self.switch_view(1))
155
+ sidebar_layout.addWidget(self.btn_term)
156
+
157
+ self.btn_chat = QPushButton("๐Ÿ’ฌ Copilot Chat")
158
+ self.btn_chat.clicked.connect(lambda: self.switch_view(2))
159
+ sidebar_layout.addWidget(self.btn_chat)
160
+
161
+ # Cockpit Controls Header
162
+ cockpit_header = QLabel("๐ŸŽ›๏ธ COCKPIT CONTROLS")
163
+ cockpit_header.setStyleSheet(
164
+ "font-size: 10px; font-weight: bold; color: #8A8A93; padding-left: 10px; margin-top: 15px; margin-bottom: 5px;"
165
+ )
166
+ sidebar_layout.addWidget(cockpit_header)
167
+
168
+ self.btn_graph = QPushButton("๐ŸŒŒ Graph Explorer")
169
+ self.btn_graph.clicked.connect(lambda: self.switch_view(3))
170
+ sidebar_layout.addWidget(self.btn_graph)
171
+
172
+ self.btn_telemetry = QPushButton("๐Ÿ“ˆ Live Telemetry")
173
+ self.btn_telemetry.clicked.connect(lambda: self.switch_view(4))
174
+ sidebar_layout.addWidget(self.btn_telemetry)
175
+
176
+ self.btn_workflow = QPushButton("โ›“๏ธ Swarm Builder")
177
+ self.btn_workflow.clicked.connect(lambda: self.switch_view(5))
178
+ sidebar_layout.addWidget(self.btn_workflow)
179
+
180
+ self.btn_security = QPushButton("๐Ÿ›ก๏ธ Security Policies")
181
+ self.btn_security.clicked.connect(lambda: self.switch_view(6))
182
+ sidebar_layout.addWidget(self.btn_security)
183
+
184
+ self.btn_infra = QPushButton("๐Ÿฅ Infrastructure")
185
+ self.btn_infra.clicked.connect(lambda: self.switch_view(7))
186
+ sidebar_layout.addWidget(self.btn_infra)
187
+
188
+ self.btn_finance = QPushButton("๐Ÿ“Š Trading Cockpit")
189
+ self.btn_finance.clicked.connect(lambda: self.switch_view(8))
190
+ sidebar_layout.addWidget(self.btn_finance)
191
+
192
+ self.btn_dashboard = QPushButton("๐Ÿ  Service Dashboard")
193
+ self.btn_dashboard.clicked.connect(lambda: self.switch_view(9))
194
+ sidebar_layout.addWidget(self.btn_dashboard)
195
+
196
+ sidebar_layout.addStretch()
197
+
198
+ # Sidebar footer status
199
+ self.lbl_status = QLabel("System Ready")
200
+ self.lbl_status.setStyleSheet(
201
+ "color: #8A8A93; font-size: 11px; padding-left: 10px;"
202
+ )
203
+ sidebar_layout.addWidget(self.lbl_status)
204
+ self.centralSplitter.addWidget(self.sidebar)
205
+
206
+ def _setup_central_pane(self):
207
+ """
208
+ CONCEPT:GBOT-6.0
209
+ Setup the main central content stacked widget.
210
+ """
211
+ self.centralStackWidget = QStackedWidget()
212
+
213
+ # View 0: Agent Deck (Scroll Area)
214
+ self.deck_scroll = QScrollArea()
215
+ self.deck_scroll.setWidgetResizable(True)
216
+ self.deck_scroll.setStyleSheet(
217
+ "QScrollArea { border: none; background: transparent; }"
218
+ )
219
+ self.deck_container = QWidget()
220
+ self.deck_layout = QVBoxLayout(self.deck_container)
221
+ self.deck_layout.setSpacing(16)
222
+ self.deck_layout.setContentsMargins(20, 20, 20, 20)
223
+ self.deck_scroll.setWidget(self.deck_container)
224
+ self.centralStackWidget.addWidget(self.deck_scroll)
225
+
226
+ # View 1: xterm.js Terminal
227
+ self.term_widget = TerminalWidget()
228
+ self.centralStackWidget.addWidget(self.term_widget)
229
+
230
+ # View 2: Copilot Chat
231
+ self._setup_copilot_chat()
232
+
233
+ # View 3-9: Lazy-loaded panel placeholders
234
+ self.graph_panel = None
235
+ self.telemetry_panel = None
236
+ self.workflow_panel = None
237
+ self.security_panel = None
238
+ self.infra_panel = None
239
+ self.finance_panel = None
240
+ self.dashboard_panel = None
241
+
242
+ for _ in range(7):
243
+ self.centralStackWidget.addWidget(QWidget())
244
+
245
+ self.centralSplitter.addWidget(self.centralStackWidget)
246
+
247
+ def _setup_copilot_chat(self):
248
+ """
249
+ CONCEPT:GBOT-6.0
250
+ Setup the Copilot chat pane inside the central stack.
251
+ """
252
+ self.chat_container = QWidget()
253
+ chat_layout = QVBoxLayout(self.chat_container)
254
+ chat_layout.setContentsMargins(20, 20, 20, 20)
255
+ chat_layout.setSpacing(12)
256
+
257
+ self.chat_log = QTextEdit()
258
+ self.chat_log.setReadOnly(True)
259
+ self.chat_log.setStyleSheet(
260
+ f"background-color: #121214; border: 1px solid {BORDER_COLOR}; border-radius: 6px; padding: 10px;"
261
+ )
262
+ chat_layout.addWidget(self.chat_log)
263
+
264
+ input_row = QHBoxLayout()
265
+ self.chat_input = QLineEdit()
266
+ self.chat_input.setPlaceholderText("Ask the master agent anything...")
267
+ self.chat_input.returnPressed.connect(self.send_chat_message)
268
+
269
+ # Native Autocomplete Completer
270
+ self.completer = QCompleter([], self)
271
+ self.completer.setCaseSensitivity(Qt.CaseInsensitive)
272
+ self.completer.setFilterMode(Qt.MatchStartsWith)
273
+ self.completer.setCompletionMode(QCompleter.PopupCompletion)
274
+ self.chat_input.setCompleter(self.completer)
275
+ self.chat_input.textChanged.connect(self.handle_input_text_changed)
276
+
277
+ input_row.addWidget(self.chat_input)
278
+
279
+ self.btn_send = QPushButton("Send")
280
+ self.btn_send.clicked.connect(self.send_chat_message)
281
+ input_row.addWidget(self.btn_send)
282
+ chat_layout.addLayout(input_row)
283
+
284
+ self.centralStackWidget.addWidget(self.chat_container)
285
+
286
+ def _setup_detail_drawer(self):
287
+ """
288
+ CONCEPT:GBOT-6.0
289
+ Setup the right slide-out telemetry detail drawer.
290
+ """
291
+ self.detail_drawer = QFrame()
292
+ self.detail_drawer.setStyleSheet(
293
+ f"background-color: {BG_SECONDARY}; border-left: 1px solid {BORDER_COLOR};"
294
+ )
295
+ self.detail_drawer.setMinimumWidth(320)
296
+ self.detail_drawer.setMaximumWidth(400)
297
+
298
+ drawer_layout = QVBoxLayout(self.detail_drawer)
299
+ drawer_layout.setContentsMargins(15, 20, 15, 20)
300
+ drawer_layout.setSpacing(12)
301
+
302
+ drawer_title = QLabel("๐Ÿ”ฎ TELEMETRY & LOGS")
303
+ drawer_title.setStyleSheet(
304
+ "font-size: 14px; font-weight: bold; color: #7C4DFF;"
305
+ )
306
+ drawer_layout.addWidget(drawer_title)
307
+
308
+ drawer_layout.addWidget(QLabel("Telemetry / Diagnostics Info:"))
309
+ self.telemetry_log = QTextEdit()
310
+ self.telemetry_log.setReadOnly(True)
311
+ self.telemetry_log.setStyleSheet(
312
+ "background-color: #121214; border-radius: 6px; font-family: monospace; font-size: 11px;"
313
+ )
314
+ drawer_layout.addWidget(self.telemetry_log)
315
+
316
+ drawer_layout.addWidget(QLabel("Live Execution Graph Flow:"))
317
+ self.graph_display = QLabel("No active execution diagram.")
318
+ self.graph_display.setWordWrap(True)
319
+ self.graph_display.setStyleSheet(
320
+ f"background-color: #121214; border: 1px solid {BORDER_COLOR}; border-radius: 6px; padding: 10px; font-family: monospace; font-size: 11px;"
321
+ )
322
+ drawer_layout.addWidget(self.graph_display)
323
+
324
+ self.centralSplitter.addWidget(self.detail_drawer)
325
+
326
+ def _setup_console_wrapper(self):
327
+ """
328
+ CONCEPT:GBOT-6.0
329
+ Setup the bottom global terminal logger.
330
+ """
331
+ # Splitter sizing ratio: 15% sidebar, 50% central view, 35% right drawer
332
+ self.centralSplitter.setSizes([180, 600, 360])
333
+
334
+ self.console = QTextEdit()
335
+ self.console.setReadOnly(True)
336
+ self.console.setMaximumHeight(150)
337
+ self.console.setStyleSheet(
338
+ "background-color: #0b0b0d; color: #8A8A93; border: none; font-family: monospace; font-size: 11px;"
339
+ )
340
+
341
+ self.stdout_wrapper = OutputWrapper(self, True)
342
+ self.stdout_wrapper.outputWritten.connect(self.log_to_console)
343
+ self.stderr_wrapper = OutputWrapper(self, False)
344
+ self.stderr_wrapper.outputWritten.connect(self.log_to_console)
345
+
346
+ main_layout = QVBoxLayout()
347
+ main_layout.addWidget(self.centralSplitter)
348
+ main_layout.addWidget(self.console)
349
+ main_layout.setContentsMargins(0, 0, 0, 0)
350
+ main_layout.setSpacing(0)
351
+
352
+ container = QWidget()
353
+ container.setLayout(main_layout)
354
+ self.setCentralWidget(container)
355
+
356
+ def _swap_placeholder(self, index: int, new_widget: QWidget):
357
+ placeholder = self.centralStackWidget.widget(index)
358
+ self.centralStackWidget.removeWidget(placeholder)
359
+ placeholder.deleteLater()
360
+ self.centralStackWidget.insertWidget(index, new_widget)
361
+
362
+ def switch_view(self, index: int):
363
+ if index == 3 and self.graph_panel is None:
364
+ from geniusbot.qt.graph_explorer import GraphExplorerPanel
365
+
366
+ self.graph_panel = GraphExplorerPanel(self.worker)
367
+ self._swap_placeholder(3, self.graph_panel)
368
+ elif index == 4 and self.telemetry_panel is None:
369
+ from geniusbot.qt.telemetry_dashboard import TelemetryDashboardPanel
370
+
371
+ self.telemetry_panel = TelemetryDashboardPanel(self.worker)
372
+ self._swap_placeholder(4, self.telemetry_panel)
373
+ elif index == 5 and self.workflow_panel is None:
374
+ from geniusbot.qt.workflow_builder import WorkflowBuilderPanel
375
+
376
+ self.workflow_panel = WorkflowBuilderPanel(self.worker)
377
+ self._swap_placeholder(5, self.workflow_panel)
378
+ elif index == 6 and self.security_panel is None:
379
+ from geniusbot.qt.security_policy import SecurityPolicyPanel
380
+
381
+ self.security_panel = SecurityPolicyPanel(self.worker)
382
+ self._swap_placeholder(6, self.security_panel)
383
+ elif index == 7 and self.infra_panel is None:
384
+ from geniusbot.qt.infra_cockpit import InfrastructureCockpitPanel
385
+
386
+ self.infra_panel = InfrastructureCockpitPanel(self.worker)
387
+ self._swap_placeholder(7, self.infra_panel)
388
+ elif index == 8 and self.finance_panel is None:
389
+ from geniusbot.qt.finance_cockpit import FinanceCockpitPanel
390
+
391
+ self.finance_panel = FinanceCockpitPanel(self.worker)
392
+ self._swap_placeholder(8, self.finance_panel)
393
+ elif index == 9 and self.dashboard_panel is None:
394
+ from geniusbot.qt.service_dashboard import ServiceDashboardPanel
395
+
396
+ self.dashboard_panel = ServiceDashboardPanel(self.worker)
397
+ self._swap_placeholder(9, self.dashboard_panel)
398
+
399
+ self.centralStackWidget.setCurrentIndex(index)
400
+
401
+ # Style active sidebar button
402
+ buttons = [
403
+ (0, self.btn_deck),
404
+ (1, self.btn_term),
405
+ (2, self.btn_chat),
406
+ (3, self.btn_graph),
407
+ (4, self.btn_telemetry),
408
+ (5, self.btn_workflow),
409
+ (6, self.btn_security),
410
+ (7, self.btn_infra),
411
+ (8, self.btn_finance),
412
+ (9, self.btn_dashboard),
413
+ ]
414
+
415
+ for idx, btn in buttons:
416
+ btn.setStyleSheet(
417
+ "background-color: transparent; border: none;" if index != idx else ""
418
+ )
419
+
420
+ if index == 1 and not self.term_widget.fd:
421
+ self.term_widget.start_shell("agent-terminal-ui")
422
+
423
+ def setup_tray_daemon(self):
424
+ """Bind Daemon trays and system states."""
425
+ self.daemon.show_requested.connect(self.showNormal)
426
+ self.daemon.terminal_requested.connect(
427
+ lambda: (self.showNormal(), self.switch_view(1))
428
+ )
429
+ self.daemon.health_check_requested.connect(self.run_health_check)
430
+ self.daemon.exit_requested.connect(self.close)
431
+ self.daemon.start()
432
+
433
+ def async_load_specialists(self):
434
+ """
435
+ CONCEPT:GBOT-6.0
436
+ Asynchronously load all specialists from the Knowledge Graph via the Gateway.
437
+ """
438
+ self.lbl_status.setText("Connecting Graph...")
439
+
440
+ async def fetch(progress_cb=None):
441
+ return await self.gateway.fetch_specialists()
442
+
443
+ def on_finished(specs):
444
+ self.discovered_specialists = specs
445
+ self.lbl_status.setText(f"{len(specs)} specialists loaded.")
446
+ self.populate_specialist_deck()
447
+
448
+ def on_error(err):
449
+ logger.error(f"Discovery failed: {err}")
450
+ self.lbl_status.setText("Graph offline.")
451
+
452
+ self.worker.run_agent_task(fetch, on_finished=on_finished, on_error=on_error)
453
+
454
+ def populate_specialist_deck(self):
455
+ """Add discovered specialists control widgets into the scrolling deck layout."""
456
+ for i in reversed(range(self.deck_layout.count())):
457
+ widget = self.deck_layout.itemAt(i).widget()
458
+ if widget:
459
+ widget.setParent(None)
460
+
461
+ cards = WidgetSchemaMapper.build_deck(
462
+ self.discovered_specialists, self.worker, self
463
+ )
464
+ for card in cards:
465
+ card.execution_started.connect(self.on_agent_started)
466
+ card.execution_finished.connect(self.on_agent_finished)
467
+ card.execution_failed.connect(self.on_agent_failed)
468
+ self.deck_layout.addWidget(card)
469
+
470
+ self.deck_layout.addStretch()
471
+
472
+ def on_agent_started(self, agent_name):
473
+ self.lbl_status.setText(f"Running {agent_name}...")
474
+ self.telemetry_log.append(f"โฑ๏ธ Spawning {agent_name} Specialist...")
475
+
476
+ def on_agent_finished(self, agent_name, result):
477
+ self.lbl_status.setText(f"{agent_name} Complete.")
478
+ self.telemetry_log.append(f"โœ… {agent_name} Completed execution.\n")
479
+ result_text = result.get("result", str(result))
480
+ self.telemetry_log.append(f"Output:\n{result_text}\n")
481
+ mermaid = result.get("mermaid")
482
+ if mermaid:
483
+ self.graph_display.setText(mermaid)
484
+
485
+ def on_agent_failed(self, agent_name, error_trace):
486
+ self.lbl_status.setText(f"{agent_name} Failed!")
487
+ self.telemetry_log.append(f"โŒ {agent_name} Crashed:\n{error_trace}\n")
488
+
489
+ def run_health_check(self):
490
+ """Run health check against the centralized Gateway."""
491
+ self.telemetry_log.append("๐Ÿฅ Initiating Engine Diagnostics...")
492
+ self.lbl_status.setText("Health checking...")
493
+
494
+ async def verify(progress_cb=None):
495
+ return await self.gateway.run_health_check()
496
+
497
+ self.worker.run_agent_task(
498
+ verify,
499
+ on_finished=lambda res: self.telemetry_log.append(
500
+ f"Diagnostics:\n{res.get('result')}\n"
501
+ ),
502
+ on_error=lambda err: self.telemetry_log.append(
503
+ f"Health check failed:\n{err}\n"
504
+ ),
505
+ )
506
+
507
+ def handle_input_text_changed(self, text):
508
+ """Asynchronously fetch autocomplete suggestions and populate QCompleter."""
509
+ if text.startswith("/"):
510
+
511
+ async def fetch_suggestions(progress_cb=None):
512
+ return await self.gateway.fetch_autocomplete_suggestions(text)
513
+
514
+ def on_finished(suggestions):
515
+ if suggestions:
516
+ from PySide6.QtCore import QStringListModel
517
+
518
+ model = QStringListModel(suggestions, self.completer)
519
+ self.completer.setModel(model)
520
+ self.completer.complete()
521
+
522
+ self.worker.run_agent_task(fetch_suggestions, on_finished=on_finished)
523
+
524
+ def send_chat_message(self):
525
+ """
526
+ CONCEPT:GBOT-6.0
527
+ Execute master copilot query with prompt injection scan and secure guard confirmations.
528
+ """
529
+ query = self.chat_input.text().strip()
530
+ if not query:
531
+ return
532
+
533
+ self.chat_input.clear()
534
+ self.chat_log.append(f"\n๐Ÿ‘ค You: {query}")
535
+
536
+ self._execute_copilot_request(query)
537
+
538
+ def _execute_copilot_request(self, query: str):
539
+ """
540
+ CONCEPT:GBOT-6.0
541
+ Internal async handler to route the copilot request to the gateway.
542
+ """
543
+
544
+ async def ask_copilot(progress_cb=None):
545
+ if query.startswith("/"):
546
+ return await self.gateway.execute_slash_command(query)
547
+ return await self.gateway.stream_copilot_query(query, progress_cb)
548
+
549
+ def on_done(res):
550
+ ans = res.get("result", str(res))
551
+ self.chat_log.append(f"๐Ÿค– Copilot: {ans}")
552
+ if res.get("mermaid"):
553
+ self.graph_display.setText(res.get("mermaid"))
554
+
555
+ for action_dict in res.get("client_actions", []):
556
+ if action_dict.get("action") == "clear_chat":
557
+ self.chat_log.clear()
558
+ self.chat_log.append("๐Ÿงน Chat log cleared via slash command.")
559
+
560
+ def on_fail(err):
561
+ self.chat_log.append(f"โŒ Error: {err}")
562
+
563
+ def on_progress(msg):
564
+ self.telemetry_log.append(msg)
565
+ self.lbl_status.setText("Agent thinking...")
566
+
567
+ self.worker.run_agent_task(
568
+ ask_copilot, on_finished=on_done, on_error=on_fail, on_progress=on_progress
569
+ )
570
+
571
+ @Slot(str, bool)
572
+ def log_to_console(self, text, is_stdout=True):
573
+ self.console.moveCursor(self.console.textCursor().End)
574
+ self.console.insertPlainText(text)
575
+
576
+ def closeEvent(self, event):
577
+ """Minimize window to tray instead of quitting."""
578
+ if self.daemon.tray_icon.isVisible():
579
+ self.hide()
580
+ self.daemon.tray_icon.showMessage(
581
+ "GeniusBot Cockpit",
582
+ "Application is still running in background tray.",
583
+ QSystemTrayIcon.Information,
584
+ 2000,
585
+ )
586
+ event.ignore()
587
+ else:
588
+ self.daemon.stop()
589
+ event.accept()
590
+
591
+
592
+ def geniusbot():
593
+ app = QApplication(sys.argv)
594
+ app.setQuitOnLastWindowClosed(False)
595
+ bot_window = GeniusBot()
596
+ bot_window.show()
597
+ sys.exit(app.exec())
598
+
599
+
600
+ def main():
601
+ geniusbot()
602
+
603
+
604
+ if __name__ == "__main__":
605
+ geniusbot()
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file