Skip to content

Commit dc016f4

Browse files
fix: resolve event loop conflicts and mermaid diagram rendering
Signed-off-by: gopal-raj-suresh <gopal.raj.dummugudupu@cloud2labs.com>
1 parent ef5fe28 commit dc016f4

5 files changed

Lines changed: 63 additions & 24 deletions

File tree

sample_solutions/Docugen-Microagents/api/agents/mermaid_agent.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,29 @@
5454
4. VALIDATE with validate_mermaid_syntax()
5555
5. Fix errors if validation fails
5656
57+
**FORBIDDEN Patterns (will cause syntax errors):**
58+
- ❌ NO self-referencing edges: Service -->|X| Service
59+
- ❌ NO curly braces in labels: -->|GET {id}|
60+
- ❌ NO endpoint paths in labels: -->|POST /upload|
61+
- ❌ NO colons in labels: -->|Method: POST|
62+
- ✅ GOOD: -->|Upload File|, -->|Process Request|
63+
64+
**Required Architecture Pattern:**
65+
```
66+
User → Frontend → Backend Service(s) → Database/Storage
67+
```
68+
Show the FLOW of data, NOT the API endpoints.
69+
70+
**CRITICAL - Final Response Format:**
71+
Your FINAL response MUST contain ONLY the mermaid diagram code wrapped in triple backticks.
72+
Do NOT add any explanatory text before or after the diagram.
73+
Format your final response EXACTLY like this:
74+
75+
```mermaid
76+
graph TD
77+
[your diagram here]
78+
```
79+
5780
**Limit:** 12 tool calls."""
5881

5982

sample_solutions/Docugen-Microagents/api/models/log_manager.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""
55

66
import asyncio
7+
import threading
78
import logging
89
from collections import defaultdict
910
from typing import Dict, List, Optional
@@ -29,7 +30,7 @@ def __init__(self, max_logs_per_job: int = 1000):
2930
self.max_logs_per_job = max_logs_per_job
3031
self._logs: Dict[str, List[AgentLog]] = defaultdict(list)
3132
self._subscribers: Dict[str, List[asyncio.Queue]] = defaultdict(list)
32-
self._lock = asyncio.Lock()
33+
self._lock = threading.Lock()
3334

3435
async def add_log(self, log: AgentLog) -> None:
3536
"""
@@ -38,7 +39,7 @@ async def add_log(self, log: AgentLog) -> None:
3839
Args:
3940
log: Agent log entry
4041
"""
41-
async with self._lock:
42+
with self._lock:
4243
# Add to storage
4344
job_logs = self._logs[log.job_id]
4445
job_logs.append(log)
@@ -51,10 +52,10 @@ async def add_log(self, log: AgentLog) -> None:
5152
dead_queues = []
5253
for queue in self._subscribers[log.job_id]:
5354
try:
54-
await asyncio.wait_for(queue.put(log), timeout=1.0)
55-
except (asyncio.TimeoutError, asyncio.QueueFull):
55+
queue.put_nowait(log)
56+
except asyncio.QueueFull:
5657
dead_queues.append(queue)
57-
logger.warning(f"Queue full or timeout for job {log.job_id}")
58+
logger.warning(f"Queue full for job {log.job_id}")
5859

5960
# Clean up dead queues
6061
for queue in dead_queues:
@@ -153,13 +154,13 @@ async def subscribe(self, job_id: str) -> asyncio.Queue:
153154
Queue that will receive new logs
154155
"""
155156
queue: asyncio.Queue = asyncio.Queue(maxsize=100)
156-
async with self._lock:
157+
with self._lock:
157158
self._subscribers[job_id].append(queue)
158159

