Open task views in a sheet over the left pane
This commit is contained in:
@@ -513,20 +513,19 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
|
||||
}),
|
||||
|
||||
tool("show",
|
||||
"Point the human's right pane at a task, or at a project with no task, and select one of its tabs. The tabs' order is fixed. "+
|
||||
"Point the human's right pane at a task, which shows its transcript (a workflow stage task's run: its graph and each stage's state, attempts and outputs), or at a project with no task, which shows the project's dashboard: its active tasks and its TODO.md items. "+
|
||||
"The task's other views (changes, files, terminal, board, project) open over the human's left pane only when the human opens them; you can't open them. "+
|
||||
"Whenever the human asks you to show something (\"show me that when you can\") or you want to show something, call show right away; never hold back because you expect a refusal, since only a refused show arranges byre's signal to try again. "+
|
||||
"Tabs: transcript, board (a team task's board: its agents' posts, the human's and yours), changes, files, terminal (the task's shells in its worktree, and buttons that start one running a saved command), workflow (a workflow stage task's run: its graph and each stage's state, attempts and outputs), project (the project's dashboard: its active tasks and its TODO.md items); with only project_id, only project shows anything. "+
|
||||
"Omit both task_id and project_id to clear the pane. "+
|
||||
"If the pane already shows that task (or project) on that tab, nothing changes and you are told so. "+
|
||||
"Otherwise refused for 10 seconds after the human last moved the pane themselves (switching task or tab), whatever else holds; if a show was refused for it, byre signals you \"The move hold is over\" when those 10 seconds pass without another move, and sends no signal otherwise. "+
|
||||
"Otherwise refused while the human is working in the right pane (focused in it, or with unsent text in it), unless it is on the project tab, or what it shows is finished (a merged or discarded task),"+
|
||||
"or it is on the transcript tab of a task whose agent is mid-turn, the human has no unsent text there, and either the human sent the message that started that turn since the pane last moved or the pane moved there 10 seconds ago or more; byre signals you \"Your right pane is free\" when either happens. "+
|
||||
"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; if a show was refused for it, byre signals you \"The start hold is over\" when those 10 seconds pass with the pane still on the project tab, and sends no signal otherwise.",
|
||||
"If the pane already shows that task (or project), nothing changes and you are told so. "+
|
||||
"Otherwise refused for 10 seconds after the human last moved the pane themselves (switching task), whatever else holds; if a show was refused for it, byre signals you \"The move hold is over\" when those 10 seconds pass without another move, and sends no signal otherwise. "+
|
||||
"Otherwise refused while the human is working on what the pane shows (focused in it or in a view of its task, or with unsent text there), unless it shows a project with no task, or what it shows is finished (a merged or discarded task), "+
|
||||
"or it shows a task whose agent is mid-turn, the human has no unsent text there, and either the human sent the message that started that turn since the pane last moved or the pane moved there 10 seconds ago or more; byre signals you \"Your right pane is free\" when either happens. "+
|
||||
"Also refused for 10 seconds after the human started a TODO item, unless they switched task or messaged you since; if a show was refused for it, byre signals you \"The start hold is over\" when those 10 seconds pass, and sends no signal otherwise.",
|
||||
`{"type": "object", "properties": {
|
||||
"task_id": {"type": "string"},
|
||||
"project_id": {"type": "string", "description": "Ignored when task_id is given."},
|
||||
"tab": {"type": "string", "enum": ["transcript", "board", "changes", "files", "terminal", "workflow", "project"]}
|
||||
}, "required": ["tab"]}`,
|
||||
"project_id": {"type": "string", "description": "Ignored when task_id is given."}
|
||||
}}`,
|
||||
func(ctx context.Context, user api.User, raw json.RawMessage) (string, error) {
|
||||
f := api.Focus{}
|
||||
err := json.Unmarshal(raw, &f)
|
||||
@@ -545,7 +544,7 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
|
||||
humanMoved := m.humanMoved[user.Login]
|
||||
since := time.Since(humanMoved)
|
||||
moveHeld := since < moveHold
|
||||
startHeld := !moveHeld && time.Since(m.startedTodo[user.Login]) < startHold && current.Tab == api.TabProject
|
||||
startHeld := !moveHeld && time.Since(m.startedTodo[user.Login]) < startHold
|
||||
if moveHeld {
|
||||
m.moveRefused[user.Login] = true
|
||||
}
|
||||
@@ -557,9 +556,9 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
|
||||
return "", fmt.Errorf("%w: the human moved the right pane %s ago, so it was left as it is; tell them in chat instead. The hold ends %s after their last move; byre signals you \"The move hold is over\" when it ends, because this show was refused", ErrConflict, since.Round(time.Second), moveHold)
|
||||
}
|
||||
if startHeld {
|
||||
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, because this show was refused", ErrConflict, startHold)
|
||||
return "", fmt.Errorf("%w: the human just started a TODO item 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, because this show was refused", ErrConflict, startHold)
|
||||
}
|
||||
if working && current.Tab != api.TabProject {
|
||||
if working && current.TaskId != nil {
|
||||
finished, err := m.paneFinished(ctx, current)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -572,7 +571,7 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
|
||||
}
|
||||
}
|
||||
if finished == "" && !waiting {
|
||||
return "", fmt.Errorf("%w: the human is working in the right pane, so it was left as it is; tell them in chat instead", ErrConflict)
|
||||
return "", fmt.Errorf("%w: the human is working on the task the right pane shows, so it was left as it is; tell them in chat instead", ErrConflict)
|
||||
}
|
||||
}
|
||||
err = m.SetFocus(ctx, user.Login, f, leadActor(user.Login))
|
||||
@@ -595,9 +594,6 @@ func (m *Manager) leadTools(l *live) []mcp.Tool {
|
||||
}
|
||||
|
||||
func (m *Manager) SetFocus(ctx context.Context, login string, f api.Focus, actor string) error {
|
||||
if !f.Tab.Valid() {
|
||||
return fmt.Errorf("%w: unknown tab %q", ErrInvalid, f.Tab)
|
||||
}
|
||||
if f.TaskId != nil && *f.TaskId == "" {
|
||||
f.TaskId = nil
|
||||
}
|
||||
@@ -672,9 +668,6 @@ func (m *Manager) endWatchHold(ctx context.Context, login string, at time.Time)
|
||||
}
|
||||
|
||||
func sameView(a, b api.Focus) bool {
|
||||
if a.Tab != b.Tab {
|
||||
return false
|
||||
}
|
||||
at, bt := deref(a.TaskId), deref(b.TaskId)
|
||||
if at != "" || bt != "" {
|
||||
return at == bt
|
||||
@@ -702,7 +695,7 @@ func (m *Manager) paneFinished(ctx context.Context, f api.Focus) (string, error)
|
||||
const watchHold = 10 * time.Second
|
||||
|
||||
func (m *Manager) paneWaiting(ctx context.Context, login string, f api.Focus) (bool, error) {
|
||||
if f.TaskId == nil || f.Tab != api.TabTranscript {
|
||||
if f.TaskId == nil {
|
||||
return false, nil
|
||||
}
|
||||
m.mu.Lock()
|
||||
@@ -751,7 +744,7 @@ func (m *Manager) endMoveHold(ctx context.Context, login string, at time.Time) e
|
||||
|
||||
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, and a show of yours was refused in that time, so show works again."
|
||||
const startHoldEnded = "The start hold is over: the human started a TODO item 10 seconds ago, and a show of yours was refused in that time, so show works again."
|
||||
|
||||
func (m *Manager) setStartedTodo(login string, started bool) {
|
||||
m.mu.Lock()
|
||||
@@ -785,13 +778,6 @@ func (m *Manager) endStartHold(ctx context.Context, login string, at time.Time)
|
||||
if !refused {
|
||||
return nil
|
||||
}
|
||||
f, err := m.store.GetFocus(ctx, login)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f.Tab != api.TabProject {
|
||||
return nil
|
||||
}
|
||||
return m.addLeadInput(ctx, store.LeadInput{Owner: login, Kind: store.LeadSignal, Actor: "byre", Text: startHoldEnded})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user