mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-10-27 07:51:52 +00:00
Merge pull request #299 from PR0M3TH3AN/landing-agent-showcase-6257913996332399187
feat: Add agent showcase to landing page
This commit is contained in:
1 file changed
+319
@@ -593,6 +593,157 @@
|
|||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Agent Showcase Section */
|
||||||
|
.agent-showcase {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 4rem auto;
|
||||||
|
padding: 0 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agent-showcase h2 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--text-strong);
|
||||||
|
}
|
||||||
|
|
||||||
|
.agent-category-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: var(--accent);
|
||||||
|
margin: 2rem 0 1.5rem;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.functional-agent-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.functional-agent-card {
|
||||||
|
background: rgba(255, 255, 255, 0.02);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
padding: 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.functional-agent-card:hover {
|
||||||
|
border-color: var(--accent);
|
||||||
|
background: rgba(79, 140, 255, 0.05);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.functional-agent-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.functional-agent-title {
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-strong);
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.functional-agent-schedule {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: 0.2rem 0.5rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: var(--surface-alt);
|
||||||
|
color: var(--muted);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.functional-agent-desc {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--muted);
|
||||||
|
line-height: 1.5;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-prompt-btn {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
color: var(--text);
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-prompt-btn:hover {
|
||||||
|
border-color: var(--accent);
|
||||||
|
color: var(--accent);
|
||||||
|
background: rgba(79, 140, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prompt Modal */
|
||||||
|
#promptModal .modal-content {
|
||||||
|
max-width: 900px;
|
||||||
|
width: 90%;
|
||||||
|
height: 85vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0;
|
||||||
|
background: var(--surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
#promptModal .modal-header {
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background: var(--surface-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
#promptModal .modal-title {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: var(--text-strong);
|
||||||
|
}
|
||||||
|
|
||||||
|
#promptModal .modal-body {
|
||||||
|
flex: 1;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 0;
|
||||||
|
background: #0d1117;
|
||||||
|
}
|
||||||
|
|
||||||
|
#promptModal .modal-body pre {
|
||||||
|
margin: 0;
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#promptModal .modal-body code {
|
||||||
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #e6edf3;
|
||||||
|
line-height: 1.5;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#promptModal .close-prompt {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 1.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#promptModal .close-prompt:hover {
|
||||||
|
color: var(--text-strong);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -732,6 +883,14 @@ npm install https://github.com/PR0M3TH3AN/TORCH/archive/refs/heads/main.tar.gz &
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="agent-showcase" id="agent-showcase">
|
||||||
|
<h2>Functional Agents</h2>
|
||||||
|
<div id="functional-agent-list">
|
||||||
|
<!-- Populated by JS -->
|
||||||
|
<p class="text-center text-muted">Loading agents...</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section class="meta-prompts">
|
<section class="meta-prompts">
|
||||||
<h2>Scheduler Meta Prompts</h2>
|
<h2>Scheduler Meta Prompts</h2>
|
||||||
<div class="prompts-grid">
|
<div class="prompts-grid">
|
||||||
@@ -775,6 +934,22 @@ npm install https://github.com/PR0M3TH3AN/TORCH/archive/refs/heads/main.tar.gz &
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Agent Prompt Modal -->
|
||||||
|
<div id="promptModal" class="modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<span class="modal-title" id="promptModalTitle">Agent Prompt</span>
|
||||||
|
<div style="display: flex; gap: 1rem; align-items: center;">
|
||||||
|
<button class="copy-btn" id="copyPromptBtn">Copy</button>
|
||||||
|
<span class="close-prompt">×</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<pre><code id="promptModalCode">Loading...</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Acknowledgement Modal -->
|
<!-- Acknowledgement Modal -->
|
||||||
<div id="ackModal" class="modal">
|
<div id="ackModal" class="modal">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@@ -815,6 +990,23 @@ npm install https://github.com/PR0M3TH3AN/TORCH/archive/refs/heads/main.tar.gz &
|
|||||||
modal.classList.remove("show");
|
modal.classList.remove("show");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Agent Prompt Modal Logic
|
||||||
|
const promptModal = document.getElementById("promptModal");
|
||||||
|
const closePromptBtn = document.querySelector("#promptModal .close-prompt");
|
||||||
|
const copyPromptBtn = document.getElementById("copyPromptBtn");
|
||||||
|
|
||||||
|
if (closePromptBtn) {
|
||||||
|
closePromptBtn.onclick = function() {
|
||||||
|
promptModal.classList.remove("show");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copyPromptBtn) {
|
||||||
|
copyPromptBtn.onclick = function() {
|
||||||
|
copyToClipboard('promptModalCode', copyPromptBtn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
window.onclick = function(event) {
|
window.onclick = function(event) {
|
||||||
if (event.target == modal) {
|
if (event.target == modal) {
|
||||||
modal.classList.remove("show");
|
modal.classList.remove("show");
|
||||||
@@ -822,6 +1014,9 @@ npm install https://github.com/PR0M3TH3AN/TORCH/archive/refs/heads/main.tar.gz &
|
|||||||
if (event.target == ackModal) {
|
if (event.target == ackModal) {
|
||||||
dismissAckModal();
|
dismissAckModal();
|
||||||
}
|
}
|
||||||
|
if (event.target == promptModal) {
|
||||||
|
promptModal.classList.remove("show");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch and Render Markdown
|
// Fetch and Render Markdown
|
||||||
@@ -918,6 +1113,130 @@ npm install https://github.com/PR0M3TH3AN/TORCH/archive/refs/heads/main.tar.gz &
|
|||||||
|
|
||||||
// Initialize Meta Prompts
|
// Initialize Meta Prompts
|
||||||
fetchMetaPrompts();
|
fetchMetaPrompts();
|
||||||
|
|
||||||
|
// Initialize Agent Showcase
|
||||||
|
fetchAgents();
|
||||||
|
|
||||||
|
// Store agent data globally
|
||||||
|
window.agentData = {};
|
||||||
|
|
||||||
|
async function fetchAgents() {
|
||||||
|
const container = document.getElementById('functional-agent-list');
|
||||||
|
try {
|
||||||
|
const response = await fetch('../src/prompts/roster.json');
|
||||||
|
if (!response.ok) throw new Error('Failed to load roster');
|
||||||
|
const roster = await response.json();
|
||||||
|
|
||||||
|
container.innerHTML = ''; // Clear loading state
|
||||||
|
|
||||||
|
for (const category of ['daily', 'weekly']) {
|
||||||
|
if (!roster[category] || roster[category].length === 0) continue;
|
||||||
|
|
||||||
|
// Category Title
|
||||||
|
const categoryTitle = document.createElement('div');
|
||||||
|
categoryTitle.className = 'agent-category-title';
|
||||||
|
categoryTitle.textContent = category.charAt(0).toUpperCase() + category.slice(1) + ' Agents';
|
||||||
|
container.appendChild(categoryTitle);
|
||||||
|
|
||||||
|
// Grid
|
||||||
|
const grid = document.createElement('div');
|
||||||
|
grid.className = 'functional-agent-grid';
|
||||||
|
|
||||||
|
// Process agents in parallel
|
||||||
|
const agentPromises = roster[category].map(async (agentName) => {
|
||||||
|
try {
|
||||||
|
const mdResponse = await fetch(`../src/prompts/${category}/${agentName}.md`);
|
||||||
|
if (!mdResponse.ok) return null;
|
||||||
|
const content = await mdResponse.text();
|
||||||
|
|
||||||
|
// Extract Metadata
|
||||||
|
const meta = extractAgentMetadata(content, agentName);
|
||||||
|
return { ...meta, content, agentName, category };
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Failed to load ${agentName}`, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const agents = (await Promise.all(agentPromises)).filter(Boolean);
|
||||||
|
|
||||||
|
agents.forEach(agent => {
|
||||||
|
// Store in global map
|
||||||
|
window.agentData[agent.agentName] = agent;
|
||||||
|
|
||||||
|
const card = document.createElement('div');
|
||||||
|
card.className = 'functional-agent-card';
|
||||||
|
|
||||||
|
// Use data-agent-name attribute for safer handling if needed,
|
||||||
|
// but passing string literal ID is safe here as agentName is strict.
|
||||||
|
card.innerHTML = `
|
||||||
|
<div class="functional-agent-header">
|
||||||
|
<span class="functional-agent-title">${escapeHtml(agent.title)}</span>
|
||||||
|
<span class="functional-agent-schedule">${agent.category}</span>
|
||||||
|
</div>
|
||||||
|
<div class="functional-agent-desc">${escapeHtml(agent.description)}</div>
|
||||||
|
<button class="view-prompt-btn" onclick="openAgentModal('${agent.agentName}')">View Prompt</button>
|
||||||
|
`;
|
||||||
|
grid.appendChild(card);
|
||||||
|
});
|
||||||
|
|
||||||
|
container.appendChild(grid);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching agents:', error);
|
||||||
|
container.innerHTML = `<p class="text-center" style="color: var(--danger)">Error loading agents: ${error.message}</p>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractAgentMetadata(content, agentName) {
|
||||||
|
let title = agentName;
|
||||||
|
let description = "No description available.";
|
||||||
|
|
||||||
|
// Normalize newlines
|
||||||
|
content = content.replace(/\r\n/g, '\n');
|
||||||
|
|
||||||
|
// Title extraction
|
||||||
|
const titleMatch = content.match(/You are:\s*\*\*?([^\*\n,.]+)\*\*?/i);
|
||||||
|
if (titleMatch) {
|
||||||
|
title = titleMatch[1].trim();
|
||||||
|
// Ensure Title Case if it looks like kebab-case
|
||||||
|
if (title.includes('-') && title.toLowerCase() === title) {
|
||||||
|
title = title.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
title = agentName.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Description extraction
|
||||||
|
const missionRegex = /(?:\bYour single-purpose mission\b|\bMission\b|\bYour mission\b):?\s*(?:\*\*)?([^\n]+)/i;
|
||||||
|
const missionMatch = content.match(missionRegex);
|
||||||
|
|
||||||
|
if (missionMatch) {
|
||||||
|
description = missionMatch[1].replace(/\*\*/g, '').trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return { title, description };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expose to window for onclick
|
||||||
|
window.openAgentModal = function(agentName) {
|
||||||
|
const agent = window.agentData[agentName];
|
||||||
|
if (!agent) return;
|
||||||
|
|
||||||
|
document.getElementById('promptModalTitle').textContent = agent.title;
|
||||||
|
document.getElementById('promptModalCode').textContent = agent.content;
|
||||||
|
document.getElementById('promptModal').classList.add('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml(unsafe) {
|
||||||
|
return unsafe
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """)
|
||||||
|
.replace(/'/g, "'");
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in new issue
Block a user