159160
# Send existing logs immediately
160161
for log in self._logs.get(job_id, []):
161162
try:
162-
await queue.put(log)
163+
queue.put_nowait(log)
163164
except asyncio.QueueFull:
164165
logger.warning(f"Initial logs queue full for job {job_id}")
165166
break
@@ -174,7 +175,7 @@ async def unsubscribe(self, job_id: str, queue: asyncio.Queue) -> None:
174175
job_id: Job identifier
175176
queue: Queue to remove
176177
"""
177-
async with self._lock:
178+
with self._lock:
178179
if queue in self._subscribers[job_id]:
179180
self._subscribers[job_id].remove(queue)
180181

sample_solutions/Docugen-Microagents/api/services/llm_service.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,8 @@ def get_llm(model_name: Optional[str] = None, temperature: float = 0.7) -> ChatO
3030

3131
logger.info(f"Initializing LLM with model: {model_name}")
3232

33-
# Create httpx client with configurable SSL verification
33+
# Create httpx async client with configurable SSL verification
3434
import httpx
35-
http_client = httpx.Client(verify=settings.VERIFY_SSL)
3635
async_http_client = httpx.AsyncClient(verify=settings.VERIFY_SSL)
3736

3837
return ChatOpenAI(
@@ -41,6 +40,5 @@ def get_llm(model_name: Optional[str] = None, temperature: float = 0.7) -> ChatO
4140
openai_api_key=settings.INFERENCE_API_TOKEN,
4241
openai_api_base=f"{settings.INFERENCE_API_ENDPOINT}/v1",
4342
max_tokens=settings.AGENT_MAX_TOKENS,
44-
http_client=http_client,
4543
http_async_client=async_http_client
4644
)

sample_solutions/Docugen-Microagents/api/tools/repo_tools.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,7 @@ def validate_mermaid_syntax_tool(mermaid_code: str) -> str:
10281028
# Check 3: Edge labels must not contain unsafe characters
10291029
# Pattern: |label text|
10301030
edge_label_pattern = r'\|([^|]+)\|'
1031-
unsafe_edge_chars = ['/', '(', ')', ':', '`', '"']
1031+
unsafe_edge_chars = ['/', '(', ')', ':', '`', '"', '{', '}']
10321032
for line in lines[1:]:
10331033
if not line.strip():
10341034
continue
@@ -1046,6 +1046,18 @@ def validate_mermaid_syntax_tool(mermaid_code: str) -> str:
10461046
)
10471047
break
10481048

1049+
# Check 4: No self-referencing edges (Node --> Node)
1050+
self_ref_pattern = r'([A-Za-z][A-Za-z0-9_]*)\s*-->\s*\1(?:\s|$|\|)'
1051+
for line in lines[1:]:
1052+
if not line.strip():
1053+
continue
1054+
matches = re.findall(self_ref_pattern, line)
1055+
for node_id in matches:
1056+
errors.append(
1057+
f"Self-referencing edge detected: {node_id} --> {node_id}. "
1058+
f"Show data flow between different components instead."
1059+
)
1060+
10491061
# Check sequenceDiagram syntax
10501062
if code.startswith("sequenceDiagram"):
10511063
if "->" not in code and "->>" not in code:
Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import { useEffect, useRef } from 'react'
22
import mermaid from 'mermaid'
33

4-
// Initialize mermaid with default config
5-
mermaid.initialize({
6-
startOnLoad: false,
7-
theme: 'default',
8-
securityLevel: 'strict',
9-
fontFamily: 'ui-sans-serif, system-ui, sans-serif'
10-
})
11-
124
function Mermaid({ chart }) {
135
const containerRef = useRef(null)
14-
const idRef = useRef(`mermaid-${Math.random().toString(36).substr(2, 9)}`)
6+
7+
useEffect(() => {
8+
// Initialize mermaid with config
9+
mermaid.initialize({
10+
startOnLoad: false,
11+
theme: 'default',
12+
securityLevel: 'strict',
13+
fontFamily: 'ui-sans-serif, system-ui, sans-serif'
14+
})
15+
}, [])
1516

1617
useEffect(() => {
1718
if (containerRef.current && chart) {
@@ -20,20 +21,24 @@ function Mermaid({ chart }) {
2021
// Clear previous content
2122
containerRef.current.innerHTML = ''
2223

24+
// Generate new ID for each render to avoid conflicts
25+
const newId = `mermaid-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
26+
2327
// Render the mermaid chart
24-
const { svg } = await mermaid.render(idRef.current, chart)
28+
const { svg } = await mermaid.render(newId, chart)
2529
containerRef.current.innerHTML = svg
2630
} catch (error) {
2731
console.error('Mermaid rendering error:', error)
28-
containerRef.current.innerHTML = `<pre style="color: red;">Error rendering diagram: ${error.message}</pre>`
32+
console.error('Chart content:', chart)
33+
containerRef.current.innerHTML = `<pre style="color: red; padding: 1rem; background: #fee; border-radius: 8px;">Error rendering diagram: ${error.message}</pre>`
2934
}
3035
}
3136

3237
renderDiagram()
3338
}
3439
}, [chart])
3540

36-
return <div ref={containerRef} />
41+
return <div ref={containerRef} style={{ minHeight: '200px' }} />
3742
}
3843

3944
export default Mermaid

0 commit comments

Comments
 (0)