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 +14 -0
- geniusbot/documentation/README.md +1 -0
- geniusbot/geniusbot.py +605 -0
- geniusbot/img/geniusbot-small.png +0 -0
- geniusbot/img/geniusbot.ico +0 -0
- geniusbot/img/geniusbot.png +0 -0
- geniusbot/img/img_append.png +0 -0
- geniusbot/img/img_fulljoin.png +0 -0
- geniusbot/img/img_innerjoin.png +0 -0
- geniusbot/img/img_leftjoin.png +0 -0
- geniusbot/img/img_rightjoin.png +0 -0
- geniusbot/logger.py +105 -0
- geniusbot/plugins/__init__.py +1 -0
- geniusbot/qt/__init__.py +12 -0
- geniusbot/qt/colors.py +142 -0
- geniusbot/qt/finance_cockpit.py +586 -0
- geniusbot/qt/graph_explorer.py +224 -0
- geniusbot/qt/infra_cockpit.py +286 -0
- geniusbot/qt/scrollable_widget.py +59 -0
- geniusbot/qt/security_policy.py +213 -0
- geniusbot/qt/service_dashboard.py +400 -0
- geniusbot/qt/telemetry_dashboard.py +266 -0
- geniusbot/qt/terminal_widget.py +224 -0
- geniusbot/qt/tool_guard.py +143 -0
- geniusbot/qt/widget_mapper.py +244 -0
- geniusbot/qt/workflow_builder.py +230 -0
- geniusbot/services/__init__.py +1 -0
- geniusbot/services/backend_adapter.py +154 -0
- geniusbot/services/gateway_client.py +124 -0
- geniusbot/utils/__init__.py +5 -0
- geniusbot/utils/agent_bridge.py +80 -0
- geniusbot/utils/daemon.py +73 -0
- geniusbot/utils/utils.py +44 -0
- geniusbot-3.37.0.dist-info/METADATA +212 -0
- geniusbot-3.37.0.dist-info/RECORD +38 -0
- geniusbot-3.37.0.dist-info/WHEEL +4 -0
- geniusbot-3.37.0.dist-info/entry_points.txt +2 -0
- geniusbot-3.37.0.dist-info/licenses/LICENSE +20 -0
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
|