Deminiko commited on
Commit
b86397a
·
1 Parent(s): 07a35f8
.gitignore CHANGED
@@ -25,9 +25,9 @@ wheels/
25
  venv/
26
  ENV/
27
  env/
28
-
29
- # Environment Variables
30
- .env # Actual secrets - never commit
31
  # .env.example IS committed as a template - do not exclude it
32
 
33
  # Database and Logs
 
25
  venv/
26
  ENV/
27
  env/
28
+
29
+ # Environment Variables # Actual secrets - never commit
30
+ .env
31
  # .env.example IS committed as a template - do not exclude it
32
 
33
  # Database and Logs
agents/base_agent.py CHANGED
@@ -145,10 +145,21 @@ class LLMAgent(BaseAgent):
145
  from config import config
146
  from agents.llm_adapter import get_llm_adapter
147
 
 
 
 
 
 
 
 
 
 
 
 
148
  self._adapter = get_llm_adapter(
149
  provider=config.llm.provider,
150
  model=config.llm.model,
151
- api_key=config.llm.api_key
152
  )
153
  return self._adapter
154
 
 
145
  from config import config
146
  from agents.llm_adapter import get_llm_adapter
147
 
148
+ # Get API key dynamically (supports HF Spaces Secrets)
149
+ api_key = config.llm.get_api_key()
150
+
151
+ if not api_key:
152
+ raise ValueError(
153
+ "Missing API key! To use the Google AI API, provide api_key via:\n"
154
+ " 1. GOOGLE_API_KEY environment variable (HF Spaces Secrets)\n"
155
+ " 2. GENAI_API_KEY environment variable (fallback)\n"
156
+ " 3. Set in .env file (local development)"
157
+ )
158
+
159
  self._adapter = get_llm_adapter(
160
  provider=config.llm.provider,
161
  model=config.llm.model,
162
+ api_key=api_key
163
  )
164
  return self._adapter
165
 
app.py CHANGED
@@ -20,6 +20,13 @@ import requests
20
  import time
21
  from typing import Optional, List, Dict, Any
22
 
 
 
 
 
 
 
 
23
  # Note: Gradio 6.0 doesn't support custom CSS in gr.Blocks()
24
  # UI styles module available but not used in this version
25
 
@@ -221,6 +228,32 @@ def quick_build_circuit(template: str, num_qubits: int) -> str:
221
  except Exception as e:
222
  logger.error(f"Quick build error: {e}")
223
  return f"# Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  # =============================================================================
225
  # GRADIO INTERFACE
226
  # =============================================================================
@@ -235,22 +268,137 @@ with gr.Blocks(title="QAgents - Quantum Circuit Assistant") as demo:
235
  """)
236
 
237
  with gr.Tabs():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  # =================================================================
239
  # TAB 1: CHAT INTERFACE
240
  # =================================================================
241
  with gr.TabItem("💬 Chat"):
242
- gr.Markdown("### Chat with Quantum Circuit Agent")
243
- gr.Markdown("Ask me to create quantum circuits! Try: *'Create a Bell state'* or *'Generate a 3-qubit GHZ state'*")
244
 
245
  chatbot = gr.Chatbot(
246
  value=[],
247
- height=400,
248
  label="Quantum Circuit Agent"
249
  )
250
 
251
  with gr.Row():
252
  msg_input = gr.Textbox(
253
- placeholder="Ask me to create a quantum circuit...",
254
  label="Your Message",
255
  scale=4,
256
  lines=1
@@ -262,6 +410,22 @@ with gr.Blocks(title="QAgents - Quantum Circuit Assistant") as demo:
262
  help_btn = gr.Button("❓ Help", size="sm")
263
  status_btn = gr.Button("📊 Status", size="sm")
264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  # Chat handlers
266
  def respond(message: str, chat_history: List):
267
  if not message.strip():
@@ -284,11 +448,28 @@ with gr.Blocks(title="QAgents - Quantum Circuit Assistant") as demo:
284
  chat_history.append({"role": "assistant", "content": status_text})
285
  return chat_history
286
 
 
 
 
 
 
 
 
287
  send_btn.click(respond, [msg_input, chatbot], [msg_input, chatbot])
288
  msg_input.submit(respond, [msg_input, chatbot], [msg_input, chatbot])
289
  clear_btn.click(lambda: [], outputs=[chatbot])
290
  help_btn.click(show_help, [chatbot], [chatbot])
291
  status_btn.click(show_status, [chatbot], [chatbot])
 
 
 
 
 
 
 
 
 
 
292
 
293
  # =================================================================
294
  # TAB 2: MCP ENDPOINTS HEALTH
@@ -364,29 +545,87 @@ with gr.Blocks(title="QAgents - Quantum Circuit Assistant") as demo:
364
  build_btn.click(quick_build_circuit, [template_select, qubits_slider], [qasm_output])
365
 
366
  # =================================================================
367
- # TAB 4: ABOUT
368
  # =================================================================
369
  with gr.TabItem("ℹ️ About"):
370
  gr.Markdown("""
