Deminiko commited on
Commit
89bf8af
·
1 Parent(s): 5dea71c
Files changed (3) hide show
  1. app.py +526 -72
  2. client/mcp_client.py +7 -4
  3. tasks-project-state.json +65 -116
app.py CHANGED
@@ -1,120 +1,574 @@
1
  """
2
  QAgents-Workflows: Hugging Face Space Entry Point
3
- Provides a Gradio interface for the Quantum Circuit Orchestrator.
 
 
 
 
 
 
 
4
  Reads all configuration from environment variables for HF Space deployment.
5
  """
6
 
7
  import os
8
  import gradio as gr
9
  import logging
 
 
 
10
  from config import LLMConfig
11
  from orchestrators import create_orchestrator
12
- from client.mcp_client import get_client
13
 
14
  # Configure logging
15
  logging.basicConfig(level=logging.INFO)
16
  logger = logging.getLogger(__name__)
17
 
 
 
 
 
 
 
18
  # Log environment configuration at startup
19
  logger.info("=" * 70)
20
  logger.info("QAgents Quantum Circuit Orchestrator - Initialization")
21
  logger.info("=" * 70)
22
  logger.info(f"LLM Provider: {os.getenv('LLM_PROVIDER', 'gemini (default)')}")
23
  logger.info(f"LLM Model: {os.getenv('LLM_MODEL', 'gemini-2.5-flash-lite (default)')}")
24
- logger.info(f"MCP Server URL: {os.getenv('MCP_SERVER_URL', 'http://127.0.0.1:7861 (default)')}")
25
  logger.info(f"Google API Key configured: {bool(os.getenv('GOOGLE_API_KEY') or os.getenv('GENAI_API_KEY'))}")
26
  logger.info("=" * 70)
27
 
28
- # Initialize MCP client (will use MCP_SERVER_URL env var if set)
29
- mcp_client = get_client()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
- def generate_circuit(prompt, mode, difficulty):
32
- """Generate a quantum circuit based on the prompt and mode."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  try:
34
- logger.info(f"Generating circuit: mode={mode}, difficulty={difficulty}")
35
- logger.info(f"Prompt: {prompt}")
36
 
37
- # Create orchestrator
38
- orch = create_orchestrator(mode.lower())
39
 
40
- # Run generation
41
- # Note: In a real deployment, we might want to map difficulty to specific constraints
42
- # For now, we pass the prompt directly
43
- result = orch.run(prompt)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  if result.success:
46
- output = f"✅ Success ({result.execution_time_ms:.0f}ms)\n\n"
47
  if result.final_output:
48
- output += result.final_output
 
 
 
 
49
  else:
50
- output += "No QASM generated."
51
-
52
- # Add metrics if available
53
- metrics = f"LLM Calls: {result.steps_completed}\n"
54
- if hasattr(result, 'tokens_used'):
55
- metrics += f"Tokens: {result.tokens_used}\n"
56
-
57
- return output, metrics
58
- else:
59
- error_msg = "\n".join(result.errors)
60
- return f"❌ Failed ({result.execution_time_ms:.0f}ms)\n\nErrors:\n{error_msg}", "N/A"
61
 
 
 
 
 
 
 
 
 
 
 
62
  except Exception as e:
63
- logger.error(f"Error generating circuit: {e}")
64
- return f"❌ System Error: {str(e)}", "Error"
 
 
65
 
66
- def check_mcp_status():
67
- """Check connection to MCP server."""
 
 
 
 
 
68
  try:
69
- is_healthy = mcp_client.health_check()
70
- status = "🟢 Connected" if is_healthy else "🔴 Disconnected"
71
- url = os.environ.get("MCP_SERVER_URL", "http://127.0.0.1:7861")
72
- return f"{status} ({url})"
 
 
 
 
 
73
  except Exception as e:
74
- return f"🔴 Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
- # Create Gradio Interface
77
- with gr.Blocks(title="Quantum Circuit Orchestrator") as demo:
78
- gr.Markdown("# ⚛️ QAgents: Quantum Circuit Orchestrator")
79
- gr.Markdown("Multi-agent system for generating optimized quantum circuits.")
 
 
 
 
80
 
81
- with gr.Row():
82
- with gr.Column(scale=2):
83
- prompt_input = gr.Textbox(
84
- label="Circuit Description",
85
- placeholder="e.g., Create a 3-qubit GHZ state",
86
- lines=3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  with gr.Row():
89
- mode_select = gr.Dropdown(
90
- choices=["naked", "quasar", "hybrid", "blackboard"],
91
- value="naked",
92
- label="Orchestration Mode"
93
- )
94
- difficulty_select = gr.Dropdown(
95
- choices=["EASY", "MEDIUM", "HARD", "VERY_HARD"],
96
- value="EASY",
97
- label="Estimated Difficulty"
 
 
 
 
98
  )
 
99
 
100
- generate_btn = gr.Button("Generate Circuit", variant="primary")
101
 
102
- with gr.Column(scale=1):
103
- mcp_status = gr.Textbox(label="MCP Server Status", value="⏳ Initializing...", interactive=False)
104
- metrics_output = gr.Textbox(label="Execution Metrics", lines=4)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
- with gr.Row():
107
- qasm_output = gr.Code(label="Generated QASM", language="python", lines=15)
108
-
109
- # Event handlers
110
- generate_btn.click(
111
- fn=generate_circuit,
112
- inputs=[prompt_input, mode_select, difficulty_select],
113
- outputs=[qasm_output, metrics_output]
114
  )
115
-
116
- # Refresh status on load
117
- demo.load(fn=check_mcp_status, outputs=[mcp_status])
118
 
 
119
  if __name__ == "__main__":
120
- demo.launch()
 
 
 
 
 
1
  """
