Merge branch 'worktree-ui-refine'
This commit is contained in:
commit
c6b5af426c
2 changed files with 40 additions and 25 deletions
|
|
@ -825,18 +825,16 @@ func (al *AgentLoop) runAgentLoop(ctx context.Context, agent *AgentInstance, opt
|
||||||
// 5a. Auto-advance plan phases after LLM iteration
|
// 5a. Auto-advance plan phases after LLM iteration
|
||||||
postStatus := agent.ContextBuilder.GetPlanStatus()
|
postStatus := agent.ContextBuilder.GetPlanStatus()
|
||||||
if agent.ContextBuilder.HasActivePlan() && postStatus == "executing" {
|
if agent.ContextBuilder.HasActivePlan() && postStatus == "executing" {
|
||||||
// Intercept: if AI changed status from interviewing to executing,
|
// Intercept: if AI changed status to executing without user approval
|
||||||
// hijack to "review" and show the plan for user approval.
|
// (from interviewing or review), validate and set to "review".
|
||||||
if preStatus == "interviewing" {
|
if preStatus == "interviewing" || preStatus == "review" {
|
||||||
if err := agent.ContextBuilder.ValidatePlanStructure(); err != nil {
|
if err := agent.ContextBuilder.ValidatePlanStructure(); err != nil {
|
||||||
_ = agent.ContextBuilder.SetPlanStatus("interviewing")
|
_ = agent.ContextBuilder.SetPlanStatus("interviewing")
|
||||||
logger.WarnCF("agent", "Reverted plan to interviewing: "+err.Error(),
|
logger.WarnCF("agent", "Reverted plan to interviewing: "+err.Error(),
|
||||||
map[string]interface{}{"agent_id": agent.ID})
|
map[string]interface{}{"agent_id": agent.ID})
|
||||||
// Inject rejection so LLM knows what to fix
|
// Inject rejection into session history so LLM sees it next iteration
|
||||||
messages = append(messages, providers.Message{
|
rejectionMsg := "[System] Plan rejected: " + err.Error() + ". Fix and try again."
|
||||||
Role: "user",
|
agent.Sessions.AddMessage(opts.SessionKey, "user", rejectionMsg)
|
||||||
Content: "[System] Plan rejected: " + err.Error() + ". Fix and try again.",
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
_ = agent.ContextBuilder.SetPlanStatus("review")
|
_ = agent.ContextBuilder.SetPlanStatus("review")
|
||||||
if !constants.IsInternalChannel(opts.Channel) {
|
if !constants.IsInternalChannel(opts.Channel) {
|
||||||
|
|
|
||||||
|
|
@ -487,37 +487,47 @@
|
||||||
|
|
||||||
.slide-approve-track {
|
.slide-approve-track {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 52px;
|
height: 56px;
|
||||||
border-radius: 26px;
|
border-radius: 28px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
transition: background 0.3s, border-color 0.3s;
|
border: 1.5px solid;
|
||||||
|
border-image: linear-gradient(135deg, var(--btn), var(--glass-border)) 1;
|
||||||
|
border-image: none;
|
||||||
|
border-color: var(--btn);
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.18), inset 0 1px 0 rgba(255,255,255,0.08);
|
||||||
|
transition: background 0.3s, border-color 0.3s, box-shadow 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.slide-approve-track.approved {
|
.slide-approve-track.approved {
|
||||||
background: var(--done);
|
background: var(--done);
|
||||||
border-color: var(--done);
|
border-color: var(--done);
|
||||||
|
box-shadow: 0 0 16px rgba(76,175,80,0.4), 0 2px 8px rgba(0,0,0,0.18);
|
||||||
}
|
}
|
||||||
|
|
||||||
.slide-approve-thumb {
|
.slide-approve-thumb {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 2px;
|
top: 3px;
|
||||||
left: 2px;
|
left: 3px;
|
||||||
width: 48px;
|
width: 50px;
|
||||||
height: 48px;
|
height: 50px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: var(--btn);
|
background: var(--btn);
|
||||||
color: var(--btn-text);
|
color: var(--btn-text);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 700;
|
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
transition: left 0.3s cubic-bezier(0.25, 1, 0.5, 1);
|
transition: left 0.3s cubic-bezier(0.25, 1, 0.5, 1);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-approve-thumb svg {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.slide-approve-thumb.dragging {
|
.slide-approve-thumb.dragging {
|
||||||
|
|
@ -525,6 +535,11 @@
|
||||||
cursor: grabbing;
|
cursor: grabbing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes shimmer {
|
||||||
|
0%, 100% { opacity: 0.7; }
|
||||||
|
50% { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
.slide-approve-label {
|
.slide-approve-label {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
@ -534,17 +549,19 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
color: var(--hint);
|
color: var(--text);
|
||||||
font-size: 14px;
|
font-size: 15px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
transition: color 0.3s;
|
transition: color 0.3s;
|
||||||
|
animation: shimmer 2.5s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.slide-approve-track.approved .slide-approve-label {
|
.slide-approve-track.approved .slide-approve-label {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
animation: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -736,7 +753,7 @@ function renderPlanFromData(data) {
|
||||||
if (data.status === 'review') {
|
if (data.status === 'review') {
|
||||||
html += `<div class="slide-approve-wrap">
|
html += `<div class="slide-approve-wrap">
|
||||||
<div class="slide-approve-track glass glass-interactive">
|
<div class="slide-approve-track glass glass-interactive">
|
||||||
<div class="slide-approve-thumb">»</div>
|
<div class="slide-approve-thumb"><svg viewBox="0 0 24 24"><path d="M5 12h14m-6-6 6 6-6 6" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/></svg></div>
|
||||||
<div class="slide-approve-label">Slide to Approve</div>
|
<div class="slide-approve-label">Slide to Approve</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
@ -766,7 +783,7 @@ function setupSlideApprove() {
|
||||||
var thumbStartLeft = 0;
|
var thumbStartLeft = 0;
|
||||||
|
|
||||||
function getMaxLeft() {
|
function getMaxLeft() {
|
||||||
return track.offsetWidth - thumb.offsetWidth - 4; // 2px padding each side
|
return track.offsetWidth - thumb.offsetWidth - 6; // 3px padding each side
|
||||||
}
|
}
|
||||||
|
|
||||||
function onStart(e) {
|
function onStart(e) {
|
||||||
|
|
@ -775,7 +792,7 @@ function setupSlideApprove() {
|
||||||
thumb.classList.add('dragging');
|
thumb.classList.add('dragging');
|
||||||
var clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
var clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
||||||
startX = clientX;
|
startX = clientX;
|
||||||
thumbStartLeft = thumb.offsetLeft - 2; // subtract initial 2px offset
|
thumbStartLeft = thumb.offsetLeft - 3; // subtract initial 3px offset
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -784,7 +801,7 @@ function setupSlideApprove() {
|
||||||
var clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
var clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
||||||
var dx = clientX - startX;
|
var dx = clientX - startX;
|
||||||
var newLeft = Math.max(0, Math.min(thumbStartLeft + dx, getMaxLeft()));
|
var newLeft = Math.max(0, Math.min(thumbStartLeft + dx, getMaxLeft()));
|
||||||
thumb.style.left = (newLeft + 2) + 'px';
|
thumb.style.left = (newLeft + 3) + 'px';
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -792,7 +809,7 @@ function setupSlideApprove() {
|
||||||
if (!dragging) return;
|
if (!dragging) return;
|
||||||
dragging = false;
|
dragging = false;
|
||||||
thumb.classList.remove('dragging');
|
thumb.classList.remove('dragging');
|
||||||
var currentLeft = thumb.offsetLeft - 2;
|
var currentLeft = thumb.offsetLeft - 3;
|
||||||
var maxLeft = getMaxLeft();
|
var maxLeft = getMaxLeft();
|
||||||
if (currentLeft >= maxLeft * 0.8) {
|
if (currentLeft >= maxLeft * 0.8) {
|
||||||
// Approved
|
// Approved
|
||||||
|
|
@ -802,7 +819,7 @@ function setupSlideApprove() {
|
||||||
sendCommand('/plan start');
|
sendCommand('/plan start');
|
||||||
} else {
|
} else {
|
||||||
// Snap back
|
// Snap back
|
||||||
thumb.style.left = '2px';
|
thumb.style.left = '3px';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue