Spaces:
Sleeping
Sleeping
Commit ·
0b9dfdd
1
Parent(s): e74a008
feat: add confirm/revise buttons to agent recommendations
Browse filesAgent messages now show CONFIRM and REVISE buttons. Confirming sends the
recommendation as a decision that updates the design state. Revising
pre-fills the input with context for the user to edit.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- agents/design_state.py +6 -0
- web/index.html +91 -1
agents/design_state.py
CHANGED
|
@@ -168,6 +168,12 @@ class DesignState(BaseModel):
|
|
| 168 |
if s not in state.decisions and len(state.decisions) < max_decisions:
|
| 169 |
state.decisions.append(s)
|
| 170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
# Extract part name from user message if not set
|
| 172 |
if not state.part_name and user_message:
|
| 173 |
name_patterns = [
|
|
|
|
| 168 |
if s not in state.decisions and len(state.decisions) < max_decisions:
|
| 169 |
state.decisions.append(s)
|
| 170 |
|
| 171 |
+
# Extract confirmed decisions from user messages ("Confirmed: Agent: ...")
|
| 172 |
+
if user_message.lower().startswith("confirmed:"):
|
| 173 |
+
decision = user_message.split(":", 2)[-1].strip()
|
| 174 |
+
if decision and decision not in state.decisions and len(state.decisions) < max_decisions:
|
| 175 |
+
state.decisions.append(decision)
|
| 176 |
+
|
| 177 |
# Extract part name from user message if not set
|
| 178 |
if not state.part_name and user_message:
|
| 179 |
name_patterns = [
|
web/index.html
CHANGED
|
@@ -694,6 +694,54 @@
|
|
| 694 |
|
| 695 |
.msg-view-code:hover { opacity: 0.7; }
|
| 696 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 697 |
/* Typing indicator */
|
| 698 |
.typing-indicator {
|
| 699 |
display: flex;
|
|
@@ -1626,6 +1674,7 @@ function addMessage(msg) {
|
|
| 1626 |
const isCad = agentId === 'cad';
|
| 1627 |
|
| 1628 |
el.className = 'msg msg-agent';
|
|
|
|
| 1629 |
|
| 1630 |
let html = '<div class="msg-avatar" style="background: ' + color + ';">' + avatar + '</div>';
|
| 1631 |
html += '<div class="msg-agent-body">';
|
|
@@ -1637,14 +1686,55 @@ function addMessage(msg) {
|
|
| 1637 |
html += '<br><a class="msg-view-code" onclick="openCodeModal()">▶ View code</a>';
|
| 1638 |
}
|
| 1639 |
|
| 1640 |
-
html += '</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1641 |
el.innerHTML = html;
|
|
|
|
|
|
|
| 1642 |
}
|
| 1643 |
|
| 1644 |
container.appendChild(el);
|
| 1645 |
scrollChatToBottom();
|
| 1646 |
}
|
| 1647 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1648 |
function showTyping() {
|
| 1649 |
const container = document.getElementById('chat-messages');
|
| 1650 |
const el = document.createElement('div');
|
|
|
|
| 694 |
|
| 695 |
.msg-view-code:hover { opacity: 0.7; }
|
| 696 |
|
| 697 |
+
.msg-actions {
|
| 698 |
+
display: flex;
|
| 699 |
+
gap: 6px;
|
| 700 |
+
margin-top: 8px;
|
| 701 |
+
}
|
| 702 |
+
|
| 703 |
+
.msg-actions.resolved { display: none; }
|
| 704 |
+
|
| 705 |
+
.msg-action-btn {
|
| 706 |
+
all: unset;
|
| 707 |
+
font-family: var(--font-mono);
|
| 708 |
+
font-size: 10px;
|
| 709 |
+
font-weight: 600;
|
| 710 |
+
letter-spacing: 0.5px;
|
| 711 |
+
padding: 4px 12px;
|
| 712 |
+
border-radius: 3px;
|
| 713 |
+
cursor: pointer;
|
| 714 |
+
transition: all 0.15s;
|
| 715 |
+
}
|
| 716 |
+
|
| 717 |
+
.msg-action-btn.confirm {
|
| 718 |
+
background: rgba(0, 230, 118, 0.1);
|
| 719 |
+
border: 1px solid rgba(0, 230, 118, 0.3);
|
| 720 |
+
color: var(--success);
|
| 721 |
+
}
|
| 722 |
+
|
| 723 |
+
.msg-action-btn.confirm:hover {
|
| 724 |
+
background: rgba(0, 230, 118, 0.2);
|
| 725 |
+
}
|
| 726 |
+
|
| 727 |
+
.msg-action-btn.revise {
|
| 728 |
+
background: rgba(255, 171, 64, 0.08);
|
| 729 |
+
border: 1px solid rgba(255, 171, 64, 0.25);
|
| 730 |
+
color: var(--warning);
|
| 731 |
+
}
|
| 732 |
+
|
| 733 |
+
.msg-action-btn.revise:hover {
|
| 734 |
+
background: rgba(255, 171, 64, 0.15);
|
| 735 |
+
}
|
| 736 |
+
|
| 737 |
+
.msg-confirmed {
|
| 738 |
+
font-family: var(--font-mono);
|
| 739 |
+
font-size: 10px;
|
| 740 |
+
color: var(--success);
|
| 741 |
+
margin-top: 6px;
|
| 742 |
+
letter-spacing: 0.5px;
|
| 743 |
+
}
|
| 744 |
+
|
| 745 |
/* Typing indicator */
|
| 746 |
.typing-indicator {
|
| 747 |
display: flex;
|
|
|
|
| 1674 |
const isCad = agentId === 'cad';
|
| 1675 |
|
| 1676 |
el.className = 'msg msg-agent';
|
| 1677 |
+
const msgId = 'msg-' + Date.now() + '-' + Math.random().toString(36).slice(2, 6);
|
| 1678 |
|
| 1679 |
let html = '<div class="msg-avatar" style="background: ' + color + ';">' + avatar + '</div>';
|
| 1680 |
html += '<div class="msg-agent-body">';
|
|
|
|
| 1686 |
html += '<br><a class="msg-view-code" onclick="openCodeModal()">▶ View code</a>';
|
| 1687 |
}
|
| 1688 |
|
| 1689 |
+
html += '</div>';
|
| 1690 |
+
|
| 1691 |
+
// Add confirm/revise buttons for agent recommendations (not system, not code-only)
|
| 1692 |
+
const isSystem = agentId === 'system';
|
| 1693 |
+
const isCodeOnly = isCad && msg.code;
|
| 1694 |
+
if (!isSystem && !isCodeOnly && msg.content && !msg.content.startsWith('NOT READY:')) {
|
| 1695 |
+
html += '<div class="msg-actions" id="' + msgId + '-actions">';
|
| 1696 |
+
html += '<button class="msg-action-btn confirm" onclick="confirmRecommendation(\'' + msgId + '\', \'' + escapeHtml(agentId) + '\')">CONFIRM</button>';
|
| 1697 |
+
html += '<button class="msg-action-btn revise" onclick="reviseRecommendation(\'' + msgId + '\', \'' + escapeHtml(agentId) + '\')">REVISE</button>';
|
| 1698 |
+
html += '</div>';
|
| 1699 |
+
}
|
| 1700 |
+
|
| 1701 |
+
html += '</div>';
|
| 1702 |
el.innerHTML = html;
|
| 1703 |
+
el.dataset.msgId = msgId;
|
| 1704 |
+
el.dataset.content = msg.content;
|
| 1705 |
}
|
| 1706 |
|
| 1707 |
container.appendChild(el);
|
| 1708 |
scrollChatToBottom();
|
| 1709 |
}
|
| 1710 |
|
| 1711 |
+
function confirmRecommendation(msgId, agentId) {
|
| 1712 |
+
const el = document.querySelector('[data-msg-id="' + msgId + '"]');
|
| 1713 |
+
if (!el) return;
|
| 1714 |
+
const content = el.dataset.content;
|
| 1715 |
+
const actions = document.getElementById(msgId + '-actions');
|
| 1716 |
+
if (actions) {
|
| 1717 |
+
actions.innerHTML = '<div class="msg-confirmed">CONFIRMED</div>';
|
| 1718 |
+
}
|
| 1719 |
+
// Send confirmation as user message so it updates design state
|
| 1720 |
+
const agentName = (AGENTS[agentId] || {}).name || agentId;
|
| 1721 |
+
sendMessage('Confirmed: ' + agentName + ': ' + content);
|
| 1722 |
+
}
|
| 1723 |
+
|
| 1724 |
+
function reviseRecommendation(msgId, agentId) {
|
| 1725 |
+
const el = document.querySelector('[data-msg-id="' + msgId + '"]');
|
| 1726 |
+
if (!el) return;
|
| 1727 |
+
const content = el.dataset.content;
|
| 1728 |
+
const actions = document.getElementById(msgId + '-actions');
|
| 1729 |
+
if (actions) actions.classList.add('resolved');
|
| 1730 |
+
// Pre-fill input with context for the user to edit
|
| 1731 |
+
const input = document.getElementById('chat-input');
|
| 1732 |
+
const agentName = (AGENTS[agentId] || {}).name || agentId;
|
| 1733 |
+
input.value = 'Regarding ' + agentName + '\'s suggestion: ';
|
| 1734 |
+
input.focus();
|
| 1735 |
+
input.setSelectionRange(input.value.length, input.value.length);
|
| 1736 |
+
}
|
| 1737 |
+
|
| 1738 |
function showTyping() {
|
| 1739 |
const container = document.getElementById('chat-messages');
|
| 1740 |
const el = document.createElement('div');
|