2
  QAgents-Workflows: Hugging Face Space Entry Point
3
+ Path: QAgents-workflows/app.py
4
+ Related: client/mcp_client.py (MCP connection), orchestrators/ (agent orchestration)
5
+
6
+ Provides a Gradio interface with:
7
+ - Chat UI for interacting with quantum circuit agents
8
+ - MCP Endpoints health monitoring tab
9
+ - Circuit generation and validation tools
10
+
11
  Reads all configuration from environment variables for HF Space deployment.
12
  """
13
 
14
  import os
15
  import gradio as gr
16
  import logging
17
+ import requests
18
+ import time
19
+ from typing import Optional, List, Tuple
20
  from config import LLMConfig
21
  from orchestrators import create_orchestrator
22
+ from client.mcp_client import get_client, MCPClient
23
 
24
  # Configure logging
25
  logging.basicConfig(level=logging.INFO)
26
  logger = logging.getLogger(__name__)
27
 
28
+ # MCP Server URL for QuantumArchitect-MCP on HuggingFace
29
+ MCP_SERVER_URL = os.environ.get(
30
+ "MCP_SERVER_URL",
31
+ "https://mcp-1st-birthday-quantumarchitect-mcp.hf.space"
32
+ )
33
+
34
  # Log environment configuration at startup
35
  logger.info("=" * 70)
36
  logger.info("QAgents Quantum Circuit Orchestrator - Initialization")
37
  logger.info("=" * 70)
38
  logger.info(f"LLM Provider: {os.getenv('LLM_PROVIDER', 'gemini (default)')}")
39
  logger.info(f"LLM Model: {os.getenv('LLM_MODEL', 'gemini-2.5-flash-lite (default)')}")
40
+ logger.info(f"MCP Server URL: {MCP_SERVER_URL}")
41
  logger.info(f"Google API Key configured: {bool(os.getenv('GOOGLE_API_KEY') or os.getenv('GENAI_API_KEY'))}")
42
  logger.info("=" * 70)
43
 
44
+ # Initialize MCP client
45
+ mcp_client = get_client(MCP_SERVER_URL)
46
+
47
+ # =============================================================================
48
+ # MCP ENDPOINTS DEFINITIONS
49
+ # =============================================================================
50
+
51
+ MCP_ENDPOINTS = [
52
+ {"name": "create_circuit", "category": "Creation", "description": "Create circuit from template"},
53
+ {"name": "parse_qasm", "category": "Creation", "description": "Parse OpenQASM code"},
54
+ {"name": "build_circuit", "category": "Creation", "description": "Build custom circuit from gates"},
55
+ {"name": "validate_circuit", "category": "Validation", "description": "Full circuit validation"},
56
+ {"name": "check_hardware", "category": "Validation", "description": "Hardware compatibility check"},
57
+ {"name": "simulate", "category": "Simulation", "description": "Simulate with measurements"},
58
+ {"name": "get_statevector", "category": "Simulation", "description": "Extract statevector"},
59
+ {"name": "estimate_fidelity", "category": "Simulation", "description": "Hardware fidelity estimation"},
60
+ {"name": "score_circuit", "category": "Scoring", "description": "Circuit scoring metrics"},
61
+ {"name": "compare_circuits", "category": "Scoring", "description": "Compare multiple circuits"},
62
+ {"name": "get_gate_info", "category": "Documentation", "description": "Gate documentation"},
63
+ {"name": "get_algorithm_info", "category": "Documentation", "description": "Algorithm documentation"},
64
+ {"name": "list_hardware", "category": "Documentation", "description": "Available hardware profiles"},
65
+ {"name": "list_templates", "category": "Documentation", "description": "Available circuit templates"},
66
+ ]
67
+
68
+ # =============================================================================
69
+ # CHAT FUNCTIONALITY
70
+ # =============================================================================
71
+
72
+ def format_circuit_response(result) -> str:
73
+ """Format circuit generation result for chat display."""
74
+ if result.success:
75
+ output = f"✅ **Circuit Generated Successfully** ({result.execution_time_ms:.0f}ms)\n\n"
76
+ if result.final_output:
77
+ output += f"```qasm\n{result.final_output}\n```\n"
78
+ if hasattr(result, 'metrics') and result.metrics:
79
+ output += f"\n**Metrics:** {result.metrics}"
80
+ return output
81
+ else:
82
+ error_msg = "\n".join(result.errors) if hasattr(result, 'errors') else str(result)
83
+ return f"❌ **Generation Failed**\n\n{error_msg}"
84
 
85
+
86
+ def chat_with_agent(
87
+ message: str,
88
+ history: List[Tuple[str, str]],
89
+ mode: str,
90
+ difficulty: str
91
+ ) -> Tuple[str, List[Tuple[str, str]]]:
92
+ """
93
+ Process user message and generate response from quantum circuit agent.
94
+
95
+ Args:
96
+ message: User's input message
97
+ history: Chat history [(user_msg, bot_msg), ...]
98
+ mode: Orchestration mode (naked, quasar, hybrid, blackboard)
99
+ difficulty: Problem difficulty level
100
+
101
+ Returns:
102
+ Tuple of (bot_response, updated_history)
103
+ """
104
  try:
105
+ logger.info(f"Chat: mode={mode}, difficulty={difficulty}")
106
+ logger.info(f"User message: {message}")
107
 
108
+ # Check for special commands
109
+ message_lower = message.lower().strip()
110
 
111
+ # Help command
112
+ if message_lower in ['help', '/help', '?']:
113
+ response = """## 🤖 QAgents Help
114
+
115
+ I can help you with quantum circuits! Try asking me to:
116
+
117
+ **Create Circuits:**
118
+ - "Create a Bell state"
119
+ - "Generate a 3-qubit GHZ state"
120
+ - "Make a QFT circuit for 4 qubits"
121
+ - "Build a Grover search circuit"
122
+
123
+ **Analyze Circuits:**
124
+ - Paste QASM code and ask "validate this circuit"
125
+ - "Score this circuit for IBM hardware"
126
+
127
+ **Learn:**
128
+ - "Explain the Hadamard gate"
129
+ - "How does quantum entanglement work?"
130
+
131
+ **Settings:**
132
+ - Use the dropdowns to change orchestration mode and difficulty
133
+ - `naked`: Direct LLM + MCP tools
134
+ - `quasar`: Structured workflow with validation
135
+ - `hybrid`: Combined approach
136
+ - `blackboard`: Multi-agent collaboration
137
+
138
+ 💡 **Tip:** Start with simple requests and increase complexity!
139
+ """
140
+ history.append((message, response))
141
+ return response, history
142
+
143
+ # Status command
144
+ if message_lower in ['status', '/status']:
145
+ mcp_status = check_mcp_health()
146
+ response = f"## 📊 System Status\n\n{mcp_status}"
147
+ history.append((message, response))
148
+ return response, history
149
+
150
+ # Generate circuit using orchestrator
151
+ orch = create_orchestrator(mode.lower())
152
+ result = orch.run(message)
153
 
154
  if result.success:
155
+ response = f"✅ **Success** ({result.execution_time_ms:.0f}ms)\n\n"
156
  if result.final_output:
157
+ # Check if output looks like QASM
158
+ if 'OPENQASM' in str(result.final_output) or 'qreg' in str(result.final_output):
159
+ response += f"```qasm\n{result.final_output}\n```"
160
+ else:
161
+ response += result.final_output
162
  else:
163
+ response += "Circuit generated but no QASM output available."
 
 
 
 
 
 
 
 
 
 
164
 
165
+ # Add step info if available
166
+ if result.steps_completed > 0:
167
+ response += f"\n\n*Completed {result.steps_completed} steps*"
168
+ else:
169
+ error_msg = "\n".join(result.errors) if result.errors else "Unknown error"
170
+ response = f"❌ **Failed** ({result.execution_time_ms:.0f}ms)\n\n{error_msg}"
171
+
172
+ history.append((message, response))
173
+ return response, history
174
+
175
  except Exception as e:
176
+ logger.error(f"Chat error: {e}")
177
+ error_response = f"❌ **System Error**\n\n{str(e)}"
178
+ history.append((message, error_response))
179
+ return error_response, history
180
 
181
+
182
+ # =============================================================================
183
+ # MCP HEALTH CHECK FUNCTIONS
184
+ # =============================================================================
185
+
186
+ def check_mcp_health() -> str:
187
+ """Check overall MCP server health."""
188
  try:
189
+ response = requests.head(f"{MCP_SERVER_URL}/", timeout=10)
190
+ if response.status_code == 200:
191
+ return f"🟢 **Connected** to `{MCP_SERVER_URL}`"
192
+ else:
193
+ return f"🟡 **Partial** - Status {response.status_code}"
194
+ except requests.exceptions.Timeout:
195
+ return f"🟠 **Timeout** - Server slow to respond"
196
+ except requests.exceptions.ConnectionError:
197
+ return f"🔴 **Disconnected** - Cannot reach server"
198
  except Exception as e:
199
+ return f"🔴 **Error**: {str(e)}"
200
+
201
+
202
+ def check_endpoint_health(endpoint_name: str) -> dict:
203
+ """Check health of a specific MCP endpoint."""
204
+ start = time.perf_counter()
205
+ try:
206
+ # Try to call the Gradio API endpoint
207
+ url = f"{MCP_SERVER_URL}/gradio_api/call/ui_{endpoint_name}"
208
+ response = requests.post(
209
+ url,
210
+ json={"data": []},
211
+ timeout=15
212
+ )
213
+ elapsed = (time.perf_counter() - start) * 1000
214
+
215
+ if response.status_code == 200:
216
+ return {"status": "🟢", "latency_ms": round(elapsed, 1), "error": None}
217
+ elif response.status_code == 404:
218
+ return {"status": "🟡", "latency_ms": round(elapsed, 1), "error": "Not found"}
219
+ else:
220
+ return {"status": "🟠", "latency_ms": round(elapsed, 1), "error": f"HTTP {response.status_code}"}
221
+ except requests.exceptions.Timeout:
222
+ return {"status": "🟠", "latency_ms": 15000, "error": "Timeout"}
223
+ except Exception as e:
224
+ elapsed = (time.perf_counter() - start) * 1000
225
+ return {"status": "🔴", "latency_ms": round(elapsed, 1), "error": str(e)[:50]}
226
+
227
+
228
+ def get_all_endpoints_health() -> str:
229
+ """Get health status of all MCP endpoints as formatted markdown."""
230
+ output_lines = [
231
+ "## 🔗 MCP Endpoints Health Check",
232
+ f"**Server:** `{MCP_SERVER_URL}`\n",
233
+ "| Endpoint | Category | Status | Latency | Error |",
234
+ "|----------|----------|--------|---------|-------|"
235
+ ]
236
+
237
+ # Check server first
238
+ server_status = check_mcp_health()
239
+
240
+ for endpoint in MCP_ENDPOINTS:
241
+ health = check_endpoint_health(endpoint["name"])
242
+ error_str = health["error"] or "-"
243
+ output_lines.append(
244
+ f"| `{endpoint['name']}` | {endpoint['category']} | {health['status']} | {health['latency_ms']}ms | {error_str} |"
245
+ )
246
+
247
+ output_lines.append(f"\n**Last checked:** {time.strftime('%Y-%m-%d %H:%M:%S UTC')}")
248
+ output_lines.append(f"\n**Server Status:** {server_status}")
249
+
250
+ return "\n".join(output_lines)
251
+
252
+
253
+ def refresh_health_check():
254
+ """Refresh the health check display."""
255
+ return get_all_endpoints_health()
256
+
257
+
258
+ def check_single_endpoint(endpoint_name: str) -> str:
259
+ """Check a single endpoint and return formatted result."""
260
+ if not endpoint_name:
261
+ return "Please select an endpoint to check."
262
+
263
+ health = check_endpoint_health(endpoint_name)
264
+
265
+ output = f"## Endpoint: `{endpoint_name}`\n\n"
266
+ output += f"- **Status:** {health['status']}\n"
267
+ output += f"- **Latency:** {health['latency_ms']}ms\n"
268
+ if health['error']:
269
+ output += f"- **Error:** {health['error']}\n"
270
+ output += f"\n*Checked at {time.strftime('%H:%M:%S')}*"
271
+
272
+ return output
273
+
274
+
275
+ # =============================================================================
276
+ # GRADIO INTERFACE
277
+ # =============================================================================
278
+
279
+ # Custom CSS for better chat appearance
280
+ CUSTOM_CSS = """
281
+ .chat-container {
282
+ max-height: 600px;
283
+ overflow-y: auto;
284
+ }
285
+ .status-panel {
286
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
287
+ border-radius: 10px;
288
+ padding: 15px;
289
+ }
290
+ """
291
 
292
+ with gr.Blocks(
293
+ title="QAgents - Quantum Circuit Assistant",
294
+ theme=gr.themes.Soft(
295
+ primary_hue="blue",
296
+ secondary_hue="purple",
297
+ ),
298
+ css=CUSTOM_CSS
299
+ ) as demo:
300
 
301
+ # Header
302
+ gr.Markdown("""
303
+ # ⚛️ QAgents: Quantum Circuit Assistant
304
+
305
+ Multi-agent system for generating optimized quantum circuits using MCP tools.
306
+
307
+ **Connected to:** [QuantumArchitect-MCP](https://huggingface.co/spaces/MCP-1st-Birthday/QuantumArchitect-MCP) on HuggingFace
308
+ """)
309
+
310
+ with gr.Tabs():
311
+ # =================================================================
312
+ # TAB 1: CHAT INTERFACE
313
+ # =================================================================
314
+ with gr.TabItem("💬 Chat", id="chat-tab"):
315
+ with gr.Row():
316
+ with gr.Column(scale=3):
317
+ chatbot = gr.Chatbot(
318
+ label="Quantum Circuit Agent",
319
+ height=500,
320
+ show_label=True,
321
+ avatar_images=(None, "https://em-content.zobj.net/source/twitter/376/atom-symbol_269b.png"),
322
+ bubble_full_width=False,
323
+ )
324
+
325
+ with gr.Row():
326
+ msg_input = gr.Textbox(
327
+ label="Your Message",
328
+ placeholder="Ask me to create a quantum circuit... (e.g., 'Create a Bell state')",
329
+ lines=2,
330
+ scale=4,
331
+ )
332
+ send_btn = gr.Button("Send 🚀", variant="primary", scale=1)
333
+
334
+ with gr.Row():
335
+ clear_btn = gr.Button("🗑️ Clear Chat", size="sm")
336
+ help_btn = gr.Button("❓ Help", size="sm")
337
+ status_btn = gr.Button("📊 Status", size="sm")
338
+
339
+ with gr.Column(scale=1):
340
+ gr.Markdown("### ⚙️ Settings")
341
+
342
+ mode_select = gr.Dropdown(
343
+ choices=["naked", "quasar", "hybrid", "blackboard"],
344
+ value="naked",
345
+ label="Orchestration Mode",
346
+ info="How agents collaborate"
347
+ )
348
+
349
+ difficulty_select = gr.Dropdown(
350
+ choices=["EASY", "MEDIUM", "HARD", "VERY_HARD"],
351
+ value="EASY",
352
+ label="Complexity Level",
353
+ info="Expected circuit complexity"
354
+ )
355
+
356
+ gr.Markdown("---")
357
+ gr.Markdown("### 📡 Quick Status")
358
+ mcp_status_display = gr.Markdown(value="⏳ Checking...")
359
+ refresh_btn = gr.Button("🔄 Refresh", size="sm")
360
+
361
+ # Chat event handlers
362
+ def user_submit(message, history, mode, difficulty):
363
+ if not message.strip():
364
+ return "", history
365
+ response, new_history = chat_with_agent(message, history, mode, difficulty)
366
+ return "", new_history
367
+
368
+ send_btn.click(
369
+ fn=user_submit,
370
+ inputs=[msg_input, chatbot, mode_select, difficulty_select],
371
+ outputs=[msg_input, chatbot]
372
+ )
373
+
374
+ msg_input.submit(
375
+ fn=user_submit,
376
+ inputs=[msg_input, chatbot, mode_select, difficulty_select],
377
+ outputs=[msg_input, chatbot]
378
+ )
379
+
380
+ clear_btn.click(
381
+ fn=lambda: [],
382
+ outputs=[chatbot]
383
+ )
384
+
385
+ help_btn.click(
386
+ fn=lambda h: chat_with_agent("help", h, "naked", "EASY"),
387
+ inputs=[chatbot],
388
+ outputs=[msg_input, chatbot]
389
  )
390
+
391
+ status_btn.click(
392
+ fn=lambda h: chat_with_agent("status", h, "naked", "EASY"),
393
+ inputs=[chatbot],
394
+ outputs=[msg_input, chatbot]
395
+ )
396
+
397
+ refresh_btn.click(
398
+ fn=check_mcp_health,
399
+ outputs=[mcp_status_display]
400
+ )
401
+
402
+ # =================================================================
403
+ # TAB 2: MCP ENDPOINTS HEALTH
404
+ # =================================================================
405
+ with gr.TabItem("🔗 MCP Endpoints", id="mcp-tab"):
406
+ gr.Markdown("""
407
+ ## 🔗 MCP Endpoints Health Monitor
408
+
409
+ Monitor the health and availability of QuantumArchitect-MCP endpoints.
410
+
411
+ **MCP Server:** [QuantumArchitect-MCP](https://huggingface.co/spaces/MCP-1st-Birthday/QuantumArchitect-MCP)
412
+ """)
413
+
414
  with gr.Row():
415
+ check_all_btn = gr.Button("🔄 Check All Endpoints", variant="primary")
416
+
417
+ health_display = gr.Markdown(value="Click 'Check All Endpoints' to start health check...")
418
+
419
+ gr.Markdown("---")
420
+ gr.Markdown("### 🔍 Check Single Endpoint")
421
+
422
+ with gr.Row():
423
+ endpoint_dropdown = gr.Dropdown(
424
+ choices=[ep["name"] for ep in MCP_ENDPOINTS],
425
+ label="Select Endpoint",
426
+ value=None,
427
+ scale=3
428
  )
429
+ check_single_btn = gr.Button("Check", scale=1)
430
 
431
+ single_result = gr.Markdown(value="")
432
 
433
+ gr.Markdown("---")
434
+ gr.Markdown("""
435
+ ### 📚 Available MCP Endpoints
436
+
437
+ | Category | Endpoints |
438
+ |----------|-----------|
439
+ | **Creation** | `create_circuit`, `parse_qasm`, `build_circuit` |
440
+ | **Validation** | `validate_circuit`, `check_hardware` |
441
+ | **Simulation** | `simulate`, `get_statevector`, `estimate_fidelity` |
442
+ | **Scoring** | `score_circuit`, `compare_circuits` |
443
+ | **Documentation** | `get_gate_info`, `get_algorithm_info`, `list_hardware`, `list_templates` |
444
+
445
+ All endpoints accept JSON and return JSON via the Gradio MCP protocol.
446
+ """)
447
+
448
+ # Event handlers
449
+ check_all_btn.click(
450
+ fn=refresh_health_check,
451
+ outputs=[health_display]
452
+ )
453
+
454
+ check_single_btn.click(
455
+ fn=check_single_endpoint,
456
+ inputs=[endpoint_dropdown],
457
+ outputs=[single_result]
458
+ )
459
+
460
+ # =================================================================
461
+ # TAB 3: QUICK CIRCUIT BUILDER
462
+ # =================================================================
463
+ with gr.TabItem("🛠️ Quick Build", id="build-tab"):
464
+ gr.Markdown("""
465
+ ## 🛠️ Quick Circuit Builder
466
+
467
+ Generate circuits directly from templates without chat.
468
+ """)
469
+
470
+ with gr.Row():
471
+ with gr.Column():
472
+ template_select = gr.Dropdown(
473
+ choices=["bell_state", "ghz_state", "qft", "grover", "vqe", "superposition"],
474
+ value="bell_state",
475
+ label="Circuit Template"
476
+ )
477
+ qubits_slider = gr.Slider(
478
+ minimum=2,
479
+ maximum=10,
480
+ value=2,
481
+ step=1,
482
+ label="Number of Qubits"
483
+ )
484
+ build_btn = gr.Button("⚡ Generate Circuit", variant="primary")
485
+
486
+ with gr.Column():
487
+ qasm_output = gr.Code(
488
+ label="Generated QASM",
489
+ language="python",
490
+ lines=15
491
+ )
492
+
493
+ def quick_build(template, num_qubits):
494
+ try:
495
+ result = mcp_client.create_circuit_from_template(template, int(num_qubits))
496
+ if result.success and result.data:
497
+ if isinstance(result.data, dict) and 'qasm' in result.data:
498
+ return result.data['qasm']
499
+ return str(result.data)
500
+ return f"# Error: {result.error or 'Unknown error'}"
501
+ except Exception as e:
502
+ return f"# Error: {str(e)}"
503
+
504
+ build_btn.click(
505
+ fn=quick_build,
506
+ inputs=[template_select, qubits_slider],
507
+ outputs=[qasm_output]
508
+ )
509
+
510
+ # =================================================================
511
+ # TAB 4: ABOUT
512
+ # =================================================================
513
+ with gr.TabItem("ℹ️ About", id="about-tab"):
514
+ gr.Markdown("""
515
+ ## ℹ️ About QAgents
516
+
517
+ **QAgents** is a multi-agent system for quantum circuit generation and optimization.
518
+
519
+ ### 🏗️ Architecture
520
+
521
+ ```
522
+ ┌─────────────────────────────────────────────┐
523
+ │ QAgents-Workflows │
524
+ │ (This App - Agent Orchestration) │
525
+ ├─────────────────────────────────────────────┤
526
+ │ • Chat Interface │
527
+ │ • Multi-mode Orchestrators │
528
+ │ • LLM Integration (Gemini/LiteLLM) │
529
+ └─────────────────┬───────────────────────────┘
530
+ │ MCP Protocol
531
+
532
+ ┌─────────────────────────────────────────────┐
533
+ │ QuantumArchitect-MCP │
534
+ │ (HuggingFace Space - Circuit Tools) │
535
+ ├─────────────────────────────────────────────┤
536
+ │ ��� Circuit Creation & Templates │
537
+ │ • Validation & Syntax Checking │
538
+ │ • Simulation & Statevectors │
539
+ │ • Scoring & Hardware Fitness │
540
+ └─────────────────────────────────────────────┘
541
+ ```
542
+
543
+ ### 🤖 Orchestration Modes
544
+
545
+ | Mode | Description | Best For |
546
+ |------|-------------|----------|
547
+ | **naked** | Direct LLM + MCP tools | Simple queries |
548
+ | **quasar** | Structured workflow | Complex circuits |
549
+ | **hybrid** | Adaptive approach | General use |
550
+ | **blackboard** | Multi-agent collab | Hard problems |
551
+
552
+ ### 🔗 Links
553
+
554
+ - [QuantumArchitect-MCP](https://huggingface.co/spaces/MCP-1st-Birthday/QuantumArchitect-MCP)
555
+ - [QAgents Source](https://github.com/NLarchive/QAgents-workflows)
556
+
557
+ ### 📝 License
558
+
559
+ MIT License - Feel free to use and modify!
560
+ """)
561
 
562
+ # Load initial status on app start
563
+ demo.load(
564
+ fn=check_mcp_health,
565
+ outputs=[mcp_status_display]
 
 
 
 
566
  )
 
 
 
567
 
568
+ # Launch configuration for HuggingFace Spaces
569
  if __name__ == "__main__":
570
+ demo.launch(
571
+ server_name="0.0.0.0",
572
+ show_error=True,
573
+ mcp_server=True,
574
+ )
client/mcp_client.py CHANGED
@@ -684,15 +684,18 @@ _client: Optional[MCPClient] = None
684
  def get_client(base_url: Optional[str] = None) -> MCPClient:
685
  """
686
  Get or create the MCP client singleton.
687
-
688
  Args:
689
  base_url: Optional URL override. If None, checks MCP_SERVER_URL env var,
690
- then defaults to http://127.0.0.1:7861
691
  """
692
  global _client
693
  if _client is None:
694
  if base_url is None:
695
  import os
696
- base_url = os.environ.get("MCP_SERVER_URL", "http://127.0.0.1:7861")
 
 
 
697
  _client = MCPClient(base_url)
698
- return _client
 
684
  def get_client(base_url: Optional[str] = None) -> MCPClient:
685
  """
686
  Get or create the MCP client singleton.
687
+
688
  Args:
689
  base_url: Optional URL override. If None, checks MCP_SERVER_URL env var,
690
+ then defaults to the HuggingFace Space URL
691
  """
692
  global _client
693
  if _client is None:
694
  if base_url is None:
695
  import os
696
+ base_url = os.environ.get(
697
+ "MCP_SERVER_URL",
698
+ "https://mcp-1st-birthday-quantumarchitect-mcp.hf.space"
699
+ )
700
  _client = MCPClient(base_url)
701
+ return _client
tasks-project-state.json CHANGED
@@ -1,80 +1,67 @@
1
  {
2
  "project": "QAgents-Workflows",
3
- "version": "0.8.0",
4
- "description": "Multi-agent quantum circuit optimization system with multi-model fallback",
5
- "last_updated": "2024-11-28",
6
- "status": "BLACKBOARD_FIXED_QUASAR_ADDED",
7
- "notes": "Fixed BLACKBOARD NoneType errors. Added QUASAR orchestrator with tiered verification. Added VERY_HARD problems. Mini test shows NAKED 3.3s and BLACKBOARD 15s both pass EASY.",
8
 
9
- "comprehensive_test_results": {
10
- "test_date": "2024-11-29",
11
- "previous_results": {
12
- "naked": {"success": "9/9 (100%)", "avg_time_ms": 3929},
13
- "guided": {"success": "7/9 (78%)", "avg_time_ms": 23120},
14
- "blackboard": {"success": "2/9 (22%)", "avg_time_ms": 13507}
15
- },
16
- "latest_test_20241129": {
17
- "problem": "HARD - Deutsch Algorithm",
18
- "naked": {"success": true, "time_ms": 3914, "gates": 5},
19
- "quasar": {"success": true, "time_ms": 7254, "gates": 5},
20
- "hybrid": {"success": true, "time_ms": 7181, "gates": 5},
21
- "blackboard": {"success": true, "time_ms": 20915, "gates": 2},
22
- "result": "ALL 4 MODES PASSED"
23
- },
24
- "very_hard_test": {
25
- "problem": "VERY_HARD - 4-Qubit QFT",
26
- "naked": {"success": true, "time_ms": 4473, "gates": 12},
27
- "quasar": {"success": true, "time_ms": 7811, "gates": 12},
28
- "hybrid": "interrupted - rate limiting",
29
- "blackboard": "interrupted - rate limiting"
30
- }
31
  },
32
 
33
- "fixes_applied_20241128": {
34
- "blackboard_null_safety": {
35
- "file": "orchestrators/orchestrator.py",
36
- "changes": ["Added try/except in agent execution loop", "Added null-checking for action and result"]
 
 
 
 
 
37
  },
38
- "llm_adapter_null_safety": {
39
- "file": "agents/llm_adapter.py",
40
- "changes": ["Fixed response.text None handling", "Fixed _estimate_tokens with null-safe len()"]
41
- }
42
- },
43
-
44
- "new_orchestrators": {
45
- "quasar": {
46
- "file": "orchestrators/quasar_orchestrator.py",
47
- "description": "Tiered verification orchestrator (QUASAR-lite)",
48
- "tiers": [
49
- "Tier 1: Syntax validation via MCP",
50
- "Tier 2: Circuit analysis (depth, gates)",
51
- "Tier 3: Simulation verification",
52
- "Tier 4: Semantic correctness"
53
  ]
54
  },
55
- "hybrid": {
56
- "description": "NAKED first, QUASAR fallback on failure"
 
57
  }
58
  },
59
 
60
- "new_problems": {
61
- "very_hard_difficulty": [
62
- "4-Qubit QFT",
63
- "5-Qubit Entanglement Chain",
64
- "Simon's Algorithm (2-bit)",
65
- "Quantum Adder (1+1=10)"
66
- ]
67
- },
 
 
 
 
 
 
 
 
68
 
69
- "model_cascade": {
70
- "preferred_model": "gemini-2.5-flash-lite",
71
- "models": [
72
- {"name": "gemma-3-27b-it", "rpd": 14400, "priority": 1},
73
- {"name": "gemini-2.5-flash-lite", "rpd": 1000, "priority": 2, "default": true},
74
- {"name": "gemini-2.5-flash", "rpd": 250, "priority": 3},
75
- {"name": "gemini-2.0-flash", "rpd": 200, "priority": 4},
76
- {"name": "gemini-2.5-pro", "rpd": 50, "priority": 5}
77
- ]
78
  },
79
 
80
  "architectures": {
@@ -84,66 +71,28 @@
84
  "success_rate": "100%",
85
  "recommended": true
86
  },
87
- "guided": {
88
- "description": "4-agent pipeline (Analyzer, Designer, Generator, Validator)",
89
- "status": "DEPRECATED",
90
- "success_rate": "78%",
91
- "note": "Replaced by QUASAR"
92
- },
93
- "blackboard": {
94
- "description": "Event-driven multi-agent blackboard",
95
- "status": "FIXED",
96
- "success_rate": "~100% (needs full retest)",
97
- "note": "NoneType errors fixed, ~5x slower than NAKED"
98
- },
99
  "quasar": {
100
  "description": "Tiered verification with MCP tools",
101
- "status": "NEW",
102
- "file": "orchestrators/quasar_orchestrator.py"
103
  },
104
  "hybrid": {
105
  "description": "NAKED first, QUASAR fallback",
106
- "status": "NEW"
 
 
 
 
107
  }
108
  },
109
 
110
- "new_files_created": [
111
- {"file": "prompts/optimized_prompts.py", "purpose": "Enhanced prompts for NAKED mode"},
112
- {"file": "orchestrators/router.py", "purpose": "Difficulty-aware orchestrator selection"},
113
- {"file": "tests/comprehensive_test.py", "purpose": "Full diagnostic test script"},
114
- {"file": "docs/COMPREHENSIVE_TEST_ANALYSIS.md", "purpose": "Analysis of all test results"},
115
- {"file": "docs/STRATEGIC_IMPROVEMENTS.md", "purpose": "Improvement roadmap based on findings"},
116
- {"file": "docs/PROJECT_ANALYSIS_20251128.md", "purpose": "Deep project analysis"}
117
- ],
118
-
119
- "recommendations": {
120
- "immediate": [
121
- "Adopt NAKED mode for production - 100% success, fastest, most efficient",
122
- "Fix BLACKBOARD null-checking or deprecate entirely",
123
- "Integrate optimized_prompts.py into NAKED orchestrator"
124
- ],
125
- "short_term": [
126
- "Add circuit quality scoring beyond gate count",
127
- "Improve GUIDED generator for hard problems",
128
- "Implement hybrid: NAKED first, GUIDED on failure"
129
- ],
130
- "long_term": [
131
- "Auto-select mode based on problem difficulty",
132
- "MCP validation integration for correctness verification",
133
- "Cost-aware orchestrator selection"
134
- ]
135
- },
136
-
137
  "usage": {
138
- "prerequisites": [
139
- "Start MCP server: python QuantumArchitect-MCP/app.py",
140
- "Set GOOGLE_API_KEY environment variable",
141
- "Activate venv: & .venv/Scripts/Activate.ps1"
142
- ],
143
- "commands": {
144
- "comprehensive_test": "python tests/comprehensive_test.py",
145
- "quality_eval": "python tests/run_quality_eval.py --mode all --difficulty all",
146
- "quick_test": "python tests/run_quality_eval.py --quick"
147
  }
148
  }
149
  }
 
1
  {
2
  "project": "QAgents-Workflows",
3
+ "version": "0.9.0",
4
+ "description": "Multi-agent quantum circuit optimization system with chat UI and MCP integration",
5
+ "last_updated": "2024-11-30",
6
+ "status": "CHAT_UI_AND_MCP_HEALTH_MONITOR_ADDED",
7
+ "notes": "Added Gradio chat interface for agent interaction. Added MCP endpoints health monitor tab. Updated MCP client to connect to HuggingFace Space.",
8
 
9
+ "huggingface_deployment": {
10
+ "qagents_space": "https://huggingface.co/spaces/NLarchive/Qagents-workflows",
11
+ "mcp_server_space": "https://mcp-1st-birthday-quantumarchitect-mcp.hf.space",
12
+ "gradio_version": "6.0.0",
13
+ "mcp_enabled": true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  },
15
 
16
+ "app_features": {
17
+ "chat_tab": {
18
+ "description": "Interactive chat UI for quantum circuit generation",
19
+ "features": [
20
+ "Natural language circuit requests",
21
+ "Multiple orchestration modes (naked, quasar, hybrid, blackboard)",
22
+ "Difficulty level selection",
23
+ "Help and status commands"
24
+ ]
25
  },
26
+ "mcp_endpoints_tab": {
27
+ "description": "Health monitor for QuantumArchitect-MCP endpoints",
28
+ "features": [
29
+ "Check all endpoints health",
30
+ "Individual endpoint testing",
31
+ "Latency monitoring",
32
+ "Status indicators (🟢🟡🟠🔴)"
 
 
 
 
 
 
 
 
33
  ]
34
  },
35
+ "quick_build_tab": {
36
+ "description": "Direct circuit template generation",
37
+ "templates": ["bell_state", "ghz_state", "qft", "grover", "vqe", "superposition"]
38
  }
39
  },
40
 
41
+ "mcp_endpoints": [
42
+ {"name": "create_circuit", "category": "Creation"},
43
+ {"name": "parse_qasm", "category": "Creation"},
44
+ {"name": "build_circuit", "category": "Creation"},
45
+ {"name": "validate_circuit", "category": "Validation"},
46
+ {"name": "check_hardware", "category": "Validation"},
47
+ {"name": "simulate", "category": "Simulation"},
48
+ {"name": "get_statevector", "category": "Simulation"},
49
+ {"name": "estimate_fidelity", "category": "Simulation"},
50
+ {"name": "score_circuit", "category": "Scoring"},
51
+ {"name": "compare_circuits", "category": "Scoring"},
52
+ {"name": "get_gate_info", "category": "Documentation"},
53
+ {"name": "get_algorithm_info", "category": "Documentation"},
54
+ {"name": "list_hardware", "category": "Documentation"},
55
+ {"name": "list_templates", "category": "Documentation"}
56
+ ],
57
 
58
+ "comprehensive_test_results": {
59
+ "test_date": "2024-11-29",
60
+ "previous_results": {
61
+ "naked": {"success": "9/9 (100%)", "avg_time_ms": 3929},
62
+ "guided": {"success": "7/9 (78%)", "avg_time_ms": 23120},
63
+ "blackboard": {"success": "2/9 (22%)", "avg_time_ms": 13507}
64
+ }
 
 
65
  },
66
 
67
  "architectures": {
 
71
  "success_rate": "100%",
72
  "recommended": true
73
  },
 
 
 
 
 
 
 
 
 
 
 
 
74
  "quasar": {
75
  "description": "Tiered verification with MCP tools",
76
+ "status": "STABLE"
 
77
  },
78
  "hybrid": {
79
  "description": "NAKED first, QUASAR fallback",
80
+ "status": "STABLE"
81
+ },
82
+ "blackboard": {
83
+ "description": "Event-driven multi-agent blackboard",
84
+ "status": "FIXED"
85
  }
86
  },
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  "usage": {
89
+ "huggingface": "Visit https://huggingface.co/spaces/NLarchive/Qagents-workflows",
90
+ "local": {
91
+ "prerequisites": [
92
+ "Activate venv: & .venv/Scripts/Activate.ps1",
93
+ "Set GOOGLE_API_KEY environment variable"
94
+ ],
95
+ "run": "python app.py"
 
 
96
  }
97
  }
98
  }