371
- ## ℹ️ About QAgents
372
-
373
- **QAgents** is a multi-agent system for quantum circuit generation.
374
-
375
- ### 🏗️ How it Works
376
-
377
- 1. **You ask** for a quantum circuit in natural language
378
- 2. **NAKED mode** uses an LLM to generate OpenQASM code directly
379
- 3. **MCP tools** validate and simulate your circuits
380
-
381
- ### 🔗 Architecture
382
-
383
- - **Frontend**: This Gradio app (QAgents-Workflows)
384
- - **Backend**: QuantumArchitect-MCP on HuggingFace
385
- - **LLM**: Gemini 2.5 Flash (configurable)
386
-
387
- ### 📝 License
388
-
389
- MIT License - Feel free to use and modify!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390
  """)
391
 
392
  # Launch for HuggingFace Spaces
 
20
  import time
21
  from typing import Optional, List, Dict, Any
22
 
23
+ # Load environment variables from .env file (for local development)
24
+ try:
25
+ from dotenv import load_dotenv
26
+ load_dotenv()
27
+ except ImportError:
28
+ pass
29
+
30
  # Note: Gradio 6.0 doesn't support custom CSS in gr.Blocks()
31
  # UI styles module available but not used in this version
32
 
 
228
  except Exception as e:
229
  logger.error(f"Quick build error: {e}")
230
  return f"# Error: {str(e)}"
231
+ # =============================================================================
232
+ # EXAMPLE QUESTIONS FOR UI
233
+ # =============================================================================
234
+
235
+ EXAMPLE_QUESTIONS = [
236
+ # Basic circuits
237
+ {"category": "🌟 Beginner", "question": "Create a Bell state circuit", "description": "Classic 2-qubit entanglement"},
238
+ {"category": "🌟 Beginner", "question": "Put a qubit in superposition", "description": "Single Hadamard gate"},
239
+ {"category": "🌟 Beginner", "question": "Create a simple NOT gate on qubit 0", "description": "X gate application"},
240
+
241
+ # Entanglement
242
+ {"category": "🔗 Entanglement", "question": "Generate a 3-qubit GHZ state", "description": "Greenberger-Horne-Zeilinger state"},
243
+ {"category": "🔗 Entanglement", "question": "Create a 4-qubit GHZ state with measurements", "description": "GHZ with classical bits"},
244
+ {"category": "🔗 Entanglement", "question": "Build a W state for 3 qubits", "description": "Another entangled state type"},
245
+
246
+ # Algorithms
247
+ {"category": "⚙️ Algorithms", "question": "Create a 4-qubit QFT circuit", "description": "Quantum Fourier Transform"},
248
+ {"category": "⚙️ Algorithms", "question": "Build a 2-qubit Grover search circuit", "description": "Quantum search algorithm"},
249
+ {"category": "⚙️ Algorithms", "question": "Generate a quantum teleportation circuit", "description": "State teleportation protocol"},
250
+
251
+ # Custom circuits
252
+ {"category": "🔧 Custom", "question": "Apply H gate to qubit 0, then CNOT from 0 to 1", "description": "Step-by-step gates"},
253
+ {"category": "🔧 Custom", "question": "Create a circuit with Rx(π/4) on qubit 0 and Ry(π/2) on qubit 1", "description": "Rotation gates"},
254
+ {"category": "🔧 Custom", "question": "Build a circuit that swaps qubit 0 and qubit 1", "description": "SWAP operation"},
255
+ ]
256
+
257
  # =============================================================================
258
  # GRADIO INTERFACE
259
  # =============================================================================
 
268
  """)
269
 
270
  with gr.Tabs():
