Spaces:
Sleeping
Sleeping
Commit
Β·
9c03abd
1
Parent(s):
807e3cf
update the app.py file
Browse files- app.py +287 -170
- backend/api/services/agent_orchestrator.py +2 -2
- backend/tests/README_RETRY_TESTS.md +1 -0
app.py
CHANGED
|
@@ -1336,178 +1336,226 @@ with gr.Blocks(
|
|
| 1336 |
font=("Inter", "system-ui", "sans-serif")
|
| 1337 |
),
|
| 1338 |
css="""
|
| 1339 |
-
/* Global
|
| 1340 |
-
.gradio-container {
|
| 1341 |
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
|
|
|
|
|
|
| 1342 |
}
|
| 1343 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1344 |
/* Header styling */
|
| 1345 |
.header-section {
|
| 1346 |
-
background:
|
| 1347 |
-
padding:
|
| 1348 |
-
border-radius:
|
| 1349 |
margin-bottom: 24px;
|
| 1350 |
-
box-shadow: 0
|
| 1351 |
-
border: 1px solid rgba(148, 163, 184, 0.
|
| 1352 |
}
|
| 1353 |
-
|
| 1354 |
.header-section h1 {
|
| 1355 |
-
|
| 1356 |
-
-
|
| 1357 |
-
-webkit-text-fill-color: transparent;
|
| 1358 |
-
background-clip: text;
|
| 1359 |
-
font-size: 2.5rem;
|
| 1360 |
font-weight: 700;
|
| 1361 |
-
margin-bottom:
|
|
|
|
| 1362 |
}
|
| 1363 |
-
|
| 1364 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1365 |
.input-container {
|
| 1366 |
-
background:
|
| 1367 |
-
padding: 20px;
|
| 1368 |
-
border-radius:
|
| 1369 |
-
border: 1px solid rgba(148, 163, 184, 0.
|
| 1370 |
-
backdrop-filter: blur(
|
|
|
|
|
|
|
| 1371 |
}
|
| 1372 |
-
|
| 1373 |
-
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1374 |
.stat-card {
|
| 1375 |
-
background:
|
| 1376 |
-
padding:
|
| 1377 |
border-radius: 16px;
|
| 1378 |
color: white;
|
| 1379 |
-
text-align:
|
| 1380 |
-
box-shadow: 0
|
| 1381 |
-
transition:
|
| 1382 |
-
border: 1px solid rgba(
|
| 1383 |
}
|
| 1384 |
.stat-card:hover {
|
| 1385 |
-
transform: translateY(-
|
| 1386 |
-
box-shadow: 0
|
|
|
|
| 1387 |
}
|
| 1388 |
.stat-card h3 {
|
| 1389 |
-
margin: 0 0
|
| 1390 |
-
font-size:
|
| 1391 |
-
opacity: 0.
|
| 1392 |
-
font-weight:
|
| 1393 |
-
letter-spacing: 0.
|
| 1394 |
text-transform: uppercase;
|
| 1395 |
}
|
| 1396 |
.stat-card strong {
|
| 1397 |
-
font-size:
|
| 1398 |
font-weight: 700;
|
| 1399 |
display: block;
|
| 1400 |
margin-top: 8px;
|
| 1401 |
}
|
| 1402 |
-
|
| 1403 |
-
/*
|
| 1404 |
.summary-box {
|
| 1405 |
-
background:
|
| 1406 |
-
padding:
|
| 1407 |
-
border-radius:
|
| 1408 |
-
border: 1px solid rgba(148, 163, 184, 0.
|
| 1409 |
-
max-height:
|
| 1410 |
overflow-y: auto;
|
| 1411 |
-
box-shadow: 0
|
| 1412 |
-
color: #
|
| 1413 |
-
backdrop-filter: blur(
|
|
|
|
| 1414 |
}
|
| 1415 |
.summary-box::-webkit-scrollbar {
|
| 1416 |
width: 8px;
|
| 1417 |
}
|
| 1418 |
.summary-box::-webkit-scrollbar-track {
|
| 1419 |
-
background: rgba(
|
| 1420 |
-
border-radius:
|
| 1421 |
}
|
| 1422 |
.summary-box::-webkit-scrollbar-thumb {
|
| 1423 |
-
background: rgba(148, 163, 184, 0.
|
| 1424 |
-
border-radius:
|
| 1425 |
}
|
| 1426 |
-
|
| 1427 |
-
|
|
|
|
|
|
|
|
|
|
| 1428 |
}
|
| 1429 |
.summary-box h3, .summary-box h4 {
|
| 1430 |
margin-top: 0;
|
| 1431 |
-
margin-bottom: 16px;
|
| 1432 |
-
color: #ffffff;
|
| 1433 |
-
font-weight: 600;
|
| 1434 |
-
}
|
| 1435 |
-
.summary-box h4 {
|
| 1436 |
-
color: #e2e8f0;
|
| 1437 |
-
font-size: 16px;
|
| 1438 |
-
margin-top: 24px;
|
| 1439 |
margin-bottom: 12px;
|
|
|
|
|
|
|
| 1440 |
}
|
| 1441 |
-
.summary-box p
|
| 1442 |
-
color: #f1f5f9;
|
| 1443 |
-
margin: 10px 0;
|
| 1444 |
-
line-height: 1.7;
|
| 1445 |
-
}
|
| 1446 |
-
.summary-box ul {
|
| 1447 |
-
margin: 12px 0;
|
| 1448 |
-
padding-left: 28px;
|
| 1449 |
-
color: #f1f5f9;
|
| 1450 |
-
}
|
| 1451 |
.summary-box li {
|
| 1452 |
-
|
| 1453 |
-
|
| 1454 |
line-height: 1.7;
|
| 1455 |
}
|
| 1456 |
.summary-box code {
|
| 1457 |
-
background-color: rgba(
|
| 1458 |
-
color: #
|
| 1459 |
-
padding: 3px
|
| 1460 |
border-radius: 6px;
|
| 1461 |
font-family: 'Fira Code', 'Courier New', monospace;
|
| 1462 |
-
font-size:
|
| 1463 |
-
border: 1px solid rgba(148, 163, 184, 0.
|
| 1464 |
}
|
| 1465 |
-
|
| 1466 |
-
|
| 1467 |
-
border-top: 1px solid rgba(148, 163, 184, 0.2);
|
| 1468 |
-
margin: 20px 0;
|
| 1469 |
-
}
|
| 1470 |
-
.summary-box strong {
|
| 1471 |
-
color: #ffffff;
|
| 1472 |
-
font-weight: 600;
|
| 1473 |
-
}
|
| 1474 |
-
|
| 1475 |
-
/* Chart titles */
|
| 1476 |
.chart-title {
|
| 1477 |
-
margin-bottom:
|
| 1478 |
margin-top: 0;
|
| 1479 |
font-weight: 600;
|
| 1480 |
-
color: #
|
| 1481 |
text-align: center;
|
| 1482 |
-
font-size:
|
| 1483 |
}
|
| 1484 |
-
|
| 1485 |
-
/*
|
| 1486 |
button.primary {
|
| 1487 |
-
background:
|
| 1488 |
border: none;
|
| 1489 |
-
box-shadow: 0
|
| 1490 |
-
transition:
|
|
|
|
|
|
|
| 1491 |
}
|
| 1492 |
button.primary:hover {
|
| 1493 |
-
transform: translateY(-
|
| 1494 |
-
|
|
|
|
| 1495 |
}
|
| 1496 |
-
|
| 1497 |
-
/*
|
| 1498 |
.tab-nav {
|
| 1499 |
-
border-bottom:
|
| 1500 |
}
|
| 1501 |
-
|
| 1502 |
-
/* Role
|
| 1503 |
.role-badge {
|
| 1504 |
display: inline-block;
|
| 1505 |
-
padding:
|
| 1506 |
-
border-radius:
|
| 1507 |
-
font-size:
|
| 1508 |
font-weight: 600;
|
| 1509 |
text-transform: uppercase;
|
| 1510 |
-
letter-spacing: 0.
|
| 1511 |
}
|
| 1512 |
.role-viewer {
|
| 1513 |
background: linear-gradient(135deg, #64748b 0%, #475569 100%);
|
|
@@ -1525,32 +1573,77 @@ with gr.Blocks(
|
|
| 1525 |
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
|
| 1526 |
color: white;
|
| 1527 |
}
|
| 1528 |
-
|
| 1529 |
-
/*
|
| 1530 |
input[type="text"], textarea, select {
|
| 1531 |
border-radius: 10px !important;
|
| 1532 |
-
border:
|
| 1533 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1534 |
}
|
| 1535 |
input[type="text"]:focus, textarea:focus, select:focus {
|
| 1536 |
border-color: #06b6d4 !important;
|
| 1537 |
-
box-shadow: 0 0 0
|
|
|
|
| 1538 |
}
|
| 1539 |
-
|
| 1540 |
-
/*
|
| 1541 |
.section-card {
|
| 1542 |
-
background:
|
| 1543 |
-
padding:
|
| 1544 |
border-radius: 16px;
|
| 1545 |
-
border: 1px solid rgba(148, 163, 184, 0.
|
| 1546 |
-
margin-bottom:
|
| 1547 |
-
backdrop-filter: blur(
|
|
|
|
|
|
|
| 1548 |
}
|
| 1549 |
-
|
| 1550 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1551 |
.chatbot {
|
| 1552 |
-
border-radius:
|
| 1553 |
-
border: 1px solid rgba(148, 163, 184, 0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1554 |
}
|
| 1555 |
"""
|
| 1556 |
) as demo:
|
|
@@ -1576,22 +1669,46 @@ with gr.Blocks(
|
|
| 1576 |
)
|
| 1577 |
|
| 1578 |
with gr.Row(elem_classes=["input-container"]):
|
| 1579 |
-
|
| 1580 |
-
|
| 1581 |
-
|
| 1582 |
-
|
| 1583 |
-
|
| 1584 |
-
|
| 1585 |
-
|
| 1586 |
-
|
| 1587 |
-
|
| 1588 |
-
|
| 1589 |
-
|
| 1590 |
-
|
| 1591 |
-
|
| 1592 |
-
|
| 1593 |
-
|
| 1594 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1595 |
|
| 1596 |
with gr.Tabs():
|
| 1597 |
with gr.Tab("Chat"):
|
|
@@ -1614,45 +1731,45 @@ with gr.Blocks(
|
|
| 1614 |
chat_content = gr.Column(visible=True)
|
| 1615 |
|
| 1616 |
with chat_content:
|
| 1617 |
-
|
| 1618 |
-
|
|
|
|
| 1619 |
chatbot = gr.Chatbot(
|
| 1620 |
-
|
| 1621 |
-
|
| 1622 |
-
|
| 1623 |
-
|
| 1624 |
-
|
| 1625 |
-
|
| 1626 |
-
|
| 1627 |
-
with gr.Row():
|
| 1628 |
-
message_input = gr.Textbox(
|
| 1629 |
-
label="Message",
|
| 1630 |
-
placeholder="Type your message here...",
|
| 1631 |
-
scale=4,
|
| 1632 |
-
show_label=False,
|
| 1633 |
-
container=False
|
| 1634 |
)
|
| 1635 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1636 |
|
| 1637 |
-
with gr.Column(scale=1):
|
| 1638 |
gr.Markdown(
|
| 1639 |
"""
|
| 1640 |
-
<div style="background: linear-gradient(135deg, rgba(6, 182, 212, 0.1) 0%, rgba(59, 130, 246, 0.1) 100%); padding: 20px; border-radius: 12px; border: 1px solid rgba(6, 182, 212, 0.2);">
|
| 1641 |
### π Chat Instructions
|
| 1642 |
-
1. Enter your **Tenant ID** and **Role** above
|
| 1643 |
-
2. Ask a question or give a task to the agent
|
| 1644 |
3. The MCP agent will automatically select tools (RAG, Web, etc.)
|
| 1645 |
|
| 1646 |
### β‘ Features
|
| 1647 |
-
- β¨ Real-time streaming responses
|
| 1648 |
-
- π§ Multi-step planning & reasoning
|
| 1649 |
-
- π Automatic tool selection with latency prediction
|
| 1650 |
-
- π§ Context-aware routing (intelligent tool skipping)
|
| 1651 |
-
- πΎ Conversation memory
|
| 1652 |
-
- π Reasoning visualization (see Debug tab)
|
| 1653 |
-
- β‘ Per-tool latency estimates (RAG: 60-120ms, Web: 400-1800ms)
|
| 1654 |
- π Schema-validated tool outputs
|
| 1655 |
-
</div>
|
| 1656 |
"""
|
| 1657 |
)
|
| 1658 |
|
|
|
|
| 1336 |
font=("Inter", "system-ui", "sans-serif")
|
| 1337 |
),
|
| 1338 |
css="""
|
| 1339 |
+
/* Global dark theme with simpler, basic colors */
|
| 1340 |
+
body, .gradio-container {
|
| 1341 |
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
| 1342 |
+
background: #020617;
|
| 1343 |
+
color: #e5e7eb;
|
| 1344 |
}
|
| 1345 |
+
|
| 1346 |
+
/* Remove default card backgrounds so our custom sections stand out */
|
| 1347 |
+
.gradio-container .block {
|
| 1348 |
+
background: transparent;
|
| 1349 |
+
}
|
| 1350 |
+
|
| 1351 |
/* Header styling */
|
| 1352 |
.header-section {
|
| 1353 |
+
background: #020617;
|
| 1354 |
+
padding: 28px 24px;
|
| 1355 |
+
border-radius: 18px;
|
| 1356 |
margin-bottom: 24px;
|
| 1357 |
+
box-shadow: 0 18px 60px rgba(15, 23, 42, 0.9);
|
| 1358 |
+
border: 1px solid rgba(148, 163, 184, 0.25);
|
| 1359 |
}
|
| 1360 |
+
|
| 1361 |
.header-section h1 {
|
| 1362 |
+
color: #e5e7eb;
|
| 1363 |
+
font-size: 2.4rem;
|
|
|
|
|
|
|
|
|
|
| 1364 |
font-weight: 700;
|
| 1365 |
+
margin-bottom: 8px;
|
| 1366 |
+
letter-spacing: 0.02em;
|
| 1367 |
}
|
| 1368 |
+
|
| 1369 |
+
.header-section p {
|
| 1370 |
+
color: #cbd5f5;
|
| 1371 |
+
font-size: 0.98rem;
|
| 1372 |
+
max-width: 720px;
|
| 1373 |
+
}
|
| 1374 |
+
|
| 1375 |
+
/* Input fields strip */
|
| 1376 |
.input-container {
|
| 1377 |
+
background: #020617;
|
| 1378 |
+
padding: 18px 20px 22px 20px;
|
| 1379 |
+
border-radius: 14px;
|
| 1380 |
+
border: 1px solid rgba(148, 163, 184, 0.35);
|
| 1381 |
+
backdrop-filter: blur(18px);
|
| 1382 |
+
box-shadow: 0 12px 40px rgba(15, 23, 42, 0.9);
|
| 1383 |
+
margin-bottom: 18px;
|
| 1384 |
}
|
| 1385 |
+
|
| 1386 |
+
/* Tenant / role cards */
|
| 1387 |
+
.tenant-card,
|
| 1388 |
+
.role-card {
|
| 1389 |
+
background: #020617;
|
| 1390 |
+
border-radius: 14px;
|
| 1391 |
+
padding: 16px 16px 14px 16px;
|
| 1392 |
+
border: 1px solid rgba(148, 163, 184, 0.6);
|
| 1393 |
+
box-shadow: 0 8px 26px rgba(15, 23, 42, 0.9);
|
| 1394 |
+
display: flex;
|
| 1395 |
+
flex-direction: column;
|
| 1396 |
+
gap: 10px;
|
| 1397 |
+
transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
|
| 1398 |
+
}
|
| 1399 |
+
|
| 1400 |
+
.tenant-card:hover,
|
| 1401 |
+
.role-card:hover {
|
| 1402 |
+
border-color: #38bdf8;
|
| 1403 |
+
box-shadow: 0 12px 36px rgba(56, 189, 248, 0.35);
|
| 1404 |
+
transform: translateY(-1px);
|
| 1405 |
+
}
|
| 1406 |
+
|
| 1407 |
+
.field-label-pill {
|
| 1408 |
+
display: inline-flex;
|
| 1409 |
+
align-items: center;
|
| 1410 |
+
gap: 8px;
|
| 1411 |
+
padding: 6px 12px;
|
| 1412 |
+
border-radius: 999px;
|
| 1413 |
+
background: #0f172a;
|
| 1414 |
+
color: #e5e7eb;
|
| 1415 |
+
font-size: 0.8rem;
|
| 1416 |
+
font-weight: 600;
|
| 1417 |
+
letter-spacing: 0.08em;
|
| 1418 |
+
text-transform: uppercase;
|
| 1419 |
+
border: 1px solid #38bdf8;
|
| 1420 |
+
}
|
| 1421 |
+
|
| 1422 |
+
.field-label-pill span.icon {
|
| 1423 |
+
font-size: 1rem;
|
| 1424 |
+
}
|
| 1425 |
+
|
| 1426 |
+
.field-label-subtitle {
|
| 1427 |
+
margin-top: 8px;
|
| 1428 |
+
color: #9ca3af;
|
| 1429 |
+
font-size: 0.8rem;
|
| 1430 |
+
}
|
| 1431 |
+
|
| 1432 |
+
/* Left/right columns in Chat tab */
|
| 1433 |
+
.chat-row > .col:nth-child(1) {
|
| 1434 |
+
min-width: 0;
|
| 1435 |
+
}
|
| 1436 |
+
|
| 1437 |
+
/* Stat cards */
|
| 1438 |
.stat-card {
|
| 1439 |
+
background: #020617;
|
| 1440 |
+
padding: 22px;
|
| 1441 |
border-radius: 16px;
|
| 1442 |
color: white;
|
| 1443 |
+
text-align: left;
|
| 1444 |
+
box-shadow: 0 12px 32px rgba(15, 23, 42, 0.9);
|
| 1445 |
+
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
|
| 1446 |
+
border: 1px solid rgba(248, 250, 252, 0.25);
|
| 1447 |
}
|
| 1448 |
.stat-card:hover {
|
| 1449 |
+
transform: translateY(-3px) scale(1.01);
|
| 1450 |
+
box-shadow: 0 16px 40px rgba(15, 23, 42, 0.95);
|
| 1451 |
+
border-color: #38bdf8;
|
| 1452 |
}
|
| 1453 |
.stat-card h3 {
|
| 1454 |
+
margin: 0 0 6px 0;
|
| 1455 |
+
font-size: 0.78rem;
|
| 1456 |
+
opacity: 0.9;
|
| 1457 |
+
font-weight: 600;
|
| 1458 |
+
letter-spacing: 0.16em;
|
| 1459 |
text-transform: uppercase;
|
| 1460 |
}
|
| 1461 |
.stat-card strong {
|
| 1462 |
+
font-size: 1.8rem;
|
| 1463 |
font-weight: 700;
|
| 1464 |
display: block;
|
| 1465 |
margin-top: 8px;
|
| 1466 |
}
|
| 1467 |
+
|
| 1468 |
+
/* Summary / debug panel */
|
| 1469 |
.summary-box {
|
| 1470 |
+
background: #020617;
|
| 1471 |
+
padding: 24px;
|
| 1472 |
+
border-radius: 18px;
|
| 1473 |
+
border: 1px solid rgba(148, 163, 184, 0.7);
|
| 1474 |
+
max-height: 520px;
|
| 1475 |
overflow-y: auto;
|
| 1476 |
+
box-shadow: 0 18px 48px rgba(15, 23, 42, 0.95);
|
| 1477 |
+
color: #e5e7eb;
|
| 1478 |
+
backdrop-filter: blur(18px);
|
| 1479 |
+
transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
|
| 1480 |
}
|
| 1481 |
.summary-box::-webkit-scrollbar {
|
| 1482 |
width: 8px;
|
| 1483 |
}
|
| 1484 |
.summary-box::-webkit-scrollbar-track {
|
| 1485 |
+
background: rgba(15, 23, 42, 1);
|
| 1486 |
+
border-radius: 999px;
|
| 1487 |
}
|
| 1488 |
.summary-box::-webkit-scrollbar-thumb {
|
| 1489 |
+
background: rgba(148, 163, 184, 0.7);
|
| 1490 |
+
border-radius: 999px;
|
| 1491 |
}
|
| 1492 |
+
|
| 1493 |
+
.summary-box:hover {
|
| 1494 |
+
border-color: #38bdf8;
|
| 1495 |
+
box-shadow: 0 22px 60px rgba(15, 23, 42, 1);
|
| 1496 |
+
transform: translateY(-1px);
|
| 1497 |
}
|
| 1498 |
.summary-box h3, .summary-box h4 {
|
| 1499 |
margin-top: 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1500 |
margin-bottom: 12px;
|
| 1501 |
+
color: #f9fafb;
|
| 1502 |
+
font-weight: 600;
|
| 1503 |
}
|
| 1504 |
+
.summary-box p,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1505 |
.summary-box li {
|
| 1506 |
+
color: #e5e7eb;
|
| 1507 |
+
margin: 8px 0;
|
| 1508 |
line-height: 1.7;
|
| 1509 |
}
|
| 1510 |
.summary-box code {
|
| 1511 |
+
background-color: rgba(15, 23, 42, 0.9);
|
| 1512 |
+
color: #22c55e;
|
| 1513 |
+
padding: 3px 7px;
|
| 1514 |
border-radius: 6px;
|
| 1515 |
font-family: 'Fira Code', 'Courier New', monospace;
|
| 1516 |
+
font-size: 0.78rem;
|
| 1517 |
+
border: 1px solid rgba(148, 163, 184, 0.45);
|
| 1518 |
}
|
| 1519 |
+
|
| 1520 |
+
/* Chart titles / section headings */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1521 |
.chart-title {
|
| 1522 |
+
margin-bottom: 8px;
|
| 1523 |
margin-top: 0;
|
| 1524 |
font-weight: 600;
|
| 1525 |
+
color: #e5e7eb;
|
| 1526 |
text-align: center;
|
| 1527 |
+
font-size: 1rem;
|
| 1528 |
}
|
| 1529 |
+
|
| 1530 |
+
/* Primary buttons */
|
| 1531 |
button.primary {
|
| 1532 |
+
background: #0ea5e9;
|
| 1533 |
border: none;
|
| 1534 |
+
box-shadow: 0 8px 26px rgba(15, 23, 42, 0.9);
|
| 1535 |
+
transition: transform 0.15s ease, box-shadow 0.15s ease, filter 0.15s ease;
|
| 1536 |
+
border-radius: 999px;
|
| 1537 |
+
font-weight: 600;
|
| 1538 |
}
|
| 1539 |
button.primary:hover {
|
| 1540 |
+
transform: translateY(-1px);
|
| 1541 |
+
filter: brightness(1.08);
|
| 1542 |
+
box-shadow: 0 12px 32px rgba(15, 23, 42, 1);
|
| 1543 |
}
|
| 1544 |
+
|
| 1545 |
+
/* Tabs */
|
| 1546 |
.tab-nav {
|
| 1547 |
+
border-bottom: 1px solid rgba(148, 163, 184, 0.35);
|
| 1548 |
}
|
| 1549 |
+
|
| 1550 |
+
/* Role badges */
|
| 1551 |
.role-badge {
|
| 1552 |
display: inline-block;
|
| 1553 |
+
padding: 5px 11px;
|
| 1554 |
+
border-radius: 999px;
|
| 1555 |
+
font-size: 0.7rem;
|
| 1556 |
font-weight: 600;
|
| 1557 |
text-transform: uppercase;
|
| 1558 |
+
letter-spacing: 0.1em;
|
| 1559 |
}
|
| 1560 |
.role-viewer {
|
| 1561 |
background: linear-gradient(135deg, #64748b 0%, #475569 100%);
|
|
|
|
| 1573 |
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
|
| 1574 |
color: white;
|
| 1575 |
}
|
| 1576 |
+
|
| 1577 |
+
/* Inputs */
|
| 1578 |
input[type="text"], textarea, select {
|
| 1579 |
border-radius: 10px !important;
|
| 1580 |
+
border: 1px solid rgba(148, 163, 184, 0.5) !important;
|
| 1581 |
+
background: rgba(15, 23, 42, 0.92) !important;
|
| 1582 |
+
color: #e5e7eb !important;
|
| 1583 |
+
transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease !important;
|
| 1584 |
+
}
|
| 1585 |
+
input[type="text"]::placeholder,
|
| 1586 |
+
textarea::placeholder {
|
| 1587 |
+
color: rgba(148, 163, 184, 0.65) !important;
|
| 1588 |
}
|
| 1589 |
input[type="text"]:focus, textarea:focus, select:focus {
|
| 1590 |
border-color: #06b6d4 !important;
|
| 1591 |
+
box-shadow: 0 0 0 1px rgba(6, 182, 212, 0.65) !important;
|
| 1592 |
+
background: rgba(15, 23, 42, 1) !important;
|
| 1593 |
}
|
| 1594 |
+
|
| 1595 |
+
/* Generic section card */
|
| 1596 |
.section-card {
|
| 1597 |
+
background: #020617;
|
| 1598 |
+
padding: 22px;
|
| 1599 |
border-radius: 16px;
|
| 1600 |
+
border: 1px solid rgba(148, 163, 184, 0.4);
|
| 1601 |
+
margin-bottom: 18px;
|
| 1602 |
+
backdrop-filter: blur(14px);
|
| 1603 |
+
box-shadow: 0 14px 40px rgba(15, 23, 42, 0.95);
|
| 1604 |
+
transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
|
| 1605 |
}
|
| 1606 |
+
|
| 1607 |
+
.section-card:hover {
|
| 1608 |
+
border-color: #38bdf8;
|
| 1609 |
+
box-shadow: 0 18px 52px rgba(15, 23, 42, 1);
|
| 1610 |
+
transform: translateY(-1px);
|
| 1611 |
+
}
|
| 1612 |
+
|
| 1613 |
+
/* Chatbot + message bubbles */
|
| 1614 |
.chatbot {
|
| 1615 |
+
border-radius: 18px !important;
|
| 1616 |
+
border: 1px solid rgba(148, 163, 184, 0.7) !important;
|
| 1617 |
+
background: #020617 !important;
|
| 1618 |
+
box-shadow: 0 18px 60px rgba(15, 23, 42, 1);
|
| 1619 |
+
}
|
| 1620 |
+
|
| 1621 |
+
.chatbot .message {
|
| 1622 |
+
border-radius: 16px;
|
| 1623 |
+
padding: 10px 14px;
|
| 1624 |
+
font-size: 0.95rem;
|
| 1625 |
+
line-height: 1.6;
|
| 1626 |
+
max-width: 80%;
|
| 1627 |
+
}
|
| 1628 |
+
|
| 1629 |
+
.chatbot .message.user {
|
| 1630 |
+
margin-left: auto;
|
| 1631 |
+
background: #0ea5e9;
|
| 1632 |
+
color: #0b1020;
|
| 1633 |
+
box-shadow: 0 12px 32px rgba(15, 23, 42, 0.9);
|
| 1634 |
+
}
|
| 1635 |
+
|
| 1636 |
+
.chatbot .message.bot {
|
| 1637 |
+
margin-right: auto;
|
| 1638 |
+
background: #020617;
|
| 1639 |
+
border: 1px solid rgba(148, 163, 184, 0.8);
|
| 1640 |
+
color: #e5e7eb;
|
| 1641 |
+
box-shadow: 0 14px 40px rgba(15, 23, 42, 1);
|
| 1642 |
+
}
|
| 1643 |
+
|
| 1644 |
+
.chatbot .message.error {
|
| 1645 |
+
background: linear-gradient(135deg, rgba(239, 68, 68, 0.16) 0%, rgba(127, 29, 29, 0.9) 100%);
|
| 1646 |
+
border: 1px solid rgba(248, 113, 113, 0.9);
|
| 1647 |
}
|
| 1648 |
"""
|
| 1649 |
) as demo:
|
|
|
|
| 1669 |
)
|
| 1670 |
|
| 1671 |
with gr.Row(elem_classes=["input-container"]):
|
| 1672 |
+
with gr.Column(scale=2, elem_classes=["tenant-card"]):
|
| 1673 |
+
gr.Markdown(
|
| 1674 |
+
"""
|
| 1675 |
+
<div class="field-label-pill">
|
| 1676 |
+
<span class="icon">π’</span>
|
| 1677 |
+
<span>Tenant ID</span>
|
| 1678 |
+
</div>
|
| 1679 |
+
<div class="field-label-subtitle">
|
| 1680 |
+
Required for all operations. Use a unique ID per customer / environment.
|
| 1681 |
+
</div>
|
| 1682 |
+
"""
|
| 1683 |
+
)
|
| 1684 |
+
tenant_id_input = gr.Textbox(
|
| 1685 |
+
label="",
|
| 1686 |
+
placeholder="Enter your tenant ID (e.g., tenant123)",
|
| 1687 |
+
value="",
|
| 1688 |
+
interactive=True,
|
| 1689 |
+
scale=2,
|
| 1690 |
+
show_label=False,
|
| 1691 |
+
)
|
| 1692 |
+
with gr.Column(scale=1, elem_classes=["role-card"]):
|
| 1693 |
+
gr.Markdown(
|
| 1694 |
+
"""
|
| 1695 |
+
<div class="field-label-pill">
|
| 1696 |
+
<span class="icon">π€</span>
|
| 1697 |
+
<span>User Role</span>
|
| 1698 |
+
</div>
|
| 1699 |
+
<div class="field-label-subtitle">
|
| 1700 |
+
Select your role to automatically unlock the right capabilities.
|
| 1701 |
+
</div>
|
| 1702 |
+
"""
|
| 1703 |
+
)
|
| 1704 |
+
role_input = gr.Dropdown(
|
| 1705 |
+
label="",
|
| 1706 |
+
choices=VALID_ROLES,
|
| 1707 |
+
value=DEFAULT_ROLE,
|
| 1708 |
+
interactive=True,
|
| 1709 |
+
scale=1,
|
| 1710 |
+
show_label=False,
|
| 1711 |
+
)
|
| 1712 |
|
| 1713 |
with gr.Tabs():
|
| 1714 |
with gr.Tab("Chat"):
|
|
|
|
| 1731 |
chat_content = gr.Column(visible=True)
|
| 1732 |
|
| 1733 |
with chat_content:
|
| 1734 |
+
# Two-column layout: chat on the left, guidance panel on the right
|
| 1735 |
+
with gr.Row(elem_classes=["chat-row"]):
|
| 1736 |
+
with gr.Column(scale=2, elem_classes=["section-card"]):
|
| 1737 |
chatbot = gr.Chatbot(
|
| 1738 |
+
label="Chat with Agent",
|
| 1739 |
+
height=500,
|
| 1740 |
+
show_label=True,
|
| 1741 |
+
container=True,
|
| 1742 |
+
type="messages",
|
| 1743 |
+
elem_classes=["chatbot"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1744 |
)
|
| 1745 |
+
|
| 1746 |
+
with gr.Row():
|
| 1747 |
+
message_input = gr.Textbox(
|
| 1748 |
+
label="Message",
|
| 1749 |
+
placeholder="Type your message here...",
|
| 1750 |
+
scale=4,
|
| 1751 |
+
show_label=False,
|
| 1752 |
+
container=False
|
| 1753 |
+
)
|
| 1754 |
+
send_button = gr.Button("Send", variant="primary", scale=1)
|
| 1755 |
|
| 1756 |
+
with gr.Column(scale=1, elem_classes=["summary-box"]):
|
| 1757 |
gr.Markdown(
|
| 1758 |
"""
|
|
|
|
| 1759 |
### π Chat Instructions
|
| 1760 |
+
1. Enter your **Tenant ID** and **Role** above
|
| 1761 |
+
2. Ask a question or give a task to the agent
|
| 1762 |
3. The MCP agent will automatically select tools (RAG, Web, etc.)
|
| 1763 |
|
| 1764 |
### β‘ Features
|
| 1765 |
+
- β¨ Real-time streaming responses
|
| 1766 |
+
- π§ Multi-step planning & reasoning
|
| 1767 |
+
- π Automatic tool selection with latency prediction
|
| 1768 |
+
- π§ Context-aware routing (intelligent tool skipping)
|
| 1769 |
+
- πΎ Conversation memory
|
| 1770 |
+
- π Reasoning visualization (see Debug tab)
|
| 1771 |
+
- β‘ Per-tool latency estimates (RAG: 60-120ms, Web: 400-1800ms)
|
| 1772 |
- π Schema-validated tool outputs
|
|
|
|
| 1773 |
"""
|
| 1774 |
)
|
| 1775 |
|
backend/api/services/agent_orchestrator.py
CHANGED
|
@@ -386,11 +386,11 @@ Response:"""
|
|
| 386 |
|
| 387 |
# 3) Tool selection (hybrid) - pass RAG results, memory, and admin violations in context
|
| 388 |
# Get recent memory for context-aware routing
|
| 389 |
-
from backend.mcp_server.common.memory import
|
| 390 |
session_id = req.conversation_history[-1].get("session_id") if req.conversation_history else None
|
| 391 |
recent_memory = []
|
| 392 |
if session_id:
|
| 393 |
-
recent_memory =
|
| 394 |
|
| 395 |
# Get admin violations if any
|
| 396 |
admin_violations = []
|
|
|
|
| 386 |
|
| 387 |
# 3) Tool selection (hybrid) - pass RAG results, memory, and admin violations in context
|
| 388 |
# Get recent memory for context-aware routing
|
| 389 |
+
from backend.mcp_server.common.memory import get_recent
|
| 390 |
session_id = req.conversation_history[-1].get("session_id") if req.conversation_history else None
|
| 391 |
recent_memory = []
|
| 392 |
if session_id:
|
| 393 |
+
recent_memory = get_recent(session_id)
|
| 394 |
|
| 395 |
# Get admin violations if any
|
| 396 |
admin_violations = []
|
backend/tests/README_RETRY_TESTS.md
CHANGED
|
@@ -263,3 +263,4 @@ For more information, see `TESTING_GUIDE.md` in the project root.
|
|
| 263 |
|
| 264 |
|
| 265 |
|
|
|
|
|
|
| 263 |
|
| 264 |
|
| 265 |
|
| 266 |
+
|