Prompt-editori modal: avain-arvo-parit, editoitavat kentät

Klikkaa agenttia → 'Näytä viimeisin prompti' → modal-ikkuna jossa
prompti on pilkottu rakenteellisiin kenttiin (Project, CONSTRAINTS,
EXAMPLE jne.). Editoitavat kentät sinisellä ✏️, lukitut harmaalla 🔒.
'Aja uudelleen' kokoaa promptin kentistä ja ajaa sen.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-07 08:24:29 +03:00
parent 5a52f5113c
commit 6b756e2e83

View File

@@ -1076,12 +1076,8 @@
<div id="shared-prompt-section" style="display:none;margin-top:8px;font-size:12px;color:#8b949e"> <div id="shared-prompt-section" style="display:none;margin-top:8px;font-size:12px;color:#8b949e">
Yhteinen konteksti liitetään jokaisen valitun agentin oman promptin alkuun. Yhteinen konteksti liitetään jokaisen valitun agentin oman promptin alkuun.
</div> </div>
<div id="agent-last-prompt" style="display:none;margin-top:12px;border-top:1px solid var(--border-color);padding-top:10px"> <div id="agent-last-prompt" style="display:none;margin-top:8px">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px"> <button id="agent-open-modal-btn" style="background:#161b22;border:1px solid var(--accent-color);color:var(--accent-color);font-size:12px;padding:4px 12px;border-radius:4px;cursor:pointer;width:100%">📋 Näytä viimeisin prompti</button>
<span style="font-size:12px;color:#8b949e">Viimeisin pipeline-prompti:</span>
<button id="agent-rerun-btn" style="background:#161b22;border:1px solid var(--accent-color);color:var(--accent-color);font-size:11px;padding:2px 10px;border-radius:4px;cursor:pointer">▶ Aja uudelleen</button>
</div>
<textarea id="agent-last-prompt-text" style="width:100%;background:#010409;border:1px solid var(--border-color);border-radius:4px;color:#c9d1d9;font-size:12px;font-family:'Courier New',monospace;padding:8px;resize:vertical;min-height:80px;outline:none"></textarea>
</div> </div>
</div> </div>
</div> </div>
@@ -1260,14 +1256,7 @@
if (selectedAgents.size === 1) { if (selectedAgents.size === 1) {
const agent = [...selectedAgents][0]; const agent = [...selectedAgents][0];
const lastStep = [...pipelineSteps].reverse().find(s => s.agent === agent && s.status === 'done' && s.input); const lastStep = [...pipelineSteps].reverse().find(s => s.agent === agent && s.status === 'done' && s.input);
if (lastStep) { lastPromptDiv.style.display = lastStep ? 'block' : 'none';
lastPromptDiv.style.display = 'block';
lastPromptText.value = lastStep.input;
lastPromptText.dataset.agent = agent;
lastPromptText.dataset.label = lastStep.label;
} else {
lastPromptDiv.style.display = 'none';
}
} else { } else {
lastPromptDiv.style.display = 'none'; lastPromptDiv.style.display = 'none';
} }
@@ -1327,15 +1316,94 @@
saved._t = setTimeout(() => saved.style.opacity = '0', 1500); saved._t = setTimeout(() => saved.style.opacity = '0', 1500);
}); });
// "Aja uudelleen" -nappi: ajaa editoidun promptin samalla agentilla // Prompt-editori modal
document.getElementById('agent-rerun-btn')?.addEventListener('click', () => { let modalAgent = null;
const textEl = document.getElementById('agent-last-prompt-text'); let modalPromptParts = [];
const prompt = textEl?.value?.trim();
if (!prompt) return; function parsePromptToFields(prompt) {
const agent = textEl.dataset.agent; // Pilkotaan prompti avain-arvo-pareiksi
const model = agentPrompts[agent]?.model || 'qwen-coder'; const fields = [];
termLog(`<span class="terminal-prompt">$</span> <span style="color:#a371f7">↻ Aja uudelleen:</span> ${esc(agent)}${esc(prompt.substring(0, 60))}...`); const lines = prompt.split('\n');
let currentKey = null;
let currentVal = [];
for (const line of lines) {
// Tunnistetaan avain: KEYWORD: tai KEYWORD — tai rivin alku isolla
const keyMatch = line.match(/^(Project|CONSTRAINTS|EXAMPLE|RULES|IMPORTANT|Check|Files in project|Main app|Already written files|PROJECT CODE|Current code|Review feedback|Feedback)[\s:—]*(.*)/i);
if (keyMatch) {
if (currentKey) fields.push({ key: currentKey, value: currentVal.join('\n').trim(), editable: isEditable(currentKey) });
currentKey = keyMatch[1];
currentVal = keyMatch[2] ? [keyMatch[2]] : [];
} else {
currentVal.push(line);
}
}
if (currentKey) fields.push({ key: currentKey, value: currentVal.join('\n').trim(), editable: isEditable(currentKey) });
// Jos ei löytynyt rakenteellisia avaimia, näytetään koko prompti yhtenä
if (fields.length === 0) fields.push({ key: 'Prompti', value: prompt, editable: true });
return fields;
}
function isEditable(key) {
const editableKeys = ['Project', 'CONSTRAINTS', 'IMPORTANT', 'Feedback', 'Review feedback'];
return editableKeys.some(k => key.toLowerCase().includes(k.toLowerCase()));
}
function openPromptModal(agent, label, prompt) {
modalAgent = agent;
modalPromptParts = parsePromptToFields(prompt);
const modal = document.getElementById('prompt-modal');
const title = document.getElementById('prompt-modal-title');
const fields = document.getElementById('prompt-modal-fields');
const agentNames = { manager: 'Manageri', coder: 'Koodari', tester: 'DevOps', qa: 'QA', data: 'Data' };
title.textContent = `${agentNames[agent] || agent}${label}`;
fields.innerHTML = modalPromptParts.map((f, i) => `
<div style="border:1px solid #21262d;border-radius:6px;overflow:hidden">
<div style="background:#161b22;padding:6px 10px;font-size:12px;font-weight:600;color:${f.editable ? '#58a6ff' : '#8b949e'};display:flex;align-items:center;gap:6px">
${f.editable ? '✏️' : '🔒'} ${f.key}
</div>
<textarea data-field-idx="${i}" ${f.editable ? '' : 'readonly'} style="width:100%;background:${f.editable ? '#010409' : '#0d1117'};border:none;color:${f.editable ? '#c9d1d9' : '#6e7681'};font-size:12px;font-family:'Courier New',monospace;padding:8px;resize:vertical;min-height:${f.value.split('\n').length > 3 ? '100' : '40'}px;outline:none;box-sizing:border-box">${f.value.replace(/</g,'&lt;')}</textarea>
</div>
`).join('');
modal.style.display = 'block';
// Sulje klikatessa taustaa
modal.onclick = (e) => { if (e.target === modal) closePromptModal(); };
}
window.openPromptModal = openPromptModal;
function closePromptModal() {
document.getElementById('prompt-modal').style.display = 'none';
}
window.closePromptModal = closePromptModal;
function rerunFromModal() {
// Kootaan prompti takaisin kentistä
const fields = document.getElementById('prompt-modal-fields');
const textareas = fields.querySelectorAll('textarea');
const parts = [];
textareas.forEach((ta, i) => {
const key = modalPromptParts[i]?.key || '';
const val = ta.value.trim();
if (val) parts.push(`${key}: ${val}`);
});
const prompt = parts.join('\n\n');
const model = agentPrompts[modalAgent]?.model || 'qwen-coder';
closePromptModal();
termLog(`<span class="terminal-prompt">$</span> <span style="color:#a371f7">↻ Aja uudelleen:</span> ${esc(modalAgent)}`);
kpnRun(model, prompt); kpnRun(model, prompt);
}
window.rerunFromModal = rerunFromModal;
// "Näytä prompti" -nappi avaa modalin
document.getElementById('agent-open-modal-btn')?.addEventListener('click', () => {
if (selectedAgents.size !== 1) return;
const agent = [...selectedAgents][0];
const lastStep = [...pipelineSteps].reverse().find(s => s.agent === agent && s.status === 'done' && s.input);
if (lastStep) openPromptModal(agent, lastStep.label, lastStep.input);
}); });
function checkAgentConfusion() { function checkAgentConfusion() {
@@ -4112,5 +4180,20 @@ ${generatedFiles['Dockerfile'] || '(puuttuu)'}`;
return html; return html;
} }
</script> </script>
<!-- Prompt-editori modal -->
<div id="prompt-modal" style="display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);z-index:1000;backdrop-filter:blur(4px)">
<div style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:#0d1117;border:1px solid #30363d;border-radius:8px;width:700px;max-width:90vw;max-height:85vh;overflow-y:auto;padding:20px">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
<span id="prompt-modal-title" style="font-weight:600;font-size:15px;color:#58a6ff"></span>
<button onclick="closePromptModal()" style="background:none;border:none;color:#8b949e;font-size:20px;cursor:pointer;padding:0 4px">&times;</button>
</div>
<div id="prompt-modal-fields" style="display:flex;flex-direction:column;gap:10px"></div>
<div style="display:flex;gap:8px;margin-top:16px;justify-content:flex-end">
<button onclick="closePromptModal()" style="background:#161b22;border:1px solid #30363d;color:#8b949e;padding:6px 16px;border-radius:4px;cursor:pointer">Sulje</button>
<button onclick="rerunFromModal()" style="background:#238636;border:1px solid #2ea043;color:white;padding:6px 16px;border-radius:4px;cursor:pointer;font-weight:600">▶ Aja uudelleen</button>
</div>
</div>
</div>
</body> </body>
</html> </html>