271
+ # =================================================================
272
+ # TAB 0: GETTING STARTED (NEW)
273
+ # =================================================================
274
+ with gr.TabItem("🚀 Getting Started"):
275
+ gr.Markdown("""
276
+ ## 👋 Welcome to QAgents!
277
+
278
+ QAgents is an AI-powered assistant that generates **quantum circuits** from natural language descriptions.
279
+ Just describe what you want, and the agent will produce valid **OpenQASM 2.0** code.
280
+
281
+ ---
282
+
283
+ ### 🎯 What Can I Ask?
284
+
285
+ | Category | What You Can Request | Example |
286
+ |----------|---------------------|---------|
287
+ | **Basic Gates** | Single qubit operations | *"Apply a Hadamard gate to qubit 0"* |
288
+ | **Entanglement** | Bell states, GHZ states | *"Create a Bell state"* |
289
+ | **Algorithms** | QFT, Grover, Teleportation | *"Build a 4-qubit QFT"* |
290
+ | **Custom Circuits** | Step-by-step gate sequences | *"Apply H to q0, then CNOT from q0 to q1"* |
291
+ | **Measurements** | Circuits with classical output | *"Create a GHZ state with measurements"* |
292
+
293
+ ---
294
+
295
+ ### 📝 How to Write Good Prompts
296
+
297
+ **✅ Be Specific:**
298
+ - ✅ *"Create a 3-qubit GHZ state"* → Clear qubit count
299
+ - ❌ *"Make something entangled"* → Too vague
300
+
301
+ **✅ Mention Qubit Numbers:**
302
+ - ✅ *"Apply CNOT from qubit 0 to qubit 1"* → Clear targets
303
+ - ❌ *"Do a CNOT"* → Which qubits?
304
+
305
+ **✅ Include Parameters for Rotation Gates:**
306
+ - ✅ *"Apply Rx(π/4) to qubit 0"* → Clear angle
307
+ - ❌ *"Rotate qubit 0"* → What angle?
308
+
309
+ ---
310
+
311
+ ### 🔧 Output Format
312
+
313
+ The agent returns **OpenQASM 2.0** code that can be:
314
+ - Copied and used in Qiskit, Cirq, or other quantum frameworks
315
+ - Simulated on IBM Quantum, Amazon Braket, or local simulators
316
+ - Validated and scored using the **Quick Build** or **MCP Health** tabs
317
+
318
+ ---
319
+
320
+ ### ⚡ Quick Tips
321
+
322
+ | Tip | Description |
323
+ |-----|-------------|
324
+ | 💬 Type `help` | Show available commands |
325
+ | 📊 Type `status` | Check MCP server connection |
326
+ | 🛠️ Use Quick Build | Generate circuits from templates without typing |
327
+ | 🔗 Check MCP Health | Verify backend tools are available |
328
+
329
+ ---
330
+
331
+ ### 🎮 Try These Examples
332
+
333
+ Click any example below to copy it, then paste in the **Chat** tab:
334
+ """)
335
+
336
+ # Display example questions in a nice format
337
+ with gr.Accordion("🌟 Beginner Examples", open=True):
338
+ gr.Markdown("""
339
+ | Example Prompt | What It Does |
340
+ |---------------|--------------|
341
+ | `Create a Bell state circuit` | Creates the classic 2-qubit entangled state |
342
+ | `Put a qubit in superposition` | Single Hadamard gate on qubit 0 |
343
+ | `Create a simple NOT gate on qubit 0` | Applies X gate to flip the qubit |
344
+ | `Apply Hadamard gates to qubits 0 and 1` | Parallel superposition |
345
+ """)
346
+
347
+ with gr.Accordion("🔗 Entanglement Examples", open=False):
348
+ gr.Markdown("""
349
+ | Example Prompt | What It Does |
350
+ |---------------|--------------|
351
+ | `Generate a 3-qubit GHZ state` | Creates a 3-qubit maximally entangled state |
352
+ | `Create a 4-qubit GHZ state with measurements` | GHZ state + measurement on all qubits |
353
+ | `Build a W state for 3 qubits` | Alternative entangled state with different properties |
354
+ | `Create an entangled pair of qubits` | Simple Bell state (synonym) |
355
+ """)
356
+
357
+ with gr.Accordion("⚙️ Algorithm Examples", open=False):
358
+ gr.Markdown("""
359
+ | Example Prompt | What It Does |
360
+ |---------------|--------------|
361
+ | `Create a 4-qubit QFT circuit` | Quantum Fourier Transform for 4 qubits |
362
+ | `Build a 2-qubit Grover search circuit` | Amplitude amplification algorithm |
363
+ | `Generate a quantum teleportation circuit` | 3-qubit state teleportation protocol |
364
+ | `Create an inverse QFT for 3 qubits` | Inverse Quantum Fourier Transform |
365
+ """)
366
+
367
+ with gr.Accordion("🔧 Custom Circuit Examples", open=False):
368
+ gr.Markdown("""
369
+ | Example Prompt | What It Does |
370
+ |---------------|--------------|
371
+ | `Apply H gate to qubit 0, then CNOT from 0 to 1` | Step-by-step gate application |
372
+ | `Create a circuit with Rx(π/4) on qubit 0` | Rotation around X-axis |
373
+ | `Build a circuit that swaps qubit 0 and qubit 1` | SWAP gate implementation |
374
+ | `Apply T gate to qubit 0 and S gate to qubit 1` | Phase gates |
375
+ | `Create a Toffoli gate on qubits 0, 1, 2` | Controlled-controlled-NOT |
376
+ """)
377
+
378
+ gr.Markdown("""
379
+ ---
380
+
381
+ ### 🚀 Ready to Start?
382
+
383
+ Head to the **💬 Chat** tab and try your first prompt!
384
+ """)
385
+
386
  # =================================================================
