Timeout for switch lockout
This commit is contained in:
@@ -5,8 +5,10 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"g.fc.run/misc/byre/internal/api"
|
||||
"g.fc.run/misc/byre/internal/git"
|
||||
@@ -326,7 +328,7 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
|
||||
"Omit both task_id and project_id to clear the pane. "+
|
||||
"If the pane already shows that task (or project) on that tab, only the tab order changes and you are told so, even while the human is working in the pane. "+
|
||||
"Otherwise refused while the human is working in the right pane, unless it is on the project tab or what it shows is finished (a merged or discarded task, or an inbox tab with nothing left). "+
|
||||
"Also refused while the pane is on the project tab and the human's last action was starting a TODO item there, until they switch task or tab or message you.",
|
||||
"Also refused while the pane is on the project tab and the human started a TODO item there in the last 10 seconds, unless they switched task or tab or messaged you since; byre signals you \"The start hold is over\" when those 10 seconds pass with the pane still on the project tab.",
|
||||
`{"type": "object", "properties": {
|
||||
"task_id": {"type": "string"},
|
||||
"project_id": {"type": "string", "description": "Ignored when task_id is given."},
|
||||
@@ -357,8 +359,8 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
|
||||
focused := m.paneFocused[user.Login]
|
||||
startedTodo := m.startedTodo[user.Login]
|
||||
m.mu.Unlock()
|
||||
if startedTodo && current.Tab == api.TabProject {
|
||||
return "", fmt.Errorf("%w: the human just started a TODO item from the project tab and is likely to start more; tell them in chat instead", ErrConflict)
|
||||
if time.Since(startedTodo) < startHold && current.Tab == api.TabProject {
|
||||
return "", fmt.Errorf("%w: the human just started a TODO item from the project tab and is likely to start more; tell them in chat instead. The hold ends %s after that start, unless they move the pane or message you first; byre signals you \"The start hold is over\" when it ends", ErrConflict, startHold)
|
||||
}
|
||||
if focused && current.Tab != api.TabProject {
|
||||
finished, err := m.paneFinished(ctx, current)
|
||||
@@ -461,10 +463,49 @@ func (m *Manager) SetPaneFocus(login string, focused bool) {
|
||||
m.paneFocused[login] = focused
|
||||
}
|
||||
|
||||
const startHold = 10 * time.Second
|
||||
|
||||
const startHoldEnded = "The start hold is over: the human started a TODO item from the project tab 10 seconds ago and the pane is still there, so show works again."
|
||||
|
||||
func (m *Manager) setStartedTodo(login string, started bool) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.startedTodo[login] = started
|
||||
if !started {
|
||||
delete(m.startedTodo, login)
|
||||
return
|
||||
}
|
||||
at := time.Now()
|
||||
m.startedTodo[login] = at
|
||||
time.AfterFunc(startHold, func() {
|
||||
err := m.endStartHold(context.Background(), login, at)
|
||||
if err != nil {
|
||||
slog.Error("end start hold", "login", login, "err", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (m *Manager) endStartHold(ctx context.Context, login string, at time.Time) error {
|
||||
m.mu.Lock()
|
||||
current, ok := m.startedTodo[login]
|
||||
if !ok || !current.Equal(at) {
|
||||
m.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
delete(m.startedTodo, login)
|
||||
m.mu.Unlock()
|
||||
f, err := m.store.GetFocus(ctx, login)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f.Tab != api.TabProject {
|
||||
return nil
|
||||
}
|
||||
err = m.store.AddLeadInput(ctx, store.LeadInput{Owner: login, Kind: store.LeadSignal, Actor: "byre", Text: startHoldEnded})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.deliverLead(login)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) modelOr(model string, l *live) string {
|
||||
|
||||
Reference in New Issue
Block a user