387
  # TAB 1: CHAT INTERFACE
388
  # =================================================================
389
  with gr.TabItem("💬 Chat"):
390
+ gr.Markdown("### 💬 Chat with Quantum Circuit Agent")
391
+ gr.Markdown("Describe the quantum circuit you want to create in plain English!")
392
 
393
  chatbot = gr.Chatbot(
394
  value=[],
395
+ height=350,
396
  label="Quantum Circuit Agent"
397
  )
398
 
399
  with gr.Row():
400
  msg_input = gr.Textbox(
401
+ placeholder="e.g., 'Create a Bell state' or 'Build a 3-qubit GHZ state'",
402
  label="Your Message",
403
  scale=4,
404
  lines=1
 
410
  help_btn = gr.Button("❓ Help", size="sm")
411
  status_btn = gr.Button("📊 Status", size="sm")
412
 
413
+ # Example buttons section
414
+ gr.Markdown("---")
415
+ gr.Markdown("### ⚡ Quick Examples (click to use)")
416
+
417
+ with gr.Row():
418
+ ex1_btn = gr.Button("🔔 Bell State", size="sm")
419
+ ex2_btn = gr.Button("🌀 GHZ State (3q)", size="sm")
420
+ ex3_btn = gr.Button("📐 QFT (4q)", size="sm")
421
+ ex4_btn = gr.Button("🔍 Grover (2q)", size="sm")
422
+
423
+ with gr.Row():
424
+ ex5_btn = gr.Button("🌊 Superposition", size="sm")
425
+ ex6_btn = gr.Button("📡 Teleportation", size="sm")
426
+ ex7_btn = gr.Button("🔄 SWAP Gate", size="sm")
427
+ ex8_btn = gr.Button("🎛️ Custom CNOT", size="sm")
428
+
429
  # Chat handlers
430
  def respond(message: str, chat_history: List):
431
  if not message.strip():
 
448
  chat_history.append({"role": "assistant", "content": status_text})
449
  return chat_history
450
 
451
+ # Example button handlers - each returns the example text and triggers the chat
452
+ def use_example(example_text: str, chat_history: List):
453
+ bot_response = chat_response(example_text, chat_history)
454
+ chat_history.append({"role": "user", "content": example_text})
455
+ chat_history.append({"role": "assistant", "content": bot_response})
456
+ return chat_history
457
+
458
  send_btn.click(respond, [msg_input, chatbot], [msg_input, chatbot])
459
  msg_input.submit(respond, [msg_input, chatbot], [msg_input, chatbot])
460
  clear_btn.click(lambda: [], outputs=[chatbot])
461
  help_btn.click(show_help, [chatbot], [chatbot])
462
  status_btn.click(show_status, [chatbot], [chatbot])
463
+
464
+ # Wire up example buttons
465
+ ex1_btn.click(lambda h: use_example("Create a Bell state circuit", h), [chatbot], [chatbot])
466
+ ex2_btn.click(lambda h: use_example("Generate a 3-qubit GHZ state", h), [chatbot], [chatbot])
467
+ ex3_btn.click(lambda h: use_example("Create a 4-qubit QFT circuit", h), [chatbot], [chatbot])
468
+ ex4_btn.click(lambda h: use_example("Build a 2-qubit Grover search circuit", h), [chatbot], [chatbot])
469
+ ex5_btn.click(lambda h: use_example("Put 2 qubits in superposition", h), [chatbot], [chatbot])
470
+ ex6_btn.click(lambda h: use_example("Generate a quantum teleportation circuit", h), [chatbot], [chatbot])
471
+ ex7_btn.click(lambda h: use_example("Build a circuit that swaps qubit 0 and qubit 1", h), [chatbot], [chatbot])
472
+ ex8_btn.click(lambda h: use_example("Apply H gate to qubit 0, then CNOT from 0 to 1", h), [chatbot], [chatbot])
473
 
474
  # =================================================================
475
  # TAB 2: MCP ENDPOINTS HEALTH
 
545
  build_btn.click(quick_build_circuit, [template_select, qubits_slider], [qasm_output])
546
 
547
  # =================================================================
548
+ # TAB 5: ABOUT
549
  # =================================================================
550
  with gr.TabItem("ℹ️ About"):
551
  gr.Markdown("""
552
+ ## ℹ️ About QAgents
553
+
554
+ **QAgents** is a multi-agent system for quantum circuit generation using natural language.
555
+
556
+ ---
557
+
558
+ ### 🏗️ How it Works
559
+
560
+ ```
561
+ ┌─────────────────┐ ┌──────────────┐ ┌─────────────────────┐
562
+ │ Your Prompt │ ──► │ LLM Agent │ ──► │ OpenQASM 2.0 Code │
563
+ │ (Plain Text) │ │ (NAKED Mode) │ │ │
564
+ └─────────────────┘ └──────────────┘ └─────────────────────┘
565
+
566
+
567
+ ┌──────────────────┐
568
+ │ MCP Tools │
569
+ │ - Validate │
570
+ - Simulate │
571
+ │ - Score │
572
+ └──────────────────┘
573
+ ```
574
+
575
+ 1. **You describe** the quantum circuit you want in natural language
576
+ 2. **NAKED mode** uses an LLM to generate valid OpenQASM 2.0 code directly
577
+ 3. **MCP tools** can validate, simulate, and score your circuits
578
+
579
+ ---
580
+
581
+ ### 🎯 Capabilities
582
+
583
+ | Feature | Description |
584
+ |---------|-------------|
585
+ | **Circuit Generation** | Create circuits from descriptions |
586
+ | **Standard Gates** | H, X, Y, Z, S, T, Rx, Ry, Rz, CNOT, CZ, SWAP, Toffoli |
587
+ | **Templates** | Bell states, GHZ, QFT, Grover, Teleportation |
588
+ | **Output Format** | OpenQASM 2.0 (compatible with Qiskit, Cirq, etc.) |
589
+ | **Validation** | Syntax and semantic validation via MCP |
590
+
591
+ ---
592
+
593
+ ### 🔗 Architecture
594
+
595
+ | Component | Technology | Purpose |
596
+ |-----------|------------|---------|
597
+ | **Frontend** | Gradio 6.0 | This UI you're using |
598
+ | **Orchestrator** | QAgents-Workflows | Agent coordination |
599
+ | **LLM** | Gemini 2.5 Flash | Code generation |
600
+ | **Backend** | QuantumArchitect-MCP | Validation & simulation |
601
+
602
+ ---
603
+
604
+ ### 📖 Supported Quantum Operations
605
+
606
+ **Single-Qubit Gates:**
607
+ - `H` (Hadamard), `X`, `Y`, `Z` (Pauli gates)
608
+ - `S`, `T`, `Sdg`, `Tdg` (Phase gates)
609
+ - `Rx(θ)`, `Ry(θ)`, `Rz(θ)` (Rotation gates)
610
+
611
+ **Multi-Qubit Gates:**
612
+ - `CNOT/CX` (Controlled-NOT)
613
+ - `CZ` (Controlled-Z)
614
+ - `SWAP` (Swap two qubits)
615
+ - `CCX/Toffoli` (Controlled-Controlled-NOT)
616
+
617
+ ---
618
+
619
+ ### 📝 License
620
+
621
+ MIT License - Feel free to use and modify!
622
+
623
+ ---
624
+
625
+ ### 🔗 Links
626
+
627
+ - **QAgents-Workflows**: Frontend orchestration
628
+ - **QuantumArchitect-MCP**: Backend quantum tools
629
  """)
630
 
631
  # Launch for HuggingFace Spaces
config.py CHANGED
@@ -13,6 +13,15 @@ from dataclasses import dataclass, field
13
  from typing import Optional, List, Dict
14
  import os
15
 
 
 
 
 
 
 
 
 
 
16
  # Paths
17
  PROJECT_ROOT = Path(__file__).parent
18
  QUANTUM_MCP_ROOT = PROJECT_ROOT.parent / "QuantumArchitect-MCP"
@@ -162,7 +171,8 @@ class LLMConfig:
162
  # Model identifier - reads from LLM_MODEL env var, falls back to "gemini-2.5-flash-lite"
163
  model: str = field(default_factory=lambda: os.getenv("LLM_MODEL", "gemini-2.5-flash-lite"))
164
  # API key - tries GOOGLE_API_KEY first (Gemini), then GENAI_API_KEY as fallback
165
- api_key: Optional[str] = field(default_factory=lambda: os.getenv("GOOGLE_API_KEY") or os.getenv("GENAI_API_KEY"))
 
166
  temperature: float = 0.2
167
  max_tokens: int = 2000
168
 
@@ -174,6 +184,17 @@ class LLMConfig:
174
  enable_fallback: bool = True # Enable automatic model switching on rate limit
175
  fallback_on_error: bool = True # Also fallback on API errors
176
 
 
 
 
 
 
 
 
 
 
 
 
177
  @property
178
  def model_string(self) -> str:
179
  """Get full model string for API calls."""
 
13
  from typing import Optional, List, Dict
14
  import os
15
 
16
+ # Load environment variables from .env file
17
+ try:
18
+ from dotenv import load_dotenv
19
+ load_dotenv()
20
+ except ImportError:
21
+ # If python-dotenv is not installed, continue without loading .env
22
+ # (it will use system environment variables only)
23
+ pass
24
+
25
  # Paths
26
  PROJECT_ROOT = Path(__file__).parent
27
  QUANTUM_MCP_ROOT = PROJECT_ROOT.parent / "QuantumArchitect-MCP"
 
171
  # Model identifier - reads from LLM_MODEL env var, falls back to "gemini-2.5-flash-lite"
172
  model: str = field(default_factory=lambda: os.getenv("LLM_MODEL", "gemini-2.5-flash-lite"))
173
  # API key - tries GOOGLE_API_KEY first (Gemini), then GENAI_API_KEY as fallback
174
+ # Use None as default and fetch dynamically to support HuggingFace Spaces
175
+ api_key: Optional[str] = None
176
  temperature: float = 0.2
177
  max_tokens: int = 2000
178
 
 
184
  enable_fallback: bool = True # Enable automatic model switching on rate limit
185
  fallback_on_error: bool = True # Also fallback on API errors
186
 
187
+ def __post_init__(self):
188
+ """Initialize API key from environment if not set."""
189
+ if self.api_key is None:
190
+ # Try GOOGLE_API_KEY first, then GENAI_API_KEY
191
+ self.api_key = os.getenv("GOOGLE_API_KEY") or os.getenv("GENAI_API_KEY")
192
+
193
+ def get_api_key(self) -> Optional[str]:
194
+ """Get current API key, checking environment on each call for HF Spaces."""
195
+ # Always check environment first to support dynamic Secrets in HF Spaces
196
+ return os.getenv("GOOGLE_API_KEY") or os.getenv("GENAI_API_KEY") or self.api_key
197
+
198
  @property
199
  def model_string(self) -> str:
200
  """Get full model string for API calls."""
orchestrators/orchestrator.py CHANGED
@@ -379,9 +379,21 @@ class NakedOrchestrator(BaseOrchestrator):
379
  if self._llm is None:
380
  from agents.llm_adapter import get_llm_adapter
381
  from config import config
 
 
 
 
 
 
 
 
 
 
 
 
382
  self._llm = get_llm_adapter(
383
  provider="gemini",
384
- api_key=config.llm.api_key,
385
  enable_fallback=True
386
  )
387
  return self._llm
 
379
  if self._llm is None:
380
  from agents.llm_adapter import get_llm_adapter
381
  from config import config
382
+
383
+ # Get API key dynamically (supports HF Spaces Secrets)
384
+ api_key = config.llm.get_api_key()
385
+
386
+ if not api_key:
387
+ raise ValueError(
388
+ "Missing API key! To use the Google AI API, provide api_key via:\n"
389
+ " 1. GOOGLE_API_KEY environment variable (HF Spaces Secrets)\n"
390
+ " 2. GENAI_API_KEY environment variable (fallback)\n"
391
+ " 3. Set in .env file (local development)"
392
+ )
393
+
394
  self._llm = get_llm_adapter(
395
  provider="gemini",
396
+ api_key=api_key,
397
  enable_fallback=True
398
  )
399
  return self._llm
orchestrators/quasar_orchestrator.py CHANGED
@@ -76,9 +76,21 @@ class QuasarOrchestrator:
76
  if self._llm is None:
77
  from agents.llm_adapter import get_llm_adapter
78
  from config import config
 
 
 
 
 
 
 
 
 
 
 
 
79
  self._llm = get_llm_adapter(
80
  provider="gemini",
81
- api_key=config.llm.api_key,
82
  enable_fallback=True
83
  )
84
  return self._llm
 
76
  if self._llm is None:
77
  from agents.llm_adapter import get_llm_adapter
78
  from config import config
79
+
80
+ # Get API key dynamically (supports HF Spaces Secrets)
81
+ api_key = config.llm.get_api_key()
82
+
83
+ if not api_key:
84
+ raise ValueError(
85
+ "Missing API key! To use the Google AI API, provide api_key via:\n"
86
+ " 1. GOOGLE_API_KEY environment variable (HF Spaces Secrets)\n"
87
+ " 2. GENAI_API_KEY environment variable (fallback)\n"
88
+ " 3. Set in .env file (local development)"
89
+ )
90
+
91
  self._llm = get_llm_adapter(
92
  provider="gemini",
93
+ api_key=api_key,
94
  enable_fallback=True
95
  )
96
  return self._llm
tasks-project-state.json CHANGED
@@ -1,20 +1,22 @@
1
  {
2
  "project": "QAgents-Workflows",
3
- "version": "0.9.1",
4
  "description": "Multi-agent quantum circuit optimization system with chat UI and MCP integration",
5
  "last_updated": "2025-11-30",
6
- "status": "MCP_CLIENT_TIMEOUT_FIX_APPLIED",
7
- "notes": "Fixed MCP client timeout issues for HuggingFace Space cold starts. Increased timeouts (90s initial, 120s result), added retry logic with exponential backoff, added server warm-up function. Chat UI and MCP health monitor working. Local validation fallback for fast syntax checks.",
8
 
9
  "recent_changes": {
10
  "2025-11-30": [
11
- "Fixed timeout errors in mcp_client.py for HuggingFace Space cold starts",
12
- "Increased INITIAL_TIMEOUT to 90s, RESULT_TIMEOUT to 120s",
13
- "Added MAX_RETRIES=3 with exponential backoff",
14
- "Added warm_up_server() method to MCPClient",
15
- "Updated validate_syntax() to use local fallback first (faster)",
16
- "Updated app.py health check functions with extended timeouts",
17
- "Improved error messages to indicate cold start situations"
 
 
18
  ]
19
  },
20
 
@@ -42,13 +44,34 @@
42
  },
43
 
44
  "app_features": {
 
 
 
 
 
 
 
 
 
 
 
45
  "chat_tab": {
46
  "description": "Interactive chat UI for quantum circuit generation",
47
  "features": [
48
  "Natural language circuit requests",
 
49
  "Multiple orchestration modes (naked, quasar, hybrid, blackboard)",
50
- "Difficulty level selection",
51
  "Help and status commands"
 
 
 
 
 
 
 
 
 
 
52
  ]
53
  },
54
  "mcp_endpoints_tab": {
@@ -63,10 +86,42 @@
63
  },
64
  "quick_build_tab": {
65
  "description": "Direct circuit template generation",
66
- "templates": ["bell_state", "ghz_state", "qft", "grover", "vqe", "superposition"]
 
 
 
 
 
 
 
 
 
67
  }
68
  },
69
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  "mcp_endpoints": [
71
  {"name": "create_circuit", "category": "Creation"},
72
  {"name": "parse_qasm", "category": "Creation"},
@@ -84,15 +139,6 @@
84
  {"name": "list_templates", "category": "Documentation"}
85
  ],
86
 
87
- "comprehensive_test_results": {
88
- "test_date": "2024-11-29",
89
- "previous_results": {
90
- "naked": {"success": "9/9 (100%)", "avg_time_ms": 3929},
91
- "guided": {"success": "7/9 (78%)", "avg_time_ms": 23120},
92
- "blackboard": {"success": "2/9 (22%)", "avg_time_ms": 13507}
93
- }
94
- },
95
-
96
  "architectures": {
97
  "naked": {
98
  "description": "Direct LLM-to-QASM generation",
 
1
  {
2
  "project": "QAgents-Workflows",
3
+ "version": "0.9.3",
4
  "description": "Multi-agent quantum circuit optimization system with chat UI and MCP integration",
5
  "last_updated": "2025-11-30",
6
+ "status": "API_KEY_LOADING_FIXED",
7
+ "notes": "Fixed API key loading for HuggingFace Spaces. Now supports dynamic environment variable reading for Secrets. Added better error messages. Enhanced landing page with Getting Started tab, example questions, and clickable quick examples.",
8
 
9
  "recent_changes": {
10
  "2025-11-30": [
11
+ "Fixed API key loading issue - now dynamically reads from HF Space Secrets",
12
+ "Added get_api_key() method in LLMConfig for dynamic environment reading",
13
+ "Updated base_agent.py, orchestrator.py, quasar_orchestrator.py to use dynamic API key loading",
14
+ "Added clear error messages when API key is missing",
15
+ "Added new 'Getting Started' tab with comprehensive user guide",
16
+ "Added example questions organized by category (Beginner, Entanglement, Algorithms, Custom)",
17
+ "Added 8 clickable quick example buttons in Chat tab",
18
+ "Enhanced About tab with architecture diagram and detailed capabilities",
19
+ "Added prompt writing tips and output format documentation"
20
  ]
21
  },
22
 
 
44
  },
45
 
46
  "app_features": {
47
+ "getting_started_tab": {
48
+ "description": "User onboarding and guide",
49
+ "features": [
50
+ "Welcome message and overview",
51
+ "Prompt categories table",
52
+ "How to write good prompts",
53
+ "Output format explanation",
54
+ "Quick tips",
55
+ "Collapsible example sections (Beginner, Entanglement, Algorithms, Custom)"
56
+ ]
57
+ },
58
  "chat_tab": {
59
  "description": "Interactive chat UI for quantum circuit generation",
60
  "features": [
61
  "Natural language circuit requests",
62
+ "8 quick example buttons",
63
  "Multiple orchestration modes (naked, quasar, hybrid, blackboard)",
 
64
  "Help and status commands"
65
+ ],
66
+ "quick_examples": [
67
+ "Bell State",
68
+ "GHZ State (3q)",
69
+ "QFT (4q)",
70
+ "Grover (2q)",
71
+ "Superposition",
72
+ "Teleportation",
73
+ "SWAP Gate",
74
+ "Custom CNOT"
75
  ]
76
  },
77
  "mcp_endpoints_tab": {
 
86
  },
87
  "quick_build_tab": {
88
  "description": "Direct circuit template generation",
89
+ "templates": ["bell_state", "ghz_state", "qft", "grover", "superposition"]
90
+ },
91
+ "about_tab": {
92
+ "description": "Detailed system information",
93
+ "features": [
94
+ "Architecture diagram",
95
+ "Capabilities table",
96
+ "Supported quantum operations",
97
+ "Component stack details"
98
+ ]
99
  }
100
  },
101
 
102
+ "example_questions": {
103
+ "beginner": [
104
+ "Create a Bell state circuit",
105
+ "Put a qubit in superposition",
106
+ "Create a simple NOT gate on qubit 0"
107
+ ],
108
+ "entanglement": [
109
+ "Generate a 3-qubit GHZ state",
110
+ "Create a 4-qubit GHZ state with measurements",
111
+ "Build a W state for 3 qubits"
112
+ ],
113
+ "algorithms": [
114
+ "Create a 4-qubit QFT circuit",
115
+ "Build a 2-qubit Grover search circuit",
116
+ "Generate a quantum teleportation circuit"
117
+ ],
118
+ "custom": [
119
+ "Apply H gate to qubit 0, then CNOT from 0 to 1",
120
+ "Create a circuit with Rx(π/4) on qubit 0",
121
+ "Build a circuit that swaps qubit 0 and qubit 1"
122
+ ]
123
+ },
124
+
125
  "mcp_endpoints": [
126
  {"name": "create_circuit", "category": "Creation"},
127
  {"name": "parse_qasm", "category": "Creation"},
 
139
  {"name": "list_templates", "category": "Documentation"}
140
  ],
141
 
 
 
 
 
 
 
 
 
 
142
  "architectures": {
143
  "naked": {
144
  "description": "Direct LLM-to-QASM generation",